LCOV - code coverage report
Current view: top level - src/68_rsprc - m_prcref.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 74.8 % 1169 874
Test Date: 2026-09-19 15:24:51 Functions: 100.0 % 12 12

            Line data    Source code
       1              : !!****m* ABINIT/m_prcref
       2              : !! NAME
       3              : !!  m_prcref
       4              : !!
       5              : !! FUNCTION
       6              : !!  Routines to precondition residual potential (or density) and forces.
       7              : !!
       8              : !! COPYRIGHT
       9              : !!  Copyright (C) 1998-2026 ABINIT group (DCA, XG, MT, PMA)
      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              : !Include and generate MKL_RCI module
      23              : !#if defined HAVE_LINALG_MKL_OMATCOPY
      24              : !#include "mkl_rci.f90"
      25              : !#endif
      26              : 
      27              : module m_prcref
      28              : 
      29              :  use iso_c_binding
      30              :  use defs_basis
      31              :  use defs_wvltypes
      32              :  use m_errors
      33              :  use m_abicore
      34              :  use m_xmpi
      35              :  use m_xcdata
      36              :  use m_frskerker1
      37              :  use m_frskerker2
      38              :  use mod_prc_memory
      39              :  use m_dtset
      40              :  use m_precon
      41              : 
      42              :  use defs_datatypes, only : pseudopotential_type
      43              :  use defs_abitypes, only : MPI_type
      44              :  use m_time,     only : timab
      45              :  use m_numeric_tools, only : dotproduct
      46              :  use m_geometry, only : xcart2xred, metric
      47              :  use m_cgtools,  only : dotprod_vn, mean_fftr
      48              :  use m_mpinfo,   only : ptabs_fourdp, destroy_mpi_enreg, initmpi_seq
      49              :  use m_pawtab,   only : pawtab_type
      50              :  use m_pawrhoij, only : pawrhoij_type
      51              :  use m_rcpaw,    only : rcpaw_type
      52              :  use m_extfpmd,  only : extfpmd_type
      53              :  use m_fftcore,  only : kgindex
      54              :  use m_fft,      only : zerosym, indirect_parallel_fourier, fourdp
      55              :  use m_kg,       only : getph
      56              :  use m_spacepar, only : hartre, laplacian
      57              :  use m_forces,     only : fresid
      58              :  use m_atm2fft,    only : atm2fft
      59              :  use m_rhotoxc,    only : rhotoxc
      60              :  use m_mklocl,     only : mklocl
      61              :  use m_mkcore,     only : mkcore
      62              :  !use m_iterative_solvers, only : linsolve
      63              : 
      64              :  implicit none
      65              : 
      66              :  private
      67              : !!***
      68              : 
      69              :  public :: prcref
      70              :  public :: prcref_PMA
      71              :  public :: moddiel      ! Precondition the residual, using a model dielectric function.
      72              :  private :: chi0diel    ! Precondition the residual, using a model chi0 operator defined in the object precon.
      73              : 
      74              : !!***
      75              : 
      76              : contains
      77              : !!***
      78              : 
      79              : !!****f* ABINIT/prcref
      80              : !!
      81              : !! NAME
      82              : !! prcref
      83              : !!
      84              : !! FUNCTION
      85              : !! Compute preconditioned residual potential (or density) and forces.
      86              : !! iprcel, densfor_pred and iprcfc govern the choice of the preconditioner.
      87              : !! Three tasks are done:
      88              : !! 1) Preconditioning of the forces (residual has already been included)
      89              : !!     using the approximate force constant matrix. Get proposed
      90              : !!     change of atomic positions.
      91              : !! 2) Precondition the residual, get first part of proposed trial
      92              : !!     potential change.
      93              : !! 3) PAW only: precondition the rhoij residuals (simple preconditionning)
      94              : !! 4) Take into account the proposed change of atomic positions to
      95              : !!     modify the proposed trial potential change.
      96              : !!
      97              : !! NOTE
      98              : !! This routine is almost similar to prcref_PMA.F90 which is employed in
      99              : !! case of potential mixing. Yet it has undergone strong changes simultaneously
     100              : !! from two different sources at the same time which resulted in a splitting.
     101              : !!
     102              : !! INPUTS
     103              : !!  atindx(natom)=index table for atoms (see gstate.f)
     104              : !!  dielar(7)=input parameters for dielectric matrix:
     105              : !!                diecut,dielng,diemac,diemix,diegap,dielam,diemixmag.
     106              : !!  dielstrt=number of the step at which the dielectric preconditioning begins.
     107              : !!  dtset <type(dataset_type)>=all input variables in this dataset
     108              : !!   | intxc=control xc quadrature
     109              : !!   | densfor_pred= not yet used here
     110              : !!   | iprcel= governs the preconditioning of the potential residual
     111              : !!   |    0 => simple model dielectric matrix, described by the
     112              : !!   |              parameters dielng, diemac, diemix and diemixmag contained in dielar.
     113              : !!   |    between 21 and 39 => until istep=dielstart, same as iprcel=0, then uses
     114              : !!   |              the RPA dielectric matrix (routine dielmt)
     115              : !!   |    between 41 and 49 => uses the RPA dielectric matrix (routine dielmt).
     116              : !!   |    between 51 and 59 => uses the RPA dielectric matrix (routine dieltcel).
     117              : !!   |    between 61 and 69 => uses the electronic dielectric matr (routine dieltcel).
     118              : !!   |    between 71 and 79 => uses the real-space preconditioner based on Kerker prc (prcrskerkerN)
     119              : !!   |    between 81 and 99 => reserved for futur version of the real-space preconditioner
     120              : !!   |    between 141 and 169 -> same as between 41 and 69 but with a different periodicity: modulo(iprcel modulo (10))
     121              : !!   | iprcfc= governs the preconditioning of the forces
     122              : !!   |         0 => hessian is the identity matrix
     123              : !!   |         1 => hessian is 0.5 times the identity matrix
     124              : !!   |         2 => hessian is 0.25 times the identity matrix
     125              : !!   | ixc=exchange-correlation choice parameter.
     126              : !!   | natom=number of atoms
     127              : !!   | nspden=number of spin-density components
     128              : !!   | occopt=option for occupancies
     129              : !!   | prtvol=control print volume and debugging
     130              : !!   | typat(natom)=integer type for each atom in cell
     131              : !!  etotal=total ennergy
     132              : !!  extfpmd <type(extfpmd_type)>=extended first-principles molecular dynamics type
     133              : !!  fcart(3,natom)=cartesian forces (hartree/bohr)
     134              : !!  ffttomix(nfft*(1-nfftprc/nfft))=Index of the points of the FFT (fine) grid on the grid used for mixing (coarse)
     135              : !!  gmet(3,3)=metric tensor in G space in Bohr**-2.
     136              : !!  gsqcut=cutoff on (k+G)^2 (bohr^-2)
     137              : !!  istep= number of the step in the SCF cycle
     138              : !!  kg_diel(3,npwdiel)=reduced planewave coordinates for the dielectric matrix.
     139              : !!  mgfft=maximum size of 1D FFTs
     140              : !!  moved_atm_inside= if 1, then the preconditioned forces
     141              : !!    as well as the preconditioned potential residual must be computed;
     142              : !!    otherwise, compute only the preconditioned potential residual.
     143              : !!  mpi_enreg=information about MPI parallelization
     144              : !!  my_natom=number of atoms treated by current processor
     145              : !!  nattyp(ntypat)=number of atoms of each type in cell.
     146              : !!  nfft=number of fft grid points
     147              : !!  nfftprc=size of FFT grid on which the potential residual will be preconditionned
     148              : !!  ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
     149              : !!  ngfftprc(18)=contain all needed information about 3D FFT for the grid corresponding to nfftprc
     150              : !!  nkxc=second dimension of the array kxc, see rhotoxc.F90 for a description
     151              : !!  npawmix=-PAW only- number of spherical part elements to be mixed
     152              : !!  npwdiel=number of planewaves for dielectric matrix
     153              : !!  ntypat=number of types of atoms in cell.
     154              : !!  n1xccc=dimension of xccc1d ; 0 if no XC core correction is used
     155              : !!  optreal=1 if residual potential is is REAL space, 2 if it is in RECIPROCAL SPACE
     156              : !!  optres=0: the array vresid contains a potential residual
     157              : !!         1: the array vresid contains a density residual
     158              : !!  pawrhoij(my_natom*usepaw) <type(pawrhoij_type)>= paw rhoij occupancies and related data
     159              : !!                                    Use here rhoij residuals (and gradients)
     160              : !!  pawtab(ntypat*usepaw) <type(pawtab_type)>=paw tabulated starting data
     161              : !!  psps <type(pseudopotential_type)>=variables related to pseudopotentials
     162              : !!  rhog(2,nfft)=array for electron density in reciprocal space
     163              : !!  rhor(nfft,nspden)=array for electron density in electrons/bohr**3.
     164              : !!  rprimd(3,3)=dimensional primitive translations in real space (bohr)
     165              : !!  susmat(2,npwdiel,nspden,npwdiel,nspden)=
     166              : !!   the susceptibility (or density-density response) matrix in reciprocal space
     167              : !!  vresid(optreal*nfftprc,nspden)=residual potential
     168              : !!  vxc(nfft,nspden)=exchange-correlation potential (hartree)
     169              : !!  vhartr(nfft)=array for holding Hartree potential
     170              : !!  vlspl(mqgrid,2,ntypat)=q^2 v(q) spline for each type of atom.
     171              : !!  vpsp(nfft)=array for holding local psp
     172              : !!  xred(3,natom)=reduced dimensionless atomic coordinates
     173              : !!
     174              : !! OUTPUT
     175              : !!  dtn_pc(3,natom)=preconditioned change of atomic position,
     176              : !!                                          in reduced coordinates
     177              : !!  vrespc(optreal*nfftprc,nspden)=preconditioned residual of the potential
     178              : !!  ==== if psps%usepaw==1
     179              : !!    rhoijrespc(npawmix)= preconditionned rhoij residuals at output
     180              : !!
     181              : !! SIDE EFFECT
     182              : !!  dielinv(2,npwdiel,nspden,npwdiel,nspden)=
     183              : !!                              inverse of the dielectric matrix in rec. space
     184              : !!  kxc(nfft,nkxc)=exchange-correlation kernel,
     185              : !!       needed if the electronic dielectric matrix is computed
     186              : !!  ===== if densfor_pred==3 .and. moved_atm_inside==1 =====
     187              : !!    ph1d(2,3*(2*mgfft+1)*natom)=1-dim structure factor phases
     188              : !!
     189              : !! SOURCE
     190              : 
     191        12922 : subroutine prcref(atindx,dielar,dielinv,&
     192        12922 : &  dielstrt,dtn_pc,dtset,etotal,fcart,ffttomix,gmet,gsqcut,&
     193        12922 : &  istep,kg_diel,kxc,&
     194              : &  mgfft,moved_atm_inside,mpi_enreg,my_natom,&
     195        12922 : &  nattyp,nfft,nfftprc,ngfft,ngfftprc,nkxc,npawmix,npwdiel,ntypat,n1xccc,&
     196        12922 : &  optreal,optres,pawrhoij,pawtab,ph1d,precon,psps,rhog,rhoijrespc,rhor,rprimd,&
     197        12922 : &  susmat,vhartr,vpsp,vresid,vrespc,vxc,wvl,wvl_den,xred,rcpaw,extfpmd)
     198              : 
     199              : !Arguments-------------------------------
     200              : !scalars
     201              :  integer,intent(in) :: dielstrt,istep,my_natom,mgfft,moved_atm_inside,n1xccc
     202              :  integer,intent(in) :: nfft,nfftprc,nkxc,npawmix,npwdiel,ntypat,optreal,optres
     203              :  real(dp),intent(in) :: etotal,gsqcut
     204              :  type(MPI_type),intent(in) :: mpi_enreg
     205              :  type(dataset_type),intent(in) :: dtset
     206              :  type(pseudopotential_type),intent(in) :: psps
     207              :  type(wvl_internal_type), intent(in) :: wvl
     208              :  type(wvl_denspot_type), intent(inout) :: wvl_den
     209              :  type(rcpaw_type),intent(inout),pointer :: rcpaw
     210              :  type(extfpmd_type),intent(inout),pointer :: extfpmd
     211              :  type(precon_object), intent(inout) :: precon
     212              : 
     213              : !arrays
     214              :  integer,intent(in) :: atindx(dtset%natom),ffttomix(nfft*(1-nfftprc/nfft))
     215              :  integer,intent(in) :: kg_diel(3,npwdiel),nattyp(ntypat),ngfft(18),ngfftprc(18)
     216              :  real(dp),intent(in) :: dielar(7),fcart(3,dtset%natom),rhog(2,nfft)
     217              :  real(dp),intent(in) :: rhor(nfft,dtset%nspden)
     218              :  real(dp),intent(in) :: susmat(2,npwdiel,dtset%nspden,npwdiel,dtset%nspden)
     219              :  real(dp),intent(in) :: vhartr(nfft),vresid(nfftprc*optreal,dtset%nspden)
     220              :  real(dp),intent(in) :: vxc(nfft,dtset%nspden)
     221              :  real(dp),intent(inout) :: dielinv(2,npwdiel,dtset%nspden,npwdiel,dtset%nspden)
     222              :  real(dp),intent(inout) :: gmet(3,3),kxc(nfft,nkxc)
     223              :  real(dp),intent(inout) :: ph1d(2,3*(2*mgfft+1)*dtset%natom),vpsp(nfft)
     224              :  real(dp),intent(inout) :: xred(3,dtset%natom)
     225              :  real(dp),intent(out) :: dtn_pc(3,dtset%natom),rhoijrespc(npawmix),rprimd(3,3)
     226              :  real(dp),intent(out) :: vrespc(nfftprc*optreal,dtset%nspden)
     227              :  type(pawrhoij_type),intent(inout) :: pawrhoij(my_natom*psps%usepaw)
     228              :  type(pawtab_type),intent(in) :: pawtab(ntypat*psps%usepaw)
     229              : 
     230              : !Local variables-------------------------------
     231              : !scalars
     232              :  integer :: coredens_method,cplex,dielop,iatom,ier,ifft,ii,index,ipw1
     233              :  integer :: ipw2,iq,iq0,ispden,klmn,kmix,n1,n2,n3,n3xccc,nfftot,nk3xc,optatm
     234              :  integer :: optdyfr,opteltfr,optgr,option,optn,optn2,optstr,optv,vloc_method
     235              :  real(dp) :: ai,ar,diemix,diemixmag,eei,bigexc,bigsxc
     236              :  real(dp) :: mixfac
     237              :  real(dp) :: mixfac_eff,mixfacmag,ucvol,vxcavg
     238              :  logical :: computediel,non_magnetic_xc
     239              :  character(len=500) :: message
     240              :  type(xcdata_type) :: xcdata
     241              : !arrays
     242              :  integer :: qprtrb(3)
     243        12922 :  integer,allocatable :: indpw_prc(:)
     244              :  real(dp) :: dummy6(6),dummy7(6),gprimd(3,3),qphon(3),rmet(3,3)
     245        25844 :  real(dp) :: vmean(dtset%nspden),vprtrb(2)
     246        12922 :  real(dp),allocatable :: dummy(:),dummy1(:),dummy2(:),dummy3(:),dummy4(:),dummy5(:),dummy8(:),dummy9(:)
     247        12922 :  real(dp),allocatable :: dyfrlo_indx(:,:,:),dyfrx2(:,:,:)
     248        12922 :  real(dp),allocatable :: fcart_pc(:,:),gresid(:,:),grtn_indx(:,:)
     249        12922 :  real(dp),allocatable :: grxc(:,:),grxc_indx(:,:),rhog_wk(:,:),rhor_new(:,:)
     250        12922 :  real(dp),allocatable :: rhor_wk(:,:),rhor_wk0(:,:),vhartr_wk(:),vpsp_wk(:)
     251        12922 :  real(dp),allocatable :: vres_diel(:,:),vxc_wk(:,:),work(:),work1(:,:),work2(:)
     252        12922 :  real(dp),allocatable :: work3(:,:),xccc3d(:),xred_wk(:,:)
     253        12922 :  logical,allocatable :: mask(:)
     254              : ! *************************************************************************
     255              : 
     256              :  !Compute different geometric tensor, as well as ucvol, from rprimd
     257        12922 :  call metric(gmet,gprimd,-1,rmet,rprimd,ucvol)
     258              : 
     259              : !1) Eventually take care of the forces
     260              : 
     261        12922 :  if(moved_atm_inside==1)then
     262            0 :    ABI_MALLOC(fcart_pc,(3,dtset%natom))
     263              : 
     264            0 :    if(dtset%iprcfc==0)then
     265            0 :      fcart_pc(:,:)=fcart(:,:)
     266              :    else
     267            0 :      fcart_pc(:,:)= (two**dtset%iprcfc) * fcart(:,:)
     268              :    end if
     269              : 
     270              : !  Compute preconditioned delta xred from preconditioned fcart and rprimd
     271            0 :    call xcart2xred(dtset%natom,rprimd,fcart_pc,dtn_pc)
     272              : 
     273            0 :    ABI_FREE(fcart_pc)
     274              :  end if
     275              : 
     276              : !#######################################################################
     277              : 
     278              : !2) Take care of the potential residual
     279              : 
     280              : !Compute the residuals corresponding to the solution
     281              : !of an approximate realspace dielectric function according
     282              : !to X. Gonze PRB vol54 nb7 p4383 (1996) [[cite:Gonze1996]]
     283        12922 :  if(dtset%iprcel>=71.and.dtset%iprcel<=79) then
     284            0 :    if (nfft==nfftprc) then
     285            0 :      if (dtset%iprcel<=78) then
     286              :        call prcrskerker1(dtset,mpi_enreg,nfft,dtset%nspden,ngfft,dielar,etotal, &
     287            0 : &       gprimd,vresid,vrespc,rhor(:,1))
     288              :      else
     289              :        call prcrskerker2(dtset,nfft,dtset%nspden,ngfft,dielar,gprimd,rprimd, &
     290            0 : &       vresid,vrespc,dtset%natom,xred,mpi_enreg,ucvol)
     291              :      end if
     292              :    else
     293              : !    If preconditionning has to be done on a coarse grid,
     294              : !    has to transfer several arrays
     295            0 :      ABI_MALLOC(work1,(nfftprc,dtset%nspden))
     296            0 :      ABI_MALLOC(work3,(nfftprc,dtset%nspden))
     297            0 :      ABI_MALLOC(work,(2*nfftprc))
     298            0 :      do ispden=1,dtset%nspden
     299            0 :        work(:)=vresid(:,ispden)
     300            0 :        call fourdp(1,work,work1(:,ispden),+1,mpi_enreg,nfftprc,1,ngfftprc,0)
     301              :      end do
     302            0 :      ABI_FREE(work)
     303            0 :      if (dtset%iprcel<=78) then
     304            0 :        ABI_MALLOC(rhog_wk,(2,nfftprc))
     305            0 :        rhog_wk(:,:)=zero
     306            0 :        if (mpi_enreg%nproc_fft>1.and. mpi_enreg%paral_kgb==1) then
     307            0 :          nfftot=PRODUCT(ngfft(1:3))
     308              :          call indirect_parallel_Fourier(ffttomix,rhog_wk,mpi_enreg,ngfftprc,&
     309            0 : &         ngfft,nfftprc,nfft,dtset%paral_kgb,rhog,nfftot)
     310              :        else
     311            0 :          do ii=1,nfft
     312            0 :            if (ffttomix(ii)>0) rhog_wk(:,ffttomix(ii))=rhog(:,ii)
     313              :          end do
     314              :        end if
     315              :        call zerosym(rhog_wk,2,ngfftprc(1),ngfftprc(2),ngfftprc(3),&
     316            0 : &       comm_fft=mpi_enreg%comm_fft,distribfft=mpi_enreg%distribfft)
     317            0 :        ABI_MALLOC(work,(nfftprc))
     318            0 :        call fourdp(1,rhog_wk,work,+1,mpi_enreg,nfftprc,1,ngfftprc,0)
     319              :        call prcrskerker1(dtset,mpi_enreg,nfftprc,dtset%nspden,ngfftprc,dielar,etotal, &
     320            0 : &       gprimd,work1,work3,work)
     321            0 :        ABI_FREE(work)
     322              :      else
     323              :        call prcrskerker2(dtset,nfftprc,dtset%nspden,ngfftprc,dielar,gprimd,rprimd, &
     324            0 : &       work1,work3,dtset%natom,xred,mpi_enreg,ucvol)
     325              :      end if
     326            0 :      do ispden=1,dtset%nspden
     327            0 :        call fourdp(1,vrespc(:,ispden),work3(:,ispden),-1,mpi_enreg,nfftprc,1,ngfftprc,0)
     328              :      end do
     329            0 :      ABI_FREE(work1)
     330            0 :      ABI_FREE(work3)
     331              :    end if
     332              : 
     333              :  else
     334              : 
     335        12922 :    if(dtset%iprcel==0 .or. (dtset%iprcel<40.and.istep<dielstrt) )then
     336        12904 :      cplex=optreal
     337        12904 :      qphon(:)=zero
     338              : !    Simple scalar multiplication, or model dielectric function
     339        12904 :      call moddiel(cplex,dielar,mpi_enreg,nfftprc,ngfftprc,dtset%nspden,optreal,optres,qphon,rprimd,vresid,vrespc)
     340              : 
     341              : !    Use the inverse dielectric matrix in a small G sphere
     342           18 :    else if( (istep>=dielstrt .and. dtset%iprcel>=21 .and. dtset%iprcel<200) .or. modulo(dtset%iprcel,100)>=41 )then
     343              : 
     344              : !    With dielop=1, the matrices will be computed when istep=dielstrt
     345              : !    With dielop=2, the matrices will be computed when istep=dielstrt and 1
     346            0 :      dielop=1
     347            0 :      if(modulo(dtset%iprcel,100)>=41)dielop=2
     348            0 :      computediel = dtset%testsusmat(dielop, dielstrt, istep) !test if the matrix is to be computed
     349            0 :      if(computediel) then
     350              : !      Compute the inverse dielectric matrix from the susceptibility matrix
     351              : !      There are two routines for the RPA matrix, while for the electronic
     352              : !      dielectric matrix, only dieltcel will do the work
     353            0 :        if(modulo(dtset%iprcel,100)<=49)then
     354              :          call dielmt(dielinv,gmet,kg_diel,&
     355            0 : &         npwdiel,dtset%nspden,dtset%occopt,dtset%prtvol,susmat)
     356              :        else
     357            0 :          option=1
     358            0 :          if(modulo(dtset%iprcel,100)>=61)option=2
     359              :          call dieltcel(dielinv,gmet,kg_diel,kxc,&
     360            0 : &         nfft,ngfft,nkxc,npwdiel,dtset%nspden,dtset%occopt,option,dtset%prtvol,susmat)
     361              :        end if
     362              :      end if
     363              : 
     364            0 :      ABI_MALLOC(work1,(2,nfftprc))
     365            0 :      ABI_MALLOC(work2,(optreal*nfftprc))
     366              : 
     367              : !    Presently, one uses the inverse of the RPA dielectric matrix,
     368              : !    for which spin must be averaged.
     369              : 
     370              : !    Do fft from real space (work2) to G space (work1)
     371            0 :      if (optreal==1) then
     372            0 :        work2(:)=vresid(:,1)
     373              : !      Must average over spins in the case of a potential residual
     374            0 :        if(dtset%nspden/=1.and.optres==0)work2(:)=(work2(:)+vresid(:,2))*half
     375            0 :        call fourdp(1,work1,work2,-1,mpi_enreg,nfftprc,1,ngfftprc,0)
     376              :      else
     377            0 :        work1(:,:)=reshape(vresid(:,1),(/2,nfftprc/))
     378            0 :        if(dtset%nspden/=1.and.optres==0)work1(:,:)=(work1(:,:)+reshape(vresid(:,2),(/2,nfftprc/)))*half
     379              :      end if
     380              : 
     381              : !    Multiply by restricted inverse of dielectric matrix.
     382              : !    Must first copy relevant elements of work1 to a npwdiel-dimensioned array,
     383              : !    then zero work1, operate with the dielinv matrix, and store in work1.
     384              : 
     385            0 :      ABI_MALLOC(vres_diel,(2,npwdiel))
     386            0 :      ABI_MALLOC(indpw_prc,(npwdiel))
     387            0 :      ABI_MALLOC(mask,(npwdiel))
     388            0 :      mask(:)=.true.
     389            0 :      call kgindex(indpw_prc,kg_diel,mask,mpi_enreg,ngfftprc,npwdiel)
     390              : 
     391            0 :      do ipw1=1,npwdiel
     392            0 :        if(mask(ipw1)) then
     393            0 :          vres_diel(1,ipw1)=work1(1,indpw_prc(ipw1))
     394            0 :          vres_diel(2,ipw1)=work1(2,indpw_prc(ipw1))
     395              :        end if
     396              :      end do
     397            0 :      work1(:,:)=zero
     398            0 :      do ipw1=1,npwdiel
     399            0 :        ar=zero ; ai=zero
     400              : 
     401              : !      Use inverse of dielectric matrix (potential mixing)
     402            0 :        if (optres==0) then
     403            0 :          do ipw2=1,npwdiel
     404            0 :            if(mask(ipw2))then
     405              :              ar=ar+dielinv(1,ipw1,1,ipw2,1)*vres_diel(1,ipw2) &
     406            0 : &             -dielinv(2,ipw1,1,ipw2,1)*vres_diel(2,ipw2)
     407              :              ai=ai+dielinv(2,ipw1,1,ipw2,1)*vres_diel(1,ipw2) &
     408            0 : &             +dielinv(1,ipw1,1,ipw2,1)*vres_diel(2,ipw2)
     409              :            end if
     410              :          end do
     411              :        else
     412              : !        Use symetric of inverse of dielectric matrix (density mixing)
     413            0 :          do ipw2=1,npwdiel
     414            0 :            if(mask(ipw2))then
     415              :              ar=ar+dielinv(1,ipw2,1,ipw1,1)*vres_diel(1,ipw2) &
     416            0 : &             +dielinv(2,ipw2,1,ipw1,1)*vres_diel(2,ipw2)
     417              :              ai=ai-dielinv(2,ipw2,1,ipw1,1)*vres_diel(1,ipw2) &
     418            0 : &             +dielinv(1,ipw2,1,ipw1,1)*vres_diel(2,ipw2)
     419              :            end if
     420              :          end do
     421              :        end if
     422              : !      Must be careful not to count the diagonal 1 twice : it is added later,
     423              : !      so must be subtracted now.
     424            0 :        call xmpi_sum(ar,mpi_enreg%comm_fft,ier)
     425            0 :        call xmpi_sum(ai,mpi_enreg%comm_fft,ier)
     426            0 :        if(mask(ipw1)) then
     427            0 :          work1(1,indpw_prc(ipw1))=ar-vres_diel(1,ipw1)
     428            0 :          work1(2,indpw_prc(ipw1))=ai-vres_diel(2,ipw1)
     429              :        end if !mask(ipw1)
     430              :      end do ! ipw1
     431            0 :      ABI_FREE(vres_diel)
     432            0 :      ABI_FREE(indpw_prc)
     433            0 :      ABI_FREE(mask)
     434              : !    Fourier transform
     435            0 :      if (optreal==1) then
     436            0 :        call fourdp(1,work1,work2,1,mpi_enreg,nfftprc,1,ngfftprc,0)
     437              :      else
     438            0 :        work2(:)=reshape(work1(:,:),(/nfftprc*2/))
     439              :      end if
     440              : 
     441              : !    Add to get the preconditioned vresid, must be careful about spins.
     442            0 :      if(dtset%iprcel>=30)then
     443            0 :        diemix=dielar(4);diemixmag=abs(dielar(7))
     444            0 :        vrespc(:,1)=diemix*(vresid(:,1)+work2(:))
     445            0 :        if(dtset%nspden/=1.and.optres==0)vrespc(:,2)=diemixmag*(vresid(:,2)+work2(:))
     446            0 :        if(dtset%nspden==4.and.optres==0)vrespc(:,3:4)=diemixmag*vresid(:,3:4)
     447            0 :        if(dtset%nspden/=1.and.optres==1)vrespc(:,2:dtset%nspden)=diemixmag*vresid(:,2:dtset%nspden)
     448              :      else
     449            0 :        vrespc(:,1)=vresid(:,1)+work2(:)
     450            0 :        if(dtset%nspden/=1.and.optres==0)vrespc(:,2)=vresid(:,2)+work2(:)
     451            0 :        if(dtset%nspden==4.and.optres==0)vrespc(:,3:4)=vresid(:,3:4)
     452            0 :        if(dtset%nspden/=1.and.optres==1)vrespc(:,2:dtset%nspden)=vresid(:,2:dtset%nspden)
     453              :      end if
     454              : 
     455            0 :      ABI_FREE(work1)
     456            0 :      ABI_FREE(work2)
     457              : 
     458           18 :    else if (dtset%iprcel>=200 .and. dtset%iprcel<300) then
     459           18 :       call chi0diel(precon, dtset, mpi_enreg, optreal, optres, vresid, vrespc)
     460              : !    Other choice ?
     461              :  
     462              :    else
     463              :      write(message, '(a,i3,a,a,a,a)' )&
     464            0 : &     'From the calling routine, iprcel=',dtset%iprcel,ch10,&
     465            0 : &     'The only allowed values are 0 or larger than 20.',ch10,&
     466            0 : &     'Action: correct your input file.'
     467            0 :      ABI_ERROR(message)
     468              :    end if
     469              :  end if
     470              : !#######################################################################
     471              : 
     472              : !3) PAW : precondition the rhoij quantities (augmentation
     473              : !occupancies) residuals. Use a simple preconditionning
     474              : !with the same mixing factor as the model dielectric function.
     475              : ! RCPAW : precondition the core occupations residuals
     476              : !with the same mixing factor as the model dielectric function
     477              : ! Extfpmd : precondition the extfpmd number of electrons
     478              : !with the same mixing factor as the model dielectric function
     479              : 
     480        12922 :  if (istep>=dielstrt.and.dtset%iprcel>=21.and.dtset%iprcel<30) then
     481              :    mixfac=one;mixfacmag=one
     482              :  else
     483        12922 :    mixfac=dielar(4);mixfacmag=abs(dielar(7))
     484              :  end if
     485        12922 :  if (psps%usepaw==1.and.my_natom>0) then
     486        11261 :    if (pawrhoij(1)%cplex_rhoij==1) then
     487              :      index=0
     488        36945 :      do iatom=1,my_natom
     489        64362 :        do iq=1,pawrhoij(iatom)%qphase
     490        27417 :          iq0=merge(0,pawrhoij(iatom)%lmn2_size,iq==1)
     491        87312 :          do ispden=1,pawrhoij(iatom)%nspden
     492        32478 :            mixfac_eff=mixfac;if (ispden>1) mixfac_eff=mixfacmag
     493      2130107 :            do kmix=1,pawrhoij(iatom)%lmnmix_sz
     494      2070212 :              index=index+1;klmn=iq0+pawrhoij(iatom)%kpawmix(kmix)
     495      2102690 :              rhoijrespc(index)=mixfac_eff*pawrhoij(iatom)%rhoijres(klmn,ispden)
     496              :            end do
     497              :          end do
     498              :        end do
     499              :      end do
     500              :    else
     501              :      index=-1
     502         4212 :      do iatom=1,my_natom
     503         6691 :        do iq=1,pawrhoij(iatom)%qphase
     504         2479 :          iq0=merge(0,2*pawrhoij(iatom)%lmn2_size,iq==1)
     505        13833 :          do ispden=1,pawrhoij(iatom)%nspden
     506         8875 :            mixfac_eff=mixfac;if (ispden>1) mixfac_eff=mixfacmag
     507       918130 :            do kmix=1,pawrhoij(iatom)%lmnmix_sz
     508       906776 :              index=index+2;klmn=iq0+2*pawrhoij(iatom)%kpawmix(kmix)-1
     509      2729203 :              rhoijrespc(index:index+1)=mixfac_eff*pawrhoij(iatom)%rhoijres(klmn:klmn+1,ispden)
     510              :            end do
     511              :          end do
     512              :        end do
     513              :      end do
     514              :    end if
     515              :  end if
     516              : 
     517        12922 :  if (psps%usepaw==1.and.associated(rcpaw)) then
     518           18 :    mixfac_eff=mixfac!;if (ispden>1) mixfac_eff=mixfacmag
     519           36 :    do iatom=1,rcpaw%ntypat
     520           36 :      if(rcpaw%atm(iatom)%zcore_orig>zero) then
     521          108 :        rcpaw%atm(iatom)%occ_respc=mixfac_eff*rcpaw%atm(iatom)%occ_res
     522              :      endif
     523              :    enddo
     524              :  endif
     525              : 
     526        12922 :  if(associated(extfpmd)) then
     527           83 :    mixfac_eff=mixfac!;if (ispden>1) mixfac_eff=mixfacmag
     528           83 :    extfpmd%nelect_respc=mixfac_eff*extfpmd%nelect_res
     529              :  endif
     530              : 
     531              : 
     532              : !#######################################################################
     533              : 
     534              : !4) Take care of the change of atomic positions
     535              : !Note : this part is very demanding on memory...
     536              : !however, since this algorithm is still in development,
     537              : !it was NOT included in the estimation provided by memory.f
     538        12922 :  if(abs(dtset%densfor_pred)==3 .and. moved_atm_inside==1)then
     539              : 
     540              : !  Not yet compatible with resid given in reciprocal space
     541            0 :    if (optreal/=1) then
     542              :      write(message, '(5a)' )&
     543            0 : &     'From the calling routine, densfor_pred=3',ch10,&
     544            0 : &     'You cannot use residuals in reciprocal space.',ch10,&
     545            0 : &     'Action: correct your input file.'
     546            0 :      ABI_ERROR(message)
     547              :    end if
     548              : !  Not compatible with non-collinear magnetism
     549            0 :    if(dtset%nspden==4)then
     550            0 :      ABI_ERROR('densfor_pred=3 does not work for nspden=4 !')
     551              :    end if
     552              : 
     553            0 :    n1=ngfft(1) ; n2=ngfft(2) ; n3=ngfft(3)
     554            0 :    nfftot=PRODUCT(ngfft(1:3))
     555              : 
     556            0 :    if (optres==0) then  ! Array vresid contains a potential residual
     557              : !    -----------------------------------------------------------------
     558              : 
     559              : !    First subtract the current local, hartree and exchange correlation potentials
     560            0 :      do ispden=1,min(dtset%nspden,2)
     561            0 :        vrespc(:,ispden)=vrespc(:,ispden)-vpsp(:)-vhartr(:)-vxc(:,ispden)
     562              :      end do
     563            0 :      if (dtset%nspden==4) then
     564            0 :        do ispden=3,4
     565            0 :          vrespc(:,ispden)=vrespc(:,ispden)-vxc(:,ispden)
     566              :        end do
     567              :      end if
     568              : 
     569              : !    Compute the modified density, in rhor_wk
     570            0 :      option=2
     571            0 :      ABI_MALLOC(gresid,(3,dtset%natom))
     572            0 :      ABI_MALLOC(grxc,(3,dtset%natom))
     573            0 :      ABI_MALLOC(rhor_wk,(nfft,dtset%nspden))
     574            0 :      ABI_MALLOC(rhor_wk0,(nfft,dtset%nspden))
     575            0 :      ABI_MALLOC(xred_wk,(3,dtset%natom))
     576            0 :      xred_wk(:,:)=xred(:,:)+dtn_pc(:,:)
     577              :      call fresid(dtset,gresid,mpi_enreg,nfft,ngfft,&
     578              : &     ntypat,option,pawtab,rhor,rprimd,&
     579            0 : &     ucvol,rhor_wk,xred_wk,xred,psps%znuclpsp)
     580              : 
     581              : !    Compute up+down rhog_wk(G) by fft
     582            0 :      ABI_MALLOC(work,(nfft))
     583            0 :      ABI_MALLOC(rhog_wk,(2,nfft))
     584            0 :      work(:)=rhor_wk(:,1)
     585            0 :      call fourdp(1,rhog_wk,work,-1,mpi_enreg,nfft,1,ngfft,0)
     586            0 :      ABI_FREE(work)
     587              : 
     588              : !    Compute structure factor phases for new atomic pos:
     589            0 :      call getph(atindx,dtset%natom,n1,n2,n3,ph1d,xred_wk)
     590              : 
     591              : !    Compute local ionic pseudopotential vpsp:
     592              : !    and core electron density xccc3d, if needed.
     593            0 :      n3xccc=0;if (n1xccc/=0) n3xccc=nfft
     594            0 :      ABI_MALLOC(xccc3d,(n3xccc))
     595            0 :      ABI_MALLOC(vpsp_wk,(nfft))
     596            0 :      vprtrb(1:2)=zero
     597              : 
     598              : !    Determine by which method the local ionic potential and/or
     599              : !    the pseudo core charge density contributions have to be computed
     600              : !    Local ionic potential:
     601              : !     Method 1: PAW
     602              : !     Method 2: Norm-conserving PP, icoulomb>0, wavelets
     603            0 :      vloc_method=1;if (psps%usepaw==0) vloc_method=2
     604            0 :      if (dtset%icoulomb>0) vloc_method=2
     605            0 :      if (psps%usewvl==1) vloc_method=2
     606              : !    Pseudo core charge density:
     607              : !     Method 1: PAW, nc_xccc_gspace
     608              : !     Method 2: Norm-conserving PP, wavelets
     609              :      coredens_method=1;if (psps%usepaw==0) coredens_method=2
     610            0 :      if (psps%nc_xccc_gspace==1) coredens_method=1
     611            0 :      if (psps%nc_xccc_gspace==0) coredens_method=2
     612            0 :      if (psps%usewvl==1) coredens_method=2
     613              : 
     614              : !    Local ionic potential and/or pseudo core charge by method 1
     615            0 :      if (vloc_method==1.or.coredens_method==1) then
     616            0 :        optv=0;if (vloc_method==1) optv=1
     617            0 :        optn=0;if (coredens_method==1) optn=n3xccc/nfft
     618            0 :        optatm=1;optdyfr=0;optgr=0;optstr=0;optn2=1;opteltfr=0
     619              : !      Note: atindx1 should be passed to atm2fft (instead of atindx) but it is unused...
     620              :        call atm2fft(atindx,xccc3d,vpsp,dummy,dummy2,dummy9,dummy1,gmet,gprimd,dummy3,dummy4,gsqcut,&
     621              : &       mgfft,psps%mqgrid_vl,dtset%natom,nattyp,nfft,ngfft,ntypat,optatm,optdyfr,opteltfr,optgr,optn,optn2,&
     622              : &       optstr,optv,psps,pawtab,ph1d,psps%qgrid_vl,qprtrb,dtset%rcut,dummy5,rprimd,dummy6,dummy7,&
     623              : &       ucvol,psps%usepaw,dummy8,dummy8,dummy8,vprtrb,psps%vlspl,&
     624              : &       comm_fft=mpi_enreg%comm_fft,me_g0=mpi_enreg%me_g0,&
     625            0 : &       paral_kgb=mpi_enreg%paral_kgb,distribfft=mpi_enreg%distribfft)
     626              :      end if
     627              : 
     628              : !    Local ionic potential by method 2
     629            0 :      if (vloc_method==2) then
     630            0 :        option=1
     631            0 :        ABI_MALLOC(dyfrlo_indx,(3,3,dtset%natom))
     632            0 :        ABI_MALLOC(grtn_indx,(3,dtset%natom))
     633              :        call mklocl(dtset,dyfrlo_indx,eei,gmet,gprimd,grtn_indx,gsqcut,dummy6,&
     634              : &       mgfft,mpi_enreg,dtset%natom,nattyp,nfft,ngfft,dtset%nspden,&
     635              : &       ntypat,option,pawtab,ph1d,psps,qprtrb,rhog_wk,rhor_wk,rprimd,&
     636            0 : &       ucvol,vprtrb,vpsp_wk,wvl,wvl_den,xred)
     637            0 :        ABI_FREE(dyfrlo_indx)
     638            0 :        ABI_FREE(grtn_indx)
     639              :      end if
     640              : 
     641              : !    Pseudo core electron density by method 2
     642            0 :      if (coredens_method==2.and.n1xccc/=0) then
     643            0 :        option=1
     644            0 :        ABI_MALLOC(dyfrx2,(3,3,dtset%natom))
     645            0 :        ABI_MALLOC(grxc_indx,(3,dtset%natom))
     646              :        call mkcore(dummy6,dyfrx2,grxc_indx,mpi_enreg,dtset%natom,nfft,dtset%nspden,ntypat,&
     647              : &       n1,n1xccc,n2,n3,option,rprimd,dtset%typat,ucvol,vxc,psps%xcccrc,&
     648            0 : &       psps%xccc1d,xccc3d,xred_wk)
     649            0 :        ABI_FREE(dyfrx2)
     650            0 :        ABI_FREE(grxc_indx)
     651              :      end if
     652              : 
     653              : !    Compute Hartree+xc potentials
     654            0 :      ABI_MALLOC(vxc_wk,(nfft,dtset%nspden))
     655            0 :      ABI_MALLOC(vhartr_wk,(nfft))
     656            0 :      option=1
     657              : 
     658              :      call hartre(1,gsqcut,dtset%icutcoul,psps%usepaw,mpi_enreg,nfft,ngfft,&
     659            0 :                  &dtset%nkpt,dtset%rcut,rhog_wk,rprimd,dtset%vcutgeo,vhartr_wk)
     660              : 
     661              : !    Prepare the call to rhotoxc
     662            0 :      call xcdata_init(xcdata,dtset=dtset)
     663            0 :      nk3xc=1 ; non_magnetic_xc=(dtset%usepaw==1.and.mod(abs(dtset%usepawu),10)==4)
     664              :      call rhotoxc(bigexc,bigsxc,kxc,mpi_enreg,nfft,ngfft,&
     665              : &     work,0,work,0,nkxc,nk3xc,non_magnetic_xc,n3xccc,option,rhor_wk,rprimd,1,&
     666            0 : &     vxc_wk,vxcavg,xccc3d,xcdata,vhartr=vhartr_wk)
     667            0 :      ABI_FREE(xccc3d)
     668              : 
     669              : !    Sum all contributions
     670            0 :      do ispden=1,min(dtset%nspden,2)
     671            0 :        do ifft=1,nfft
     672            0 :          vrespc(ifft,ispden)=vrespc(ifft,ispden)+vpsp_wk(ifft)+vhartr_wk(ifft)+vxc_wk(ifft,ispden)
     673              :        end do
     674              :      end do
     675            0 :      if (dtset%nspden==4) then
     676            0 :        do ispden=3,4
     677            0 :          do ifft=1,nfft
     678            0 :            vrespc(ifft,ispden)=vrespc(ifft,ispden)+vxc_wk(ifft,ispden)
     679              :          end do
     680              :        end do
     681              :      end if
     682            0 :      call mean_fftr(vrespc,vmean,nfft,nfftot,dtset%nspden,mpi_comm_sphgrid=mpi_enreg%comm_fft)
     683            0 :      if(dtset%nspden==2) then
     684            0 :        vmean(1)=half*(vmean(1)+vmean(2))
     685            0 :        vmean(2)=vmean(1)
     686              :      end if
     687            0 :      do ispden=1,dtset%nspden
     688            0 :        vrespc(:,ispden)=vrespc(:,ispden)-vmean(ispden)
     689              :      end do
     690            0 :      ABI_FREE(gresid)
     691            0 :      ABI_FREE(grxc)
     692            0 :      ABI_FREE(rhog_wk)
     693            0 :      ABI_FREE(rhor_wk)
     694            0 :      ABI_FREE(rhor_wk0)
     695            0 :      ABI_FREE(xred_wk)
     696            0 :      ABI_FREE(vhartr_wk)
     697            0 :      ABI_FREE(vpsp_wk)
     698            0 :      ABI_FREE(vxc_wk)
     699              : 
     700              :    else                 ! Array vresid contains a density residual
     701              : !    -----------------------------------------------------------------
     702              : 
     703              : !    Only have to compute the modified preconditionned density residual
     704            0 :      option=2
     705            0 :      ABI_MALLOC(gresid,(3,dtset%natom))
     706            0 :      ABI_MALLOC(grxc,(3,dtset%natom))
     707            0 :      ABI_MALLOC(rhor_new,(nfft,dtset%nspden))
     708            0 :      ABI_MALLOC(rhor_wk,(nfft,dtset%nspden))
     709            0 :      ABI_MALLOC(rhor_wk0,(nfft,dtset%nspden))
     710            0 :      ABI_MALLOC(xred_wk,(3,dtset%natom))
     711            0 :      xred_wk(:,:)=xred(:,:)+dtn_pc(:,:)
     712            0 :      rhor_new(:,1)=rhor(:,1)+vrespc(:,1)
     713            0 :      if (dtset%nspden==2) then
     714            0 :        rhor_new(:,1)=rhor_new(:,1)+vrespc(:,2)
     715            0 :        rhor_new(:,2)=rhor(:,2)+vrespc(:,1)
     716              :      end if
     717              :      call fresid(dtset,gresid,mpi_enreg,nfft,ngfft,&
     718              : &     ntypat,option,pawtab,rhor,rprimd,&
     719            0 : &     ucvol,rhor_wk0,xred_wk,xred,psps%znuclpsp)
     720              :      call fresid(dtset,gresid,mpi_enreg,nfft,ngfft,&
     721              : &     ntypat,option,pawtab,rhor_new,rprimd,&
     722            0 : &     ucvol,rhor_wk,xred_wk,xred,psps%znuclpsp)
     723            0 :      vrespc(:,1)=rhor_wk(:,dtset%nspden)-rhor_wk0(:,dtset%nspden)
     724            0 :      if (dtset%nspden==2) vrespc(:,2)=rhor_wk(:,1)-rhor_wk0(:,1)-vrespc(:,1)
     725            0 :      ABI_FREE(gresid)
     726            0 :      ABI_FREE(grxc)
     727            0 :      ABI_FREE(rhor_new)
     728            0 :      ABI_FREE(rhor_wk)
     729            0 :      ABI_FREE(rhor_wk0)
     730            0 :      ABI_FREE(xred_wk)
     731              :    end if
     732              : 
     733              :  end if
     734              : 
     735        12922 : end subroutine prcref
     736              : !!***
     737              : 
     738              : !!****f* ABINIT/prcref_PMA
     739              : !!
     740              : !! NAME
     741              : !! prcref_PMA
     742              : !!
     743              : !! FUNCTION
     744              : !! Compute preconditioned residual potential (or density) and forces.
     745              : !! iprcel, densfor_pred and iprcfc govern the choice of the preconditioner.
     746              : !! Three tasks are done:
     747              : !! 1) Preconditioning of the forces (residual has already been included)
     748              : !!     using the approximate force constant matrix. Get proposed
     749              : !!     change of atomic positions.
     750              : !! 2) Precondition the residual, get first part of proposed trial
     751              : !!     potential change.
     752              : !! 3) PAW only: precondition the rhoij residuals (simple preconditionning)
     753              : !! 4) Take into account the proposed change of atomic positions to
     754              : !!     modify the proposed trial potential change.
     755              : !!
     756              : !! NOTE
     757              : !! This routine is almost similar to prcref.F90 which is employed in
     758              : !! case of density mixing. Yet it has undergone strong changes simultaneously
     759              : !! from two different sources at the same time which resulted in a splitting.
     760              : !!
     761              : !! INPUTS
     762              : !!  atindx(natom)=index table for atoms (see gstate.f)
     763              : !!  dielar(7)=input parameters for dielectric matrix:
     764              : !!                diecut,dielng,diemac,diemix,diegap,dielam,diemixmag.
     765              : !!  dielstrt=number of the step at which the dielectric preconditioning begins.
     766              : !!  dtset <type(dataset_type)>=all input variables in this dataset
     767              : !!   | intxc=control xc quadrature
     768              : !!   | densfor_pred= not yet used here
     769              : !!   | iprcel= governs the preconditioning of the potential residual
     770              : !!   |    0 => simple model dielectric matrix, described by the
     771              : !!   |              parameters dielng, diemac, diemix and diemixmag contained in dielar.
     772              : !!   |    between 21 and 39 => until istep=dielstart, same as iprcel=0, then uses
     773              : !!   |              the RPA dielectric matrix (routine dielmt)
     774              : !!   |    between 41 and 49 => uses the RPA dielectric matrix (routine dielmt).
     775              : !!   |    between 51 and 59 => uses the RPA dielectric matrix (routine dieltcel).
     776              : !!   |    between 61 and 69 => uses the electronic dielectric matr (routine dieltcel).
     777              : !!   |    between 71 and 79 => uses the real-space preconditioner based on Kerker prc (prcrskerkerN)
     778              : !!   |    between 81 and 99 => reserved for futur version of the real-space preconditioner
     779              : !!   |    between 141 and 169 -> same as between 41 and 69 but with a different periodicity: modulo(iprcel modulo (10))
     780              : !!   | iprcfc= governs the preconditioning of the forces
     781              : !!   |         0 => hessian is the identity matrix
     782              : !!   |         1 => hessian is 0.5 times the identity matrix
     783              : !!   |         2 => hessian is 0.25 times the identity matrix
     784              : !!   | ixc=exchange-correlation choice parameter.
     785              : !!   | natom=number of atoms
     786              : !!   | nspden=number of spin-density components
     787              : !!   | occopt=option for occupancies
     788              : !!   | prtvol=control print volume and debugging
     789              : !!   | typat(natom)=integer type for each atom in cell
     790              : !!  fcart(3,natom)=cartesian forces (hartree/bohr)
     791              : !!  ffttomix(nfft*(1-nfftprc/nfft))=Index of the points of the FFT (fine) grid on the grid used for mixing (coarse)
     792              : !!  gmet(3,3)=metric tensor in G space in Bohr**-2.
     793              : !!  gsqcut=cutoff on (k+G)^2 (bohr^-2)
     794              : !!  istep= number of the step in the SCF cycle
     795              : !!  kg_diel(3,npwdiel)=reduced planewave coordinates for the dielectric matrix.
     796              : !!  mgfft=maximum size of 1D FFTs
     797              : !!  moved_atm_inside= if 1, then the preconditioned forces
     798              : !!    as well as the preconditioned potential residual must be computed;
     799              : !!    otherwise, compute only the preconditioned potential residual.
     800              : !!  mpi_enreg=information about MPI parallelization
     801              : !!  my_natom=number of atoms treated by current processor
     802              : !!  nattyp(ntypat)=number of atoms of each type in cell.
     803              : !!  nfft=number of fft grid points
     804              : !!  nfftprc=size of FFT grid on which the potential residual will be preconditionned
     805              : !!  ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
     806              : !!  ngfftprc(18)=contain all needed information about 3D FFT for the grid corresponding to nfftprc
     807              : !!  nkxc=second dimension of the array kxc, see rhotoxc.f for a description
     808              : !!  npawmix=-PAW only- number of spherical part elements to be mixed
     809              : !!  npwdiel=number of planewaves for dielectric matrix
     810              : !!  ntypat=number of types of atoms in cell.
     811              : !!  n1xccc=dimension of xccc1d ; 0 if no XC core correction is used
     812              : !!  optreal=1 if residual potential is is REAL space, 2 if it is in RECIPROCAL SPACE
     813              : !!  optres=0: the array vresid contains a potential residual
     814              : !!         1: the array vresid contains a density residual
     815              : !!  pawrhoij(my_natom) <type(pawrhoij_type)>= paw rhoij occupancies and related data
     816              : !!                                    Use here rhoij residuals (and gradients)
     817              : !!  psps <type(pseudopotential_type)>=variables related to pseudopotentials
     818              : !!  rhog(2,nfft)=array for electron density in reciprocal space
     819              : !!  rhor(nfft,nspden)=array for electron density in electrons/bohr**3.
     820              : !!  rprimd(3,3)=dimensional primitive translations in real space (bohr)
     821              : !!  susmat(2,npwdiel,nspden,npwdiel,nspden)=
     822              : !!   the susceptibility (or density-density response) matrix in reciprocal space
     823              : !!  vresid(optreal*nfftprc,nspden)=residual potential
     824              : !!  vxc(nfft,nspden)=exchange-correlation potential (hartree)
     825              : !!  vhartr(nfft)=array for holding Hartree potential
     826              : !!  vlspl(mqgrid,2,ntypat)=q^2 v(q) spline for each type of atom.
     827              : !!  vpsp(nfft)=array for holding local psp
     828              : !!  xred(3,natom)=reduced dimensionless atomic coordinates
     829              : !!
     830              : !!  etotal
     831              : !!  pawtab
     832              : !!
     833              : !! OUTPUT
     834              : !!  dtn_pc(3,natom)=preconditioned change of atomic position,
     835              : !!                                          in reduced coordinates
     836              : !!  vrespc(optreal*nfftprc,nspden)=preconditioned residual of the potential
     837              : !!  ==== if psps%usepaw==1
     838              : !!    rhoijrespc(npawmix)= preconditionned rhoij residuals at output
     839              : !!
     840              : !! SIDE EFFECT
     841              : !!  dielinv(2,npwdiel,nspden,npwdiel,nspden)=
     842              : !!                              inverse of the dielectric matrix in rec. space
     843              : !!  kxc(nfft,nkxc)=exchange-correlation kernel,
     844              : !!       needed if the electronic dielectric matrix is computed
     845              : !!  ===== if densfor_pred==3 .and. moved_atm_inside==1 =====
     846              : !!    ph1d(2,3*(2*mgfft+1)*natom)=1-dim structure factor phases
     847              : !!
     848              : !! SOURCE
     849              : 
     850        28280 :   subroutine prcref_PMA(atindx,dielar,dielinv,&
     851        28280 : &  dielstrt,dtn_pc,dtset,fcart,ffttomix,gmet,gsqcut,&
     852        28280 : &  istep,kg_diel,kxc,&
     853              : &  mgfft,moved_atm_inside,mpi_enreg,my_natom,&
     854        28280 : &  nattyp,nfft,nfftprc,ngfft,ngfftprc,nkxc,npawmix,npwdiel,ntypat,n1xccc,&
     855        28280 : &  optreal,optres,pawrhoij,ph1d,precon,psps,rhog, rhoijrespc,rhor,rprimd,&
     856        28280 : &  susmat,vhartr,vpsp,vresid,vrespc,vxc,xred,&
     857        28280 : &  etotal,pawtab,wvl)
     858              : 
     859              : !Arguments-------------------------------
     860              : !variables used for tfvw
     861              : !scalars
     862              :  integer,intent(in) :: dielstrt,istep,mgfft,moved_atm_inside,my_natom,n1xccc
     863              :  integer,intent(in) :: nfft,nfftprc,nkxc,npawmix,npwdiel,ntypat
     864              :  integer,intent(in) :: optreal,optres
     865              :  real(dp),intent(in) :: etotal,gsqcut
     866              :  type(MPI_type),intent(in) :: mpi_enreg
     867              :  type(dataset_type),intent(in) :: dtset
     868              :  type(pseudopotential_type),intent(in) :: psps
     869              :  type(wvl_data), intent(inout) :: wvl
     870              :  type(precon_object), intent(inout) :: precon
     871              : 
     872              : !arrays
     873              :  integer,intent(in) :: atindx(dtset%natom),ffttomix(nfft*(1-nfftprc/nfft))
     874              :  integer,intent(in) :: kg_diel(3,npwdiel),nattyp(ntypat),ngfft(18),ngfftprc(18)
     875              :  real(dp),intent(in) :: dielar(7),fcart(3,dtset%natom)
     876              :  real(dp),intent(in) :: rhog(2,nfft)
     877              :  real(dp),intent(in) :: rhor(nfft,dtset%nspden)
     878              :  real(dp),intent(in) :: susmat(2,npwdiel,dtset%nspden,npwdiel,dtset%nspden)
     879              :  real(dp),intent(in) :: vhartr(nfft),vresid(nfftprc*optreal,dtset%nspden)
     880              :  real(dp),intent(in) :: vxc(nfft,dtset%nspden)
     881              :  real(dp),intent(inout) :: dielinv(2,npwdiel,dtset%nspden,npwdiel,dtset%nspden)
     882              :  real(dp),intent(inout) :: gmet(3,3),kxc(nfft,nkxc)
     883              :  real(dp),intent(inout) :: ph1d(2,3*(2*mgfft+1)*dtset%natom),vpsp(nfft)
     884              :  real(dp),intent(inout) :: xred(3,dtset%natom),rprimd(3,3)
     885              :  real(dp),intent(out) :: dtn_pc(3,dtset%natom),rhoijrespc(npawmix)
     886              :  real(dp),intent(out) :: vrespc(nfftprc*optreal,dtset%nspden)
     887              :  type(pawrhoij_type),intent(inout) :: pawrhoij(my_natom*psps%usepaw)
     888              :  type(pawtab_type),intent(in) :: pawtab(ntypat*psps%usepaw)
     889              : 
     890              : !Local variables-------------------------------
     891              : !scalars
     892              :  integer :: coredens_method,cplex,dielop,iatom,ier,ifft,ii,index,ipw1
     893              :  integer :: ipw2,ispden,klmn,kmix,n1,n2,n3,n3xccc,nfftot,nk3xc,optatm
     894              :  integer :: optdyfr,opteltfr,optgr,option,optn,optn2,optstr,optv,vloc_method
     895              :  real(dp) :: ai,ar,diemix,diemixmag,eei,bigexc,bigsxc
     896              :  real(dp) :: mixfac
     897              :  real(dp) :: mixfac_eff,mixfacmag,ucvol,vxcavg
     898              :  logical :: computediel,non_magnetic_xc
     899              :  character(len=500) :: message
     900              :  type(xcdata_type) :: xcdata
     901              : !arrays
     902              :  integer :: qprtrb(3)
     903        28280 :  integer,allocatable :: indpw_prc(:)
     904              :  real(dp) :: dummy6(6),gprimd(3,3),qphon(3),rmet(3,3)
     905        56560 :  real(dp) :: vmean(dtset%nspden),vprtrb(2)
     906        28280 :  real(dp),allocatable :: dummy_in(:)
     907              :  real(dp) :: dummy_out1(0),dummy_out2(0),dummy_out3(0),dummy_out4(0),dummy_out5(0),dummy_out6(0),dummy_out7(0)
     908        28280 :  real(dp),allocatable :: dyfrlo_indx(:,:,:),dyfrx2(:,:,:)
     909        28280 :  real(dp),allocatable :: fcart_pc(:,:),gresid(:,:),grtn_indx(:,:)
     910        28280 :  real(dp),allocatable :: grxc(:,:),grxc_indx(:,:),rhog_wk(:,:)
     911        28280 :  real(dp),allocatable :: rhor_wk(:,:),rhor_wk0(:,:),vhartr_wk(:),vpsp_wk(:)
     912        28280 :  real(dp),allocatable :: vres_diel(:,:),vxc_wk(:,:),work(:),work1(:,:),work2(:)
     913        28280 :  real(dp),allocatable :: work3(:,:),xccc3d(:),xred_wk(:,:)
     914        28280 :  logical,allocatable :: mask(:)
     915              : ! *************************************************************************
     916              : 
     917        28280 :  if(optres==1)then
     918            0 :    ABI_ERROR('density mixing (optres=1) not admitted!')
     919              :  end if
     920              : 
     921              : !Compute different geometric tensor, as well as ucvol, from rprimd
     922        28280 :  call metric(gmet,gprimd,-1,rmet,rprimd,ucvol)
     923              : 
     924              : !1) Eventually take care of the forces
     925              : 
     926        28280 :  if(moved_atm_inside==1)then
     927          330 :    ABI_MALLOC(fcart_pc,(3,dtset%natom))
     928              : 
     929          110 :    if(dtset%iprcfc==0)then
     930          288 :      fcart_pc(:,:)=fcart(:,:)
     931              :    else
     932         1158 :      fcart_pc(:,:)= (two**dtset%iprcfc) * fcart(:,:)
     933              :    end if
     934              : 
     935              : !  Compute preconditioned delta xred from preconditioned fcart and rprimd
     936          110 :    call xcart2xred(dtset%natom,rprimd,fcart_pc,dtn_pc)
     937              : 
     938          110 :    ABI_FREE(fcart_pc)
     939              :  end if
     940              : 
     941              : !#######################################################################
     942              : 
     943              : !2) Take care of the potential residual
     944              : 
     945              : !Compute the residuals corresponding to the solution
     946              : !of an approximate realspace dielectric function according
     947              : !to X. Gonze PRB vol54 nb7 p4383 (1996) [[cite:Gonze1996]]
     948        28280 :  if(dtset%iprcel>=71.and.dtset%iprcel<=79) then
     949           11 :    if (nfft==nfftprc) then
     950           11 :      if (dtset%iprcel<=78) then
     951              :        call prcrskerker1(dtset,mpi_enreg,nfft,dtset%nspden,ngfft,dielar,etotal, &
     952            7 : &       gprimd,vresid,vrespc,rhor(:,1))
     953              :      else
     954              :        call prcrskerker2(dtset,nfft,dtset%nspden,ngfft,dielar,gprimd,rprimd, &
     955            4 : &       vresid,vrespc,dtset%natom,xred,mpi_enreg,ucvol)
     956              :      end if
     957              :    else
     958              : !    If preconditionning has to be done on a coarse grid,
     959              : !    has to transfer several arrays
     960            0 :      ABI_MALLOC(work1,(nfftprc,dtset%nspden))
     961            0 :      ABI_MALLOC(work3,(nfftprc,dtset%nspden))
     962            0 :      ABI_MALLOC(work,(2*nfftprc))
     963            0 :      do ispden=1,dtset%nspden
     964            0 :        work(:)=vresid(:,ispden)
     965            0 :        call fourdp(1,work,work1(:,ispden),+1,mpi_enreg,nfftprc,1,ngfftprc,0)
     966              :      end do
     967            0 :      ABI_FREE(work)
     968            0 :      if (dtset%iprcel<=78) then
     969            0 :        ABI_MALLOC(rhog_wk,(2,nfftprc))
     970            0 :        rhog_wk(:,:)=zero
     971            0 :        if (mpi_enreg%nproc_fft>1.and. mpi_enreg%paral_kgb==1) then
     972            0 :          nfftot=PRODUCT(ngfft(1:3))
     973              :          call indirect_parallel_Fourier(ffttomix,rhog_wk,mpi_enreg,ngfftprc,&
     974            0 : &         ngfft,nfftprc,nfft,dtset%paral_kgb,rhog,nfftot)
     975              :        else
     976            0 :          do ii=1,nfft
     977            0 :            if (ffttomix(ii)>0) rhog_wk(:,ffttomix(ii))=rhog(:,ii)
     978              :          end do
     979              :        end if
     980              :        call zerosym(rhog_wk,2,ngfftprc(1),ngfftprc(2),ngfftprc(3),&
     981            0 : &       comm_fft=mpi_enreg%comm_fft,distribfft=mpi_enreg%distribfft)
     982            0 :        ABI_MALLOC(work,(nfftprc))
     983            0 :        call fourdp(1,rhog_wk,work,+1,mpi_enreg,nfftprc,1,ngfftprc,0)
     984              :        call prcrskerker1(dtset,mpi_enreg,nfftprc,dtset%nspden,ngfftprc,dielar,etotal, &
     985            0 : &       gprimd,work1,work3,work)
     986            0 :        ABI_FREE(work)
     987              :      else
     988              :        call prcrskerker2(dtset,nfftprc,dtset%nspden,ngfftprc,dielar,gprimd,rprimd, &
     989            0 : &       work1,work3,dtset%natom,xred,mpi_enreg,ucvol)
     990              :      end if
     991            0 :      do ispden=1,dtset%nspden
     992            0 :        call fourdp(1,vrespc(:,ispden),work3(:,ispden),-1,mpi_enreg,nfftprc,1,ngfftprc,0)
     993              :      end do
     994            0 :      ABI_FREE(work1)
     995            0 :      ABI_FREE(work3)
     996              :    end if
     997              : 
     998              :  else
     999              : 
    1000        28269 :    if(dtset%iprcel==0 .or. (dtset%iprcel<40.and.istep<dielstrt) )then
    1001        27923 :      cplex=optreal
    1002        27923 :      qphon(:)=zero
    1003              : !    Simple scalar multiplication, or model dielectric function
    1004        27923 :      call moddiel(cplex,dielar,mpi_enreg,nfftprc,ngfftprc,dtset%nspden,optreal,optres,qphon,rprimd,vresid,vrespc)
    1005              : 
    1006              : !    Use the inverse dielectric matrix in a small G sphere
    1007          346 :    else if( (istep>=dielstrt .and. dtset%iprcel>=21 .and. dtset%iprcel<200) .or. modulo(dtset%iprcel,100)>=41 )then
    1008              : 
    1009              : !    Wnith dielop=1, the matrices will be computed when istep=dielstrt
    1010              : !    With dielop=2, the matrices will be computed when istep=dielstrt and 1
    1011          346 :      dielop=1
    1012          346 :      if(modulo(dtset%iprcel,100)>=41)dielop=2
    1013          346 :      computediel = dtset%testsusmat(dielop, dielstrt, istep) !test if the matrix is to be computed
    1014          346 :      if(computediel) then
    1015              : !      Compute the inverse dielectric matrix from the susceptibility matrix
    1016              : !      There are two routines for the RPA matrix, while for the electronic
    1017              : !      dielectric matrix, only dieltcel will do the work
    1018           74 :        if(modulo(dtset%iprcel,100)<=49)then
    1019              :          call dielmt(dielinv,gmet,kg_diel,&
    1020           68 : &         npwdiel,dtset%nspden,dtset%occopt,dtset%prtvol,susmat)
    1021              :        else
    1022            6 :          option=1
    1023            6 :          if(modulo(dtset%iprcel,100)>=61)option=2
    1024              :          call dieltcel(dielinv,gmet,kg_diel,kxc,&
    1025            6 : &         nfft,ngfft,nkxc,npwdiel,dtset%nspden,dtset%occopt,option,dtset%prtvol,susmat)
    1026              :        end if
    1027              :      end if
    1028              : 
    1029         1038 :      ABI_MALLOC(work1,(2,nfftprc))
    1030         1038 :      ABI_MALLOC(work2,(optreal*nfftprc))
    1031              : 
    1032              : !    Presently, one uses the inverse of the RPA dielectric matrix,
    1033              : !    for which spin must be averaged.
    1034              : 
    1035              : !    Do fft from real space (work2) to G space (work1)
    1036          346 :      if (optreal==1) then
    1037      3628122 :        work2(:)=vresid(:,1)
    1038              : !      Must average over spins if needed.
    1039       228346 :        if(dtset%nspden/=1)work2(:)=(work2(:)+vresid(:,2))*half
    1040          346 :        call fourdp(1,work1,work2,-1,mpi_enreg,nfftprc,1,ngfftprc,0)
    1041              :      else
    1042            0 :        work1(:,:)=reshape(vresid(:,1),(/2,nfftprc/))
    1043            0 :        if (dtset%nspden/=1) work1(:,:)=(work1(:,:)+reshape(vresid(:,2),(/2,nfftprc/)))*half
    1044              :      end if
    1045              : 
    1046              : !    Multiply by restricted inverse of dielectric matrix.
    1047              : !    Must first copy relevant elements of work1 to a npwdiel-dimensioned array,
    1048              : !    then zero work1, operate with the dielinv matrix, and store in work1.
    1049              : 
    1050         1038 :      ABI_MALLOC(vres_diel,(2,npwdiel))
    1051         1038 :      ABI_MALLOC(indpw_prc,(npwdiel))
    1052          692 :      ABI_MALLOC(mask,(npwdiel))
    1053        64568 :      mask(:)=.true.
    1054          346 :      call kgindex(indpw_prc,kg_diel,mask,mpi_enreg,ngfftprc,npwdiel)
    1055        64568 :      do ipw1=1,npwdiel
    1056        64568 :        if(mask(ipw1)) then
    1057        64222 :          vres_diel(1,ipw1)=work1(1,indpw_prc(ipw1))
    1058        64222 :          vres_diel(2,ipw1)=work1(2,indpw_prc(ipw1))
    1059              :        end if
    1060              :      end do
    1061              : 
    1062     10883674 :      work1(:,:)=zero
    1063        64568 :      do ipw1=1,npwdiel
    1064        64222 :        ar=zero ; ai=zero
    1065              : 
    1066              : !      Use inverse of dielectric matrix (potential mixing)
    1067     17247856 :        do ipw2=1,npwdiel
    1068     17247856 :          if(mask(ipw2))then
    1069              :            ar=ar+dielinv(1,ipw1,1,ipw2,1)*vres_diel(1,ipw2) &
    1070     17183634 : &           -dielinv(2,ipw1,1,ipw2,1)*vres_diel(2,ipw2)
    1071              :            ai=ai+dielinv(2,ipw1,1,ipw2,1)*vres_diel(1,ipw2) &
    1072     17183634 : &           +dielinv(1,ipw1,1,ipw2,1)*vres_diel(2,ipw2)
    1073              :          end if
    1074              :        end do
    1075              : !      Must be careful not to count the diagonal 1 twice : it is added later,
    1076              : !      so must be subtracted now.
    1077        64222 :        call xmpi_sum(ar,mpi_enreg%comm_fft,ier)
    1078        64222 :        call xmpi_sum(ai,mpi_enreg%comm_fft,ier)
    1079        64568 :        if(mask(ipw1)) then
    1080        64222 :          work1(1,indpw_prc(ipw1))=ar-vres_diel(1,ipw1)
    1081        64222 :          work1(2,indpw_prc(ipw1))=ai-vres_diel(2,ipw1)
    1082              :        end if !mask(ipw1)
    1083              :      end do ! ipw1
    1084          346 :      ABI_FREE(vres_diel)
    1085          346 :      ABI_FREE(indpw_prc)
    1086          346 :      ABI_FREE(mask)
    1087              : 
    1088              : !    Fourier transform
    1089          346 :      if (optreal==1) then
    1090          346 :        call fourdp(1,work1,work2,1,mpi_enreg,nfftprc,1,ngfftprc,0)
    1091              :      else
    1092            0 :        work2(:)=reshape(work1(:,:),(/nfftprc*2/))
    1093              :      end if
    1094              : 
    1095              : !    Add to get the preconditioned vresid, must be careful about spins.
    1096          346 :      if(dtset%iprcel>=30)then
    1097          309 :        diemix=dielar(4);diemixmag=abs(dielar(7))
    1098      3286133 :        vrespc(:,1)=diemix*(vresid(:,1)+work2(:))
    1099          309 :        if(dtset%nspden/=1)vrespc(:,2)=diemixmag*(vresid(:,2)+work2(:))
    1100          309 :        if(dtset%nspden==4)vrespc(:,3:4)=diemixmag*vresid(:,3:4)
    1101              :      else
    1102       341989 :        vrespc(:,1)=vresid(:,1)+work2(:)
    1103       228037 :        if(dtset%nspden/=1)vrespc(:,2)=vresid(:,2)+work2(:)
    1104           37 :        if(dtset%nspden==4)vrespc(:,3:4)=vresid(:,3:4)
    1105              :      end if
    1106              : 
    1107          346 :      ABI_FREE(work1)
    1108          346 :      ABI_FREE(work2)
    1109              : 
    1110            0 :    else if (dtset%iprcel>=200 .and. dtset%iprcel<300) then
    1111            0 :      call chi0diel(precon, dtset, mpi_enreg, optreal, optres, vresid, vrespc)
    1112              :  
    1113              : !    Other choice ?
    1114              :    else
    1115              :      write(message, '(a,i0,a,a,a,a)' )&
    1116            0 : &     'From the calling routine, iprcel= ',dtset%iprcel,ch10,&
    1117            0 : &     'The only allowed values are 0 or larger than 20.',ch10,&
    1118            0 : &     'Action: correct your input file.'
    1119            0 :      ABI_ERROR(message)
    1120              :    end if
    1121              :  end if
    1122              : !#######################################################################
    1123              : 
    1124              : !3) PAW only : precondition the rhoij quantities (augmentation
    1125              : !occupancies) residuals. Use a simple preconditionning
    1126              : !with the same mixing factor as the model dielectric function.
    1127              : 
    1128        28280 :  if (psps%usepaw==1.and.my_natom>0) then
    1129          782 :    if (istep>=dielstrt.and.dtset%iprcel>=21.and.dtset%iprcel<30) then
    1130              :      mixfac=one;mixfacmag=one
    1131              :    else
    1132          782 :      mixfac=dielar(4);mixfacmag=abs(dielar(7))
    1133              :    end if
    1134          782 :    if (pawrhoij(1)%cplex_rhoij==1) then
    1135              :      index=0
    1136         1921 :      do iatom=1,my_natom
    1137         3675 :        do ispden=1,pawrhoij(iatom)%nspden
    1138         1754 :          mixfac_eff=mixfac;if (ispden>1) mixfac_eff=mixfacmag
    1139       243057 :          do kmix=1,pawrhoij(iatom)%lmnmix_sz
    1140       240164 :            index=index+1;klmn=pawrhoij(iatom)%kpawmix(kmix)
    1141       241918 :            rhoijrespc(index)=mixfac_eff*pawrhoij(iatom)%rhoijres(klmn,ispden)
    1142              :          end do
    1143              :        end do
    1144              :      end do
    1145              :    else
    1146              :      index=-1
    1147            0 :      do iatom=1,my_natom
    1148            0 :        do ispden=1,pawrhoij(iatom)%nspden
    1149            0 :          mixfac_eff=mixfac;if (ispden>1) mixfac_eff=mixfacmag
    1150            0 :          do kmix=1,pawrhoij(iatom)%lmnmix_sz
    1151            0 :            index=index+2;klmn=2*pawrhoij(iatom)%kpawmix(kmix)-1
    1152            0 :            rhoijrespc(index:index+1)=mixfac_eff*pawrhoij(iatom)%rhoijres(klmn:klmn+1,ispden)
    1153              :          end do
    1154              :        end do
    1155              :      end do
    1156              :    end if
    1157              :  end if
    1158              : !#######################################################################
    1159              : 
    1160              : !4) Take care of the change of atomic positions
    1161              : !Note : this part is very demanding on memory...
    1162              : !however, since this algorithm is still in development,
    1163              : !it was NOT included in the estimation provided by memory.f
    1164        28280 :  if(abs(dtset%densfor_pred)==3 .and. moved_atm_inside==1)then
    1165              : 
    1166              : !  Not yet compatible with resid given in reciprocal space
    1167           41 :    if (optreal/=1) then
    1168              :      write(message, '(5a)' )&
    1169            0 : &     'From the calling routine, densfor_pred=3',ch10,&
    1170            0 : &     'You cannot use residuals in reciprocal space.',ch10,&
    1171            0 : &     'Action: correct your input file.'
    1172            0 :      ABI_ERROR(message)
    1173              :    end if
    1174              : 
    1175              : !  Not compatible with non-collinear magnetism
    1176           41 :    if(dtset%nspden==4)then
    1177            0 :      ABI_ERROR('densfor_pred=3 does not work for nspden=4!')
    1178              :    end if
    1179              : 
    1180           41 :    n1=ngfft(1) ; n2=ngfft(2) ; n3=ngfft(3)
    1181          164 :    nfftot=PRODUCT(ngfft(1:3))
    1182              : 
    1183              : !  First subtract the current local, hartree and exchange correlation potentials
    1184          123 :    do ispden=1,min(dtset%nspden,2)
    1185       984123 :      vrespc(:,ispden)=vrespc(:,ispden)-vpsp(:)-vhartr(:)-vxc(:,ispden)
    1186              :    end do
    1187           41 :    if (dtset%nspden==4) then
    1188            0 :      do ispden=3,4
    1189            0 :        vrespc(:,ispden)=vrespc(:,ispden)-vxc(:,ispden)
    1190              :      end do
    1191              :    end if
    1192              : 
    1193              : !  Compute the modified density, in rhor_wk
    1194           41 :    option=2
    1195          123 :    ABI_MALLOC(gresid,(3,dtset%natom))
    1196           82 :    ABI_MALLOC(grxc,(3,dtset%natom))
    1197          164 :    ABI_MALLOC(rhor_wk,(nfft,dtset%nspden))
    1198          123 :    ABI_MALLOC(rhor_wk0,(nfft,dtset%nspden))
    1199           82 :    ABI_MALLOC(xred_wk,(3,dtset%natom))
    1200          369 :    xred_wk(:,:)=xred(:,:)+dtn_pc(:,:)
    1201              : 
    1202              :    call fresid(dtset,gresid,mpi_enreg,nfft,ngfft,&
    1203              : &   ntypat,option,pawtab,rhor,rprimd,&
    1204           41 : &   ucvol,rhor_wk,xred_wk,xred,psps%znuclpsp)
    1205              : 
    1206              : !  Compute up+down rhog_wk(G) by fft
    1207          123 :    ABI_MALLOC(work,(nfft))
    1208          123 :    ABI_MALLOC(rhog_wk,(2,nfft))
    1209       492041 :    work(:)=rhor_wk(:,1)
    1210           41 :    call fourdp(1,rhog_wk,work,-1,mpi_enreg,nfft,1,ngfft,0)
    1211           41 :    ABI_FREE(work)
    1212              : 
    1213              : !  Compute structure factor phases for new atomic pos:
    1214           41 :    call getph(atindx,dtset%natom,n1,n2,n3,ph1d,xred_wk)
    1215              : 
    1216              : !  Compute local ionic pseudopotential vpsp:
    1217              : !  and core electron density xccc3d, if needed.
    1218           41 :    n3xccc=0;if (n1xccc/=0) n3xccc=nfft
    1219          123 :    ABI_MALLOC(xccc3d,(n3xccc))
    1220           82 :    ABI_MALLOC(vpsp_wk,(nfft))
    1221           41 :    vprtrb(1:2)=zero
    1222              : 
    1223              : !  Determine by which method the local ionic potential and/or
    1224              : !  the pseudo core charge density have to be computed
    1225              : !  Local ionic potential:
    1226              : !   Method 1: PAW
    1227              : !   Method 2: Norm-conserving PP, icoulomb>0, wavelets
    1228           41 :    vloc_method=1;if (psps%usepaw==0) vloc_method=2
    1229           41 :    if (dtset%icoulomb>0) vloc_method=2
    1230           41 :    if (psps%usewvl==1) vloc_method=2
    1231              : !  Pseudo core charge density:
    1232              : !   Method 1: PAW, nc_xccc_gspace
    1233              : !   Method 2: Norm-conserving PP, wavelets
    1234              :    coredens_method=1;if (psps%usepaw==0) coredens_method=2
    1235           41 :    if (psps%nc_xccc_gspace==1) coredens_method=1
    1236           41 :    if (psps%nc_xccc_gspace==0) coredens_method=2
    1237           41 :    if (psps%usewvl==1) coredens_method=2
    1238              : 
    1239              : !  Local ionic potential and/or pseudo core charge by method 1
    1240           41 :    if (vloc_method==1.or.coredens_method==1) then
    1241            0 :      optv=0;if (vloc_method==1) optv=1
    1242            0 :      optn=0;if (coredens_method==1) optn=n3xccc/nfft
    1243            0 :      optatm=1;optdyfr=0;opteltfr=0;optgr=0;optstr=0;optn2=1
    1244              : !    Note: atindx1 should be passed to atm2fft (instead of atindx) but it is unused...
    1245              :      call atm2fft(atindx,xccc3d,vpsp,dummy_out1,dummy_out2,dummy_out3,dummy_in,gmet,&
    1246              : &     gprimd,dummy_out4,dummy_out5,gsqcut,mgfft,psps%mqgrid_vl,dtset%natom,nattyp,&
    1247              : &     nfft,ngfft,ntypat,optatm,optdyfr,opteltfr,optgr,optn,optn2,optstr,optv,&
    1248              : &     psps,pawtab,ph1d,psps%qgrid_vl,qprtrb,dtset%rcut,dummy_in,rprimd,dummy_out6,dummy_out7,ucvol,&
    1249              : &     psps%usepaw,dummy_in,dummy_in,dummy_in,vprtrb,psps%vlspl,&
    1250              : &     comm_fft=mpi_enreg%comm_fft,me_g0=mpi_enreg%me_g0,&
    1251            0 : &     paral_kgb=mpi_enreg%paral_kgb,distribfft=mpi_enreg%distribfft)
    1252              :    end if
    1253              : 
    1254              : !  Local ionic potential by method 2
    1255           41 :    if (vloc_method==2) then
    1256           41 :      option=1
    1257          123 :      ABI_MALLOC(dyfrlo_indx,(3,3,dtset%natom))
    1258           82 :      ABI_MALLOC(grtn_indx,(3,dtset%natom))
    1259              :      call mklocl(dtset,dyfrlo_indx,eei,gmet,gprimd,grtn_indx,gsqcut,dummy6,&
    1260              : &     mgfft,mpi_enreg,dtset%natom,nattyp,nfft,ngfft,dtset%nspden,&
    1261              : &     ntypat,option,pawtab,ph1d,psps,qprtrb,rhog_wk,rhor_wk,rprimd,&
    1262           41 : &     ucvol,vprtrb,vpsp_wk,wvl%descr,wvl%den,xred)
    1263           41 :      ABI_FREE(dyfrlo_indx)
    1264           41 :      ABI_FREE(grtn_indx)
    1265              :    end if
    1266              : 
    1267              : !  Pseudo core electron density by method 2
    1268           41 :    if (coredens_method==2.and.n1xccc/=0) then
    1269           41 :      option=1
    1270          123 :      ABI_MALLOC(dyfrx2,(3,3,dtset%natom))
    1271           82 :      ABI_MALLOC(grxc_indx,(3,dtset%natom))
    1272              :      call mkcore(dummy6,dyfrx2,grxc_indx,mpi_enreg,dtset%natom,nfft,dtset%nspden,ntypat,&
    1273              : &     n1,n1xccc,n2,n3,option,rprimd,dtset%typat,ucvol,vxc,psps%xcccrc,&
    1274           41 : &     psps%xccc1d,xccc3d,xred_wk)
    1275           41 :      ABI_FREE(dyfrx2)
    1276           41 :      ABI_FREE(grxc_indx)
    1277              :    end if
    1278              : 
    1279              : !  Compute Hartree+xc potentials
    1280          123 :    ABI_MALLOC(vxc_wk,(nfft,dtset%nspden))
    1281           82 :    ABI_MALLOC(vhartr_wk,(nfft))
    1282           41 :    option=1
    1283              : 
    1284              :    call hartre(1,gsqcut,dtset%icutcoul,psps%usepaw,mpi_enreg,nfft,ngfft,&
    1285           41 :                &dtset%nkpt,dtset%rcut,rhog_wk,rprimd,dtset%vcutgeo,vhartr_wk)
    1286              : 
    1287              : !  Prepare the call to rhotoxc
    1288           41 :    call xcdata_init(xcdata,dtset=dtset)
    1289           41 :    nk3xc=1 ; non_magnetic_xc=(dtset%usepaw==1.and.mod(abs(dtset%usepawu),10)==4)
    1290           41 :    ABI_MALLOC(work,(0))
    1291              :    call rhotoxc(bigexc,bigsxc,kxc,mpi_enreg,nfft,ngfft,&
    1292              : &   work,0,work,0,nkxc,nk3xc,non_magnetic_xc,n3xccc,option,rhor_wk,rprimd,1,&
    1293           41 : &   vxc_wk,vxcavg,xccc3d,xcdata,vhartr=vhartr_wk)
    1294           41 :    ABI_FREE(work)
    1295           41 :    ABI_FREE(xccc3d)
    1296              : 
    1297              : !  Sum all contributions
    1298          123 :    do ispden=1,min(dtset%nspden,2)
    1299       984123 :      do ifft=1,nfft
    1300       984082 :        vrespc(ifft,ispden)=vrespc(ifft,ispden)+vpsp_wk(ifft)+vhartr_wk(ifft)+vxc_wk(ifft,ispden)
    1301              :      end do
    1302              :    end do
    1303           41 :    if (dtset%nspden==4) then
    1304            0 :      do ispden=3,4
    1305            0 :        do ifft=1,nfft
    1306            0 :          vrespc(ifft,ispden)=vrespc(ifft,ispden)+vxc_wk(ifft,ispden)
    1307              :        end do
    1308              :      end do
    1309              :    end if
    1310           41 :    call mean_fftr(vrespc,vmean,nfft,nfftot,dtset%nspden,mpi_comm_sphgrid=mpi_enreg%comm_fft)
    1311           41 :    if(dtset%nspden==2) then
    1312           41 :      vmean(1)=half*(vmean(1)+vmean(2))
    1313           41 :      vmean(2)=vmean(1)
    1314              :    end if
    1315          123 :    do ispden=1,dtset%nspden
    1316       984123 :      vrespc(:,ispden)=vrespc(:,ispden)-vmean(ispden)
    1317              :    end do
    1318           41 :    ABI_FREE(gresid)
    1319           41 :    ABI_FREE(grxc)
    1320           41 :    ABI_FREE(rhog_wk)
    1321           41 :    ABI_FREE(rhor_wk)
    1322           41 :    ABI_FREE(rhor_wk0)
    1323           41 :    ABI_FREE(xred_wk)
    1324           41 :    ABI_FREE(vhartr_wk)
    1325           41 :    ABI_FREE(vpsp_wk)
    1326           82 :    ABI_FREE(vxc_wk)
    1327              : 
    1328              :  end if
    1329              : 
    1330        28280 : end subroutine prcref_PMA
    1331              : !!***
    1332              : 
    1333              : 
    1334              : !!****f* ABINIT/moddiel
    1335              : !! NAME
    1336              : !! moddiel
    1337              : !!
    1338              : !! FUNCTION
    1339              : !! Precondition the residual, using a model dielectric function.
    1340              : !! When cplex=1, assume q=(0 0 0), and vresid and vrespc will be REAL
    1341              : !! When cplex=2, q must be taken into account, and vresid and vrespc will be COMPLEX
    1342              : !!
    1343              : !! INPUTS
    1344              : !!  cplex= if 1, vhartr is REAL, if 2, vhartr is COMPLEX
    1345              : !!  dielar(7)=input parameters for dielectric matrix:
    1346              : !!                diecut,dielng,diemac,diemix,diegap,dielam,diemixmag.
    1347              : !!  mpi_enreg=information about MPI parallelization
    1348              : !!  nfft=(effective) number of FFT grid points (for this processor)
    1349              : !!  ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
    1350              : !!  nspden=number of spin-density components
    1351              : !!  optreal=1 if residual potential is in REAL space, 2 if it is in RECIPROCAL SPACE
    1352              : !!  optres=0: the array vresid contains a potential residual
    1353              : !!         1: the array vresid contains a density residual
    1354              : !!  qphon(3)=reduced coordinates for the phonon wavelength (needed if cplex==2).
    1355              : !!  rprimd(3,3)=dimensional primitive translations in real space (bohr)
    1356              : !!  vresid(cplex*nfft,nspden)=residual density/potential in REAL space       (if optreal==1)
    1357              : !!                            residual density/potential in RECIPROCAL space (if optreal==2)
    1358              : !!
    1359              : !! OUTPUT
    1360              : !!  vrespc(cplex*nfft,nspden)=preconditioned residual of the density/potential
    1361              : !!                            in REAL space       if optreal==1
    1362              : !!                            in RECIPROCAL space if optreal==2
    1363              : !!
    1364              : !! SIDE EFFECTS
    1365              : !!
    1366              : !! NOTES
    1367              : !! optreal==2 is not compatible with cplex==1
    1368              : !!
    1369              : !! SOURCE
    1370              : 
    1371        54368 : subroutine moddiel(cplex,dielar,mpi_enreg,nfft,ngfft,nspden,optreal,optres,qphon,rprimd,vresid,vrespc)
    1372              : 
    1373              : !Arguments-------------------------------
    1374              : !scalars
    1375              :  integer,intent(in) :: cplex,nfft,nspden,optreal,optres
    1376              :  type(MPI_type),intent(in) :: mpi_enreg
    1377              : !arrays
    1378              :  integer,intent(in) :: ngfft(18)
    1379              :  real(dp),intent(in) :: dielar(7),qphon(3),rprimd(3,3)
    1380              :  real(dp),intent(in) :: vresid(cplex*nfft,nspden)
    1381              :  real(dp),intent(out) :: vrespc(cplex*nfft,nspden)
    1382              : 
    1383              : !Local variables-------------------------------
    1384              : !scalars
    1385              :  integer,parameter :: im=2,re=1
    1386              :  integer :: i1,i2,i23,i3,ifft,ig,ii,ii1,ing,ispden,me_fft,mg,n1,n2,n3,nproc_fft
    1387              :  integer :: nspden_eff,qeq0
    1388              :  logical :: magn_precon
    1389              :  real(dp) :: dielng,diemac,diemac_inv,diemix,diemixmag,diemix_eff,factor,gqg2p3,gqgm12,gqgm13
    1390              :  real(dp) :: gqgm23,gs,gs2,gs3,l2g2,length2,ucvol
    1391              :  character(len=500) :: message
    1392              : !arrays
    1393              :  integer :: id(3)
    1394        54368 :  integer, contiguous, pointer :: fftn2_distrib(:),ffti2_local(:)
    1395        54368 :  integer, contiguous, pointer :: fftn3_distrib(:),ffti3_local(:)
    1396              :  real(dp) :: gmet(3,3),gprimd(3,3),potg0(4),rmet(3,3)
    1397        54368 :  real(dp),allocatable :: gq(:,:),work1(:,:),work2(:)
    1398              : ! *************************************************************************
    1399              : 
    1400              : !Check that cplex has an allowed value
    1401        54368 :  if(cplex/=1 .and. cplex/=2)then
    1402              :    write(message,'(a,i0,a,a)')&
    1403            0 : &   '  From the calling routine, cplex=',cplex,ch10,&
    1404            0 : &   '  but the only value allowed are 1 and 2.'
    1405            0 :    ABI_BUG(message)
    1406              :  end if
    1407              : 
    1408        54368 :  if(cplex==1.and.optreal==2)then
    1409            0 :    ABI_BUG('When optreal=2, cplex must be 2.')
    1410              :  end if
    1411              : 
    1412              : !This is to allow q=0
    1413        54368 :  qeq0=0
    1414        54368 :  if(qphon(1)**2+qphon(2)**2+qphon(3)**2<1.d-15) qeq0=1
    1415              : 
    1416              : !If cplex=1 then qphon should be 0 0 0
    1417        54368 :  if (cplex==1.and. qeq0/=1) then
    1418            0 :    write(message,'(a,3e12.4,a)' )' cplex=1 but qphon=',qphon,' qphon should be 0 0 0.'
    1419            0 :    ABI_BUG(message)
    1420              :  end if
    1421              : 
    1422        54368 :  n1=ngfft(1) ; n2=ngfft(2) ; n3=ngfft(3)
    1423        54368 :  me_fft=ngfft(11)
    1424        54368 :  nproc_fft=ngfft(10)
    1425              : 
    1426              : !Get the distrib associated with this fft_grid
    1427        54368 :  call ptabs_fourdp(mpi_enreg,n2,n3,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local)
    1428              : 
    1429              : !Compute different geometric tensor, as well as ucvol, from rprimd
    1430        54368 :  call metric(gmet,gprimd,-1,rmet,rprimd,ucvol)
    1431              : 
    1432        54368 :  dielng=dielar(2) ; diemac=dielar(3) ; diemix=dielar(4) ; diemixmag=dielar(7)
    1433              : 
    1434        54368 :  magn_precon=(diemixmag>=zero) ! Set to true if magnetization has to be preconditionned
    1435        54368 :  diemixmag=abs(diemixmag)
    1436              : 
    1437              : !write(std_out,*)' moddiel : diemac, diemix, diemixmag =',diemac,diemix,diemixmag
    1438              : 
    1439        54368 :  if(abs(diemac-1.0_dp)<1.0d-6)then
    1440              : 
    1441              : !  Here, simple mixing is required, through macroscopic
    1442              : !  dielectric constant set to 1.0_dp .
    1443    149078034 :    vrespc(:,1)=diemix*vresid(:,1)
    1444     52532569 :    if (nspden/=1) vrespc(:,2:nspden)=diemixmag*vresid(:,2:nspden)
    1445              :  else
    1446              : 
    1447              : !  Magnetization is not preconditionned
    1448      1752658 :    if (optres==1.and.nspden>1.and.(.not.magn_precon)) vrespc(:,2:nspden)=diemixmag*vresid(:,2:nspden)
    1449              : 
    1450              : !  Here, model dielectric function (G-diagonal operator)
    1451              : 
    1452        47550 :    length2=(two_pi*dielng)**2
    1453        47550 :    diemac_inv=1.0_dp/diemac
    1454       142650 :    ABI_MALLOC(work1,(2,nfft))
    1455        47550 :    if (optreal==1) then
    1456       114430 :      ABI_MALLOC(work2,(cplex*nfft))
    1457              :    end if
    1458              : 
    1459              : !  In order to speed the routine, precompute the components of g
    1460       903450 :    mg=maxval(ngfft)
    1461       142650 :    ABI_MALLOC(gq,(3,mg))
    1462       190200 :    do ii=1,3
    1463       142650 :      id(ii)=ngfft(ii)/2+2
    1464      3000467 :      do ing=1,ngfft(ii)
    1465      2810267 :        ig=ing-(ing/id(ii))*ngfft(ii)-1
    1466      2952917 :        gq(ii,ing)=ig+qphon(ii)
    1467              :      end do
    1468              :    end do
    1469              : 
    1470              : !  Do-loop on spins
    1471              : !  Note XG 010922 : I doubt the preconditioner is OK for the magnetization
    1472        47550 :    nspden_eff=nspden;if (optres==1.and.(.not.magn_precon)) nspden_eff=1
    1473       106525 :    do ispden=1,nspden_eff
    1474              : 
    1475        58975 :      diemix_eff=diemix;if (ispden>1) diemix_eff=diemixmag
    1476              : 
    1477              : !    Do fft from real space (work2) to G space (work1)
    1478        58975 :      if (optreal==1) then
    1479    565062320 :        work2(:)=vresid(:,ispden)
    1480        40048 :        call fourdp(cplex,work1,work2,-1,mpi_enreg,nfft,1,ngfft,0)
    1481              :      else
    1482              : !      work1(:,:)=reshape(vresid(:,ispden),(/2,nfft/))
    1483              : !      Reshape function does not work with big arrays for some compilers
    1484    234145414 :        do ifft=1,nfft
    1485    234126487 :          work1(1,ifft)=vresid(2*ifft-1,ispden)
    1486    234145414 :          work1(2,ifft)=vresid(2*ifft  ,ispden)
    1487              :        end do
    1488              :      end if
    1489              : 
    1490              : !    Store G=0 value
    1491        58975 :      potg0(ispden)=work1(re,1)
    1492              : 
    1493              : !    Triple loop, for the three dimensions
    1494      1274247 :      do i3=1,n3
    1495              : !      Precompute some products that do not depend on i2 and i1
    1496      1215272 :        gs3=gq(3,i3)*gq(3,i3)*gmet(3,3)
    1497      1215272 :        gqgm23=gq(3,i3)*gmet(2,3)*2
    1498      1215272 :        gqgm13=gq(3,i3)*gmet(1,3)*2
    1499     28775584 :        do i2=1,n2
    1500     28716609 :          if (fftn2_distrib(i2)==me_fft) then
    1501     26390001 :            gs2=gs3+ gq(2,i2)*(gq(2,i2)*gmet(2,2)+gqgm23)
    1502     26390001 :            gqgm12=gq(2,i2)*gmet(1,2)*2
    1503     26390001 :            gqg2p3=gqgm13+gqgm12
    1504     26390001 :            i23=n1*( ffti2_local(i2)-1+(n2/nproc_fft)*(i3-1))
    1505              : 
    1506              : !          Do the test that eliminates the Gamma point outside
    1507              : !          of the inner loop
    1508     26390001 :            ii1=1
    1509     26390001 :            if(i2 == 1 .and. i3 == 1 .and. qeq0==1)then
    1510              : !            if(i23==0 .and. qeq0==1)then: this changes with the number of fft procs...
    1511              : !            and seems to be wrong.Pls check
    1512     26390001 :              ii1=2
    1513              :            end if
    1514              : 
    1515              : !          Here, unlike in hartre.f, the G=0 term is not eliminated, albeit
    1516              : !          not changed.
    1517    796117921 :            do i1=ii1,n1
    1518              : 
    1519              : !            One obtains the square of the norm of q+G (defined by i1,i2,i3)
    1520    769727920 :              gs=gs2+ gq(1,i1)*(gq(1,i1)*gmet(1,1)+gqg2p3)
    1521    769727920 :              ifft=i1+i23
    1522              : 
    1523    769727920 :              l2g2=length2*gs
    1524              : !            The model dielectric function is now computed
    1525    769727920 :              factor = (l2g2+diemac_inv)/(l2g2+1.0_dp) * diemix_eff
    1526    769727920 :              work1(re,ifft)=work1(re,ifft)*factor
    1527    796117921 :              work1(im,ifft)=work1(im,ifft)*factor
    1528              : 
    1529              :            end do
    1530              :          end if
    1531              :        end do
    1532              :      end do
    1533              : 
    1534              : !    Might get rid of the G=0 term
    1535              : !    if(qeq0==1)then
    1536              : !    work1(re,1)=0.0_dp
    1537              : !    work1(im,1)=0.0_dp
    1538              : !    end if
    1539              : 
    1540              : !    Fourier transform
    1541       106525 :      if (optreal==1) then
    1542        40048 :        call fourdp(cplex,work1,work2,1,mpi_enreg,nfft,1,ngfft,0)
    1543    565062320 :        vrespc(:,ispden)=work2(:)
    1544              :      else
    1545              : !      vrespc(:,ispden)=reshape(work1(:,:),(/nfft*2/))
    1546              : !      Reshape function does not work with big arrays for some compilers
    1547    234145414 :        do ifft=1,nfft
    1548    234126487 :          vrespc(2*ifft-1,ispden)=work1(1,ifft)
    1549    234145414 :          vrespc(2*ifft  ,ispden)=work1(2,ifft)
    1550              :        end do
    1551              :      end if
    1552              : 
    1553              : !    End of loop on spin polarizations
    1554              :    end do
    1555              : 
    1556        47550 :    ABI_FREE(gq)
    1557        47550 :    ABI_FREE(work1)
    1558        47550 :    if (optreal==1) then
    1559        33440 :      ABI_FREE(work2)
    1560              :    end if
    1561              : 
    1562              : !  End condition diemac/=1.0
    1563              :  end if
    1564              : 
    1565       108736 : end subroutine moddiel
    1566              : !!***
    1567              : 
    1568              : !!****f* ABINIT/dielmt
    1569              : !! NAME
    1570              : !! dielmt
    1571              : !!
    1572              : !! FUNCTION
    1573              : !! Compute dielectric matrix from susceptibility matrix
    1574              : !! Diagonalize it, then invert it.
    1575              : !!
    1576              : !! INPUTS
    1577              : !!  gmet(3,3)=reciprocal space metric tensor in bohr**-2.
    1578              : !!  kg_diel(3,npwdiel)=reduced planewave coordinates for the dielectric matrix.
    1579              : !!  npwdiel=size of the dielinv and susmat arrays.
    1580              : !!  nspden=number of spin-density components
    1581              : !!  occopt=option for occupancies
    1582              : !!  prtvol=control print volume and debugging output
    1583              : !!  susmat(2,npwdiel,nspden,npwdiel,nspden)=
    1584              : !!   the susceptibility (or density-density response) matrix in reciprocal space
    1585              : !!
    1586              : !! OUTPUT
    1587              : !!  dielinv(2,npwdiel,(nspden+4)/3,npwdiel,(nspden+4)/3)=inverse of the (non-hermitian)
    1588              : !!      TC dielectric matrix in reciprocal space.
    1589              : !!
    1590              : !! NOTES
    1591              : !! Warning : will not work in the spin-polarized, metallic case.
    1592              : !! Output (not cleaned)
    1593              : !! !!! Spin behaviour is not obvious !!!
    1594              : !!
    1595              : !! TODO
    1596              : !! Write equation below (hermitian matrix)
    1597              : !!
    1598              : !! SOURCE
    1599              : 
    1600           68 : subroutine dielmt(dielinv,gmet,kg_diel,npwdiel,nspden,occopt,prtvol,susmat)
    1601              : 
    1602              : !Arguments ------------------------------------
    1603              : !scalars
    1604              :  integer,intent(in) :: npwdiel,nspden,occopt,prtvol
    1605              : !arrays
    1606              :  integer,intent(in) :: kg_diel(3,npwdiel)
    1607              :  real(dp),intent(in) :: gmet(3,3)
    1608              :  real(dp),intent(in) :: susmat(2,npwdiel,nspden,npwdiel,nspden)
    1609              :  real(dp),intent(out) :: dielinv(2,npwdiel,nspden,npwdiel,nspden)
    1610              : 
    1611              : !Local variables-------------------------------
    1612              : !scalars
    1613              :  integer :: ieig,ier,ii,index,ipw,ipw1,ipw2,isp,jj,npwsp
    1614              :  real(dp) :: ai1,ai2,ar1,ar2,eiginv,gfact,gfactinv,kg_red1,kg_red2,kg_red3,gsquar
    1615              :  real(dp) :: tpisq
    1616              :  character(len=500) :: message
    1617              : !arrays
    1618              :  real(dp) :: tsec(2)
    1619           68 :  real(dp),allocatable :: dielh(:),dielmat(:,:,:,:,:),dielvec(:,:,:)
    1620           68 :  real(dp),allocatable :: eig_diel(:),zhpev1(:,:),zhpev2(:)
    1621              : !integer :: ipw3
    1622              : !real(dp) :: elementi,elementr
    1623              : ! *************************************************************************
    1624              : 
    1625              : !DEBUG
    1626              : !write(std_out,*)' dielmt : enter '
    1627              : !ENDDEBUG
    1628              : 
    1629              : !tpisq is (2 Pi) **2:
    1630           68 :  tpisq=(two_pi)**2
    1631              : 
    1632           68 :  call timab(90,1,tsec)
    1633              : 
    1634              : !-Compute now the hermitian dielectric matrix------------------------------
    1635              : !Following remarks are only valid within RPA approximation (Kxc=0):
    1636              : 
    1637              : !for the spin-unpolarized case, 1 - 4pi (1/G) chi0(G,Gp) (1/Gp)
    1638              : 
    1639              : !for the spin-polarized case,
    1640              : !( 1  0 ) - 4pi ( 1/G  1/G )   ( chi0 upup  chi0 updn )   ( 1/Gp 1/Gp )
    1641              : !( 0  1 )       ( 1/G  1/G )   ( chi0 dnup  chi0 dndn )   ( 1/Gp 1/Gp )
    1642              : !which is equal to
    1643              : !( 1  0 ) - 4pi (1/G  0 ) (chi0 upup+dndn+updn+dnup  chi0 upup+dndn+updn+dnup) (1/Gp 0  )
    1644              : !( 0  1 )       ( 0  1/G) (chi0 upup+dndn+updn+dnup  chi0 upup+dndn+updn+dnup) ( 0  1/Gp)
    1645              : !So, if spin-polarized, sum all spin contributions
    1646              : !Note: chi0 updn = chi0 dnup = zero for non-metallic systems
    1647              : 
    1648              : !In the case of non-collinear magnetism, within RPA, this is the same because:
    1649              : !chi0_(s1,s2),(s3,s4) = delta_s1,s2 * delta_s3,s4 * chi0_(s1,s1),(s3,s3)
    1650              : !Only chi_upup,upup, chi_dndn,dndn, chi_upup,dndn and chi_dndn,upup
    1651              : !have to be taken into account (stored, susmat(:,ipw1,1:2,ipw2,1:2)
    1652              : 
    1653          408 :  ABI_MALLOC(dielmat,(2,npwdiel,min(nspden,2),npwdiel,min(nspden,2)))
    1654              : 
    1655           68 :  if(nspden/=1)then
    1656            2 :    if (occopt<3) then
    1657          120 :      do ipw2=1,npwdiel
    1658         7082 :        do ipw1=1,npwdiel
    1659         6962 :          dielmat(1,ipw1,1,ipw2,1)=susmat(1,ipw1,1,ipw2,1)+susmat(1,ipw1,2,ipw2,2)
    1660         7080 :          dielmat(2,ipw1,1,ipw2,1)=susmat(2,ipw1,1,ipw2,1)+susmat(2,ipw1,2,ipw2,2)
    1661              :        end do
    1662              :      end do
    1663              :    else
    1664            0 :      do ipw2=1,npwdiel
    1665            0 :        do ipw1=1,npwdiel
    1666            0 :          dielmat(1,ipw1,1,ipw2,1)=susmat(1,ipw1,1,ipw2,1)+susmat(1,ipw1,2,ipw2,2)+susmat(1,ipw1,1,ipw2,2)+susmat(1,ipw1,2,ipw2,1)
    1667            0 :          dielmat(2,ipw1,1,ipw2,1)=susmat(2,ipw1,1,ipw2,1)+susmat(2,ipw1,2,ipw2,2)+susmat(2,ipw1,1,ipw2,2)+susmat(2,ipw1,2,ipw2,1)
    1668              :        end do
    1669              :      end do
    1670              :    end if
    1671              :  else
    1672        11080 :    do ipw2=1,npwdiel
    1673      2602266 :      do ipw1=1,npwdiel
    1674      2591186 :        dielmat(1,ipw1,1,ipw2,1)=susmat(1,ipw1,1,ipw2,1)
    1675      2602200 :        dielmat(2,ipw1,1,ipw2,1)=susmat(2,ipw1,1,ipw2,1)
    1676              :      end do
    1677              :    end do
    1678              :  end if
    1679              : !Compute 1/G factors and include them in the dielectric matrix
    1680        11200 :  do ipw1=1,npwdiel
    1681        11132 :    kg_red1=dble(kg_diel(1,ipw1))
    1682        11132 :    kg_red2=dble(kg_diel(2,ipw1))
    1683        11132 :    kg_red3=dble(kg_diel(3,ipw1))
    1684              :    gsquar=tpisq*(gmet(1,1)*kg_red1**2+gmet(2,2)*kg_red2**2+gmet(3,3)*kg_red3**2 &
    1685              : &   +two*( (gmet(1,2)*kg_red2+gmet(1,3)*kg_red3)* kg_red1 +      &
    1686        11132 : &   gmet(2,3)*kg_red2*kg_red3)                        )
    1687              : !  Distinguish G=0 from other elements
    1688        11200 :    if(gsquar>tol12)then
    1689              : !    !$ gfact=\sqrt (4.0_dp \pi/gsquar/dble(nspden))$
    1690        11064 :      gfact=sqrt(four_pi/gsquar)
    1691      2598080 :      do ipw2=1,npwdiel
    1692              : !      Must multiply both rows and columns, and also changes the sign
    1693      2587016 :        dielmat(1,ipw2,1,ipw1,1)=-dielmat(1,ipw2,1,ipw1,1)*gfact
    1694      2587016 :        dielmat(2,ipw2,1,ipw1,1)=-dielmat(2,ipw2,1,ipw1,1)*gfact
    1695      2587016 :        dielmat(1,ipw1,1,ipw2,1)= dielmat(1,ipw1,1,ipw2,1)*gfact
    1696      2598080 :        dielmat(2,ipw1,1,ipw2,1)= dielmat(2,ipw1,1,ipw2,1)*gfact
    1697              :      end do
    1698              :    else
    1699              : !    Zero the G=0 elements, head and wings
    1700        11200 :      do ipw2=1,npwdiel
    1701        11132 :        dielmat(1,ipw2,1,ipw1,1)=zero
    1702        11132 :        dielmat(2,ipw2,1,ipw1,1)=zero
    1703        11132 :        dielmat(1,ipw1,1,ipw2,1)=zero
    1704        11200 :        dielmat(2,ipw1,1,ipw2,1)=zero
    1705              :      end do
    1706              :    end if
    1707              :  end do
    1708              : 
    1709              : !Complete the matrix in the spin-polarized case
    1710              : !should this be nspden==2??
    1711           68 :  if(nspden/=1)then
    1712          120 :    do ipw1=1,npwdiel
    1713         7082 :      do ipw2=1,npwdiel
    1714         6962 :        dielmat(1,ipw1,1,ipw2,2)=dielmat(1,ipw1,1,ipw2,1)
    1715         6962 :        dielmat(2,ipw1,1,ipw2,2)=dielmat(2,ipw1,1,ipw2,1)
    1716         6962 :        dielmat(1,ipw1,2,ipw2,1)=dielmat(1,ipw1,1,ipw2,1)
    1717         6962 :        dielmat(2,ipw1,2,ipw2,1)=dielmat(2,ipw1,1,ipw2,1)
    1718         6962 :        dielmat(1,ipw1,2,ipw2,2)=dielmat(1,ipw1,1,ipw2,1)
    1719         7080 :        dielmat(2,ipw1,2,ipw2,2)=dielmat(2,ipw1,1,ipw2,1)
    1720              :      end do
    1721              :    end do
    1722              :  end if
    1723              : 
    1724              : !DEBUG
    1725              : !write(std_out,*)' dielmt : make dielmat equal to identity matrix '
    1726              : !do ipw1=1,npwdiel
    1727              : !do ipw2=1,npwdiel
    1728              : !dielmat(1,ipw1,1,ipw2,1)=0.0_dp
    1729              : !dielmat(2,ipw1,1,ipw2,1)=0.0_dp
    1730              : !end do
    1731              : !end do
    1732              : !ENDDEBUG
    1733              : 
    1734              : !Add the diagonal part
    1735          138 :  do isp=1,min(nspden,2)
    1736        11388 :    do ipw=1,npwdiel
    1737        11320 :      dielmat(1,ipw,isp,ipw,isp)=one+dielmat(1,ipw,isp,ipw,isp)
    1738              :    end do
    1739              :  end do
    1740              : 
    1741              : !-The hermitian dielectric matrix is computed ------------------------------
    1742              : !-Now, diagonalize it ------------------------------------------------------
    1743              : 
    1744              : !In RPA, everything is projected on the spin-symmetrized
    1745              : !space. This was coded here (for the time being).
    1746              : 
    1747              : !Diagonalize the hermitian dielectric matrix
    1748              : 
    1749              : !npwsp=npwdiel*nspden
    1750           68 :  npwsp=npwdiel
    1751              : 
    1752          204 :  ABI_MALLOC(dielh,(npwsp*(npwsp+1)))
    1753          272 :  ABI_MALLOC(dielvec,(2,npwsp,npwsp))
    1754          204 :  ABI_MALLOC(eig_diel,(npwsp))
    1755          204 :  ABI_MALLOC(zhpev1,(2,2*npwsp-1))
    1756          204 :  ABI_MALLOC(zhpev2,(3*npwsp-2))
    1757           68 :  ier=0
    1758              : !Store the dielectric matrix in proper mode before calling zhpev
    1759           68 :  index=1
    1760        11200 :  do ii=1,npwdiel
    1761      1315840 :    do jj=1,ii
    1762      1304640 :      dielh(index  )=dielmat(1,jj,1,ii,1)
    1763      1304640 :      dielh(index+1)=dielmat(2,jj,1,ii,1)
    1764      1315772 :      index=index+2
    1765              :    end do
    1766              :  end do
    1767              : !If spin-polarized and non RPA, need to store other parts of the matrix
    1768              : !if(nspden/=1)then
    1769              : !do ii=1,npwdiel
    1770              : !Here, spin-flip contribution
    1771              : !do jj=1,npwdiel
    1772              : !dielh(index  )=dielmat(1,jj,1,ii,2)
    1773              : !dielh(index+1)=dielmat(2,jj,1,ii,2)
    1774              : !index=index+2
    1775              : !end do
    1776              : !Here spin down-spin down upper matrix
    1777              : !do jj=1,ii
    1778              : !dielh(index  )=dielmat(1,jj,2,ii,2)
    1779              : !dielh(index+1)=dielmat(2,jj,2,ii,2)
    1780              : !index=index+2
    1781              : !end do
    1782              : !end do
    1783              : !end if
    1784              : 
    1785              :  call ZHPEV ('V','U',npwsp,dielh,eig_diel,dielvec,npwdiel,zhpev1,&
    1786           68 : & zhpev2,ier)
    1787           68 :  ABI_FREE(zhpev1)
    1788           68 :  ABI_FREE(zhpev2)
    1789              : 
    1790           68 :  if(prtvol>=10)then
    1791           15 :    write(message, '(a,a,a,5es12.4)' )ch10,&
    1792           15 : &   ' Five largest eigenvalues of the hermitian RPA dielectric matrix:',&
    1793           30 : &   ch10,eig_diel(npwdiel:npwdiel-4:-1)
    1794           15 :    call wrtout(ab_out,message,'COLL')
    1795              :  end if
    1796              : 
    1797           68 :  write(message, '(a,a)' )ch10,&
    1798          136 : & ' dielmt : 15 largest eigenvalues of the hermitian RPA dielectric matrix'
    1799           68 :  call wrtout(std_out,message,'COLL')
    1800           68 :  write(message, '(a,5es12.5)' )'  1-5  :',eig_diel(npwdiel:npwdiel-4:-1)
    1801           68 :  call wrtout(std_out,message,'COLL')
    1802           68 :  write(message, '(a,5es12.5)' )'  6-10 :',eig_diel(npwdiel-5:npwdiel-9:-1)
    1803           68 :  call wrtout(std_out,message,'COLL')
    1804           68 :  write(message, '(a,5es12.5)' )'  11-15:',eig_diel(npwdiel-10:npwdiel-14:-1)
    1805           68 :  call wrtout(std_out,message,'COLL')
    1806           68 :  write(message, '(a,a)' )ch10,&
    1807          136 : & ' dielmt : 5 smallest eigenvalues of the hermitian RPA dielectric matrix'
    1808           68 :  call wrtout(std_out,message,'COLL')
    1809           68 :  write(message, '(a,5es12.5)' )'  1-5  :',eig_diel(1:5)
    1810           68 :  call wrtout(std_out,message,'COLL')
    1811              : 
    1812              : !Invert the hermitian dielectric matrix,
    1813              : !Should use a BLAS call !
    1814        11200 :  do ipw2=1,npwdiel
    1815      1315840 :    do ipw1=ipw2,npwdiel
    1816      1304640 :      dielinv(1,ipw1,1,ipw2,1)=zero
    1817      1315772 :      dielinv(2,ipw1,1,ipw2,1)=zero
    1818              :    end do
    1819              :  end do
    1820        11200 :  do ieig=1,npwdiel
    1821        11132 :    eiginv=one/eig_diel(ieig)
    1822      2609348 :    do ipw2=1,npwdiel
    1823    384025872 :      do ipw1=ipw2,npwdiel
    1824    381416592 :        ar1=dielvec(1,ipw1,ieig)
    1825    381416592 :        ai1=dielvec(2,ipw1,ieig)
    1826    381416592 :        ar2=dielvec(1,ipw2,ieig)
    1827    381416592 :        ai2=dielvec(2,ipw2,ieig)
    1828              :        dielinv(1,ipw1,1,ipw2,1)=dielinv(1,ipw1,1,ipw2,1)+&
    1829    381416592 : &       (ar1*ar2+ai1*ai2)*eiginv
    1830              :        dielinv(2,ipw1,1,ipw2,1)=dielinv(2,ipw1,1,ipw2,1)+&
    1831    384014740 : &       (ai1*ar2-ar1*ai2)*eiginv
    1832              :      end do
    1833              :    end do
    1834              :  end do
    1835        11132 :  do ipw2=1,npwdiel-1
    1836      1304640 :    do ipw1=ipw2+1,npwdiel
    1837      1293508 :      dielinv(1,ipw2,1,ipw1,1)= dielinv(1,ipw1,1,ipw2,1)
    1838      1304572 :      dielinv(2,ipw2,1,ipw1,1)=-dielinv(2,ipw1,1,ipw2,1)
    1839              :    end do
    1840              :  end do
    1841              : 
    1842           68 :  ABI_FREE(dielh)
    1843           68 :  ABI_FREE(dielvec)
    1844           68 :  ABI_FREE(eig_diel)
    1845              : 
    1846              : !DEBUG
    1847              : !Checks whether the inverse of the hermitian dielectric matrix
    1848              : !has been correctly generated
    1849              : !do ipw1=1,npwdiel
    1850              : !do ipw2=1,npwdiel
    1851              : !elementr=0.0_dp
    1852              : !elementi=0.0_dp
    1853              : !do ipw3=1,npwdiel
    1854              : !elementr=elementr+dielinv(1,ipw1,1,ipw3,1)*dielmat(1,ipw3,1,ipw2,1)&
    1855              : !&                    -dielinv(2,ipw1,1,ipw3,1)*dielmat(2,ipw3,1,ipw2,1)
    1856              : !elementi=elementi+dielinv(1,ipw1,1,ipw3,1)*dielmat(2,ipw3,1,ipw2,1)&
    1857              : !&                    +dielinv(2,ipw1,1,ipw3,1)*dielmat(1,ipw3,1,ipw2,1)
    1858              : !end do
    1859              : !if(elementr**2+elementi**2 > 1.0d-12)then
    1860              : !if( ipw1 /= ipw2 .or. &
    1861              : !&        ( abs(elementr-1.0_dp)>1.0d-6 .or. abs(elementi)>1.0d-6 ))then
    1862              : !write(std_out,*)' dielmt : the inversion procedure is not correct '
    1863              : !write(std_out,*)' ipw1, ipw2 =',ipw1,ipw2
    1864              : !write(std_out,*)' elementr,elementi=',elementr,elementi
    1865              : !stop
    1866              : !end if
    1867              : !end if
    1868              : !end do
    1869              : !end do
    1870              : !write(std_out,*)'dielmt : matrix has been inverted successfully '
    1871              : !stop
    1872              : !ENDDEBUG
    1873              : 
    1874              : !Then get the inverse of the asymmetric
    1875              : !dielectric matrix, as required for the preconditioning.
    1876              : 
    1877              : !Inverse of the dielectric matrix : ( 1 - 4pi (1/G^2) chi0(G,Gp) )^(-1)
    1878              : !In dielinv there is now (1 - 4pi (1/G) chi0(G,Gp) (1/Gp) )^(-1)
    1879              : !So, evaluate dielinv_after(G,Gp) =
    1880              : !(4pi/G^2)^(1/2) dielinv_before(G,Gp) (4pi/Gp^2)^(-1/2)
    1881              : !In RPA, can focus on the spin-averaged quantities
    1882        11200 :  do ipw1=1,npwdiel
    1883        11132 :    kg_red1=dble(kg_diel(1,ipw1))
    1884        11132 :    kg_red2=dble(kg_diel(2,ipw1))
    1885        11132 :    kg_red3=dble(kg_diel(3,ipw1))
    1886              :    gsquar=tpisq*(gmet(1,1)*kg_red1**2+gmet(2,2)*kg_red2**2+gmet(3,3)*kg_red3**2 &
    1887              : &   +two*( (gmet(1,2)*kg_red2+gmet(1,3)*kg_red3)* kg_red1 +      &
    1888        11132 : &   gmet(2,3)*kg_red2*kg_red3)                        )
    1889              : !  Distinguish G=0 from other elements
    1890        11200 :    if(gsquar>tol12)then
    1891        11064 :      gfact=sqrt(four_pi/gsquar)
    1892        11064 :      gfactinv=one/gfact
    1893      2598080 :      do ipw2=1,npwdiel
    1894              : !      Must multiply both rows and columns
    1895      2587016 :        dielinv(1,ipw2,1,ipw1,1)=dielinv(1,ipw2,1,ipw1,1)*gfactinv
    1896      2587016 :        dielinv(2,ipw2,1,ipw1,1)=dielinv(2,ipw2,1,ipw1,1)*gfactinv
    1897      2587016 :        dielinv(1,ipw1,1,ipw2,1)=dielinv(1,ipw1,1,ipw2,1)*gfact
    1898      2598080 :        dielinv(2,ipw1,1,ipw2,1)=dielinv(2,ipw1,1,ipw2,1)*gfact
    1899              :      end do
    1900              :    else
    1901              : !    Zero the G=0 elements, head
    1902        11200 :      do ipw2=1,npwdiel
    1903        33328 :        if (ipw2/=ipw1) dielinv(1:2,ipw1,1,ipw2,1)=zero
    1904              :      end do
    1905              :    end if
    1906              :  end do
    1907              : 
    1908           68 :  ABI_FREE(dielmat)
    1909              : 
    1910           68 :  call timab(90,2,tsec)
    1911              : 
    1912           68 : end subroutine dielmt
    1913              : !!***
    1914              : 
    1915              : 
    1916              : !!****f* ABINIT/dieltcel
    1917              : !! NAME
    1918              : !! dieltcel
    1919              : !!
    1920              : !! FUNCTION
    1921              : !! Compute either test charge or electronic dielectric matrices
    1922              : !! from susceptibility matrix
    1923              : !! Diagonalize it, then invert it.
    1924              : !!
    1925              : !! INPUTS
    1926              : !!  gmet(3,3)=reciprocal space metric tensor in bohr**-2.
    1927              : !!  kg_diel(3,npwdiel)=reduced planewave coordinates for the dielectric matrix.
    1928              : !!  kxc(nfft,nkxc)=exchange-correlation kernel,
    1929              : !!       needed if the electronic dielectric matrix is computed
    1930              : !!  nfft=(effective) number of FFT grid points (for this processor)
    1931              : !!  ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
    1932              : !!  nkxc=second dimension of the array kxc, see rhotoxc.f for a description
    1933              : !!  npwdiel=size of the dielinv and susmat arrays.
    1934              : !!  nspden=number of spin-density components
    1935              : !!  occopt=option for occupancies
    1936              : !!  option=1 for Test Charge dielectric matrix, 2 for electronic dielectric matrix
    1937              : !!  prtvol=control print volume and debugging output
    1938              : !!  susmat(2,npwdiel,nspden,npwdiel,nspden)=
    1939              : !!   the susceptibility (or density-density response) matrix in reciprocal space
    1940              : !!
    1941              : !! OUTPUT
    1942              : !!  dielinv(2,npwdiel,nspden,npwdiel,nspden)=inverse of the (non-hermitian)
    1943              : !!      TC dielectric matrix in reciprocal space.
    1944              : !!
    1945              : !! NOTES
    1946              : !! Output (not cleaned)
    1947              : !! !!! Spin behaviour is not obvious !!!
    1948              : !! Will not work in the spin-polarized, metallic case.
    1949              : !!
    1950              : !! SOURCE
    1951              : 
    1952            6 : subroutine dieltcel(dielinv,gmet,kg_diel,kxc,nfft,ngfft,nkxc,npwdiel,nspden,occopt,option,prtvol,susmat)
    1953              : 
    1954              : !Arguments ------------------------------------
    1955              : !scalars
    1956              :  integer,intent(in) :: nfft,nkxc,npwdiel,nspden,occopt,option
    1957              :  integer,intent(in) :: prtvol
    1958              : !arrays
    1959              :  integer,intent(in) :: kg_diel(3,npwdiel),ngfft(18)
    1960              :  real(dp),intent(in) :: gmet(3,3),kxc(nfft,nkxc)
    1961              :  real(dp),intent(in) :: susmat(2,npwdiel,nspden,npwdiel,nspden)
    1962              :  real(dp),intent(out) :: dielinv(2,npwdiel,nspden,npwdiel,nspden)
    1963              : 
    1964              : !Local variables-------------------------------
    1965              : !scalars
    1966              :  integer :: i1,i2,i3,ieig,ier,ifft,ii,index,ipw0,ipw1,ipw2,ispden,j1
    1967              :  integer :: j2,j3,jj,k1,k2,k3,n1,n2,n3
    1968              :  real(dp) :: ai,ai2,ar,ar2,eiginv,kg_red1,kg_red2,kg_red3,gsquar,si
    1969              :  real(dp) :: sr,tpisq
    1970              :  character(len=500) :: message
    1971            6 :  type(MPI_type) :: mpi_enreg_seq
    1972              : !arrays
    1973              :  real(dp) :: tsec(2)
    1974            6 :  real(dp),allocatable :: eig_msusinvsqr(:),eig_msussqr(:)
    1975            6 :  real(dp),allocatable :: eig_sus(:),eig_sym(:),invsqrsus(:,:,:,:,:)
    1976            6 :  real(dp),allocatable :: khxc(:,:,:,:,:),kxcg(:,:),sqrsus(:,:,:,:,:),sush(:)
    1977            6 :  real(dp),allocatable :: susvec(:,:,:),symdielmat(:,:,:,:,:),symh(:)
    1978            6 :  real(dp),allocatable :: symvec(:,:,:,:,:),wkxc(:),work(:,:,:,:,:)
    1979            6 :  real(dp),allocatable :: work2(:,:,:,:,:),zhpev1(:,:),zhpev2(:)
    1980              : !no_abirules
    1981              : !integer :: ipw3
    1982              : !real(dp) :: elementi,elementr
    1983              : !DEBUG
    1984              : !Used to moderate divergence effect near rho=0 of the Kxc
    1985              : !this limit value is truly empirical (exprmt on small Sr cell).
    1986              : !real(dp) :: kxc_min=-200.0
    1987              : !ENDDEBUG
    1988              : ! *************************************************************************
    1989              : 
    1990            6 :  call timab(96,1,tsec)
    1991              : 
    1992              : !tpisq is (2 Pi) **2:
    1993            6 :  tpisq=(two_pi)**2
    1994              : 
    1995            6 :  if(nspden/=1 .and. (occopt>=3 .and. occopt<=8) )then
    1996              :    write(message, '(a,a,a)' )&
    1997            0 : &   'In the present version of the code, one cannot produce',ch10,&
    1998            0 : &   'the dielectric matrix in the metallic, spin-polarized case.'
    1999            0 :    ABI_BUG(message)
    2000              :  end if
    2001              : 
    2002            6 :  if(nspden==4)then
    2003              :    write(message,'(a,a,a)')&
    2004            0 : &   'In the present version of the code, one cannot produce',ch10,&
    2005            0 : &   'the dielectric matrix in the non-collinear spin-polarized case.'
    2006            0 :    ABI_ERROR(message)
    2007              :  end if
    2008              : 
    2009              : 
    2010              : !-Diagonalize the susceptibility matrix
    2011              : 
    2012           18 :  ABI_MALLOC(sush,(npwdiel*(npwdiel+1)))
    2013           24 :  ABI_MALLOC(susvec,(2,npwdiel,npwdiel))
    2014           18 :  ABI_MALLOC(eig_msusinvsqr,(npwdiel))
    2015           12 :  ABI_MALLOC(eig_msussqr,(npwdiel))
    2016           12 :  ABI_MALLOC(eig_sus,(npwdiel))
    2017           18 :  ABI_MALLOC(zhpev1,(2,2*npwdiel-1))
    2018           18 :  ABI_MALLOC(zhpev2,(3*npwdiel-2))
    2019           36 :  ABI_MALLOC(work,(2,npwdiel,nspden,npwdiel,nspden))
    2020           30 :  ABI_MALLOC(work2,(2,npwdiel,nspden,npwdiel,nspden))
    2021           30 :  ABI_MALLOC(sqrsus,(2,npwdiel,nspden,npwdiel,nspden))
    2022           30 :  ABI_MALLOC(invsqrsus,(2,npwdiel,nspden,npwdiel,nspden))
    2023              : 
    2024              : !At some time, should take care of different spin channels
    2025           12 :  do ispden=1,nspden
    2026              : 
    2027            6 :    if(nspden/=1)then
    2028            0 :      ABI_ERROR('dieltcel : stop, nspden/=1')
    2029              :    end if
    2030              : 
    2031              : !  Store the susceptibility matrix in proper mode before calling zhpev
    2032              :    index=1
    2033          240 :    do ii=1,npwdiel
    2034         4920 :      do jj=1,ii
    2035         4680 :        sush(index  )=susmat(1,jj,1,ii,1)
    2036         4680 :        sush(index+1)=susmat(2,jj,1,ii,1)
    2037         4914 :        index=index+2
    2038              :      end do
    2039              :    end do
    2040              : 
    2041            6 :    ier=0
    2042            6 :    call ZHPEV ('V','U',npwdiel,sush,eig_sus,susvec,npwdiel,zhpev1,zhpev2,ier)
    2043              : 
    2044              : !  DEBUG
    2045              : !  write(std_out,*)' dieltcel : print eigenvalues of the susceptibility matrix'
    2046              : !  do ii=1,npwdiel
    2047              : !  write(std_out,'(i5,es16.6)' )ii,eig_sus(ii)
    2048              : !  end do
    2049              : !  ENDDEBUG
    2050              : 
    2051          240 :    do ii=1,npwdiel
    2052          240 :      if(-eig_sus(ii)>1.d-12)then
    2053          228 :        eig_msussqr(ii)=sqrt(-eig_sus(ii))
    2054          228 :        eig_msusinvsqr(ii)=1._dp/eig_msussqr(ii)
    2055            6 :      else if(-eig_sus(ii)< -1.d-12)then
    2056            0 :        message = "Found positive eigenvalue of susceptibility matrix."
    2057            0 :        ABI_BUG(message)
    2058              :      else
    2059              : !      Set the eigenvalue corresponding to a constant potential change to 1,
    2060              : !      while it will be set to zero in Khx.
    2061            6 :        eig_msussqr(ii)=1._dp
    2062            6 :        eig_msusinvsqr(ii)=1._dp
    2063              :      end if
    2064              :    end do
    2065              : 
    2066              : !  Compute square root of minus susceptibility matrix
    2067              : !  and inverse square root of minus susceptibility matrix
    2068          240 :    do ii=1,npwdiel
    2069        27612 :      work(:,:,1,ii,1)=susvec(:,:,ii)*eig_msussqr(ii)
    2070        27618 :      work2(:,:,1,ii,1)=susvec(:,:,ii)*eig_msusinvsqr(ii)
    2071              :    end do
    2072          246 :    do ipw2=1,npwdiel
    2073         4920 :      do ipw1=ipw2,npwdiel
    2074              :        ar=0._dp ; ai=0._dp ; ar2=0._dp ; ai2=0._dp
    2075       187200 :        do ii=1,npwdiel
    2076       182520 :          sr=susvec(1,ipw2,ii) ; si=susvec(2,ipw2,ii)
    2077       182520 :          ar =ar  +work(1,ipw1,1,ii,1)*sr  +work(2,ipw1,1,ii,1)*si
    2078       182520 :          ai =ai  +work(2,ipw1,1,ii,1)*sr  -work(1,ipw1,1,ii,1)*si
    2079       182520 :          ar2=ar2 +work2(1,ipw1,1,ii,1)*sr +work2(2,ipw1,1,ii,1)*si
    2080       187200 :          ai2=ai2 +work2(2,ipw1,1,ii,1)*sr -work2(1,ipw1,1,ii,1)*si
    2081              :        end do
    2082         4680 :        sqrsus(1,ipw1,1,ipw2,1)=ar
    2083         4680 :        sqrsus(2,ipw1,1,ipw2,1)=ai
    2084         4680 :        invsqrsus(1,ipw1,1,ipw2,1)=ar2
    2085         4680 :        invsqrsus(2,ipw1,1,ipw2,1)=ai2
    2086         4914 :        if(ipw1/=ipw2)then
    2087         4446 :          sqrsus(1,ipw2,1,ipw1,1)=ar
    2088         4446 :          sqrsus(2,ipw2,1,ipw1,1)=-ai
    2089         4446 :          invsqrsus(1,ipw2,1,ipw1,1)=ar2
    2090         4446 :          invsqrsus(2,ipw2,1,ipw1,1)=-ai2
    2091              :        end if
    2092              :      end do
    2093              :    end do
    2094              : 
    2095              : !  DEBUG
    2096              : !  Checks whether sqrsus and invsqrsus are inverse of each other.
    2097              : !  do ipw1=1,npwdiel
    2098              : !  do ipw2=1,npwdiel
    2099              : !  elementr=0.0_dp
    2100              : !  elementi=0.0_dp
    2101              : !  do ipw3=1,npwdiel
    2102              : !  elementr=elementr+sqrsus(1,ipw1,1,ipw3,1)*invsqrsus(1,ipw3,1,ipw2,1)&
    2103              : !  &                    -sqrsus(2,ipw1,1,ipw3,1)*invsqrsus(2,ipw3,1,ipw2,1)
    2104              : !  elementi=elementi+sqrsus(1,ipw1,1,ipw3,1)*invsqrsus(2,ipw3,1,ipw2,1)&
    2105              : !  &                    +sqrsus(2,ipw1,1,ipw3,1)*invsqrsus(1,ipw3,1,ipw2,1)
    2106              : !  end do
    2107              : !  if(elementr**2+elementi**2 > 1.0d-12)then
    2108              : !  if( ipw1 /= ipw2 .or. &
    2109              : !  &        ( abs(elementr-1.0_dp)>1.0d-6 .or. abs(elementi)>1.0d-6 ))then
    2110              : !  write(std_out,*)' dieltcel : sqrsus and invsqrsus are not (pseudo)',&
    2111              : !  &        'inverse of each other'
    2112              : !  write(std_out,*)' ipw1, ipw2 =',ipw1,ipw2
    2113              : !  write(std_out,*)' elementr,elementi=',elementr,elementi
    2114              : !  stop
    2115              : !  end if
    2116              : !  end if
    2117              : !  end do
    2118              : !  end do
    2119              : !  ENDDEBUG
    2120              : 
    2121              : !  End loop over spins
    2122              :  end do
    2123              : 
    2124            6 :  ABI_FREE(eig_msusinvsqr)
    2125            6 :  ABI_FREE(eig_msussqr)
    2126            6 :  ABI_FREE(eig_sus)
    2127            6 :  ABI_FREE(sush)
    2128            6 :  ABI_FREE(susvec)
    2129              : 
    2130              : !-Compute the Hxc kernel
    2131              : 
    2132           30 :  ABI_MALLOC(khxc,(2,npwdiel,nspden,npwdiel,nspden))
    2133           30 :  ABI_MALLOC(symdielmat,(2,npwdiel,nspden,npwdiel,nspden))
    2134              : 
    2135        27858 :  khxc(:,:,:,:,:)=0.0_dp
    2136              : 
    2137              : !Compute Hartree kernel
    2138          240 :  do ipw1=1,npwdiel
    2139          234 :    kg_red1=dble(kg_diel(1,ipw1))
    2140          234 :    kg_red2=dble(kg_diel(2,ipw1))
    2141          234 :    kg_red3=dble(kg_diel(3,ipw1))
    2142              :    gsquar=tpisq*(gmet(1,1)*kg_red1**2+gmet(2,2)*kg_red2**2+gmet(3,3)*kg_red3**2 &
    2143              : &   +2.0_dp*( (gmet(1,2)*kg_red2+gmet(1,3)*kg_red3)* kg_red1 +      &
    2144          234 : &   gmet(2,3)*kg_red2*kg_red3)                        )
    2145              : !  Distinguish G=0 from other elements
    2146          240 :    if(gsquar>1.0d-12)then
    2147          228 :      khxc(1,ipw1,1,ipw1,1)= 4.0_dp*pi/gsquar
    2148              :    else
    2149              : !    G=0
    2150              :      ipw0=ipw1
    2151              :    end if
    2152              :  end do
    2153              : 
    2154              : !Eventually add the xc part
    2155            6 :  if(option>=2)then
    2156              : 
    2157           12 :    ABI_MALLOC(wkxc,(nfft))
    2158           12 :    ABI_MALLOC(kxcg,(2,nfft))
    2159        25924 :    wkxc(:)=kxc(:,1)
    2160              : !  DEBUG
    2161              : !  Used to moderate divergenc effect near rho=0 of the Kxc (see above).
    2162              : !  wkxc(:)=merge(kxc(:,1), kxc_min, kxc(:,1) > kxc_min)
    2163              : !  ENDDEBUG
    2164            4 :    call initmpi_seq(mpi_enreg_seq)
    2165            4 :    call MPI_enreg_seq%distribfft%init_seq('c',ngfft(2),ngfft(3),'all')
    2166            4 :    call fourdp(1,kxcg,wkxc,-1,mpi_enreg_seq,nfft,1,ngfft,0) ! trsfrm R to G
    2167            4 :    call destroy_mpi_enreg(mpi_enreg_seq)
    2168              : 
    2169              : !  Compute difference in G vectors
    2170            4 :    n1=ngfft(1) ; n2=ngfft(2) ; n3=ngfft(3)
    2171          160 :    do ipw2=1,npwdiel
    2172          160 :      if(ipw2/=ipw0)then
    2173              : 
    2174          152 :        j1=kg_diel(1,ipw2) ; j2=kg_diel(2,ipw2) ; j3=kg_diel(3,ipw2)
    2175              : !      Fills diagonal
    2176          152 :        khxc(1,ipw2,1,ipw2,1)=khxc(1,ipw2,1,ipw2,1)+kxcg(1,1)
    2177          152 :        khxc(2,ipw2,1,ipw2,1)=khxc(2,ipw2,1,ipw2,1)+kxcg(2,1)
    2178              : 
    2179          152 :        if(ipw2/=npwdiel)then
    2180              : !        Fills off-diagonal part of the matrix, except G=0
    2181         2960 :          do ipw1=ipw2+1,npwdiel
    2182         2960 :            if(ipw1/=ipw0)then
    2183         2812 :              i1=kg_diel(1,ipw1) ; i2=kg_diel(2,ipw1) ; i3=kg_diel(3,ipw1)
    2184              : !            Use of two mod calls handles both i1-j1>=ndiel1 AND i1-j1<0
    2185         2812 :              k1=mod(n1+mod(i1-j1,n1),n1)
    2186         2812 :              k2=mod(n2+mod(i2-j2,n2),n2)
    2187         2812 :              k3=mod(n3+mod(i3-j3,n3),n3)
    2188         2812 :              ifft=k1+1+n1*(k2+n2*k3)
    2189              : !            The signs of imaginary contributions have been checked
    2190         2812 :              khxc(1,ipw1,1,ipw2,1)=kxcg(1,ifft)
    2191         2812 :              khxc(2,ipw1,1,ipw2,1)=kxcg(2,ifft)
    2192         2812 :              khxc(1,ipw2,1,ipw1,1)=kxcg(1,ifft)
    2193         2812 :              khxc(2,ipw2,1,ipw1,1)=-kxcg(2,ifft)
    2194              :            end if
    2195              :          end do
    2196              :        end if
    2197              : 
    2198              :      end if
    2199              :    end do
    2200              : 
    2201            4 :    ABI_FREE(wkxc)
    2202            4 :    ABI_FREE(kxcg)
    2203              : 
    2204              : !  Endif option 2
    2205              :  end if
    2206              : 
    2207              : !Now, get the symmetric dielectric matrix
    2208              : !Premultiplication by square root of minus susceptibility matrix
    2209          240 :  do ipw2=1,npwdiel
    2210         9366 :    do ipw1=1,npwdiel
    2211              :      ar=0._dp ; ai=0._dp
    2212       365040 :      do ii=1,npwdiel
    2213              :        ar=ar+sqrsus(1,ipw1,1,ii,1)*khxc(1,ii,1,ipw2,1) &
    2214       355914 : &       -sqrsus(2,ipw1,1,ii,1)*khxc(2,ii,1,ipw2,1)
    2215              :        ai=ai+sqrsus(2,ipw1,1,ii,1)*khxc(1,ii,1,ipw2,1) &
    2216       365040 : &       +sqrsus(1,ipw1,1,ii,1)*khxc(2,ii,1,ipw2,1)
    2217              :      end do
    2218         9126 :      work(1,ipw1,1,ipw2,1)=ar
    2219         9360 :      work(2,ipw1,1,ipw2,1)=ai
    2220              :    end do
    2221              :  end do
    2222              : !Postmultiplication by square root of minus susceptibility matrix
    2223          240 :  do ipw2=1,npwdiel
    2224              : !  do ipw1=ipw2,npwdiel
    2225         9360 :    do ipw1=1,npwdiel
    2226              :      ar=0._dp ; ai=0._dp
    2227       365040 :      do ii=1,npwdiel
    2228              :        ar=ar+work(1,ipw1,1,ii,1)*sqrsus(1,ii,1,ipw2,1) &
    2229       355914 : &       -work(2,ipw1,1,ii,1)*sqrsus(2,ii,1,ipw2,1)
    2230              :        ai=ai+work(2,ipw1,1,ii,1)*sqrsus(1,ii,1,ipw2,1) &
    2231       365040 : &       +work(1,ipw1,1,ii,1)*sqrsus(2,ii,1,ipw2,1)
    2232              :      end do
    2233         9126 :      symdielmat(1,ipw1,1,ipw2,1)=ar
    2234         9360 :      symdielmat(2,ipw1,1,ipw2,1)=ai
    2235              : !    if(ipw1/=ipw2)then
    2236              : !    symdielmat(1,ipw2,1,ipw1,1)=ar
    2237              : !    symdielmat(2,ipw2,1,ipw1,1)=-ai
    2238              : !    end if
    2239              :    end do
    2240              : !  Add the unity matrix
    2241          240 :    symdielmat(1,ipw2,1,ipw2,1)=1._dp+symdielmat(1,ipw2,1,ipw2,1)
    2242              :  end do
    2243              : 
    2244            6 :  ABI_FREE(khxc)
    2245              : 
    2246           12 :  ABI_MALLOC(symh,(npwdiel*(npwdiel+1)))
    2247           30 :  ABI_MALLOC(symvec,(2,npwdiel,nspden,npwdiel,nspden))
    2248           12 :  ABI_MALLOC(eig_sym,(npwdiel))
    2249              : 
    2250              : !Store the symmetrized dielectric matrix in proper mode before calling zhpev
    2251          240 :  index=1
    2252          240 :  do ii=1,npwdiel
    2253         4920 :    do jj=1,ii
    2254         4680 :      symh(index  )=symdielmat(1,jj,1,ii,1)
    2255         4680 :      symh(index+1)=symdielmat(2,jj,1,ii,1)
    2256         4914 :      index=index+2
    2257              :    end do
    2258              :  end do
    2259              : 
    2260            6 :  ier=0
    2261              :  call ZHPEV ('V','U',npwdiel,symh,eig_sym,symvec,npwdiel,zhpev1,&
    2262            6 : & zhpev2,ier)
    2263              : 
    2264            6 :  if(prtvol>=10)then
    2265            6 :    write(message, '(a,a,a,5es12.4)' )ch10,&
    2266            6 : &   ' Five largest eigenvalues of the symmetrized dielectric matrix:',&
    2267           12 : &   ch10,eig_sym(npwdiel:npwdiel-4:-1)
    2268            6 :    call wrtout(ab_out,message,'COLL')
    2269              :  end if
    2270              : 
    2271            6 :  write(message,'(2a)')ch10,' dieltcel : 15 largest eigenvalues of the symmetrized dielectric matrix'
    2272            6 :  call wrtout(std_out,message,'COLL')
    2273            6 :  write(message, '(a,5es12.5)' )'  1-5  :',eig_sym(npwdiel:npwdiel-4:-1)
    2274            6 :  call wrtout(std_out,message,'COLL')
    2275            6 :  write(message, '(a,5es12.5)' )'  6-10 :',eig_sym(npwdiel-5:npwdiel-9:-1)
    2276            6 :  call wrtout(std_out,message,'COLL')
    2277            6 :  write(message, '(a,5es12.5)' )'  11-15:',eig_sym(npwdiel-10:npwdiel-14:-1)
    2278            6 :  call wrtout(std_out,message,'COLL')
    2279            6 :  write(message, '(2a)' )ch10,' dieltcel : 5 smallest eigenvalues of the symmetrized dielectric matrix'
    2280            6 :  call wrtout(std_out,message,'COLL')
    2281            6 :  write(message, '(a,5es12.5)' )'  1-5  :',eig_sym(1:5)
    2282            6 :  call wrtout(std_out,message,'COLL')
    2283              : 
    2284              : !Invert the hermitian dielectric matrix,
    2285        27858 :  work(:,:,:,:,:)=0.0_dp
    2286          240 :  do ieig=1,npwdiel
    2287          234 :    eiginv=1.0_dp/eig_sym(ieig)
    2288         9366 :    do ipw2=1,npwdiel
    2289              : !    do ipw1=ipw2,npwdiel
    2290       365274 :      do ipw1=1,npwdiel
    2291              :        work(1,ipw1,1,ipw2,1)=work(1,ipw1,1,ipw2,1)+&
    2292              : &       (symvec(1,ipw1,1,ieig,1)*symvec(1,ipw2,1,ieig,1)+ &
    2293       355914 : &       symvec(2,ipw1,1,ieig,1)*symvec(2,ipw2,1,ieig,1) ) * eiginv
    2294              :        work(2,ipw1,1,ipw2,1)=work(2,ipw1,1,ipw2,1)+&
    2295              : &       (symvec(2,ipw1,1,ieig,1)*symvec(1,ipw2,1,ieig,1)- &
    2296       365040 : &       symvec(1,ipw1,1,ieig,1)*symvec(2,ipw2,1,ieig,1) ) * eiginv
    2297              :      end do
    2298              :    end do
    2299              :  end do
    2300              : !if(npwdiel>1)then
    2301              : !do ipw2=2,npwdiel
    2302              : !do ipw1=1,ipw2-1
    2303              : !work(1,ipw1,1,ipw2,1)= work(1,ipw2,1,ipw1,1)
    2304              : !work(2,ipw1,1,ipw2,1)=-work(2,ipw2,1,ipw1,1)
    2305              : !end do
    2306              : !end do
    2307              : !end if
    2308              : 
    2309            6 :  ABI_FREE(eig_sym)
    2310            6 :  ABI_FREE(symh)
    2311            6 :  ABI_FREE(symvec)
    2312              : 
    2313              : !DEBUG
    2314              : !Checks whether the inverse of the symmetric dielectric matrix
    2315              : !has been correctly generated
    2316              : !do ipw1=1,npwdiel
    2317              : !do ipw2=1,npwdiel
    2318              : !elementr=0.0_dp
    2319              : !elementi=0.0_dp
    2320              : !do ipw3=1,npwdiel
    2321              : !elementr=elementr+work(1,ipw1,1,ipw3,1)*symdielmat(1,ipw3,1,ipw2,1)&
    2322              : !&                    -work(2,ipw1,1,ipw3,1)*symdielmat(2,ipw3,1,ipw2,1)
    2323              : !elementi=elementi+work(1,ipw1,1,ipw3,1)*symdielmat(2,ipw3,1,ipw2,1)&
    2324              : !&                    +work(2,ipw1,1,ipw3,1)*symdielmat(1,ipw3,1,ipw2,1)
    2325              : !end do
    2326              : !if(elementr**2+elementi**2 > 1.0d-12)then
    2327              : !if( ipw1 /= ipw2 .or. &
    2328              : !&        ( abs(elementr-1.0_dp)>1.0d-6 .or. abs(elementi)>1.0d-6 ))then
    2329              : !write(std_out,*)' dieltcel : the inversion procedure is not correct '
    2330              : !write(std_out,*)' ipw1, ipw2 =',ipw1,ipw2
    2331              : !write(std_out,*)' elementr,elementi=',elementr,elementi
    2332              : !stop
    2333              : !end if
    2334              : !end if
    2335              : !end do
    2336              : !end do
    2337              : !write(std_out,*)'dieltcel : matrix has been inverted successfully '
    2338              : !ENDDEBUG
    2339              : 
    2340            6 :  ABI_FREE(symdielmat)
    2341              : 
    2342              : !Then get the inverse of the asymmetric
    2343              : !dielectric matrix, as required for the preconditioning.
    2344              : !Premultiplication by square root of minus susceptibility matrix
    2345          240 :  do ipw2=1,npwdiel
    2346         9366 :    do ipw1=1,npwdiel
    2347              :      ar=0._dp ; ai=0._dp
    2348       365040 :      do ii=1,npwdiel
    2349              :        ar=ar+invsqrsus(1,ipw1,1,ii,1)*work(1,ii,1,ipw2,1) &
    2350       355914 : &       -invsqrsus(2,ipw1,1,ii,1)*work(2,ii,1,ipw2,1)
    2351              :        ai=ai+invsqrsus(2,ipw1,1,ii,1)*work(1,ii,1,ipw2,1) &
    2352       365040 : &       +invsqrsus(1,ipw1,1,ii,1)*work(2,ii,1,ipw2,1)
    2353              :      end do
    2354         9126 :      work2(1,ipw1,1,ipw2,1)=ar
    2355         9360 :      work2(2,ipw1,1,ipw2,1)=ai
    2356              :    end do
    2357              :  end do
    2358              : !Postmultiplication by square root of minus susceptibility matrix
    2359          240 :  do ipw2=1,npwdiel
    2360         9366 :    do ipw1=1,npwdiel
    2361              :      ar=0._dp ; ai=0._dp
    2362       365040 :      do ii=1,npwdiel
    2363              :        ar=ar+work2(1,ipw1,1,ii,1)*sqrsus(1,ii,1,ipw2,1) &
    2364       355914 : &       -work2(2,ipw1,1,ii,1)*sqrsus(2,ii,1,ipw2,1)
    2365              :        ai=ai+work2(2,ipw1,1,ii,1)*sqrsus(1,ii,1,ipw2,1) &
    2366       365040 : &       +work2(1,ipw1,1,ii,1)*sqrsus(2,ii,1,ipw2,1)
    2367              :      end do
    2368         9126 :      dielinv(1,ipw1,1,ipw2,1)=ar
    2369         9360 :      dielinv(2,ipw1,1,ipw2,1)=ai
    2370              :    end do
    2371              :  end do
    2372              : 
    2373            6 :  ABI_FREE(invsqrsus)
    2374            6 :  ABI_FREE(sqrsus)
    2375            6 :  ABI_FREE(work)
    2376            6 :  ABI_FREE(work2)
    2377            6 :  ABI_FREE(zhpev1)
    2378            6 :  ABI_FREE(zhpev2)
    2379              : 
    2380            6 :  call timab(96,2,tsec)
    2381              : 
    2382            6 : end subroutine dieltcel
    2383              : !!***
    2384              : 
    2385              : !!****f* ABINIT/chi0diel
    2386              : !! NAME
    2387              : !! chi0diel
    2388              : !!
    2389              : !! FUNCTION
    2390              : !!  Computes the preconditioned residual vrespc = P^-1 vresid where P is an approximation of the 
    2391              : !!  dielectric matrix (if 'optres'=0) or its adjoint (if 'optres'=1) based of a model of the 
    2392              : !!  non-interacting susceptibility chi0. The approximation is described by the object 'precon'
    2393              : !!  (see the abinit documentation of the input variable 'iprcel').
    2394              : !!
    2395              : !! INPUTS
    2396              : !!  precon        = precon_object that contain the model chi0 operator.
    2397              : !!  dtset         = All input variables for this dataset.
    2398              : !!  mpi_enreg     = Information about MPI parallelization.
    2399              : !!  optreal       = 1: vresid is given in the REAL space.
    2400              : !!                  2: vresid is given in the RECIPROCAL space.
    2401              : !!  optres        = 0: the array vresid contains a potential residual.
    2402              : !!                  1: the array vresid contains a density residual.
    2403              : !!  vresid (:, nspden) = residual density/potential in REAL space       (if optreal==1)
    2404              : !!                       residual density/potential in RECIPROCAL space (if optreal==2)
    2405              : !!
    2406              : !! OUTPUT
    2407              : !!  vrespc (:, nspden) = preconditioned residual of the density/potential in REAL space
    2408              : !!                       in REAL space (optreal==1) or RECIPROCAL space (optreal==2)
    2409              : !!
    2410              : !! SOURCE
    2411              : 
    2412           18 : subroutine chi0diel(precon, dtset, mpi_enreg, optreal, optres, vresid, vrespc)
    2413              : 
    2414              : !Arguments ------------------------------------
    2415              :  type(precon_object) :: precon
    2416              : !scalars
    2417              :  integer,intent(in) :: optreal, optres
    2418              :  type(MPI_type),intent(in) :: mpi_enreg
    2419              :  type(dataset_type),intent(in) :: dtset
    2420              : !arrays
    2421              :  real(dp),intent(in) :: vresid(optreal*precon%nfftprc, dtset%nspden)
    2422              :  real(dp),intent(out) :: vrespc(optreal*precon%nfftprc, dtset%nspden)
    2423              : 
    2424              : ! *************************************************************************
    2425              : 
    2426           18 :  call precon%apply_precon(dtset, mpi_enreg, optreal, optres, vresid, vrespc)
    2427              : 
    2428              :  !Simple mixing
    2429       121554 :  vrespc = precon%diemix * vrespc
    2430              : 
    2431           18 : end subroutine chi0diel
    2432              : !!***
    2433              : 
    2434              : !!****f* ABINIT/prcrskerker1
    2435              : !! NAME
    2436              : !! prcrskerker1
    2437              : !!
    2438              : !! FUNCTION
    2439              : !! preconditionning by a real-space conjugate gradient on residual
    2440              : !! using a model dielectric function in real space
    2441              : !!
    2442              : !! INPUTS
    2443              : !!  nfft=number of fft grid points
    2444              : !!  nspden=number of spin-density components
    2445              : !!  ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
    2446              : !!  dielar(7)=input parameters for dielectric matrix:
    2447              : !!                diecut,dielng,diemac,diemix,diegap,dielam,diemixmag.
    2448              : !!  gprimd(3,3)=dimensional primitive translations in fourier space (bohr**-1)
    2449              : !!  rprimd(3,3)=dimensional primitive translations in real space (bohr)
    2450              : !!  vresid(nfft,nspden)=residual potential
    2451              : !!  base(nfft) = real space function used as a basis to guess a fine dielectric function
    2452              : !!  see the calling routine to know the content
    2453              : !!
    2454              : !! OUTPUT
    2455              : !!  vrespc(nfft,nspden)=preconditioned residual of the potential
    2456              : !!
    2457              : !! WARNINGS
    2458              : !! This is experimental code : input, ouptput, results and any other feature may vary greatly.
    2459              : !!
    2460              : !! NOTES
    2461              : !!  needs severe cleaning and this is abuse of modules as common blocks...
    2462              : !!
    2463              : !! SOURCE
    2464              : 
    2465            7 : subroutine prcrskerker1(dtset,mpi_enreg,nfft,nspden,ngfft,dielar,etotal,gprimd,vresid,vrespc,base)
    2466              : 
    2467              : !Arguments ------------------------------------
    2468              : !scalars
    2469              :  integer,intent(in) :: nfft,nspden
    2470              :  real(dp) :: etotal
    2471              :  type(MPI_type),intent(in) :: mpi_enreg
    2472              :  type(dataset_type),intent(in) :: dtset
    2473              : !arrays
    2474              :  integer,intent(in) :: ngfft(18)
    2475              :  real(dp),intent(in) :: base(nfft),dielar(7),gprimd(3,3)
    2476              :  real(dp),intent(in) :: vresid(nfft,nspden)
    2477              :  real(dp),intent(out) :: vrespc(nfft,nspden)
    2478              : 
    2479              : !Local variables-------------------------------
    2480              : !scalars
    2481              :  integer ::  ifft,ispden,n1,n2,n3
    2482              :  real(dp) :: base_delta,base_max,base_min,dielng,diemac,diemix
    2483              :  real(dp) :: diemixmag
    2484              :  real(dp) :: rdummy1,rdummy2
    2485              :  logical ::  new_prc_func
    2486              : !arrays
    2487           14 :  real(dp) :: deltaW(nfft,nspden)
    2488           14 :  real(dp) :: g2cart(nfft)
    2489           14 :  real(dp) :: mat(nfft,nspden)
    2490              : ! *************************************************************************
    2491              : 
    2492              : !DEBUG
    2493              : !write(std_out,*)' prckerker1 : enter '
    2494              : !ENDDEBUG
    2495              : !if(cycle==0) then
    2496            7 :  call prc_mem_init(nfft)
    2497              : 
    2498            7 :  if(cycle==0) then
    2499            1 :    new_prc_func=.TRUE.
    2500            1 :    energy_min=etotal
    2501            6 :  else if(etotal < energy_min) then
    2502            5 :    new_prc_func=.TRUE.
    2503            5 :    energy_min=etotal
    2504              :  else
    2505              :    new_prc_func=.FALSE.
    2506              :  end if
    2507              : 
    2508              : 
    2509            7 :  dielng=dielar(2)
    2510            7 :  diemac=dielar(3)
    2511            7 :  diemix=dielar(4)
    2512            7 :  diemixmag=dielar(7)
    2513              : !******************************************************************
    2514              : !compute the diemac(r)                                          **
    2515              : !******************************************************************
    2516              : !this task will be devoted to a general function later
    2517            7 :  n1=ngfft(1)
    2518            7 :  n2=ngfft(2)
    2519            7 :  n3=ngfft(3)
    2520              : !base_cp=base
    2521            7 :  if(new_prc_func) then
    2522            6 :    base_min=base(1)
    2523            6 :    base_max=base(1)
    2524        60006 :    do ifft=1,nfft
    2525        60000 :      base_min = min(base_min,base(ifft))
    2526        60006 :      base_max = max(base_max,base(ifft))
    2527              :    end do
    2528            6 :    base_delta = base_max - base_min
    2529              : !  if(cycle.lt.2) then
    2530        60006 :    rdiemac(:) = (((base(:)-base_min) / (base_delta) ) *(diemac-one) + one)
    2531              : !  else
    2532              : !  rdiemac(:) = rdiemac(:)*0.5_dp+0.5_dp*(((base(:)-base_min) / (base_delta) ) *(diemac-one) + one)
    2533              : !  end if
    2534              : !  if(cycle==0) rdiemac(:) = (((base(:)-base_min) / (base_delta) ) *(diemac-one) + one)
    2535              : !  rdiemac(:) = exp(((base(:)-base_min) / (base_delta) *log(diemac)))
    2536              :  end if
    2537            7 :  cycle=cycle+1
    2538              : !if(cycle==5) cycle=0
    2539              : !end if
    2540              : !******************************************************************
    2541              : !compute deltaW                                                 **
    2542              : !******************************************************************
    2543        70014 :  vrespc=vresid !starting point
    2544              :  ! put the laplacian of the residuals into deltaW
    2545            7 :  call laplacian(gprimd,mpi_enreg,nfft,nspden,ngfft,rdfuncr=vrespc,laplacerdfuncr=deltaW,g2cart_out=g2cart)
    2546              : 
    2547              : !call laplacian(vrespc,buffer,ngfft,gprimd) ! put the laplacian of the residuals into deltaW
    2548              : !do ifft=1,nfft
    2549              : !if (buffer(ifft,1)/=deltaW(ifft,1)) then
    2550              : !stop
    2551              : !end if
    2552              : !end do
    2553        70007 :  deltaW(:,1)= diemix*(((one/rdiemac(:))*vresid(:,1))-(((dielng)**2)*deltaW(:,1)))
    2554            7 :  if (nspden>1.and.(diemixmag>=zero)) then
    2555            0 :    do ispden=2,nspden
    2556            0 :      deltaW(:,ispden)= abs(diemixmag)*(((one/rdiemac(:))*vresid(:,ispden))-(((dielng)**2)*deltaW(:,ispden)))
    2557              :    end do
    2558              :  end if
    2559              : !call random_number(deltaW)
    2560              : !call random_number(vrespc)
    2561              : !******************************************************************
    2562              : !Finding the preconditionned residuals which minimizes          **
    2563              : !half*(vrespc*(1-dielng2/4pi2 nabla2) vrespc) - vrespc * deltaW **
    2564              : !***********************************************************************
    2565        70007 :  vrespc(:,1)=diemix*vrespc(:,1)
    2566            7 :  if (nspden>1) vrespc(:,2:nspden)=abs(diemixmag)*vrespc(:,2:nspden)
    2567              : !buffer=vrespc
    2568              : 
    2569              : 
    2570              : !==============================================================================
    2571              : !==============================================================================
    2572              : !! Original loop
    2573              : !==============================================================================
    2574              : !==============================================================================
    2575              : 
    2576            7 :  call frskerker1__init(dtset,mpi_enreg,nfft,ngfft,nspden,dielng,deltaW,gprimd,mat,g2cart)
    2577              : 
    2578              : !call cgpr(pf_rscgres,dpf_rscgres,newvres,real(1e-40,dp),700,vrespc,rdummy1,rdummy2)
    2579              : !rdummy1 = pf_rscgres(nfft,nspden,vrespc)
    2580              :  call cgpr(nfft,nspden,frskerker1__pf,frskerker1__dpf,frskerker1__newvres,&
    2581            7 : & real(1e-10,dp),700,vrespc,rdummy1,rdummy2)
    2582            7 :  call frskerker1__end()
    2583              : 
    2584              : !==============================================================================
    2585              : !==============================================================================
    2586              : !! Original loop end
    2587              : !==============================================================================
    2588              : !==============================================================================
    2589              : 
    2590              : 
    2591              : !cplex=1
    2592              : !qphon(:)=zero
    2593              : !call moddiel(cplex,dielar,nfft,ngfft,nspden,1,0,qphon,rprimd,vresid,buffer)
    2594              : !c1=0
    2595              : !do ifft=1,nfft,1
    2596              : !if((abs(buffer(ifft,1)-vrespc(ifft,1))/(abs(buffer(ifft,1)+vrespc(ifft,1))*half)) > 5e-3) then
    2597              : !c1=c1+1
    2598              : !end if
    2599              : !end do
    2600              : !call laplacian(vrespc,buffer,ngfft,gprimd)
    2601              : !buffer=vrespc(:,:)-buffer(:,:)*dielng**2
    2602              : !c2=0
    2603              : !do ifft=1,nfft,1
    2604              : !if((abs(buffer(ifft,1)-deltaW(ifft,1))/(abs(buffer(ifft,1)+deltaW(ifft,1))*half)) > 5e-3) then
    2605              : !c2=c2+1
    2606              : !end if
    2607              : !end do
    2608              : !!!  !stop
    2609              : !call laplacian(gprimd,mpi_enreg,nfft,nspden,ngfft,&
    2610              : !& g2cart_out=g2cart)
    2611              : 
    2612              : !vrespc=vresid
    2613              : !do ispden=1,nspden
    2614              : !call fourdp(1, gvrespc(:,:,ispden), vrespc(:,ispden),-1,mpi_enreg,nfft,ngfft,0)
    2615              : !end do
    2616              : !filtering
    2617              : !do ispden=1,nspden
    2618              : !do ifft=1,nfft
    2619              : !!    gvrespc(:,ifft,ispden)=(one-exp(-g2cart(ifft)*15.0_dp))*gvrespc(:,ifft,ispden)
    2620              : !!      gvrespc(:,ifft,ispden)=(exp(-g2cart(ifft)*10.0_dp))*gvrespc(:,ifft,ispden)
    2621              : !!      gvrespc(:,ifft,ispden)=(one-one/(exp(-0.002_dp/g2cart(ifft)**2)+one))*gvrespc(:,ifft,ispden)
    2622              : !gvrespc(:,ifft,ispden)=(two-2_dp/(exp(-0.008_dp/(g2cart(ifft)+0.0012_dp))+one))*gvrespc(:,ifft,ispden)
    2623              : !gvrespc(:,ifft,ispden)=min(one,(sqrt(g2cart(ifft)/0.006_dp))**(one))*gvrespc(:,ifft,ispden)
    2624              : !end do
    2625              : !end do
    2626              : !change resulting potential to real space
    2627              : !do ispden=1,nspden
    2628              : !call fourdp(1,gvrespc(:,:,ispden),vrespc(:,ispden),1,mpi_enreg,nfft,ngfft,0)
    2629              : !end do
    2630              : !vrespc=vrespc*diemix
    2631              : !maxg2=g2cart(1)
    2632              : !ming2=g2cart(5)
    2633              : !do ifft=1,nfft
    2634              : !maxg2=max(g2cart(ifft),maxg2)
    2635              : !if(g2cart(ifft) .gt. zero) ming2=min(g2cart(ifft),ming2)
    2636              : !end do
    2637              : !stop
    2638              : 
    2639              : !DEBUG
    2640              : !write(std_out,*)' prckerker1 : exit '
    2641              : !ENDDEBUG
    2642              : 
    2643            7 : end subroutine prcrskerker1
    2644              : !!***
    2645              : 
    2646              : !!****f* ABINIT/prcrskerker2
    2647              : !! NAME
    2648              : !! prcrskerker2
    2649              : !!
    2650              : !! FUNCTION
    2651              : !! preconditionning by a real-space conjugate gradient on residual
    2652              : !! using a model dielectric function in real space
    2653              : !! differing from prcrskerker1 by the
    2654              : !! use of a linear response approach
    2655              : !!
    2656              : !! INPUTS
    2657              : !!  nfft=number of fft grid points
    2658              : !!  nspden=number of spin-density components
    2659              : !!  ngfft(18)=contain all needed information about 3D FFT, see ~abinit/doc/variables/vargs.htm#ngfft
    2660              : !!  dielar(7)=input parameters for dielectric matrix:
    2661              : !!                diecut,dielng,diemac,diemix,diegap,dielam,diemixmag.
    2662              : !!  gprimd(3,3)=dimensional primitive translations in fourier space (bohr**-1)
    2663              : !!  rprimd(3,3)=dimensional primitive translations in real space (bohr)
    2664              : !!  vresid(nfft,nspden)=residual potential
    2665              : !!
    2666              : !! OUTPUT
    2667              : !!  vrespc(nfft,nspden)=preconditioned residual of the potential
    2668              : !!
    2669              : !! WARNINGS
    2670              : !! This is experimental code : input, ouptput, results and any other feature may vary greatly.
    2671              : !!
    2672              : !! NOTES
    2673              : !!
    2674              : !! SOURCE
    2675              : 
    2676            4 : subroutine prcrskerker2(dtset,nfft,nspden,ngfft,dielar,gprimd,rprimd,vresid,vrespc,natom,xred,mpi_enreg,ucvol)
    2677              : 
    2678              : !Arguments ------------------------------------
    2679              : !scalars
    2680              :  integer,intent(in) :: natom,nfft,nspden
    2681              :  real(dp),intent(in) :: ucvol
    2682              :  type(MPI_type),intent(in) :: mpi_enreg
    2683              :  type(dataset_type),intent(in) :: dtset
    2684              : !arrays
    2685              :  integer,intent(in) :: ngfft(18)
    2686              :  real(dp),intent(in) :: dielar(7),gprimd(3,3),rprimd(3,3),vresid(nfft,nspden)
    2687              :  real(dp),intent(in) :: xred(3,natom)
    2688              :  real(dp),intent(out) :: vrespc(nfft,nspden)
    2689              : 
    2690              : !Local variables-------------------------------
    2691              :   !logical,save ::ok=.FALSE.
    2692              : !scalars
    2693              :  integer :: cplex,i1,i2,i3,iatom,iatom27,ifft,ispden,n1,n2,n3,natom27,nfftotf
    2694              :  integer :: option
    2695              :  real(dp),save :: lastp1=one,lastp2=one
    2696              :  real(dp) :: C1,C2,DE,core,dielng,diemac,diemix,diemixmag,doti,dr,l1,l2,l3,l4,r
    2697              :  real(dp) :: rdummy1,rdummy2,rmin,xr,y,yr,zr
    2698              : !arrays
    2699            4 :  integer, contiguous, pointer :: fftn2_distrib(:),ffti2_local(:)
    2700            4 :  integer, contiguous, pointer :: fftn3_distrib(:),ffti3_local(:)
    2701            8 :  real(dp) :: V1(nfft,nspden),V2(nfft,nspden),buffer(nfft,nspden)
    2702            8 :  real(dp) :: deltaW(nfft,nspden)
    2703            8 :  real(dp) :: mat(nfft,nspden)
    2704            8 :  real(dp) :: rdielng(nfft),rdiemac(nfft),xcart(3,natom)
    2705            8 :  real(dp) :: xcart27(3,natom*27)
    2706              : ! *************************************************************************
    2707              : 
    2708            4 :  dielng=dielar(2)
    2709            4 :  diemac=dielar(3)
    2710            4 :  diemix=dielar(4)
    2711            4 :  diemixmag=dielar(7)
    2712              : !******************************************************************
    2713              : !compute the diemac(r)                                          **
    2714              : !******************************************************************
    2715              : !this task will be devoted to a general function later
    2716            4 :  n1=ngfft(1)
    2717            4 :  n2=ngfft(2)
    2718            4 :  n3=ngfft(3)
    2719            4 :  nfftotf=n1*n2*n3
    2720              : !if(.not.ok) then
    2721           36 :  xcart(1,:)=xred(1,:)*rprimd(1,1)+xred(2,:)*rprimd(1,2)+xred(3,:)*rprimd(1,3)
    2722           36 :  xcart(2,:)=xred(1,:)*rprimd(2,1)+xred(2,:)*rprimd(2,2)+xred(3,:)*rprimd(2,3)
    2723           36 :  xcart(3,:)=xred(1,:)*rprimd(3,1)+xred(2,:)*rprimd(3,2)+xred(3,:)*rprimd(3,3)
    2724              : 
    2725              :  iatom27=0
    2726           16 :  do i1=-1,1
    2727           52 :    do i2=-1,1
    2728          156 :      do i3=-1,1
    2729         1008 :        do iatom=1,natom
    2730          864 :          iatom27=iatom27+1
    2731         3564 :          xcart27(:,iatom27)=xcart(:,iatom)+rprimd(:,1)*i1+rprimd(:,2)*i2+rprimd(:,3)*i3
    2732              :        end do
    2733              :      end do
    2734              :    end do
    2735              :  end do
    2736              : 
    2737              : !stop
    2738              :  natom27=27*natom
    2739              : 
    2740              :  l1=0.34580850339844665
    2741              : !l2=0.5123510203906797 !0.41242551019533985
    2742              : !l3=0.8001489796093203 !0.90007448980466009
    2743              : 
    2744              :  l2=0.41242551019533985
    2745              :  l3=0.90007448980466009
    2746              :  l4=0.9666914966015534
    2747              : 
    2748              : 
    2749              :  l1=0.31387233559896449
    2750              :  l2=0.35828367346355994
    2751              :  l3=0.9333829932031068
    2752              :  l4=0.9777943310677023
    2753              : 
    2754              :  l1=3.5
    2755              :  l2=11.5
    2756              :  l3=2.5
    2757              :  l4=6.5
    2758              : !l1=30. !cellules pleines
    2759              : 
    2760        40004 :  rdielng=zero
    2761            4 :  core=1. !(value of Er at the core of atoms)
    2762            4 :  dr=2.65 ! radius of atoms=2.65165
    2763            4 :  y=1. ! value of Er in the empty region
    2764              : 
    2765              : !Get the distrib associated with this fft_grid
    2766            4 :  call ptabs_fourdp(mpi_enreg,n2,n3,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local)
    2767              : 
    2768          404 :  do i3=1,n3
    2769          400 :    ifft=(i3-1)*n1*(n2/mpi_enreg%nproc_fft)
    2770         4404 :    do i2=1,n2
    2771         4400 :      if (fftn2_distrib(i2)==mpi_enreg%me_fft) then
    2772        44000 :        do i1=1,n1
    2773        40000 :          ifft=ifft+1
    2774              : !        !!!!!!!!!!!!!!!!!!!!!!!!!
    2775              : !        ! calculation of the simplest part void/metal
    2776              : !        !!              x=real(real(i3,dp)/real(n3,dp),dp)
    2777              : !        !!              !x=i3/n3
    2778              : !        !!              if(x < l1) then
    2779              : !        !!                 rdiemac(ifft)=diemac
    2780              : !        !!                 rdielng(ifft)=dielng
    2781              : !        !!              else if(x < l2) then
    2782              : !        !!                 xp=(l2-x)/(l2-l1)
    2783              : !        !!                 rdiemac(ifft)=y+(diemac-y)&
    2784              : !        !!                      & * (1.-(1.-xp)**4)**4
    2785              : !        !!                 rdielng(ifft)=dielng*(1.-(1.-xp)**4)**4
    2786              : !        !!              else if(x < l3) then
    2787              : !        !!                 rdiemac(ifft)=y
    2788              : !        !!                 rdielng(ifft)=zero
    2789              : !        !!              else if(x < l4) then
    2790              : !        !!                 xp=(l3-x)/(l3-l4)
    2791              : !        !!                 rdiemac(ifft)=y+(diemac-y)&
    2792              : !        !!                      & * (1.-(1.-xp)**4)**4
    2793              : !        !!                 rdielng(ifft)=dielng*(1.-(1.-xp)**4)**4
    2794              : !        !!              else
    2795              : !        !!                 rdiemac(ifft)=diemac
    2796              : !        !!                 rdielng(ifft)=dielng
    2797              : !        !!              end if
    2798              : !        !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    2799              : !        !!!! calculation of atomic core dielectric
    2800              : !        !!              rmin=1e16
    2801              : !        !!              xr=real(real((i1-1),dp)/n1,dp)*rprimd(1,1)+real(real((i2-1),dp)/n2,dp)*rprimd(1,2)&
    2802              : !        !!                   &+real((i3-1),dp)/real(n3,dp)*rprimd(1,3)
    2803              : !        !!              yr=real(real((i1-1),dp)/n1,dp)*rprimd(2,1)+real(real((i2-1),dp)/n2,dp)*rprimd(2,2)&
    2804              : !        !!                   &+real((i3-1),dp)/real(n3,dp)*rprimd(2,3)
    2805              : !        !!              zr=real(real((i1-1),dp)/n1,dp)*rprimd(3,1)+real(real((i2-1),dp)/n2,dp)*rprimd(3,2)&
    2806              : !        !!                   &+real((i3-1),dp)/real(n3,dp)*rprimd(3,3)
    2807              : !        !!              do iatom=1,natom27
    2808              : !        !!                 r=(xr-xcart27(1,iatom))**2+(yr-xcart27(2,iatom))**2+(zr-xcart27(3,iatom))**2
    2809              : !        !!                 if (r<rmin) then
    2810              : !        !!                    rmin=r
    2811              : !        !!                 end if
    2812              : !        !!              end do
    2813              : !        !!              if(rmin < dr**2) then
    2814              : !        !!                 rdiemac(ifft)=min(rdiemac(ifft),core+(diemac-core)*(1.-(1.-sqrt(rmin)/dr)**2)**2)
    2815              : !        !!                 rdielng(ifft)=dielng-dielng*(1.-(1.-sqrt(rmin)/dr)**4)**4
    2816              : !        !!              else
    2817              : !        !!                 rdiemac(ifft)=min(rdiemac(ifft),diemac)
    2818              : !        !!              end if
    2819        40000 :          rmin=1e16
    2820              :          xr=real(real((i1-1),dp)/n1,dp)*rprimd(1,1)+real(real((i2-1),dp)/n2,dp)*rprimd(1,2)&
    2821        40000 : &         +real((i3-1),dp)/real(n3,dp)*rprimd(1,3)
    2822              :          yr=real(real((i1-1),dp)/n1,dp)*rprimd(2,1)+real(real((i2-1),dp)/n2,dp)*rprimd(2,2)&
    2823        40000 : &         +real((i3-1),dp)/real(n3,dp)*rprimd(2,3)
    2824              :          zr=real(real((i1-1),dp)/n1,dp)*rprimd(3,1)+real(real((i2-1),dp)/n2,dp)*rprimd(3,2)&
    2825        40000 : &         +real((i3-1),dp)/real(n3,dp)*rprimd(3,3)
    2826              : 
    2827        40000 :          rdiemac(ifft)=y
    2828        40000 :          rdielng(ifft)=zero
    2829      8680000 :          do iatom=1,natom27
    2830      8640000 :            r=(xr-xcart27(1,iatom))**2+(yr-xcart27(2,iatom))**2+(zr-xcart27(3,iatom))**2
    2831              :            if (r<rmin) then
    2832              :              rmin=r
    2833              :            end if
    2834      8640000 :            if(r < l1) then
    2835         4840 :              rdiemac(ifft)= rdiemac(ifft) +  0.7_dp * (diemac-y)
    2836      8635160 :            else if(r < l2) then
    2837        23680 :              rdiemac(ifft)= rdiemac(ifft) + 0.7_dp * (diemac-y)*(one-((sqrt(r)-l1)/(l2-l1))**2)**2
    2838              :            else
    2839              :              rdiemac(ifft)=rdiemac(ifft)
    2840              :            end if
    2841      8680000 :            if(r < l3) then
    2842         2792 :              rdielng(ifft)= rdielng(ifft) +  0.5_dp * (dielng)
    2843      8637208 :            else if(r < l4) then
    2844         9408 :              rdielng(ifft)= rdielng(ifft) + 0.5_dp * (dielng)  *(one-((sqrt(r)-l3)/(l4-l3))**2)**2
    2845              :            end if
    2846              :          end do
    2847              : 
    2848        40000 :          rdielng(ifft)=min(rdielng(ifft),dielng)
    2849              : !        rdielng(ifft)=dielng
    2850              :          rdiemac(ifft)=min(rdiemac(ifft),diemac)
    2851        44000 :          rdiemac(ifft)=diemac
    2852              :        end do
    2853              :      end if
    2854              :    end do
    2855              :  end do
    2856              : !rdielng(:)=dielng
    2857              : 
    2858              : !****************************************************************************************
    2859              : !****************************************************************************************
    2860              : !****************************************************************************************
    2861              : !****************************************************************************************
    2862              : !******************************************************************
    2863              : !compute V1
    2864              : !******************************************************************
    2865        40008 :  V1=vresid
    2866            4 :  call laplacian(gprimd,mpi_enreg,nfft,nspden,ngfft,rdfuncr=V1,laplacerdfuncr=deltaW)
    2867        40004 :  deltaW(:,1)= (((one/rdiemac(:))*V1(:,1))-(((rdielng(:))**2)*deltaW(:,1)))
    2868              : !deltaW(:,1)= -diemix*(((rdielng(:))**2)*deltaW(:,ispden))
    2869            4 :  if (nspden>1) then
    2870            0 :    do ispden=2,nspden
    2871            0 :      deltaW(:,ispden)= (((one/rdiemac(:))*V1(:,ispden))-(((rdielng(:))**2)*deltaW(:,ispden)))
    2872              : !    deltaW(:,ispden)= -abs(diemixmag)*(((rdielng(:))**2)*deltaW(:,ispden))
    2873              :    end do
    2874              :  end if
    2875            4 :  call frskerker2__init(dtset,mpi_enreg,nfft,ngfft,nspden,rdielng,deltaW,gprimd,mat)
    2876              :  call cgpr(nfft,nspden,frskerker2__pf,frskerker2__dpf,&
    2877            4 : & frskerker2__newvres2,lastp1*real(1e-6 ,dp),700,V1,rdummy1,rdummy2)
    2878            4 :  lastp1=min(abs(rdummy1),1e-6_dp)
    2879            4 :  call frskerker2__end()
    2880              : 
    2881              : !******************************************************************
    2882              : !compute V2
    2883              : !******************************************************************
    2884        40008 :  V2=vresid
    2885            8 :  do ispden=1,nspden
    2886        40008 :    deltaW(:,ispden)= (rdielng(:)**2)
    2887              :  end do
    2888            4 :  call frskerker2__init(dtset,mpi_enreg,nfft,ngfft,nspden,rdielng,deltaW,gprimd,mat)
    2889              :  call cgpr(nfft,nspden,frskerker2__pf,frskerker2__dpf,&
    2890            4 : & frskerker2__newvres2,lastp2*real(1e-6,dp),700,V2,rdummy1,rdummy2)
    2891            4 :  lastp2=min(abs(rdummy1),1e-6_dp)
    2892            4 :  call frskerker2__end()
    2893              : 
    2894              : 
    2895              : !******************************************************************
    2896              : !compute C1, C2 & DE
    2897              : !******************************************************************
    2898            4 :  cplex=1;
    2899            4 :  option=1;
    2900              :  call dotprod_vn(cplex,& !complex density/pot
    2901              : &rdielng,&          !the density
    2902              : &DE,&  !resulting dorproduct integrated over r  ! here DE is used has a buffer
    2903              : &doti,&          !imaginary part of the integral
    2904              : &size(rdielng,1),&          !number of locally(cpu) attributed grid point
    2905              : &nfftotf,&        !real total number of grid point
    2906              : &nspden,&        !nspden
    2907              : &option,&        !1=compute only the real part 2=compute also the imaginary part
    2908              : &rdielng,&          !the potential
    2909              : &ucvol,&          !cell volume
    2910            4 : &mpi_comm_sphgrid=mpi_enreg%comm_fft)
    2911            8 :  do ispden=1,nspden
    2912        40008 :    buffer(:,ispden)=rdielng(:)*V1(:,ispden)
    2913              :  end do
    2914              :  call dotprod_vn(cplex,& !complex density/pot
    2915              : &rdielng,&          !the density
    2916              : &C1,&  !resulting dorproduct integrated over r  ! here DE is used has a buffer
    2917              : &doti,&          !imaginary part of the integral
    2918              : &size(rdielng,1),&          !number of locally(cpu) attributed grid point
    2919              : &nfftotf,&        !real total number of grid point
    2920              : &nspden,&        !nspden
    2921              : &option,&        !1=compute only the real part 2=compute also the imaginary part
    2922              : &buffer,&          !the potential
    2923              : &ucvol,&         !cell volume
    2924            4 : &mpi_comm_sphgrid=mpi_enreg%comm_fft)
    2925            8 :  do ispden=1,nspden
    2926        40008 :    buffer(:,ispden)=rdielng(:)*V2(:,ispden)
    2927              :  end do
    2928              :  call dotprod_vn(cplex,& !complex density/pot
    2929              : &rdielng,&          !the density
    2930              : &C2,&  !resulting dorproduct integrated over r  ! here DE is used has a buffer
    2931              : &doti,&          !imaginary part of the integral
    2932              : &size(rdielng,1),&          !number of locally(cpu) attributed grid point
    2933              : &nfftotf,&        !real total number of grid point
    2934              : &nspden,&        !nspden
    2935              : &option,&        !1=compute only the real part 2=compute also the imaginary part
    2936              : &buffer,&          !the potential
    2937              : &ucvol,&         !cell volume
    2938            4 : &mpi_comm_sphgrid=mpi_enreg%comm_fft)
    2939            4 :  C1=C1/DE
    2940            4 :  C2=C2/DE
    2941            4 :  DE=C1/(one-C2)
    2942              : 
    2943              : !******************************************************************
    2944              : !compute the new preconditionned residuals
    2945              : !******************************************************************
    2946        40004 :  vrespc(:,1)=diemix*(V1(:,1)+DE*V2(:,1))
    2947            4 :  if (nspden>1) vrespc(:,2:nspden)=abs(diemixmag)*(V1(:,2:nspden)+DE*V2(:,2:nspden))
    2948              : 
    2949            4 : end subroutine prcrskerker2
    2950              : !!***
    2951              : 
    2952              : !!****f* ABINIT/cgpr
    2953              : !! NAME
    2954              : !! cgpr
    2955              : !!
    2956              : !! FUNCTION
    2957              : !! perform Polak-Ribiere conjugate gradient on a function f
    2958              : !! implementation based on the cg recipe of "numerical recipe"
    2959              : !!
    2960              : !! INPUTS
    2961              : !! dp_dum_vdp: function  to be minimized (return a dp from a vector of dp)
    2962              : !! vdp_dum_vdp: derivative of f
    2963              : !! dtol: precision precision required for the minimization
    2964              : !! itmax: number of iterations allowed (each linmin will be done with at max 10 times
    2965              : !! this number
    2966              : !!
    2967              : !! OUTPUT
    2968              : !! fmin: value of f at the minimum
    2969              : !! lastdelta: absolute value of the last delta between steps
    2970              : !! SIDE EFFECTS
    2971              : !! v: vector on which minimization is to be performed, starting point
    2972              : !! and resulting min
    2973              : !!
    2974              : !! SOURCE
    2975              : 
    2976           15 : subroutine cgpr(nv1,nv2,dp_dum_v2dp,v2dp_dum_v2dp,sub_dum_dp_v2dp_v2dp,dtol,itmax,v,fmin,delta)
    2977              : 
    2978              : !Arguments ------------------------------------
    2979              : include "dummy_functions.inc"
    2980              : !scalars
    2981              :  integer,intent(in) :: itmax,nv1,nv2
    2982              :  real(dp),intent(in) :: dtol
    2983              :  real(dp),intent(out) :: delta,fmin
    2984              : !arrays
    2985              :  real(dp),intent(inout) :: v(nv1,nv2)
    2986              : 
    2987              : !Local variables-------------------------------
    2988              : !scalars
    2989              :  integer :: iiter
    2990              :  real(dp) :: fv,gam,gscal,gscal2,sto
    2991              : !arrays
    2992           15 :  real(dp) :: grad0(nv1,nv2),grad1(nv1,nv2),grad2(nv1,nv2),grad3(nv1,nv2)
    2993              : !no_abirules
    2994              : 
    2995              : !************************************************************************
    2996           15 :  fv = dp_dum_v2dp(nv1,nv2,v(:,:))
    2997       150030 :  grad0(:,:) = -v2dp_dum_v2dp(nv1,nv2,v(:,:))
    2998       150030 :  grad1(:,:) = grad0(:,:)
    2999       150030 :  grad2(:,:) = grad0(:,:)
    3000          448 :  do iiter=1,itmax
    3001          448 :   call linmin(nv1,nv2,dp_dum_v2dp,v2dp_dum_v2dp,sub_dum_dp_v2dp_v2dp,v,grad0,fmin)
    3002              : ! return if the min is reached
    3003          448 :   sto=dtol*(abs(fmin)+abs(fv)+tol14)
    3004          448 :   delta=abs(fv-fmin)
    3005              :   delta=abs(delta)
    3006          448 :   if((delta.lt.sto).or.(iiter==itmax)) then
    3007              : !  DEBUG
    3008              : !  write(std_out,*) 'cgpr (01cg) : stop cond for cgpr:',sto,'delta:',delta,'fv:',fv,'fmin:',fmin
    3009              : !  ENDDEBUG
    3010              :    return
    3011              :   end if
    3012              : ! a new step
    3013          433 :   fv=fmin
    3014          433 :   grad0(:,:)=v2dp_dum_v2dp(nv1,nv2,v(:,:))
    3015          433 :   gscal=dotproduct(nv1,nv2,grad1(:,:),grad1(:,:))
    3016      4330866 :   grad3(:,:)=grad0(:,:)+grad1(:,:)
    3017          433 :   gscal2=dotproduct(nv1,nv2,grad3(:,:),grad0(:,:))
    3018          433 :   gam=gscal2/gscal
    3019      4330866 :   grad1(:,:)=-grad0(:,:)
    3020      4330866 :   grad2(:,:)=grad1(:,:)+gam*grad2(:,:)
    3021      4331314 :   grad0(:,:)=grad2(:,:)
    3022              : ! DEBUG
    3023              : ! write(std_out,*) 'cgpr (01cg) :================================================================================='
    3024              : ! write(std_out,*) 'cgpr (01cg) : step',iiter,'delta:',delta ,'fv',fv,'fmin',fmin
    3025              : ! write(std_out,*) 'cgpr (01cg) :================================================================================='
    3026              : ! ENDDEBUG
    3027              :  end do
    3028              : 
    3029            0 : end subroutine cgpr
    3030              : !!***
    3031              : 
    3032              : !!****f* ABINIT/linmin
    3033              : !! NAME
    3034              : !! linmin
    3035              : !!
    3036              : !! FUNCTION
    3037              : !! minimizes a function along a gradient line:
    3038              : !! first bracket the minimum then perform the minimization
    3039              : !!
    3040              : !! COPYRIGHT
    3041              : !! Copyright (C) 1998-2026 ABINIT group (DCA, XG, MT)
    3042              : !! This file is distributed under the terms of the
    3043              : !! GNU General Public License, see ~ABINIT/COPYING
    3044              : !! or http://www.gnu.org/copyleft/gpl.txt .
    3045              : !! For the initials of contributors, see ~ABINIT/Infos/contributors .
    3046              : !!
    3047              : !! INPUTS
    3048              : !! dp_dum_vdp: function  to be minimized (return a dp from a vector of dp)
    3049              : !! vdp_dum_vdp: derivative of f
    3050              : !!
    3051              : !! OUTPUT
    3052              : !! fmin: minimum value reached for dp_dum_vdp
    3053              : !!
    3054              : !! SIDE EFFECTS
    3055              : !! grad: the gradient line along which the minimization is performed (not changed)
    3056              : !! v: the starting and then ending point of the minimization
    3057              : !!
    3058              : !! SOURCE
    3059              : 
    3060          448 : subroutine linmin(nv1,nv2,dp_dum_v2dp,v2dp_dum_v2dp,sub_dum_dp_v2dp_v2dp,v,grad,fmin)
    3061              : 
    3062              : !Arguments ------------------------------------
    3063              : include "dummy_functions.inc"
    3064              : !scalars
    3065              :  integer,intent(in) :: nv1,nv2
    3066              :  real(dp),intent(out) :: fmin
    3067              : !arrays
    3068              :  real(dp),intent(inout) :: grad(nv1,nv2),v(nv1,nv2)
    3069              : 
    3070              : !Local variables-------------------------------
    3071              : !scalars
    3072              :  real(dp),parameter :: maglimit=10000.0_dp,tol=tol8*tol8*tol8
    3073              :  real(dp) :: a,b,fa,fb,fx,x,xmin
    3074              : !no_abirules
    3075              : 
    3076              : !************************************************************************
    3077          448 :  a=zero
    3078          448 :  x=ninth*real(1e-4,dp)
    3079          448 :  call bracketing (nv1,nv2,dp_dum_v2dp,v,grad,a,x,b,fa,fx,fb)
    3080              : !DEBUG
    3081              : !write(std_out,*) 'linmin (01cg) : linmin after bracketing'
    3082              : !write(std_out,*) 'linmin (01cg) : point',a,x,b,'value',fa,fx,fb
    3083              : !ENDDEBUG
    3084          448 :  fmin =brent(nv1,nv2,dp_dum_v2dp,v2dp_dum_v2dp,sub_dum_dp_v2dp_v2dp,6,v,grad,a,x,b,tol,xmin)
    3085              : 
    3086          448 : end subroutine linmin
    3087              : !!***
    3088              : 
    3089              : !!****f* ABINIT/bracketing
    3090              : !! NAME
    3091              : !! bracketing
    3092              : !!
    3093              : !! FUNCTION
    3094              : !! bracket a minimum of a function f
    3095              : !!
    3096              : !! INPUTS
    3097              : !! dp_dum_vdp: the function of which the mimimum should be bracketted
    3098              : !!
    3099              : !! OUTPUT
    3100              : !! b= last member of the bracketing triplet a < x < b
    3101              : !! fa,fx,fb= value of the function at dp_dum_vdp(v(:)+y*grad(:))
    3102              : !!
    3103              : !! SIDE EFFECTS
    3104              : !! v: the initial vector for the function (return unchanged)
    3105              : !! grad: the direction on which the bracketting is to be performed (return unchanged)
    3106              : !! a,x: two members of the bracketing triplet (see b)
    3107              : !!
    3108              : !! SOURCE
    3109              : 
    3110          448 : subroutine bracketing (nv1,nv2,dp_dum_v2dp,v,grad,a,x,b,fa,fx,fb)
    3111              : 
    3112              : !Arguments ------------------------------------
    3113              : include "dummy_functions.inc"
    3114              : !scalars
    3115              :  integer,intent(in) :: nv1,nv2
    3116              :  real(dp),intent(inout) :: a,x
    3117              :  real(dp),intent(out) :: b,fa,fb,fx
    3118              : !arrays
    3119              :  real(dp),intent(inout) :: grad(nv1,nv2),v(nv1,nv2)
    3120              : 
    3121              : !Local variables-------------------------------
    3122              : !scalars
    3123              :  real(dp),parameter :: maglimit=10000.0_dp
    3124              :  real(dp) :: c,fu,q,r,u,ulim
    3125              : ! *************************************************************************
    3126              : 
    3127      4480896 :  fa=dp_dum_v2dp(nv1,nv2,v(:,:)+(a*grad(:,:)))
    3128      4480896 :  fx=dp_dum_v2dp(nv1,nv2,(x*grad(:,:))+v(:,:))
    3129          448 :  if(fx > fa) then
    3130           26 :   c=a
    3131           26 :   a=x
    3132           26 :   x=c
    3133           26 :   c=fa
    3134           26 :   fa=fx
    3135           26 :   fx=c
    3136              :  end if
    3137          448 :  b=x+gold*(x-a)
    3138      4480896 :  fb=dp_dum_v2dp(nv1,nv2,(b*grad(:,:))+v(:,:))
    3139          574 :  do
    3140         1022 :   if (fx <= fb) return
    3141          589 :   r=(x-a)*(fx-fb)
    3142          589 :   q=(x-b)*(fx-fa)
    3143          589 :   u=x-((x-b)*q-(x-a)*r)/(two*sign(max(abs(q-r),smallest_real),q-r))
    3144          589 :   ulim=x+maglimit*(b-x)
    3145          589 :   if((x-u)*(u-b) > zero) then
    3146       150030 :    fu=dp_dum_v2dp(nv1,nv2,(u*grad(:,:))+v(:,:))
    3147           15 :    if(fu < fb) then
    3148           15 :     a=x
    3149           15 :     fa=fx
    3150           15 :     x=u
    3151           15 :     fx=fu
    3152           15 :     return
    3153            0 :    else if (fx < fu) then
    3154            0 :     b=u
    3155            0 :     fb=fu
    3156            0 :     return
    3157              :    end if
    3158            0 :    u=b+gold*(b-x)
    3159            0 :    fu=dp_dum_v2dp(nv1,nv2,(u*grad(:,:))+v(:,:))
    3160          574 :   else if((b-u)*(u-ulim) > zero) then
    3161      4880976 :    fu=dp_dum_v2dp(nv1,nv2,u*grad(:,:)+v(:,:))
    3162          488 :    if(fu<fb) then
    3163          478 :     x=b
    3164          478 :     b=u
    3165          478 :     u=b+gold*(b-x)
    3166          478 :     fx=fb
    3167          478 :     fb=fu
    3168      4780956 :     fu=dp_dum_v2dp(nv1,nv2,(u*grad(:,:))+v(:,:))
    3169              :    end if
    3170           86 :   else if((u-ulim)*(ulim-b) >= zero) then
    3171           27 :    u=ulim
    3172       270054 :    fu=dp_dum_v2dp(nv1,nv2,(u*grad(:,:))+v(:,:))
    3173              :   else
    3174           59 :    u=b+gold*(b-x)
    3175       590118 :    fu=dp_dum_v2dp(nv1,nv2,(u*grad(:,:))+v(:,:))
    3176              :   end if
    3177          574 :   a=x
    3178          574 :   x=b
    3179          574 :   b=u
    3180          574 :   fa=fx
    3181          574 :   fx=fb
    3182          574 :   fb=fu
    3183              :  end do
    3184              : 
    3185              : end subroutine bracketing
    3186              : !!***
    3187              : 
    3188              : !!****f* ABINIT/brent
    3189              : !! NAME
    3190              : !! brent
    3191              : !!
    3192              : !! FUNCTION
    3193              : !! minimizes a function along a line
    3194              : !!
    3195              : !! INPUTS
    3196              : !! dp_dum_vdp: function  to be minimized (return a dp from a vector of dp)
    3197              : !! vdp_dum_vdp: derivative of the function (return a vector of dp from a vector of dp)
    3198              : !! itmax: number of iterations allowed
    3199              : !! tol: tolerance on error. It depend on the precision of the numbers
    3200              : !! (usually chosen as sqrt(max precision available with your floating point reresentation))
    3201              : !! ax,xx,bx: a bracketing triplet around the minimum to be find
    3202              : !! OUTPUT
    3203              : !! xmin: value such that dp_dum_vdp(v(:)+xmin*grad(:)) is minimum
    3204              : !! brent:  dp_dum_vdp(v(:)+xmin*grad(:))
    3205              : !!
    3206              : !! SIDE EFFECTS
    3207              : !! grad(:): direction along which the minimization is performed
    3208              : !! v(:): starting and ending point of the minimization
    3209              : !!
    3210              : !! SOURCE
    3211              : 
    3212          448 : function brent(nv1,nv2,dp_dum_v2dp,v2dp_dum_v2dp,sub_dum_dp_v2dp_v2dp,itmax,v,grad,ax,xx,bx,tol,xmin)
    3213              : 
    3214              : !Arguments ------------------------------------
    3215              : include "dummy_functions.inc"
    3216              : !scalars
    3217              :  integer,intent(in) :: itmax,nv1,nv2
    3218              :  real(dp) :: brent
    3219              :  real(dp),intent(in) :: ax,bx,tol,xx
    3220              :  real(dp),intent(out) :: xmin
    3221              : !arrays
    3222              :  real(dp),intent(inout) :: grad(nv1,nv2),v(nv1,nv2)
    3223              : 
    3224              : !Local variables-------------------------------
    3225              : !scalars
    3226              :  integer :: iter
    3227              :  real(dp) :: a,b,d,d1,d2,du,dv,dw,dx,e,fu,fv,fw,fx,olde,tol1,tol2,u,u1,u2,vv,w
    3228              :  real(dp) :: x,xm,zeps
    3229              :  logical :: ok1,ok2,ok3,ok4
    3230              : 
    3231              : !************************************************************************
    3232          448 :  zeps=epsilon(ax*real(1e-2,dp))
    3233          448 :  a=min(ax,bx)
    3234          448 :  b=max(ax,bx)
    3235          448 :  vv=xx
    3236          448 :  w=xx
    3237          448 :  x=xx
    3238          448 :  e=zero
    3239      4480896 :  fx=dp_dum_v2dp(nv1,nv2,x*grad(:,:)+v(:,:))
    3240          448 :  fv=fx
    3241          448 :  fw=fx
    3242              : !the function sub_dum_dp_v2dp_v2dp must do the equivalent of
    3243              : !v(:,:)=v(:,:)+(grad(:,:)*x)
    3244              : !but for instance renormilizing the density if brent is used on a density...
    3245              : !vp(:,:) = v(:,:)
    3246              : !sub_dum_dp_v2dp_v2dp(x,grad(:,:),vp(:,:)
    3247              : !dx=dotproduct(v2dp_dum_v2dp(vp(:,:)),grad(:,:))
    3248      4480896 :  dx=dotproduct(nv1,nv2,v2dp_dum_v2dp(nv1,nv2,v(:,:)+x*grad(:,:)),grad(:,:))
    3249          448 :  dv=dx
    3250          448 :  dw=dx
    3251         2562 :  do iter=1,itmax
    3252         2350 :   xm=half*(a+b)
    3253         2350 :   tol1=tol*abs(x)+zeps
    3254         2350 :   tol2=two*tol1
    3255         2350 :   if(abs(x-xm) <= (tol2-half*(b-a))) then
    3256              :    exit
    3257              :   end if
    3258         2253 :   if(abs(e) > tol1) then
    3259         1744 :    d1=two*(b-a)
    3260         1744 :    d2=d1
    3261         1744 :    if(dw /= dx) d1=(w-x)*dx/(dx-dw)
    3262         1744 :    if(dv /= dx) d2=(vv-x)*dx/(dx-dv)
    3263         1744 :    u1=x+d1
    3264         1744 :    u2=x+d2
    3265         1744 :    ok1=((a-u1)*(u1-b)>zero).and.(dx*d1<=zero)
    3266         1744 :    ok2=((a-u2)*(u2-b)>zero).and.(dx*d2<=zero)
    3267         2225 :    olde=e
    3268         2225 :    e=d
    3269         1170 :    if(ok1.or.ok2) then
    3270         1055 :     if(ok1.and.ok2) then
    3271          549 :      d=merge(d1,d2,abs(d1)<abs(d2))
    3272              :     else
    3273          506 :      d=merge(d1,d2,ok1)
    3274              :     end if
    3275         1055 :     if(abs(d)<=abs(half*olde)) then
    3276         1013 :      u=x+d
    3277         1013 :      if(((u-a)<tol2).or.((b-u)<tol2)) d=sign(tol1,xm-x)
    3278              :     else
    3279           42 :      e=merge(a,b,dx>=zero)-x
    3280           42 :      d=half*e
    3281              :     end if
    3282              :    else
    3283          689 :     e=merge(a,b,dx>=zero)-x
    3284          689 :     d=half*e
    3285              :    end if
    3286              :   else
    3287          509 :    e=merge(a,b,dx>=zero)-x
    3288          509 :    d=half*e
    3289              :   end if
    3290              : 
    3291         2253 :   if(abs(d) >=tol1)then
    3292         1950 :    u=x+d
    3293     19503900 :    fu=dp_dum_v2dp(nv1,nv2,(u*grad(:,:))+v(:,:))
    3294              :   else
    3295          303 :    u=x+sign(tol1,d)
    3296      3030606 :    fu=dp_dum_v2dp(nv1,nv2,(u*grad(:,:))+v(:,:))
    3297          303 :    if(fu>fx) then
    3298              :     exit
    3299              :    end if
    3300              :   end if
    3301     21144228 :   du=dotproduct(nv1,nv2,v2dp_dum_v2dp(nv1,nv2,(u*grad(:,:))+v(:,:)),grad(:,:))
    3302         2562 :   if(fu<=fx)then
    3303          809 :    if(u>=x)then
    3304              :     a=x
    3305              :    else
    3306          412 :     b=x
    3307              :    end if
    3308          809 :    vv=w
    3309          809 :    fv=fw
    3310          809 :    dv=dw
    3311          809 :    w=x
    3312          809 :    fw=fx
    3313          809 :    dw=dx
    3314          809 :    x=u
    3315          809 :    dx=du
    3316          809 :    fx=fu
    3317              :   else
    3318         1305 :    if(u<x) then
    3319              :     a=u
    3320              :    else
    3321          733 :     b=u
    3322              :    end if
    3323         1305 :    ok3=(w==x).or.(fu.le.fw)
    3324         1305 :    ok4=(vv==w).or.(vv==x).or.(fu.lt.fv)
    3325         1305 :    if(ok3) then
    3326              :     vv=w
    3327              :     fv=fw
    3328              :     dv=dw
    3329              :     w=u
    3330              :     fw=fu
    3331              :     dw=du
    3332          160 :    else if( ok4 ) then
    3333           86 :     vv=u
    3334           86 :     fv=fu
    3335           86 :     dv=du
    3336              :    end if
    3337              :   end if
    3338              :  end do
    3339          448 :  xmin=x
    3340              : !the function sub_dum_dp_v2dp_v2dp must do the equivalent of
    3341              : !v(:,:)=v(:,:)+(grad(:,:)*x)
    3342              : !but for instance renormilizing the density if brent is used on a density...
    3343          448 :  call sub_dum_dp_v2dp_v2dp(nv1,nv2,x,grad(:,:),v(:,:))
    3344          448 :  brent=fx
    3345              : 
    3346          448 : end function brent
    3347              : !!***
    3348              : 
    3349              : end module m_prcref
    3350              : !!***
        

Generated by: LCOV version 2.3-1