TABLE OF CONTENTS


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.

COPYRIGHT

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

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

PARENTS

      dfpt_dyxc1,dfpt_eltfrxc,dfpt_looppert,dfpt_nselt,dfpt_nstdy,dfpt_nstpaw
      dfptnl_loop

CHILDREN

SOURCE

 55 #if defined HAVE_CONFIG_H
 56 #include "config.h"
 57 #endif
 58 
 59 #include "abi_common.h"
 60 
 61 
 62 subroutine dfpt_mkcore(cplex,idir,ipert,natom,ntypat,n1,n1xccc,&
 63 & n2,n3,qphon,rprimd,typat,ucvol,xcccrc,xccc1d,xccc3d1,xred)
 64 
 65  use defs_basis
 66  use m_profiling_abi
 67  use m_errors
 68 
 69 !This section has been created automatically by the script Abilint (TD).
 70 !Do not modify the following lines by hand.
 71 #undef ABI_FUNC
 72 #define ABI_FUNC 'dfpt_mkcore'
 73 !End of the abilint section
 74 
 75  implicit none
 76 
 77 !Arguments ------------------------------------
 78 !scalars
 79  integer,intent(in) :: cplex,idir,ipert,n1,n1xccc,n2,n3,natom,ntypat
 80  real(dp),intent(in) :: ucvol
 81 !arrays
 82  integer,intent(in) :: typat(natom)
 83  real(dp),intent(in) :: qphon(3),rprimd(3,3),xccc1d(n1xccc,6,ntypat)
 84  real(dp),intent(in) :: xcccrc(ntypat),xred(3,natom)
 85  real(dp),intent(out) :: xccc3d1(cplex*n1*n2*n3)
 86 
 87 !Local variables-------------------------------
 88 !scalars
 89  integer,parameter :: mshift=401
 90  integer :: i1,i2,i3,iatom,ifft,ishift,ishift1,ishift2,ishift3,istr
 91  integer :: ixp,jj,ka,kb,mrange,mu,nu
 92  real(dp) :: aa,bb,cc,dd,delta,delta2div6,deltam1,diff,difmag
 93  real(dp) :: difmag2,difmag2_fact,difmag2_part,func,phase,phi,phr,prod
 94  real(dp) :: range,range2,rangem1,rdiff1,rdiff2,rdiff3,term
 95  real(dp) :: yy
 96  character(len=500) :: message
 97 !arrays
 98  integer,save :: idx(12)=(/1,1,2,2,3,3,3,2,3,1,2,1/)
 99  integer :: igrid(3),irange(3),ngfft(3)
