File: test3.F90

package info (click to toggle)
libgridxc 2.1.0%2Breally2.0.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,920 kB
  • sloc: f90: 25,230; makefile: 389; sh: 350
file content (283 lines) | stat: -rw-r--r-- 9,776 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
#if defined HAVE_CONFIG_H
#include "config.h"
#endif

PROGRAM gridXCtest3

  ! Tester of cellXC. Compares the potential and stress with the numerical
  ! (finite-difference) derivatives of the energy. J.M.Soler. Sept.2009

  ! Used module procedures
  USE gridXC, only: cellXC => gridxc_cellXC
  USE gridXC, only: gridxc_init
  USE gridXC, only: myMeshBox 
  USE gridXC, only: nfft => gridxc_nfft
  USE gridXC, only: setMeshDistr
  USE gridXC, only: setXC => gridxc_setXC

  ! Used module parameters
  USE gridXC, only: dp
  USE gridXC, only: gp => grid_p

! Used MPI procedures and types
#ifdef HAVE_MPI
  USE mpi
#endif

  implicit none

  ! Tester parameters
  integer, parameter:: irel  = 0         ! Relativistic? 0=>no, 1=>yes
  integer, parameter:: nSpin = 2         ! Number of spin components
  integer, parameter:: nfTot = 19        ! Number of functionals available
  integer, parameter:: nRan =  6         ! Number of random points for test
  real(dp),parameter:: latConst = 10._dp ! Lattice constant, in Bohr
  real(dp),parameter:: Ecut = 30._dp     ! Planewave cutoff of the mesh
  real(dp),parameter:: Qtot = 10._dp     ! Integral of density distribution
  real(dp),parameter:: D1byD0 = 0.99_dp  ! Fractional change of density
  real(dp),parameter:: spinPol= 2._dp    ! Integral of densUp - densDown
  real(dp),parameter:: latCons= 10._dp   ! Lattice constant in Bohr
  real(dp),parameter:: asym = 0.5_dp     ! Orthorhombic asymetry 
  real(dp),parameter:: deltaDens = 1.e-6_dp ! Used for numerical derivatives
  real(dp),parameter:: deltaStrain = 1.e-4_dp ! Used for numerical derivatives

  ! List of functionals to be tested
!  integer, parameter:: nf = nfTot-4   ! Number of tested functionals
!  integer:: indexf(nf) = (/1,2,3,4,5,6,7,8,9,10,11,12,13,14,  18/) 
!                         ! Indexes from list below (only one VDW allowed)

  ! Same to test a single functional
  integer, parameter:: nf = 1        ! Number of tested functionals
  integer:: indexf(nf) = (/18/)      ! Indexes from list below

  ! All functionals available
  !                  1,           2,          3,           4,   
  !                  5,           6,          7,           8, 
  !                  9,          10,         11,          12,
  !                 13,          14,         15,          16,
  !                 17,          18,         19
  character(len=3):: &
    func(nfTot)=(/'LDA',       'LDA',       'GGA',       'GGA', &
                  'GGA',       'GGA',       'GGA',       'GGA', &
                  'GGA',       'GGA',       'GGA',       'GGA', &
                  'GGA',       'GGA',       'VDW',       'VDW', &
                  'VDW',       'VDW',       'VDW'       /)
  character(len=10):: &
    auth(nfTot)=(/'PZ        ','PW92      ','PW91      ','PBE       ', &
                  'RPBE      ','revPBE    ','LYP       ','WC        ', &
                  'PBEJsJrLO ','PBEJsJrHEG','PBEGcGxLO ','PBEGcGxHEG', &
                  'PBESOL    ','AM05      ','DRSLL     ','LMKLL     ', &
                  'C09       ','BH        ','VV        '/) 

  ! A few random numbers
  real(dp):: ran(nRan) = (/0.749218032_dp, 0.928517579_dp, 0.043866380_dp, &
                           0.669289084_dp, 0.392851044_dp, 0.502184791_dp /)

  ! Tester variables and arrays
  logical :: pointIsMine
  integer :: i, i1, i2, i3, ic, iDelta, ip, iRan, iSpin, lb1, lb2, lb3, &
             myBox(2,3), myDistr, myNode, &
             nMesh(3), nNodes, np, ub1, ub2, ub3
  real(dp):: cell(3,3), cell0(3,3), d0(nSpin), Dc, Dc0, &
             dEdDens, dEdStrain(3,3), dVol, Dx, Dx0, dxMax, &
             Ec, Ec0, Ex, Ex0, kCut, pi, &
             strain(3,3), stress(3,3), stress0(3,3), &
             tmp, volume, VxcSpin, wc(nfTot), wx(nfTot), x(3)
  real(gp),allocatable:: dens(:,:,:,:), dens0(:,:,:,:), &
                         Vxc(:,:,:,:), Vxc0(:,:,:,:)

