TABLE OF CONTENTS


ABINIT/cross_mkcore [ Functions ]

[ Top ] [ Functions ]

NAME

  cross_mkcore

FUNCTION

  Define magnitude of cross product of two vectors

SOURCE

531    function cross_mkcore(xx,yy,zz,aa,bb,cc)
532 
533    real(dp) :: cross_mkcore
534    real(dp),intent(in) :: xx,yy,zz,aa,bb,cc
535 ! *************************************************************************
536    cross_mkcore=sqrt((yy*cc-zz*bb)**2+(zz*aa-xx*cc)**2+(xx*bb-yy*aa)**2)
537  end function cross_mkcore
538 
539 end subroutine mkcore

ABINIT/cross_mkcore_alt [ Functions ]

[ Top ] [ Functions ]

NAME

  cross_mkcore_alt

FUNCTION

  Define magnitude of cross product of two vectors

SOURCE

1061    function cross_mkcore_alt(xx,yy,zz,aa,bb,cc)
1062 
1063     real(dp) :: cross_mkcore_alt
1064     real(dp),intent(in) :: xx,yy,zz,aa,bb,cc
1065 ! *************************************************************************
1066    cross_mkcore_alt=sqrt((yy*cc-zz*bb)**2+(zz*aa-xx*cc)**2+(xx*bb-yy*aa)**2)
1067  end function cross_mkcore_alt

ABINIT/dfpt_mkcore [ Functions ]

[ Top ] [ Functions ]

NAME

 dfpt_mkcore

FUNCTION

 Compute the derivative of the core electron density
 with respect to one specific atom displacement
 In case of derivative with respect to k or
 electric (magnetic) field perturbation, the 1st-order core electron density
 vanishes.

INPUTS

  cplex: if 1, real space 1-order functions on FFT grid are REAL,
    if 2, COMPLEX
  idir=direction of atomic displacement (=1,2 or 3 : displacement of
    atom ipert along the 1st, 2nd or 3rd axis) or cartesian coordinate
    pair for strain perturbation
  ipert=number of the atom being displaced or natom+3,4 for strain
    perturbation
  natom=number of atoms in cell.
  ntypat=number of types of atoms in cell.
  n1,n2,n3=fft grid dimensions.
  n1xccc=dimension of xccc1d ; 0 if no XC core correction is used
  qphon(3)=wavevector of the phonon
  rprimd(3,3)=dimensional primitive translation vectors (bohr)
  typat(natom)=integer type for each atom in cell
  ucvol=unit cell volume (bohr**3).
  xcccrc(ntypat)=XC core correction cutoff radius (bohr) for each atom type
  xccc1d(n1xccc,6,ntypat)=1D core charge function and five derivatives,
   for each type of atom, from psp
  xred(3,natom)=reduced coordinates for atoms in unit cell

OUTPUT

  xccc3d1(cplex*n1*n2*n3)=3D core electron density for XC core correction,
    bohr^-3

NOTES

 Note that this routine is tightly connected to the mkcore.f routine

SOURCE