100  integer,allocatable :: ii(:,:)
101  real(dp) :: drmetds(3,3),lencp(3),rmet(3,3),scale(3),tau(3)
102  real(dp),allocatable :: rrdiff(:,:)
103 
104 ! *************************************************************************
105 
106 ! if( ipert<1 .or. ipert> natom+7) then
107 !   write(message,'(a,i0,a,a,a,i0,a)')&
108 !&   ' The argument ipert must be between 1 and natom+7=',natom+7,',',ch10,&
109 !&   ' while it is ipert=',ipert,'.'
110 !   MSG_BUG(message)
111 ! end if
112 
113  if( (ipert==natom+3 .or. ipert==natom+4) .and. cplex/=1) then
114    write(message,'(3a,i4,a)')&
115 &   'The argument cplex must be 1 for strain perturbationh',ch10,&
116 &   'while it is cplex=',cplex,'.'
117    MSG_BUG(message)
118  end if
119 
120 !Zero out array
121  xccc3d1(:)=0.0_dp
122 
123 !For a non-linear XC core correction, the perturbation must be phonon-type or strain type
124  if(ipert<=natom .or. ipert==natom+3 .or. ipert==natom+4) then
125 
126    if( idir<1 .or. idir> 3) then
127      write(message,'(a,a,a,i4,a)')&
128 &     'The argument idir must be between 1 and 3,',ch10,&
129 &     'while it is idir=',idir,'.'
130      MSG_BUG(message)
131    end if
132 
133 !  Compute lengths of cross products for pairs of primitive
134 !  translation vectors (used in setting index search range below)
135    lencp(1)=cross_mk(rprimd(1,2),rprimd(2,2),rprimd(3,2),&
136 &   rprimd(1,3),rprimd(2,3),rprimd(3,3))
137    lencp(2)=cross_mk(rprimd(1,3),rprimd(2,3),rprimd(3,3),&
138 &   rprimd(1,1),rprimd(2,1),rprimd(3,1))
139    lencp(3)=cross_mk(rprimd(1,1),rprimd(2,1),rprimd(3,1),&
140 &   rprimd(1,2),rprimd(2,2),rprimd(3,2))
141 
142 !  Compute factor R1.(R2xR3)/|R2xR3| etc for 1, 2, 3
143 !  (recall ucvol=R1.(R2xR3))
144    scale(:)=ucvol/lencp(:)
145 
146 !  Compute metric tensor in real space rmet
147    do nu=1,3
148      rmet(:,nu)=rprimd(1,:)*rprimd(1,nu)+rprimd(2,:)*rprimd(2,nu)+&
149 &     rprimd(3,:)*rprimd(3,nu)
150    end do
151 
152 !  Section to be executed only for strain perturbation
153 !  Compute derivative of metric tensor wrt strain component istr
154    if(ipert==natom+3 .or. ipert==natom+4) then
155      istr=idir + 3*(ipert-natom-3)
156 
157      ka=idx(2*istr-1);kb=idx(2*istr)
158      do jj = 1,3
159        drmetds(:,jj)=(rprimd(ka,:)*rprimd(kb,jj)+rprimd(kb,:)*rprimd(ka,jj))
160      end do
161 !    For historical reasons:
162      drmetds(:,:)=0.5_dp*drmetds(:,:)
163 
164 !    end of strain perturbation section
165    end if
166 
167    ngfft(1)=n1
168    ngfft(2)=n2
169    ngfft(3)=n3
170 
171    delta=1.0_dp/(n1xccc-1)
172    deltam1=n1xccc-1
173    delta2div6=delta**2/6.0_dp
174 
175 !  Loop over atoms in unit cell
176 !  Note that we cycle immediately for all except the displaced atom
177 !  for such a perturbation.  The loop is executed over all the
178 !  atoms for a strain peturbation.
179    do iatom=1,natom
180      if(ipert<=natom .and. iatom/=ipert) cycle
181 !    Set search range (density cuts off perfectly beyond range)
182 !    Cycle if no range.
183      range=0.0_dp
184      range=xcccrc(typat(iatom))
185      if(range<1.d-16) cycle
186 
187      range2=range**2
188      rangem1=1.0_dp/range
189 
190 !    compute mrange for ii(:,3), rrdiff(:,3), inserted by MM (2005/12/06)
191 !    Consider each component in turn : compute range
192      do mu=1,3
193 
194 !      Convert reduced coord of given atom to [0,1)
195        tau(mu)=mod(xred(mu,iatom)+1._dp-aint(xred(mu,iatom)),1._dp)
196 
197 !      Use tau to find nearest grid point along R(mu)
198 !      (igrid=0 is the origin; shift by 1 to agree with usual index)
199        igrid(mu)=nint(tau(mu)*dble(ngfft(mu)))
200 
201 !      Use range to compute an index range along R(mu)
202 !      (add 1 to make sure it covers full range)
203        irange(mu)=1+nint((range/scale(mu))*dble(ngfft(mu)))
204 
205      end do
206 
207 !    Allocate arrays that depends on the range
208      mrange=maxval(irange(1:3))
209      ABI_ALLOCATE(ii,(2*mrange+1,3))
210      ABI_ALLOCATE(rrdiff,(2*mrange+1,3))
211 
212 !    Consider each component in turn
213      do mu=1,3
214 
215 !      temporarily suppressed by MM (2005/12/02)
216 !      Convert reduced coord of given atom to [0,1)
217 !      tau(mu)=mod(xred(mu,iatom)+1._dp-aint(xred(mu,iatom)),1._dp)
218 
219 !      Use tau to find nearest grid point along R(mu)
220 !      (igrid=0 is the origin; shift by 1 to agree with usual index)
221 !      igrid(mu)=nint(tau(mu)*dble(ngfft(mu)))
222 
223 !      Use range to compute an index range along R(mu)
224 !      (add 1 to make sure it covers full range)
225 !      irange(mu)=1+nint((range/scale(mu))*dble(ngfft(mu)))
226 
227 !      Check that the largest range is smallest than the maximum
228 !      allowed one
229 !      if(2*irange(mu)+1 > mshift)then
230 !      write(message, '(a,a,a,a,i6,a)' ) ch10,&
231 !      &    ' dfpt_mkcore : BUG -',ch10,&
232 !      &    '  The range around atom',iatom,' is too large.'
233 !      MSG_BUG(message)
234 !      end if
235 
236 !      Set up a counter that explore the relevant range
237 !      of points around the atom
238        ishift=0
239        do ixp=igrid(mu)-irange(mu),igrid(mu)+irange(mu)
240          ishift=ishift+1
241          ii(ishift,mu)=1+mod(ngfft(mu)+mod(ixp,ngfft(mu)),ngfft(mu))
242          rrdiff(ishift,mu)=dble(ixp)/dble(ngfft(mu))-tau(mu)
243        end do
244 
245 !      End loop on mu
246      end do
247 
248 !    Conduct triple loop over restricted range of grid points for iatom
249 
250      do ishift3=1,1+2*irange(3)
251 !      map back to [1,ngfft(3)] for usual fortran index in unit cell
252        i3=ii(ishift3,3)
253 !      find vector from atom location to grid point (reduced)
254        rdiff3=rrdiff(ishift3,3)
255 
256        do ishift2=1,1+2*irange(2)
257          i2=ii(ishift2,2)
258          rdiff2=rrdiff(ishift2,2)
259 !        Prepare the computation of difmag2
260          difmag2_part=rmet(3,3)*rdiff3**2+rmet(2,2)*rdiff2**2&
261 &         +2.0_dp*rmet(3,2)*rdiff3*rdiff2
262          difmag2_fact=2.0_dp*(rmet(3,1)*rdiff3+rmet(2,1)*rdiff2)
263 
264          do ishift1=1,1+2*irange(1)
265            rdiff1=rrdiff(ishift1,1)
266 
267 !          Compute (rgrid-tau-Rprim)**2
268            difmag2= difmag2_part+rdiff1*(difmag2_fact+rmet(1,1)*rdiff1)
269 
270 !          Only accept contribution inside defined range
271            if (difmag2<range2) then
272 
273 !            Prepare computation of core charge function and derivative,
274 !            using splines
275              difmag=sqrt(difmag2)
276              if (difmag>=1.0d-10) then
277                i1=ii(ishift1,1)
278                yy=difmag*rangem1
279 
280 !              Compute index of yy over 1 to n1xccc scale
281                jj=1+int(yy*(n1xccc-1))
282                diff=yy-(jj-1)*delta
283 
284 !              Will evaluate spline fit (p. 86 Numerical Recipes, Press et al;
285 !              NOTE error in book for sign of "aa" term in derivative;
286 !              also see splfit routine).
287                bb = diff*deltam1
288                aa = 1.0_dp-bb
289                cc = aa*(aa**2-1.0_dp)*delta2div6
290                dd = bb*(bb**2-1.0_dp)*delta2div6
291                
292 !              Evaluate spline fit of 1st der of core charge density
293 !              from xccc1d(:,2,:) and (:,4,:)
294                func=aa*xccc1d(jj,2,typat(iatom))+bb*xccc1d(jj+1,2,typat(iatom)) +&
295 &               cc*xccc1d(jj,4,typat(iatom))+dd* xccc1d(jj+1,4,typat(iatom))
296 
297                if(ipert<=natom) then
298                  phase=2*pi*(qphon(1)*(rdiff1+xred(1,iatom))  &
299 &                 +qphon(2)*(rdiff2+xred(2,iatom))  &
300 &                 +qphon(3)*(rdiff3+xred(3,iatom)))
301                  prod=rmet(idir,1)*rdiff1+rmet(idir,2)*rdiff2+rmet(idir,3)*rdiff3
302 
303                  term=-func*rangem1/difmag*prod
304                  ifft=i1+n1*(i2-1+n2*(i3-1))
305                  phr=cos(phase)
306                  if(cplex==1)then
307                    xccc3d1(ifft)=xccc3d1(ifft)+term*phr
308                  else
309                    phi=sin(phase)
310                    xccc3d1(2*ifft-1)=xccc3d1(2*ifft-1)+term*phr
311                    xccc3d1(2*ifft  )=xccc3d1(2*ifft  )-term*phi
312                  end if
313                else
314                  prod=&
315 &                 (rdiff1*(drmetds(1,1)*rdiff1+drmetds(1,2)*rdiff2+drmetds(1,3)*rdiff3)&
316 &                 +rdiff2*(drmetds(2,1)*rdiff1+drmetds(2,2)*rdiff2+drmetds(2,3)*rdiff3)&
317 &                 +rdiff3*(drmetds(3,1)*rdiff1+drmetds(3,2)*rdiff2+drmetds(3,3)*rdiff3))
318                  term=prod*func*rangem1/difmag
319                  
320                  ifft=i1+n1*(i2-1+n2*(i3-1))
321                  xccc3d1(ifft)=xccc3d1(ifft)+term
322 
323                end if
324 
325 !              End of the condition for the distance not to vanish
326              end if
327 
328 !            End of condition to be inside the range
329            end if
330 
331 !          End loop on ishift1
332          end do
333 
334 !        End loop on ishift2
335        end do
336 
337 !      End loop on ishift3
338      end do
339 
340      ABI_DEALLOCATE(ii)
341      ABI_DEALLOCATE(rrdiff)
342 !    End loop on atoms
343    end do
344 
345 !  End of the condition ipert corresponds to a phonon type perturbation
346 !  or strain type perturbation
347  end if
348 
349  contains
350 
351    function cross_mk(xx,yy,zz,aa,bb,cc)
352 
353 
354 !This section has been created automatically by the script Abilint (TD).
355 !Do not modify the following lines by hand.
356 #undef ABI_FUNC
357 #define ABI_FUNC 'cross_mk'
358 !End of the abilint section
359 
360    real(dp) :: cross_mk
361    real(dp),intent(in) :: xx,yy,zz,aa,bb,cc
362    cross_mk=sqrt((yy*cc-zz*bb)**2+(zz*aa-xx*cc)**2+(xx*bb-yy*aa)**2)
363  end function cross_mk
364 
365 end subroutine dfpt_mkcore