#ifdef HAVE_MPI
  ! MPI-related variables
  integer:: MPIerror
#endif

  ! Initialize hybrid XC functional with all tested functionals
  wx = 1._dp / nf
  wc = 1._dp / nf
  call setXC( nf, func(indexf), auth(indexf), wx(indexf), wc(indexf) )

  ! Define a near-orthorhombic unit cell
  ! This is just to assume orthorhombicity in calculating nMesh from Ecut
  cell(:,:) = 0
  cell(1,1) = 1 - asym
  cell(2,2) = 1
  cell(3,3) = 1 + asym
  cell(:,1) = cell(:,1) + (/ 0.000_dp,  0.120_dp, -0.175_dp /)
  cell(:,2) = cell(:,2) + (/ 0.221_dp,  0.000_dp,  0.030_dp /)
  cell(:,3) = cell(:,3) + (/ 0.116_dp, -0.231_dp,  0.000_dp /)
  cell = cell * latConst
  volume = ( cell(2,1)*cell(3,2) - cell(3,1)*cell(2,2) ) * cell(1,3)  &
         + ( cell(3,1)*cell(1,2) - cell(1,1)*cell(3,2) ) * cell(2,3)  &
         + ( cell(1,1)*cell(2,2) - cell(2,1)*cell(1,2) ) * cell(3,3)

#ifdef HAVE_MPI
  ! Initialize MPI and get myNode and nNodes
  call MPI_Init( MPIerror )
  call MPI_Comm_Rank( MPI_Comm_World, myNode, MPIerror )
  call MPI_Comm_Size( MPI_Comm_World, nNodes, MPIerror )
#else
  myNode = 0
  nNodes = 1
#endif

  ! Find the number of mesh points in each direction
  pi = acos(-1._dp)
  kCut = sqrt(Ecut)
  dxMax = pi / kCut
  do ic = 1,3
    nMesh(ic) = ceiling( cell(ic,ic) / dxMax )
    call nfft( nMesh(ic) )
  end do

  ! Print parameters
  if (myNode==0) then
    print'(/,a,10(a3,4x))', 'funcs= ', func(indexf)
    print  '(a,10(a6,1x))', 'auths= ', auth(indexf)
    print'(a,3i6,f12.6)', 'nMesh, Ecut =', nMesh, Ecut
  end if

#ifdef HAVE_MPI
  ! Initialize mpi
  call gridxc_init(comm=MPI_Comm_World)
#else
  call gridxc_init()