1141 subroutine dfpt_mkcore(cplex,idir,ipert,natom,ntypat,n1,n1xccc,&
1142 & n2,n3,qphon,rprimd,typat,ucvol,xcccrc,xccc1d,xccc3d1,xred)
1143 
1144 !Arguments ------------------------------------
1145 !scalars
1146  integer,intent(in) :: cplex,idir,ipert,n1,n1xccc,n2,n3,natom,ntypat
1147  real(dp),intent(in) :: ucvol
1148 !arrays
1149  integer,intent(in) :: typat(natom)
1150  real(dp),intent(in) :: qphon(3),rprimd(3,3),xccc1d(n1xccc,6,ntypat)
1151  real(dp),intent(in) :: xcccrc(ntypat),xred(3,natom)
1152  real(dp),intent(out) :: xccc3d1(cplex*n1*n2*n3)
1153 
1154 !Local variables-------------------------------
1155 !scalars
1156  integer,parameter :: mshift=401
1157  integer :: i1,i2,i3,iatom,ifft,ishift,ishift1,ishift2,ishift3,istr
1158  integer :: ixp,jj,ka,kb,mrange,mu,nu
1159  real(dp) :: aa,bb,cc,dd,delta,delta2div6,deltam1,diff,difmag
1160  real(dp) :: difmag2,difmag2_fact,difmag2_part,func,phase,phi,phr,prod
1161  real(dp) :: range,range2,rangem1,rdiff1,rdiff2,rdiff3,term
1162  real(dp) :: yy
1163  character(len=500) :: message
1164 !arrays
1165  integer,save :: idx(12)=(/1,1,2,2,3,3,3,2,3,1,2,1/)
1166  integer :: igrid(3),irange(3),ngfft(3)
1167  integer,allocatable :: ii(:,:)
1168  real(dp) :: drmetds(3,3),lencp(3),rmet(3,3),scale(3),tau(3)
1169  real(dp),allocatable :: rrdiff(:,:)
1170 
1171 ! *************************************************************************
1172 
1173 ! if( ipert<1 .or. ipert> natom+7) then
1174 !   write(message,'(a,i0,a,a,a,i0,a)')&
1175 !&   ' The argument ipert must be between 1 and natom+7=',natom+7,',',ch10,&
1176 !&   ' while it is ipert=',ipert,'.'
1177 !   ABI_BUG(message)
1178 ! end if
1179 
1180  if( (ipert==natom+3 .or. ipert==natom+4) .and. cplex/=1) then
1181    write(message,'(3a,i4,a)')&
1182 &   'The argument cplex must be 1 for strain perturbationh',ch10,&
1183 &   'while it is cplex=',cplex,'.'
1184    ABI_BUG(message)
1185  end if
1186 
1187 !Zero out array
1188  xccc3d1(:)=0.0_dp
1189 
1190 !For a non-linear XC core correction, the perturbation must be phonon-type or strain type
1191  if(ipert<=natom .or. ipert==natom+3 .or. ipert==natom+4) then
1192 
1193    if( idir<1 .or. idir> 3) then
1194      write(message,'(a,a,a,i4,a)')&
1195 &     'The argument idir must be between 1 and 3,',ch10,&
1196 &     'while it is idir=',idir,'.'
1197      ABI_BUG(message)
1198    end if
1199 
1200 !  Compute lengths of cross products for pairs of primitive
1201 !  translation vectors (used in setting index search range below)
1202    lencp(1)=cross_mk(rprimd(1,2),rprimd(2,2),rprimd(3,2),&
1203 &   rprimd(1,3),rprimd(2,3),rprimd(3,3))
1204    lencp(2)=cross_mk(rprimd(1,3),rprimd(2,3),rprimd(3,3),&
1205 &   rprimd(1,1),rprimd(2,1),rprimd(3,1))
1206    lencp(3)=cross_mk(rprimd(1,1),rprimd(2,1),rprimd(3,1),&
1207 &   rprimd(1,2),rprimd(2,2),rprimd(3,2))
1208 
1209 !  Compute factor R1.(R2xR3)/|R2xR3| etc for 1, 2, 3
1210 !  (recall ucvol=R1.(R2xR3))
1211    scale(:)=ucvol/lencp(:)
1212 
1213 !  Compute metric tensor in real space rmet
1214    do nu=1,3
1215      rmet(:,nu)=rprimd(1,:)*rprimd(1,nu)+rprimd(2,:)*rprimd(2,nu)+&
1216 &     rprimd(3,:)*rprimd(3,nu)
1217    end do
1218 
1219 !  Section to be executed only for strain perturbation
1220 !  Compute derivative of metric tensor wrt strain component istr
1221    if(ipert==natom+3 .or. ipert==natom+4) then
1222      istr=idir + 3*(ipert-natom-3)
1223 
1224      ka=idx(2*istr-1);kb=idx(2*istr)
1225      do jj = 1,3
1226        drmetds(:,jj)=(rprimd(ka,:)*rprimd(kb,jj)+rprimd(kb,:)*rprimd(ka,jj))
1227      end do
1228 !    For historical reasons:
1229      drmetds(:,:)=0.5_dp*drmetds(:,:)
1230 
1231 !    end of strain perturbation section
1232    end if
1233 
1234    ngfft(1)=n1
1235    ngfft(2)=n2
1236    ngfft(3)=n3
1237 
1238    delta=1.0_dp/(n1xccc-1)
1239    deltam1=n1xccc-1
1240    delta2div6=delta**2/6.0_dp
1241 
1242 !  Loop over atoms in unit cell
1243 !  Note that we cycle immediately for all except the displaced atom
1244 !  for such a perturbation.  The loop is executed over all the
1245 !  atoms for a strain peturbation.
1246    do iatom=1,natom
1247      if(ipert<=natom .and. iatom/=ipert) cycle
1248 !    Set search range (density cuts off perfectly beyond range)
1249 !    Cycle if no range.
1250      range=0.0_dp
1251      range=xcccrc(typat(iatom))
1252      if(range<1.d-16) cycle
1253 
1254      range2=range**2
1255      rangem1=1.0_dp/range
1256 
1257 !    compute mrange for ii(:,3), rrdiff(:,3), inserted by MM (2005/12/06)
1258 !    Consider each component in turn : compute range
1259      do mu=1,3
1260 
1261 !      Convert reduced coord of given atom to [0,1)
1262        tau(mu)=mod(xred(mu,iatom)+1._dp-aint(xred(mu,iatom)),1._dp)
1263 
1264 !      Use tau to find nearest grid point along R(mu)
1265 !      (igrid=0 is the origin; shift by 1 to agree with usual index)
1266        igrid(mu)=nint(tau(mu)*dble(ngfft(mu)))
1267 
1268 !      Use range to compute an index range along R(mu)
1269 !      (add 1 to make sure it covers full range)
1270        irange(mu)=1+nint((range/scale(mu))*dble(ngfft(mu)))
1271 
1272      end do
1273 
1274 !    Allocate arrays that depends on the range
1275      mrange=maxval(irange(1:3))
1276      ABI_MALLOC(ii,(2*mrange+1,3))
1277      ABI_MALLOC(rrdiff,(2*mrange+1,3))
1278 
1279 !    Consider each component in turn
1280      do mu=1,3
1281 
1282 !      temporarily suppressed by MM (2005/12/02)
1283 !      Convert reduced coord of given atom to [0,1)
1284 !      tau(mu)=mod(xred(mu,iatom)+1._dp-aint(xred(mu,iatom)),1._dp)
1285 
1286 !      Use tau to find nearest grid point along R(mu)
1287 !      (igrid=0 is the origin; shift by 1 to agree with usual index)
1288 !      igrid(mu)=nint(tau(mu)*dble(ngfft(mu)))
1289 
1290 !      Use range to compute an index range along R(mu)
1291 !      (add 1 to make sure it covers full range)
1292 !      irange(mu)=1+nint((range/scale(mu))*dble(ngfft(mu)))
1293 
1294 !      Check that the largest range is smallest than the maximum
1295 !      allowed one
1296 !      if(2*irange(mu)+1 > mshift)then
1297 !      write(message, '(a,a,a,a,i6,a)' ) ch10,&
1298 !      &    ' dfpt_mkcore : BUG -',ch10,&
1299 !      &    '  The range around atom',iatom,' is too large.'
1300 !      ABI_BUG(message)
1301 !      end if
1302 
1303 !      Set up a counter that explore the relevant range
1304 !      of points around the atom
1305        ishift=0
1306        do ixp=igrid(mu)-irange(mu),igrid(mu)+irange(mu)
1307          ishift=ishift+1
1308          ii(ishift,mu)=1+mod(ngfft(mu)+mod(ixp,ngfft(mu)),ngfft(mu))
1309          rrdiff(ishift,mu)=dble(ixp)/dble(ngfft(mu))-tau(mu)
1310        end do
1311 
1312 !      End loop on mu
1313      end do
1314 
1315 !    Conduct triple loop over restricted range of grid points for iatom
1316 
1317      do ishift3=1,1+2*irange(3)
1318 !      map back to [1,ngfft(3)] for usual fortran index in unit cell
1319        i3=ii(ishift3,3)
1320 !      find vector from atom location to grid point (reduced)
1321        rdiff3=rrdiff(ishift3,3)
1322 
1323        do ishift2=1,1+2*irange(2)
1324          i2=ii(ishift2,2)
1325          rdiff2=rrdiff(ishift2,2)
1326 !        Prepare the computation of difmag2
1327          difmag2_part=rmet(3,3)*rdiff3**2+rmet(2,2)*rdiff2**2&
1328 &         +2.0_dp*rmet(3,2)*rdiff3*rdiff2
1329          difmag2_fact=2.0_dp*(rmet(3,1)*rdiff3+rmet(2,1)*rdiff2)
1330 
1331          do ishift1=1,1+2*irange(1)
1332            rdiff1=rrdiff(ishift1,1)
1333 
1334 !          Compute (rgrid-tau-Rprim)**2
1335            difmag2= difmag2_part+rdiff1*(difmag2_fact+rmet(1,1)*rdiff1)
1336 
1337 !          Only accept contribution inside defined range
1338            if (difmag2<range2) then
1339 
1340 !            Prepare computation of core charge function and derivative,
1341 !            using splines
1342              difmag=sqrt(difmag2)
1343              if (difmag>=1.0d-10) then
1344                i1=ii(ishift1,1)
1345                yy=difmag*rangem1
1346 
1347 !              Compute index of yy over 1 to n1xccc scale
1348                jj=1+int(yy*(n1xccc-1))
1349                diff=yy-(jj-1)*delta
1350 
1351 !              Will evaluate spline fit (p. 86 Numerical Recipes, Press et al;
1352 !              NOTE error in book for sign of "aa" term in derivative;
1353 !              also see splfit routine).
1354                bb = diff*deltam1
1355                aa = 1.0_dp-bb
1356                cc = aa*(aa**2-1.0_dp)*delta2div6
1357                dd = bb*(bb**2-1.0_dp)*delta2div6
1358 
1359 !              Evaluate spline fit of 1st der of core charge density
1360 !              from xccc1d(:,2,:) and (:,4,:)
1361                func=aa*xccc1d(jj,2,typat(iatom))+bb*xccc1d(jj+1,2,typat(iatom)) +&
1362 &               cc*xccc1d(jj,4,typat(iatom))+dd* xccc1d(jj+1,4,typat(iatom))
1363 
1364                if(ipert<=natom) then
1365                  phase=2*pi*(qphon(1)*(rdiff1+xred(1,iatom))  &
1366 &                 +qphon(2)*(rdiff2+xred(2,iatom))  &
1367 &                 +qphon(3)*(rdiff3+xred(3,iatom)))
1368                  prod=rmet(idir,1)*rdiff1+rmet(idir,2)*rdiff2+rmet(idir,3)*rdiff3
1369 
1370                  term=-func*rangem1/difmag*prod
1371                  ifft=i1+n1*(i2-1+n2*(i3-1))
1372                  phr=cos(phase)
1373                  if(cplex==1)then
1374                    xccc3d1(ifft)=xccc3d1(ifft)+term*phr
1375                  else
1376                    phi=sin(phase)
1377                    xccc3d1(2*ifft-1)=xccc3d1(2*ifft-1)+term*phr
1378                    xccc3d1(2*ifft  )=xccc3d1(2*ifft  )-term*phi
1379                  end if
1380                else
1381                  prod=&
1382 &                 (rdiff1*(drmetds(1,1)*rdiff1+drmetds(1,2)*rdiff2+drmetds(1,3)*rdiff3)&
1383 &                 +rdiff2*(drmetds(2,1)*rdiff1+drmetds(2,2)*rdiff2+drmetds(2,3)*rdiff3)&
1384 &                 +rdiff3*(drmetds(3,1)*rdiff1+drmetds(3,2)*rdiff2+drmetds(3,3)*rdiff3))
1385                  term=prod*func*rangem1/difmag
1386 
1387                  ifft=i1+n1*(i2-1+n2*(i3-1))
1388                  xccc3d1(ifft)=xccc3d1(ifft)+term
1389 
1390                end if
1391 
1392 !              End of the condition for the distance not to vanish
1393              end if
1394 
1395 !            End of condition to be inside the range
1396            end if
1397 
1398 !          End loop on ishift1
1399          end do
1400 
1401 !        End loop on ishift2
1402        end do
1403 
1404 !      End loop on ishift3
1405      end do
1406 
1407      ABI_FREE(ii)
1408      ABI_FREE(rrdiff)
1409 !    End loop on atoms
1410    end do
1411 
1412 !  End of the condition ipert corresponds to a phonon type perturbation
1413 !  or strain type perturbation
1414  end if
1415 
1416  contains
1417 
1418    function cross_mk(xx,yy,zz,aa,bb,cc)
1419 
1420    real(dp) :: cross_mk
1421    real(dp),intent(in) :: xx,yy,zz,aa,bb,cc
1422    cross_mk=sqrt((yy*cc-zz*bb)**2+(zz*aa-xx*cc)**2+(xx*bb-yy*aa)**2)
1423  end function cross_mk
1424 
1425 end subroutine dfpt_mkcore

ABINIT/indpos_mkcore_alt [ Functions ]

[ Top ] [ Functions ]

NAME

  indpos_mkcore_alt

FUNCTION

  Find the grid index of a given position in the cell according to the BC
  Determine also whether the index is inside or outside the box for free BC

SOURCE

1082    subroutine indpos_mkcore_alt(periodic,ii,nn,jj,inside)
1083 !    Find the grid index of a given position in the cell according to the BC
1084 !    Determine also whether the index is inside or outside the box for free BC
1085     integer, intent(in) :: ii,nn
1086     integer, intent(out) :: jj
1087     logical, intent(in) :: periodic
1088     logical, intent(out) :: inside
1089 ! *************************************************************************
1090    if (periodic) then
1091      inside=.true. ; jj=modulo(ii-1,nn)+1
1092    else
1093      jj=ii ; inside=(ii>=1.and.ii<=nn)
1094    end if
1095  end subroutine indpos_mkcore_alt
1096 
1097 end subroutine mkcore_alt

ABINIT/m_mkcore [ Modules ]

[ Top ] [ Modules ]

NAME

  m_mkcore

FUNCTION

  Routines related to non-linear core correction.

COPYRIGHT

  Copyright (C) 1998-2024 ABINIT group (DCA, XG, GMR, TRangel, MT)
  This file is distributed under the terms of the
  GNU General Public License, see ~abinit/COPYING
  or http://www.gnu.org/copyleft/gpl.txt .

SOURCE

16 #if defined HAVE_CONFIG_H
17 #include "config.h"
18 #endif
19 
20 #include "abi_common.h"
21 
22 module m_mkcore
23 
24  use defs_basis
25  use m_abicore
26  use m_xmpi
27  use m_errors
28  use m_linalg_interfaces
29 
30  use defs_abitypes, only : mpi_type
31  use m_geometry,    only : strconv
32  use m_time,        only : timab
33  use m_mpinfo,      only : ptabs_fourdp
34  use m_sort,        only : sort_dp
35  use m_pawrad,      only : pawrad_type, pawrad_init, pawrad_free
36  use m_pawtab,      only : pawtab_type
37  use m_paw_numeric, only : paw_splint
38 
39  implicit none
40 
41  private

ABINIT/mkcore [ Functions ]

[ Top ] [ Functions ]

NAME

 mkcore

FUNCTION

 Optionally compute:
  (1) pseudo core electron density throughout unit cell
  (2) pseudo-core contribution to forces
  (3) pseudo-core contribution to stress tensor
  (4) pseudo-core contrib. to frozen-wf part the dynamical matrix (part 2)

INPUTS

  natom=number of atoms in cell.
  nfft=(effective) number of FFT grid points (for this processor)
  nspden=number of spin-density components
  ntypat=number of types of atoms in cell.
  n1,n2,n3=fft grid dimensions.
  n1xccc=dimension of xccc1d ; 0 if no XC core correction is used
  option: 1 for computing xccc3d (core charge density),
   2 for computing core charge contribution to $d(E_{xc})/d(tau)$,
   3 for computing core charge contribution to stress tensor corstr,
   4 for contribution to frozen-wavefunction part of dynamical matrix
  rprimd(3,3)=dimensional primitive translation vectors (bohr)
  typat(natom)=integer type for each atom in cell
  ucvol=unit cell volume (bohr**3).
  vxc(nfft,nspden)=exchange-correlation potential (hartree) in real
   space--only used when option=2,3, or 4,  else ignored
  xcccrc(ntypat)=XC core correction cutoff radius (bohr) for each atom type
  xccc1d(n1xccc,6,ntypat)=1D core charge function and five derivatives,
   for each type of atom, from psp
  xred(3,natom)=reduced coordinates for atoms in unit cell

OUTPUT

  corstr(6)=core charge contribution to stress tensor, only if option=3
  dyfrx2(3,3,natom)=non-linear xc core correction part of the
    frozen-wavefunction part of the dynamical matrix, only for option=4
  grxc(3,natom)=d(Exc)/d(xred), hartree (only computed when option=2, else
   ignored)

SIDE EFFECTS

  xccc3d(n1*n2*n3)=3D core electron density for XC core correction, bohr^-3
   (computed and returned when option=1, needed as input when option=3)

NOTES

 Note that this routine is tightly connected to the dfpt_mkcore.f routine

SOURCE