#endif
  ! Find the box of mesh points own by my processor
  call setMeshDistr( myDistr, nMesh )
  call myMeshBox( nMesh, myDistr, myBox )
  lb1 = myBox(1,1)
  ub1 = myBox(2,1)
  lb2 = myBox(1,2)
  ub2 = myBox(2,2)
  lb3 = myBox(1,3)
  ub3 = myBox(2,3)

  ! Allocate arrays for density and potential
  allocate( dens(lb1:ub1,lb2:ub2,lb3:ub3,nSpin), &
           dens0(lb1:ub1,lb2:ub2,lb3:ub3,nSpin), &
             Vxc(lb1:ub1,lb2:ub2,lb3:ub3,nSpin), &
            Vxc0(lb1:ub1,lb2:ub2,lb3:ub3,nSpin) )

  ! Find density at mesh points
  np = product(nMesh)
  dVol = volume / np
  if (nSpin==1) then
    d0(1) = Qtot / volume
  else
    d0(1) = (Qtot+spinPol) / 2 / volume
    d0(2) = (Qtot-spinPol) / 2 / volume
  end if
  do i3 = lb3,ub3
  do i2 = lb2,ub2
  do i1 = lb1,ub1
    x(:) = cell(:,1)*i1/nMesh(1) &   ! Mesh point position
         + cell(:,2)*i2/nMesh(2) &
         + cell(:,3)*i3/nMesh(3)
    dens(i1,i2,i3,:) = d0(:) * (1 + D1byD0 * cos( 2*pi*x(1)/cell(1,1) ) &
                                           * cos( 2*pi*x(2)/cell(2,2) ) &
                                           * cos( 2*pi*x(3)/cell(3,3) ) )
  end do ! i1
  end do ! i2
  end do ! i3

  ! Find exchange and correlation energy and potential from density in cell
  call cellXC( irel, cell, nMesh, lb1, ub1, lb2, ub2, lb3, ub3, nSpin, &
               dens, Ex, Ec, Dx, Dc, stress, Vxc )

  ! Print total energies
  if (myNode==0) then
    print'(a,2f15.9)', 'Ex, Ec =', Ex, Ec
    print'(a,2f15.9)', 'Dx, Dc =', Dx, Dc
  end if

  ! Store unperturbed magnitudes
  cell0 = cell
  dens0 = dens
  Ex0 = Ex
  Ec0 = Ec
  Dx0 = Dx
  Dc0 = Dc
  stress0 = stress
  Vxc0 = Vxc

  ! Compare Vxc with numerical derivative of d(Ex+Ec)/dDens
  do iRan = 1,nRan

    ! Choose one spin component
    if (ran(iRan)< 0.5_dp) iSpin = 1
    if (ran(iRan)>=0.5_dp) iSpin = 2
    ran(iRan) = 2*mod(ran(iRan),0.5_dp)  ! ran(iRan) again in range (0:1)

    ! Choose one mesh point. Notice that index ranges are (0:nMesh-1)
    ip = np * ran(iRan)
    i3 = ip / nMesh(1) / nMesh(2)  ! Undo ip=i1+nMesh(1)*i2+nMesh(1)*nMesh(2)*i3
    ip = ip - nMesh(1) * nMesh(2) * i3
    i2 = ip / nMesh(1)
    i1 = ip - nMesh(1) * i2
    ! Find if point i1,i2,i3 is in my box
    pointIsMine = (lb1<=i1 .and. i1<=ub1 .and. &
                   lb2<=i2 .and. i2<=ub2 .and. &
                   lb3<=i3 .and. i3<=ub3)

    ! Find energies with dens(i1,i2,i3,iSpin)+/-delta
    dEdDens = 0
    do iDelta = -1,1,2
      dens = dens0
      if (pointIsMine) &
        dens(i1,i2,i3,iSpin) = dens0(i1,i2,i3,iSpin) + iDelta*deltaDens
      call cellXC( irel, cell, nMesh, lb1, ub1, lb2, ub2, lb3, ub3, nSpin, &
               dens, Ex, Ec, Dx, Dc, stress, Vxc )
      dEdDens = dEdDens + iDelta*(Ex+Ec)/(2*deltaDens)
    end do ! iDelta

#ifdef HAVE_MPI
    ! Send Vxc(i1,i2,i3,iSpin) to other nodes
    if (pointIsMine) then
      VxcSpin = Vxc0(i1,i2,i3,iSpin)
    else
      VxcSpin = 0
    end if
    tmp = VxcSpin
    call MPI_AllReduce( tmp, VxcSpin, 1, MPI_double_precision, &
                        MPI_Sum, MPI_Comm_World, MPIerror )
#else
    VxcSpin = Vxc0(i1,i2,i3,iSpin)
#endif
    if (myNode==0) then
      if (iRan==1) print'(4a6,3a15)', &
        'i1','i2','i3','iSpin','Vxc','dExc/dDens','diff'
      print'(4i6,3f15.9)', &
        i1, i2, i3, iSpin, VxcSpin, dEdDens/dVol, VxcSpin-dEdDens/dVol
    end if

  end do ! iRan

  ! Compare stress with numerical derivative of dE/dStrain
  dens = dens0
  do i2 = 1,3
    do i1 = 1,3
      dEdStrain(i1,i2) = 0
      do iDelta = -1,1,2
        strain(:,:) = 0
        forall(i=1:3) strain(i,i) = 1
        strain(i1,i2) = strain(i1,i2) + iDelta*deltaStrain
        cell = matmul( strain, cell0 )
        call cellXC( irel, cell, nMesh, lb1, ub1, lb2, ub2, lb3, ub3, nSpin, &
               dens, Ex, Ec, Dx, Dc, stress, Vxc )
        dEdStrain(i1,i2) = dEdStrain(i1,i2) + iDelta*(Ex+Ec)/(2*deltaStrain)
      end do ! iDelta
    end do ! i1
  end do ! i2
  if (myNode==0) then
    print'(a,/,(3f15.9))', 'xc stress * volume =', stress0*volume
    print'(a,/,(3f15.9))', 'dExc/dStrain =', dEdStrain
    print'(a,/,(3f15.9))', 'diff =', (stress0*volume-dEdStrain)
  end if

! Finalize MPI
#ifdef HAVE_MPI
      call MPI_Finalize( MPIerror )
#endif

END PROGRAM gridXCtest3