100 subroutine mkcore(corstr,dyfrx2,grxc,mpi_enreg,natom,nfft,nspden,ntypat,n1,n1xccc,&
101 & n2,n3,option,rprimd,typat,ucvol,vxc,xcccrc,xccc1d,xccc3d,xred)
102 
103 !Arguments ------------------------------------
104 !scalars
105  integer,intent(in) :: n1,n1xccc,n2,n3,natom,nfft,nspden,ntypat,option
106  real(dp),intent(in) :: ucvol
107  type(mpi_type),intent(in) :: mpi_enreg
108 !arrays
109  integer,intent(in) :: typat(natom)
110  real(dp),intent(in) :: rprimd(3,3),vxc(nfft,nspden),xccc1d(n1xccc,6,ntypat)
111  real(dp),intent(in) :: xcccrc(ntypat),xred(3,natom)
112  real(dp),intent(inout) :: xccc3d(nfft)
113  real(dp),intent(out) :: corstr(6),dyfrx2(3,3,natom)
114  real(dp),intent(inout) :: grxc(3,natom)
115 
116 !Local variables-------------------------------
117 !scalars
118  integer :: i1,i2,i3,iatom,ier,ifft,ishift,ishift1,ishift2
119  integer :: ishift3,itypat,ixp,jj,me_fft,mrange,mu,nfftot,nu
120  real(dp) :: dd,delta,delta2div6,deltam1,diff,difmag,difmag2
121  real(dp) :: difmag2_fact,difmag2_part,fact,func,grxc1,grxc2,grxc3,range,range2
122  real(dp) :: rangem1,rdiff1,rdiff2,rdiff3,strdia,t1,t2,t3,term,term1,term2
123  character(len=500) :: message
124 !arrays
125  integer :: igrid(3),irange(3),ngfft(3)
126  integer, ABI_CONTIGUOUS pointer :: fftn2_distrib(:),ffti2_local(:)
127  integer, ABI_CONTIGUOUS pointer :: fftn3_distrib(:),ffti3_local(:)
128  integer,allocatable :: ii(:,:)
129  real(dp) :: yy,aa,bb,cc
130  real(dp) :: corfra(3,3),lencp(3),rmet(3,3),scale(3),tau(3),tsec(2),tt(3)
131  real(dp),allocatable :: rrdiff(:,:),work(:,:,:)
132 
133 !************************************************************************
134 
135  call timab(12,1,tsec)
136 
137 !Make sure option is acceptable
138  if (option<0.or.option>4) then
139    write(message, '(a,i12,a,a,a)' )&
140     'option=',option,' is not allowed.',ch10,&
141     'Must be 1, 2, 3 or 4.'
142    ABI_BUG(message)
143  end if
144 
145 !Zero out only the appropriate array according to option:
146 !others are dummies with no storage
147 
148  if (option==1) then
149 !  Zero out array to permit accumulation over atom types below:
150    xccc3d(:)=zero
151  else if (option==2) then
152 !  Zero out gradient of Exc array
153    grxc(:,:)=zero
154  else if (option==3) then
155 !  Zero out locally defined stress array
156    corfra(:,:)=zero
157    strdia=zero
158  else if (option==4) then
159 !  Zero out fr-wf part of the dynamical matrix
160    dyfrx2(:,:,:)=zero
161  else
162    ABI_BUG(" Can't be here! (bad option)")
163  end if
164 
165 !Compute lengths of cross products for pairs of primitive
166 !translation vectors (used in setting index search range below)
167  lencp(1)=cross_mkcore(rprimd(1,2),rprimd(2,2),rprimd(3,2),&
168 & rprimd(1,3),rprimd(2,3),rprimd(3,3))
169  lencp(2)=cross_mkcore(rprimd(1,3),rprimd(2,3),rprimd(3,3),&
170 & rprimd(1,1),rprimd(2,1),rprimd(3,1))
171  lencp(3)=cross_mkcore(rprimd(1,1),rprimd(2,1),rprimd(3,1),&
172 & rprimd(1,2),rprimd(2,2),rprimd(3,2))
173 
174 !Compute factor R1.(R2xR3)/|R2xR3| etc for 1, 2, 3
175 !(recall ucvol=R1.(R2xR3))
176  scale(:)=ucvol/lencp(:)
177 
178 !Compute metric tensor in real space rmet
179  do nu=1,3
180    rmet(:,nu)=rprimd(1,:)*rprimd(1,nu)+rprimd(2,:)*rprimd(2,nu)+rprimd(3,:)*rprimd(3,nu)
181  end do
182 
183  ngfft(1)=n1
184  ngfft(2)=n2
185  ngfft(3)=n3
186  nfftot=n1*n2*n3
187  me_fft = mpi_enreg%me_fft
188 
189  ! Get the distrib associated with this fft_grid
190  call ptabs_fourdp(mpi_enreg,n2,n3,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local)
191 
192  delta=one/(n1xccc-1)
193  deltam1=n1xccc-1
194  delta2div6=delta**2/6.0d0
195 
196  if (option>=2) then
197    ABI_MALLOC(work,(n1,n2,n3))
198 !  For spin-polarization, replace vxc by (1/2)*(vxc(up)+vxc(down))
199 !  For non-collinear magnetism, replace vxc by (1/2)*(vxc^{11}+vxc^{22})
200    if (nspden>=2) then
201      ifft=1
202      do i3=1,n3
203        if(me_fft==fftn3_distrib(i3)) then
204          do i2=1,n2
205            do i1=1,n1
206              work(i1,i2,i3)=half*(vxc(ifft,1)+vxc(ifft,2))
207              ifft=ifft+1
208            end do
209          end do
210        end if
211      end do
212    else
213      ifft=1
214      do i3=1,n3
215        if(me_fft==fftn3_distrib(i3)) then
216          do i2=1,n2
217            do i1=1,n1
218              work(i1,i2,i3)=vxc(ifft,1)
219              ifft=ifft+1
220            end do
221          end do
222        end if
223      end do
224 !    call DCOPY(nfft,vxc,1,work,1)
225    end if
226  end if
227 
228 !Loop over atoms in unit cell
229  do iatom=1,natom
230 
231    if(option==2)then
232      grxc1=zero
233      grxc2=zero
234      grxc3=zero
235    end if
236 
237 !  Set search range (density cuts off perfectly beyond range)
238    itypat=typat(iatom)
239    range=xcccrc(itypat)
240 
241 !  Skip loop if this atom has no core charge
242    if (abs(range)<1.d-16) cycle
243 
244    range2=range**2
245    rangem1=one/range
246 
247 !  Consider each component in turn : compute range
248    do mu=1,3
249 
250 !    Convert reduced coord of given atom to [0,1)
251      tau(mu)=mod(xred(mu,iatom)+one-aint(xred(mu,iatom)),one)
252 
253 !    Use tau to find nearest grid point along R(mu)
254 !    (igrid=0 is the origin; shift by 1 to agree with usual index)
255      igrid(mu)=nint(tau(mu)*dble(ngfft(mu)))
256 
257 !    Use range to compute an index range along R(mu)
258 !    (add 1 to make sure it covers full range)
259      irange(mu)=1+nint((range/scale(mu))*dble(ngfft(mu)))
260 
261    end do
262 
263 !  Allocate arrays that depends on the range
264    mrange=maxval(irange(1:3))
265    ABI_MALLOC(ii,(2*mrange+1,3))
266    ABI_MALLOC(rrdiff,(2*mrange+1,3))
267 
268 !  Set up counters that explore the relevant range
269 !  of points around the atom
270    do mu=1,3
271      ishift=0
272      do ixp=igrid(mu)-irange(mu),igrid(mu)+irange(mu)
273        ishift=ishift+1
274        ii(ishift,mu)=1+mod(ngfft(mu)+mod(ixp,ngfft(mu)),ngfft(mu))
275        rrdiff(ishift,mu)=dble(ixp)/dble(ngfft(mu))-tau(mu)
276      end do
277    end do
278 
279 !  Conduct triple loop over restricted range of grid points for iatom
280    do ishift3=1,1+2*irange(3)
281 !    map back to [1,ngfft(3)] for usual fortran index in unit cell
282      i3=ii(ishift3,3)
283      if(fftn3_distrib(i3)/=mpi_enreg%me_fft) cycle
284 !    find vector from atom location to grid point (reduced)
285      rdiff3=rrdiff(ishift3,3)
286 
287      do ishift2=1,1+2*irange(2)
288        i2=ii(ishift2,2)
289        rdiff2=rrdiff(ishift2,2)
290 !      Prepare the computation of difmag2
291        difmag2_part=rmet(3,3)*rdiff3**2+rmet(2,2)*rdiff2**2&
292 &       +2.0d0*rmet(3,2)*rdiff3*rdiff2
293        difmag2_fact=2.0d0*(rmet(3,1)*rdiff3+rmet(2,1)*rdiff2)
294 
295        do ishift1=1,1+2*irange(1)
296          rdiff1=rrdiff(ishift1,1)
297 
298 !        Compute (rgrid-tau-Rprim)**2
299          difmag2= difmag2_part+rdiff1*(difmag2_fact+rmet(1,1)*rdiff1)
300 
301 !        Only accept contribution inside defined range
302          if (difmag2<range2-tol12) then
303 
304 !          Prepare computation of core charge function and derivative,
305 !          using splines
306            i1=ii(ishift1,1)
307            difmag=sqrt(difmag2)
308            yy=difmag*rangem1
309 
310 !          Compute index of yy over 1 to n1xccc scale
311            jj=1+int(yy*(n1xccc-1))
312            diff=yy-(jj-1)*delta
313 
314 !          Will evaluate spline fit (p. 86 Numerical Recipes, Press et al;
315 !          NOTE error in book for sign of "aa" term in derivative;
316 !          also see splfit routine).
317            bb = diff*deltam1
318            aa = one-bb
319            cc = aa*(aa**2-one)*delta2div6
320            dd = bb*(bb**2-one)*delta2div6
321 
322 
323 !          Test first for option 2, the most frequently used
324            if (option==2) then
325 
326 !            Accumulate contributions to Exc gradients
327 
328              if (difmag>1.0d-10) then
329 
330 !              Evaluate spline fit of 1st der of core charge density
331 !              from xccc1d(:,2,:) and (:,4,:)
332                func=aa*xccc1d(jj,2,itypat)+bb*xccc1d(jj+1,2,itypat) +&
333 &               cc*xccc1d(jj,4,itypat)+dd*xccc1d(jj+1,4,itypat)
334                term=work(i1,i2,i3)*func/difmag
335                grxc1=grxc1+rdiff1*term
336                grxc2=grxc2+rdiff2*term
337                grxc3=grxc3+rdiff3*term
338              end if
339 
340            else if (option==1) then
341 
342 !            Evaluate spline fit of core charge density
343 !            from xccc1d(:,1,:) and (:,3,:)
344              func=aa*xccc1d(jj,1,itypat)+bb*xccc1d(jj+1,1,itypat) +&
345 &             cc*xccc1d(jj,3,itypat)+dd*xccc1d(jj+1,3,itypat)
346 
347 !            Accumulate contributions to core electron density
348 !            throughout unit cell
349              ifft=i1+n1*(i2-1+n2*(ffti3_local(i3)-1))
350              xccc3d(ifft)=xccc3d(ifft)+func
351 
352            else if (option==3) then
353 
354 !            Accumulate contributions to stress tensor
355 !            in reduced coordinates
356 
357              if (difmag>1.0d-10) then
358 
359 !              Evaluate spline fit of 1st der of core charge density
360 !              from xccc1d(:,2,:) and (:,4,:)
361                func=aa*xccc1d(jj,2,itypat)+bb*xccc1d(jj+1,2,itypat) +&
362 &               cc*xccc1d(jj,4,itypat)+dd*xccc1d(jj+1,4,itypat)
363                term=work(i1,i2,i3)*func*rangem1/difmag/dble(n1*n2*n3)
364 !              Write out the 6 symmetric components
365                corfra(1,1)=corfra(1,1)+term*rdiff1**2
366                corfra(2,2)=corfra(2,2)+term*rdiff2**2
367                corfra(3,3)=corfra(3,3)+term*rdiff3**2
368                corfra(3,2)=corfra(3,2)+term*rdiff3*rdiff2
369                corfra(3,1)=corfra(3,1)+term*rdiff3*rdiff1
370                corfra(2,1)=corfra(2,1)+term*rdiff2*rdiff1
371 !              (the above still needs to be transformed to cartesian coords)
372 
373              end if
374 
375 !            Also compute a diagonal term
376 !            Evaluate spline fit of core charge density
377 !            from xccc1d(:,1,:) and (:,3,:)
378              func=aa*xccc1d(jj,1,itypat)+bb*xccc1d(jj+1,1,itypat) +&
379 &             cc*xccc1d(jj,3,itypat)+dd*xccc1d(jj+1,3,itypat)
380              strdia=strdia+work(i1,i2,i3)*func
381 
382            else if (option==4) then
383 
384 !            Compute frozen-wf contribution to Dynamical matrix
385 
386              tt(1)=rmet(1,1)*rdiff1+rmet(1,2)*rdiff2+rmet(1,3)*rdiff3
387              tt(2)=rmet(2,1)*rdiff1+rmet(2,2)*rdiff2+rmet(2,3)*rdiff3
388              tt(3)=rmet(3,1)*rdiff1+rmet(3,2)*rdiff2+rmet(3,3)*rdiff3
389 
390              if (difmag>1.d-10) then
391 
392 !              Accumulate contributions to dynamical matrix
393                term=(ucvol/dble(nfftot))*work(i1,i2,i3)*rangem1/difmag
394 !              Evaluate spline fit of 1st der of core charge density
395 !              from xccc1d(:,2,:) and (:,4,:)
396                func=aa*xccc1d(jj,2,itypat)+bb*xccc1d(jj+1,2,itypat) +&
397 &               cc*xccc1d(jj,4,itypat)+dd*xccc1d(jj+1,4,itypat)
398                term1=term*func
399 !              Evaluate spline fit of 2nd der of core charge density
400 !              from xccc1d(:,3,:) and (:,5,:)
401                func=aa*xccc1d(jj,3,itypat)+bb*xccc1d(jj+1,3,itypat) +&
402 &               cc*xccc1d(jj,5,itypat)+dd*xccc1d(jj+1,5,itypat)
403                term2=term*func*rangem1/difmag
404                do mu=1,3
405                  do nu=1,3
406                    dyfrx2(mu,nu,iatom)=dyfrx2(mu,nu,iatom)&
407 &                   +(term2-term1/difmag**2)*tt(mu)*tt(nu)&
408 &                   +term1*rmet(mu,nu)
409                  end do
410                end do
411 
412              else
413 
414 !              There is a contribution from difmag=zero !
415 !              Evaluate spline fit of 2nd der of core charge density
416 !              from xccc1d(:,3,:) and (:,5,:)
417                func=aa*xccc1d(jj,3,itypat)+bb*xccc1d(jj+1,3,itypat) +&
418 &               cc*xccc1d(jj,5,itypat)+dd*xccc1d(jj+1,5,itypat)
419                term=(ucvol/dble(nfftot))*work(i1,i2,i3)*func*rangem1**2
420                do mu=1,3
421                  do nu=1,3
422                    dyfrx2(mu,nu,iatom)=dyfrx2(mu,nu,iatom)+term*rmet(mu,nu)
423                  end do
424                end do
425 
426 !              End of condition not to be precisely on the point (difmag=zero)
427              end if
428 
429 !            If option is not 1, 2, 3, or 4.
430            else
431              ABI_BUG("Can't be here in mkcore")
432 !            End of choice of option
433            end if
434 
435          end if ! End of condition on the range
436        end do ! End loop on ishift1
437      end do ! End loop on ishift2
438    end do ! End loop on ishift3
439 
440    ABI_FREE(ii)
441    ABI_FREE(rrdiff)
442 
443    if(option==2)then
444      fact=-(ucvol/dble(nfftot))/range
445      grxc(1,iatom)=grxc1*fact
446      grxc(2,iatom)=grxc2*fact
447      grxc(3,iatom)=grxc3*fact
448    end if
449 
450  end do !  End big loop on atoms
451 
452  if (option==2) then
453 
454 !  Apply rmet as needed to get reduced coordinate gradients
455    do iatom=1,natom
456      t1=grxc(1,iatom)
457      t2=grxc(2,iatom)
458      t3=grxc(3,iatom)
459      grxc(:,iatom)=rmet(:,1)*t1+rmet(:,2)*t2+rmet(:,3)*t3
460 
461    end do
462  end if
463 
464  if (option==3) then
465 
466 !  Transform stress tensor from full storage mode to symmetric storage mode
467    corstr(1)=corfra(1,1)
468    corstr(2)=corfra(2,2)
469    corstr(3)=corfra(3,3)
470    corstr(4)=corfra(3,2)
471    corstr(5)=corfra(3,1)
472    corstr(6)=corfra(2,1)
473 
474 !  Transform stress tensor from reduced coordinates to cartesian coordinates
475    call strconv(corstr,rprimd,corstr)
476 
477 !  Compute diagonal contribution to stress tensor (need input xccc3d)
478 !  strdia = (1/N) Sum(r) [mu_xc_avg(r) * rho_core(r)]
479    ifft=0 ; strdia=zero
480    do i3=1,n3
481      if(me_fft==fftn3_distrib(i3)) then
482        do i2=1,n2
483          do i1=1,n1
484            ifft=ifft+1
485            strdia=strdia+work(i1,i2,i3)*xccc3d(ifft)
486          end do
487        end do
488      end if
489    end do
490    strdia=strdia/dble(nfftot)
491 !  strdia=DDOT(nfft,work,1,xccc3d,1)/dble(nfftot)
492 
493 !  Add diagonal term to stress tensor
494    corstr(1)=corstr(1)+strdia
495    corstr(2)=corstr(2)+strdia
496    corstr(3)=corstr(3)+strdia
497  end if
498 
499  if(option>=2)  then
500    ABI_FREE(work)
501  end if
502 
503  if(mpi_enreg%nproc_fft > 1) then
504    call timab(539,1,tsec)
505    if(option==2) then
506      call xmpi_sum(grxc,mpi_enreg%comm_fft,ier)
507    end if
508    if(option==3) then
509      call xmpi_sum(corstr,mpi_enreg%comm_fft,ier)
510    end if
511    if(option==4) then
512      call xmpi_sum(dyfrx2,mpi_enreg%comm_fft,ier)
513    end if
514    call timab(539,2,tsec)
515  end if
516 
517  call timab(12,2,tsec)
518 
519  contains

ABINIT/mkcore_alt [ Functions ]

[ Top ] [ Functions ]

NAME

 mkcore_alt

FUNCTION

 Optionally compute:
  (1) pseudo core electron density throughout unit cell
  (2) pseudo-core contribution to forces
  (3) pseudo-core contribution to stress tensor
  (4) pseudo-core contrib. to frozen-wf part the dynamical matrix (part 2)
 This routine is an alternative to mkcore, to be used for PAW and/or WVL.

INPUTS

  atindx1(natom)=index table for atoms, inverse of atindx
  icoulomb= periodic treatment of Hartree potential: 0=periodic, 1=free BC, 2=surface BC
  mpi_enreg=information about MPI parallelization
  natom=number of atoms in cell.
  nfft=(effective) number of FFT grid points (for this processor)
  nspden=number of spin-density components
  ntypat=number of types of atoms in cell
  n1,n2,n3=fft grid dimensions.
  n1xccc=dimension of xccc1d ; 0 if no XC core correction is used
  option: 1 for computing core charge density
          2 for computing core charge contribution to forces
          3 for computing core charge contribution to stress tensor
          4 for computing contribution to frozen-wf part of dynamical matrix
  pawrad(ntypat*usepaw) <type(pawrad_type)>=paw radial mesh and related data
  pawtab(ntypat*usepaw) <type(pawtab_type)>=paw tabulated starting data
  rprimd(3,3)=dimensional primitive translation vectors (bohr)
  ucvol=unit cell volume (bohr**3)
  usepaw=flag for PAW method
  vxc(nfft,nspden)=exchange-correlation potential (hartree) in real space
  xcccrc(ntypat)=XC core correction cutoff radius (bohr) for each atom type
  xccc1d(n1xccc,6,ntypat)=1D core charge function and 5 derivatives for each atom type
  xred(3,natom)=reduced coordinates for atoms in unit cell
  [usekden]= --optional-- if TRUE, output the kinetic enrgy density instead of the density

OUTPUT

  === if option==1 ===
  xccc3d(n1*n2*n3)=3D core electron density for XC core correction (bohr^-3)
  === if option==2 ===
  grxc(3,natom)=core charge contribution to forces
  === if option==3 ===
  corstr(6)=core charge contribution to stress tensor
  === if option==4 ===
  dyfrx2(3,3,natom)=non-linear xc core correction part of the
    frozen-wavefunction part of the dynamical matrix

SIDE EFFECTS

  xccc3d(n1*n2*n3)=3D core electron density for XC core correction (bohr^-3)
   (computed and returned when option=1, needed as input when option=3)

NOTES

  Based on mkcore.F90

SOURCE

 601 subroutine mkcore_alt(atindx1,corstr,dyfrx2,grxc,icoulomb,mpi_enreg,natom,nfft,nspden,&
 602 &          nattyp,ntypat,n1,n1xccc,n2,n3,option,rprimd,ucvol,vxc,xcccrc,xccc1d,&
 603 &          xccc3d,xred,pawrad,pawtab,usepaw,&
 604 &          usekden) ! optional argument
 605 
 606 !Arguments ------------------------------------
 607 !scalars
 608  integer,intent(in) :: icoulomb,n1,n1xccc,n2,n3,natom,nfft,nspden,ntypat,option,usepaw
 609  logical,intent(in),optional :: usekden
 610  real(dp),intent(in) :: ucvol
 611  type(mpi_type),intent(in) :: mpi_enreg
 612  type(pawrad_type),intent(in) :: pawrad(:)
 613  type(pawtab_type),target,intent(in) :: pawtab(:)
 614 !arrays
 615  integer,intent(in) :: atindx1(natom),nattyp(ntypat)
 616  real(dp),intent(in) :: rprimd(3,3),xccc1d(n1xccc,6,ntypat)
 617  real(dp),intent(in) :: xcccrc(ntypat),xred(3,natom)
 618  real(dp),intent(in),target :: vxc(nfft,nspden)
 619  real(dp),intent(out) :: corstr(6),grxc(3,natom),dyfrx2(3,3,natom)
 620  real(dp),intent(inout) :: xccc3d(nfft)
 621 
 622 !Local variables-------------------------------
 623 !scalars
 624  integer :: i1,i2,i3,iat,iatm,iatom,ier,ipts
 625  integer :: ishift,ishift1,ishift2,ishift3
 626  integer :: itypat,ixp,jj,jpts,me_fft,mrange,msz,mu
 627  integer :: nfftot,npts,npts12,nu
 628  logical :: letsgo,usekden_
 629  real(dp) :: aa,bb,cc,dd,delta,delta2div6,deltam1
 630  real(dp) :: diff,difmag,fact,range,range2
 631  real(dp) :: rangem1,rdiff1,rdiff2,rdiff3
 632  real(dp) :: rnorm2,rnorm2_fact,rnorm2_part
 633  real(dp) :: strdia,t1,t2,t3,term,term1,term2,yy
 634  character(len=1) :: geocode
 635  character(len=500) :: message
 636  type(pawrad_type) :: core_mesh
 637 !arrays
 638  integer :: igrid(3),irange(3),ishiftmax(3),ngfft(3)
 639  integer,allocatable :: ii(:,:),iindex(:),indx1(:),indx2(:)
 640  integer, ABI_CONTIGUOUS pointer :: fftn2_distrib(:),ffti2_local(:)
 641  integer, ABI_CONTIGUOUS pointer :: fftn3_distrib(:),ffti3_local(:)
 642  logical :: per(3)
 643  real(dp) :: corfra(3,3),corgr(3),lencp(3),rmet(3,3)
 644  real(dp) :: scale(3),tau(3),tsec(2),tt(3)
 645  real(dp),allocatable :: dtcore(:),d2tcore(:),rnorm(:)
 646  real(dp),allocatable :: rrdiff(:,:),tcore(:)
 647  real(dp),allocatable,target :: tcoretau(:,:)
 648  real(dp), ABI_CONTIGUOUS pointer :: corespl(:,:),vxc_eff(:)
 649 
 650 !************************************************************************
 651 
 652  call timab(12,1,tsec)
 653 
 654 !Make sure options are acceptable
 655  usekden_=.false.;if (present(usekden)) usekden_=usekden
 656  if (option<0.or.option>4) then
 657    write(message, '(a,i12,a,a,a)' )&
 658     'option=',option,' is not allowed.',ch10,&
 659     'Must be 1, 2, 3 or 4.'
 660    ABI_BUG(message)
 661  end if
 662  if (usekden_) then
 663    message='usekden=1 not yet allowed!'
 664    ABI_BUG(message)
 665  end if
 666 
 667 
 668 !Zero out only the appropriate array according to option:
 669  if (option==1) then
 670    xccc3d(:)=zero
 671  else if (option==2) then
 672    grxc(:,:)=zero
 673  else if (option==3) then
 674    corfra(:,:)=zero
 675    strdia=zero
 676  else if (option==4) then
 677    dyfrx2(:,:,:)=zero
 678  end if
 679 
 680 !Conditions for periodicity in the three directions
 681  geocode='P'
 682  if (icoulomb==1) geocode='F'
 683  if (icoulomb==2) geocode='S'
 684  per(1)=(geocode /= 'F')
 685  per(2)=(geocode == 'P')
 686  per(3)=(geocode /= 'F')
 687 
 688 !Compute lengths of cross products for pairs of primitive
 689 !translation vectors (used in setting index search range below)
 690  lencp(1)=cross_mkcore_alt(rprimd(1,2),rprimd(2,2),rprimd(3,2),&
 691 & rprimd(1,3),rprimd(2,3),rprimd(3,3))
 692  lencp(2)=cross_mkcore_alt(rprimd(1,3),rprimd(2,3),rprimd(3,3),&
 693 & rprimd(1,1),rprimd(2,1),rprimd(3,1))
 694  lencp(3)=cross_mkcore_alt(rprimd(1,1),rprimd(2,1),rprimd(3,1),&
 695 & rprimd(1,2),rprimd(2,2),rprimd(3,2))
 696 
 697 !Compute factor R1.(R2xR3)/|R2xR3| etc for 1, 2, 3
 698 !(recall ucvol=R1.(R2xR3))
 699  scale(:)=ucvol/lencp(:)
 700 
 701 !Compute metric tensor in real space rmet
 702  do nu=1,3
 703    rmet(:,nu)=rprimd(1,:)*rprimd(1,nu)+rprimd(2,:)*rprimd(2,nu)+rprimd(3,:)*rprimd(3,nu)
 704  end do
 705 
 706 !Get the distrib associated with this fft_grid
 707  ngfft(1)=n1;ngfft(2)=n2;ngfft(3)=n3
 708  nfftot=n1*n2*n3 ; me_fft=mpi_enreg%me_fft
 709  call ptabs_fourdp(mpi_enreg,n2,n3,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local)
 710 
 711  delta=one/(n1xccc-1)
 712  deltam1=n1xccc-1
 713  delta2div6=delta**2/6.0_dp
 714 
 715  if (option>=2) then
 716 !  For spin-polarization, replace vxc by (1/2)*(vxc(up)+vxc(down))
 717 !  For non-collinear magnetism, replace vxc by (1/2)*(vxc^{11}+vxc^{22})
 718    if (nspden>=2) then
 719      ABI_MALLOC(vxc_eff,(nfft))
 720      do jj=1,nfft
 721        vxc_eff(jj)=half*(vxc(jj,1)+vxc(jj,2))
 722      end do
 723    else
 724      vxc_eff => vxc(1:nfft,1)
 725    end if
 726  end if
 727 
 728 !Loop over atom types
 729  iatm=0
 730  do itypat=1,ntypat
 731 
 732 !  Set search range (density cuts off perfectly beyond range)
 733    range=xcccrc(itypat);if (usepaw==1) range=pawtab(itypat)%rcore
 734    range2=range**2 ; rangem1=one/range
 735 
 736 !  Skip loop if this type has no core charge
 737    if (abs(range)<1.d-16) cycle
 738 
 739 !  PAW: select core density type and create mesh
 740    if (usepaw==1) then
 741      if (usekden_) then
 742        msz=pawtab(itypat)%coretau_mesh_size
 743        ABI_MALLOC(tcoretau,(msz,1))
 744        tcoretau(:,1)=pawtab(itypat)%coretau(:)
 745        corespl => tcoretau
 746      else
 747        msz=pawtab(itypat)%core_mesh_size
 748        corespl => pawtab(itypat)%tcoredens
 749      end if
 750      call pawrad_init(core_mesh,mesh_size=msz,&
 751 &     mesh_type=pawrad(itypat)%mesh_type,&
 752 &     rstep=pawrad(itypat)%rstep,lstep=pawrad(itypat)%lstep)
 753    end if
 754 
 755 !  Loop over atoms of the type
 756    do iat=1,nattyp(itypat)
 757      iatm=iatm+1;iatom=atindx1(iatm)
 758 
 759      if(option==2) corgr(:)=zero
 760 
 761 !    Consider each component in turn : compute range
 762      do mu=1,3
 763 !      Convert reduced coord of given atom to [0,1)
 764        tau(mu)=mod(xred(mu,iatom)+one-aint(xred(mu,iatom)),one)
 765 !      Use tau to find nearest grid point along R(mu)
 766 !      (igrid=0 is the origin; shift by 1 to agree with usual index)
 767        igrid(mu)=nint(tau(mu)*real(ngfft(mu),dp))
 768 !      Use range to compute an index range along R(mu)
 769 !      (add 1 to make sure it covers full range)
 770        irange(mu)=1+nint((range/scale(mu))*real(ngfft(mu),dp))
 771      end do
 772 
 773 !    Allocate arrays that depends on the range
 774      mrange=maxval(irange(1:3))
 775      ABI_MALLOC(ii,(2*mrange+1,3))
 776      ABI_MALLOC(rrdiff,(2*mrange+1,3))
 777 
 778 !    Set up counters that explore the relevant range of points around the atom
 779      if (geocode=='P') then
 780 !      Fully periodic version
 781        do mu=1,3
 782          ishift=0
 783          do ixp=igrid(mu)-irange(mu),igrid(mu)+irange(mu)
 784            ishift=ishift+1
 785            ii(ishift,mu)=1+mod(ngfft(mu)+mod(ixp,ngfft(mu)),ngfft(mu))
 786            rrdiff(ishift,mu)=real(ixp,dp)/real(ngfft(mu),dp)-tau(mu)
 787          end do
 788          ishiftmax(mu)=ishift
 789        end do
 790      else
 791 !      Free or surface conditions
 792        do mu=1,3
 793          ishift=0
 794          do ixp=igrid(mu)-irange(mu),igrid(mu)+irange(mu)
 795            call indpos_mkcore_alt(per(mu),ixp,ngfft(mu),jj,letsgo)
 796            if (letsgo) then
 797              ishift=ishift+1;ii(ishift,mu)=1+jj
 798              rrdiff(ishift,mu)=real(ixp,dp)/real(ngfft(mu),dp)-tau(mu)
 799            end if
 800          end do
 801          ishiftmax(mu)=ishift
 802        end do
 803      end if
 804      npts12=ishiftmax(1)*ishiftmax(2)
 805      ABI_MALLOC(indx1,(npts12))
 806      ABI_MALLOC(indx2,(npts12))
 807      ABI_MALLOC(iindex,(npts12))
 808      ABI_MALLOC(rnorm,(npts12))
 809      if (option==1.or.option==3) then
 810        ABI_MALLOC(tcore,(npts12))
 811      end if
 812      if (option>=2) then
 813        ABI_MALLOC(dtcore,(npts12))
 814      end if
 815      if (option==4) then
 816        ABI_MALLOC(d2tcore,(npts12))
 817      end if
 818 
 819 !    Conduct loop over restricted range of grid points for iatom
 820      do ishift3=1,ishiftmax(3)
 821        i3=ii(ishift3,3)
 822        rdiff3=rrdiff(ishift3,3)
 823 
 824        if(fftn3_distrib(i3)/=mpi_enreg%me_fft) cycle
 825 
 826 !      Select the vectors located around the current atom
 827 !        TR: all of the following  could be done inside or
 828 !        outside the loops (i2,i1,i3).
 829 !        Outside: the memory consumption increases.
 830 !        Inside: the time of calculation increases.
 831 !        Here, I choose to do it here, somewhere in the middle.
 832        npts=0
 833        do ishift2=1,ishiftmax(2)
 834          i2=ii(ishift2,2) ; rdiff2=rrdiff(ishift2,2)
 835          rnorm2_part=rmet(3,3)*rdiff3**2+rmet(2,2)*rdiff2**2 &
 836 &         +2.0d0*rmet(3,2)*rdiff3*rdiff2
 837          rnorm2_fact=2.0d0*(rmet(3,1)*rdiff3+rmet(2,1)*rdiff2)
 838          do ishift1=1,ishiftmax(1)
 839            i1=ii(ishift1,1) ; rdiff1=rrdiff(ishift1,1)
 840            rnorm2=rnorm2_part+rdiff1*(rnorm2_fact+rmet(1,1)*rdiff1)
 841 !          Only accept contributions inside defined range
 842            if (rnorm2<range2-tol12) then
 843              npts=npts+1 ; iindex(npts)=npts
 844              indx1(npts)=ishift1;indx2(npts)=ishift2
 845              rnorm(npts)=sqrt(rnorm2)
 846            end if
 847          end do
 848        end do
 849        if (npts==0) cycle
 850        if (npts>npts12) then
 851          message='npts>npts12!'
 852          ABI_BUG(message)
 853        end if
 854 
 855 !      Evaluate core density (and derivatives) on the set of selected points
 856        if (usepaw==1) then
 857 !        PAW: use splint routine
 858          call sort_dp(npts,rnorm(1:npts),iindex(1:npts),tol16)
 859          if (option==1.or.option==3) then
 860 !          Evaluate fit of core density
 861            call paw_splint(core_mesh%mesh_size,core_mesh%rad, &
 862 &           corespl(:,1),corespl(:,3),&
 863 &           npts,rnorm(1:npts),tcore(1:npts))
 864          end if
 865          if (option>=2) then
 866 !          Evaluate fit of 1-der of core density
 867            call paw_splint(core_mesh%mesh_size,core_mesh%rad, &
 868 &           corespl(:,2),corespl(:,4),&
 869 &           npts,rnorm(1:npts),dtcore(1:npts))
 870          end if
 871          if (option==4) then
 872 !          Evaluate fit of 2nd-der of core density
 873            call paw_splint(core_mesh%mesh_size,core_mesh%rad, &
 874 &           corespl(:,3),corespl(:,5),&
 875 &           npts,rnorm(1:npts),d2tcore(1:npts))
 876          end if
 877        else
 878 !        Norm-conserving PP:
 879 !          Evaluate spline fit with method from Numerical Recipes
 880 !          (p. 86 Numerical Recipes, Press et al;
 881 !          NOTE error in book for sign of "aa" term in derivative)
 882          do ipts=1,npts
 883            yy=rnorm(ipts)*rangem1
 884            jj=1+int(yy*(n1xccc-1))
 885            diff=yy-(jj-1)*delta
 886            bb = diff*deltam1 ; aa = one-bb
 887            cc = aa*(aa**2-one)*delta2div6
 888            dd = bb*(bb**2-one)*delta2div6
 889            if (option==1.or.option==3) then
 890              tcore(ipts)=aa*xccc1d(jj,1,itypat)+bb*xccc1d(jj+1,1,itypat) +&
 891 &             cc*xccc1d(jj,3,itypat)+dd*xccc1d(jj+1,3,itypat)
 892            end if
 893            if (option>=2) then
 894              dtcore(ipts)=aa*xccc1d(jj,2,itypat)+bb*xccc1d(jj+1,2,itypat) +&
 895 &             cc*xccc1d(jj,4,itypat)+dd*xccc1d(jj+1,4,itypat)
 896            end if
 897            if (option==4) then
 898              d2tcore(ipts)=aa*xccc1d(jj,3,itypat)+bb*xccc1d(jj+1,3,itypat) +&
 899 &             cc*xccc1d(jj,5,itypat)+dd*xccc1d(jj+1,5,itypat)
 900            end if
 901          end do
 902        end if
 903 
 904 !      Now, perform the loop over selected grid points
 905        do ipts=1,npts
 906          ishift1=indx1(iindex(ipts))
 907          ishift2=indx2(iindex(ipts))
 908          difmag=rnorm(ipts)
 909 
 910          rdiff1=rrdiff(ishift1,1);rdiff2=rrdiff(ishift2,2)
 911          jpts=ii(ishift1,1)+n1*(ii(ishift2,2)-1+n2*(ffti3_local(i3)-1))
 912 
 913 !        === Evaluate charge density
 914          if (option==1) then
 915            xccc3d(jpts)=xccc3d(jpts)+tcore(ipts)
 916 
 917 !        === Accumulate contributions to forces
 918          else if (option==2) then
 919            if (difmag>tol10) then
 920              term=vxc_eff(jpts)*dtcore(ipts)/difmag
 921              corgr(1)=corgr(1)+rdiff1*term
 922              corgr(2)=corgr(2)+rdiff2*term
 923              corgr(3)=corgr(3)+rdiff3*term
 924            end if
 925 
 926 !        === Accumulate contributions to stress tensor (in red. coordinates)
 927          else if (option==3) then
 928            if (difmag>tol10) then
 929              term=vxc_eff(jpts)*dtcore(ipts)*rangem1/difmag/real(nfftot,dp)
 930 !            Write out the 6 symmetric components
 931              corfra(1,1)=corfra(1,1)+term*rdiff1*rdiff1
 932              corfra(2,2)=corfra(2,2)+term*rdiff2*rdiff2
 933              corfra(3,3)=corfra(3,3)+term*rdiff3*rdiff3
 934              corfra(3,2)=corfra(3,2)+term*rdiff3*rdiff2
 935              corfra(3,1)=corfra(3,1)+term*rdiff3*rdiff1
 936              corfra(2,1)=corfra(2,1)+term*rdiff2*rdiff1
 937 !            (the above still needs to be transformed to cartesian coords)
 938            end if
 939 !          Also compute a diagonal term
 940            strdia=strdia+vxc_eff(jpts)*tcore(ipts)
 941 
 942 !        === Compute frozen-wf contribution to Dynamical matrix
 943          else if (option==4) then
 944            tt(1)=rmet(1,1)*rdiff1+rmet(1,2)*rdiff2+rmet(1,3)*rdiff3
 945            tt(2)=rmet(2,1)*rdiff1+rmet(2,2)*rdiff2+rmet(2,3)*rdiff3
 946            tt(3)=rmet(3,1)*rdiff1+rmet(3,2)*rdiff2+rmet(3,3)*rdiff3
 947            if (difmag>tol10) then
 948              term=(ucvol/real(nfftot,dp))*vxc_eff(jpts)*rangem1/difmag
 949              term1=term*tcore(ipts)
 950              term2=term*d2tcore(ipts)*rangem1/difmag
 951              do mu=1,3
 952                do nu=1,3
 953                  dyfrx2(mu,nu,iatom)=dyfrx2(mu,nu,iatom)&
 954 &                 +(term2-term1/difmag**2)*tt(mu)*tt(nu)&
 955 &                 +term1*rmet(mu,nu)
 956                end do
 957              end do
 958            else
 959 !            There is a contribution from difmag=zero !
 960              term=(ucvol/real(nfftot,dp))*vxc_eff(jpts)*d2tcore(ipts)*rangem1**2
 961              do mu=1,3
 962                do nu=1,3
 963                  dyfrx2(mu,nu,iatom)=dyfrx2(mu,nu,iatom)+term*rmet(mu,nu)
 964                end do
 965              end do
 966            end if
 967          end if ! Choice of option
 968 
 969        end do ! Loop on ipts (ishift1, ishift2)
 970 
 971      end do ! Loop on ishift3
 972 
 973      ABI_FREE(ii)
 974      ABI_FREE(rrdiff)
 975      ABI_FREE(indx1)
 976      ABI_FREE(indx2)
 977      ABI_FREE(iindex)
 978      ABI_FREE(rnorm)
 979      if (allocated(tcore)) then
 980        ABI_FREE(tcore)
 981      end if
 982      if (allocated(tcoretau)) then
 983        ABI_FREE(tcoretau)
 984      end if
 985      if (allocated(dtcore)) then
 986        ABI_FREE(dtcore)
 987      end if
 988      if (allocated(d2tcore)) then
 989        ABI_FREE(d2tcore)
 990      end if
 991 
 992      if (option==2) then
 993        fact=-(ucvol/real(nfftot,dp))/range
 994        grxc(:,iatom)=corgr(:)*fact
 995      end if
 996 
 997 !  End loop on atoms
 998    end do
 999 
1000    if (usepaw==1) then
1001      call pawrad_free(core_mesh)
1002    end if
1003 
1004 !End loop over atom types
1005  end do
1006 
1007  if(option>=2.and.nspden>=2)  then
1008    ABI_FREE(vxc_eff)
1009  end if
1010 
1011 !Forces: translate into reduced coordinates
1012  if (option==2) then
1013    do iatom=1,natom
1014      t1=grxc(1,iatom);t2=grxc(2,iatom);t3=grxc(3,iatom)
1015      grxc(:,iatom)=rmet(:,1)*t1+rmet(:,2)*t2+rmet(:,3)*t3
1016    end do
1017  end if
1018 
1019 !Stress tensor: symmetrize, translate into cartesian coord., add diagonal part
1020  if (option==3) then
1021    corstr(1)=corfra(1,1) ; corstr(2)=corfra(2,2)
1022    corstr(3)=corfra(3,3) ; corstr(4)=corfra(3,2)
1023    corstr(5)=corfra(3,1) ; corstr(6)=corfra(2,1)
1024    call strconv(corstr,rprimd,corstr)
1025    corstr(1)=corstr(1)+strdia/real(nfftot,dp)
1026    corstr(2)=corstr(2)+strdia/real(nfftot,dp)
1027    corstr(3)=corstr(3)+strdia/real(nfftot,dp)
1028  end if
1029 
1030 !If needed sum over MPI processes
1031  if(mpi_enreg%nproc_fft>1) then
1032    call timab(539,1,tsec)
1033    if (option==2) then
1034      call xmpi_sum(grxc,mpi_enreg%comm_fft,ier)
1035    end if
1036    if (option==3) then
1037      call xmpi_sum(corstr,mpi_enreg%comm_fft,ier)
1038    end if
1039    if (option==4) then
1040      call xmpi_sum(dyfrx2,mpi_enreg%comm_fft,ier)
1041    end if
1042    call timab(539,2,tsec)
1043  end if
1044 
1045  call timab(12,2,tsec)
1046 
1047  contains