The Elk Code
eveqnfvr.f90
Go to the documentation of this file.
1 
2 ! Copyright (C) 2011 J. K. Dewhurst, S. Sharma and E. K. U. Gross.
3 ! This file is distributed under the terms of the GNU General Public License.
4 ! See the file COPYING for license details.
5 
6 !BOP
7 ! !ROUTINE: eveqnfvr
8 ! !INTERFACE:
9 subroutine eveqnfvr(nmatp,ngp,vpc,h_,o_,evalfv,evecfv)
10 ! !USES:
11 use modmain
12 use modomp
13 use, intrinsic :: iso_c_binding
14 ! !INPUT/OUTPUT PARAMETERS:
15 ! nmatp : order of overlap and Hamiltonian matrices (in,integer)
16 ! ngp : number of G+p-vectors (in,integer)
17 ! vpc : p-vector in Cartesian coordinates (in,real(3))
18 ! h,o : Hamiltonian and overlap matrices in upper triangular form
19 ! (in,complex(*))
20 ! evalfv : first-variational eigenvalues (out,real(nstfv))
21 ! evecfv : first-variational eigenvectors (out,complex(nmatmax,nstfv))
22 ! !DESCRIPTION:
23 ! This routine solves the first-variational eigenvalue equation for the
24 ! special case when inversion symmetry is present. In this case the
25 ! Hamiltonian and overlap matrices can be made real by using appropriate
26 ! linear combinations of the local-orbitals for atoms related by inversion
27 ! symmetry. These are derived from the effect of parity and complex
28 ! conjugation on the spherical harmonics: $P Y_{lm}=(-1)^l Y_{lm}$ and
29 ! $(Y_{lm})^*=(-1)^m Y_{l-m}$.
30 !
31 ! !REVISION HISTORY:
32 ! Created May 2011 (JKD)
33 !EOP
34 !BOC
35 implicit none
36 ! arguments
37 integer, intent(in) :: nmatp,ngp
38 real(8), intent(in) :: vpc(3)
39 real(8), target :: h_(*),o_(*)
40 real(8), intent(out) :: evalfv(nstfv)
41 complex(8), intent(out) :: evecfv(nmatmax,nstfv)
42 ! local variables
43 integer is,ia,ja,jas,ilo
44 integer n2,i,j,k,l,m
45 integer i1,i2,j1,j2
46 integer k1,k2,k3,k4
47 integer l1,l2,m1,m2
48 integer info,nthd,nts
49 real(8) v(3),vl,vu
50 real(8) s1,t1,t2,t3,t4
51 real(8) ts0,ts1
52 complex(8) z1
53 ! automatic arrays
54 logical tr(nlotot),tp(nlotot)
55 integer idx(nlotot),s(nlotot)
56 integer iwork(5*nmatp),ifail(nmatp)
57 real(8) w(nmatp)
58 complex(8) zp(nlotot)
59 ! allocatable arrays and pointers
60 real(8), allocatable :: rh(:)
61 real(8), pointer, contiguous :: ro(:),rv(:,:)
62 complex(8), pointer, contiguous :: h(:),o(:)
63 call timesec(ts0)
64 ! reuse already allocated memory
65 n2=nmatp**2
66 call c_f_pointer(c_loc(h_),h,shape=[n2])
67 call c_f_pointer(c_loc(o_),o,shape=[n2])
68 call c_f_pointer(c_loc(h_),ro,shape=[n2])
69 call c_f_pointer(c_loc(h_(n2+1)),rv,shape=[nmatp,nstfv])
70 tp(1:nlotot)=.false.
71 i=0
72 do is=1,nspecies
73  do ia=1,natoms(is)
74 ! symmetry equivalent atom, mapped with inversion
75  ja=ieqatom(ia,is,2)
76  jas=idxas(ja,is)
77 ! residual phase factor
78  v(1:3)=atposc(1:3,ia,is)+atposc(1:3,ja,is)
79  t1=0.5d0*(vpc(1)*v(1)+vpc(2)*v(2)+vpc(3)*v(3))
80  z1=cmplx(cos(t1),sin(t1),8)
81  do ilo=1,nlorb(is)
82  l=lorbl(ilo,is)
83  do m=-l,l
84  i=i+1
85 ! index to conjugate local-orbital in symmetry equivalent atom
86  idx(i)=idxlo(l*(l+1)-m+1,ilo,jas)
87  if (ia /= ja) then
88 ! sign of parity and conjugation operators
89  if (mod(l+m,2) == 0) then
90  s(i)=1
91  else
92  s(i)=-1
93  end if
94  if (ia < ja) then
95 ! if ia < ja use the real part of the sum of matrix elements
96  tr(i)=.true.
97  else if (ia > ja) then
98 ! if ia > ja use the imaginary part of the difference of matrix elements
99  s(i)=-s(i)
100  tr(i)=.false.
101  end if
102  else
103 ! if ia = ja then use real function when l even and imaginary when l is odd
104  if (mod(m,2) == 0) then
105  s(i)=1
106  else
107  s(i)=-1
108  end if
109 ! new function should be real if symmetric or imaginary if antisymmetric
110  if (mod(l,2) == 0) then
111 ! l even
112  if (m >= 0) then
113  tr(i)=.true.
114  else
115  s(i)=-s(i)
116  tr(i)=.false.
117  end if
118  else
119 ! l odd
120  if (m >= 0) then
121  tr(i)=.false.
122  else
123  s(i)=-s(i)
124  tr(i)=.true.
125  end if
126  end if
127  end if
128 ! phase factors if required
129  if (abs(t1) > 1.d-8) then
130  zp(i)=z1
131  tp(i)=.true.
132  end if
133  end do
134  end do
135  end do
136 end do
137 !---------------------------------!
138 ! real Hamiltonian matrix !
139 !---------------------------------!
140 allocate(rh(n2))
141 ! ⟨APW|H|APW⟩
142 do j=1,ngp
143  k=(j-1)*nmatp+1
144  rh(k:k+j-1)=dble(h(k:k+j-1))
145 end do
146 ! ⟨APW|H|lo⟩
147 do m1=1,nlotot
148  j1=(ngp+m1-1)*nmatp
149  j2=(ngp+idx(m1)-1)*nmatp
150  z1=zp(m1); s1=s(m1)
151  if (tp(m1)) then
152  if (tr(m1)) then
153  rh(j1+1:j1+ngp)=dble(h(j1+1:j1+ngp)*z1)+s1*dble(h(j2+1:j2+ngp)*z1)
154  else
155  rh(j1+1:j1+ngp)=aimag(h(j1+1:j1+ngp)*z1)+s1*aimag(h(j2+1:j2+ngp)*z1)
156  end if
157  else
158  if (tr(m1)) then
159  rh(j1+1:j1+ngp)=dble(h(j1+1:j1+ngp))+s1*dble(h(j2+1:j2+ngp))
160  else
161  rh(j1+1:j1+ngp)=aimag(h(j1+1:j1+ngp))+s1*aimag(h(j2+1:j2+ngp))
162  end if
163  end if
164 end do
165 ! ⟨lo|H|lo⟩
166 do m1=1,nlotot
167  m2=idx(m1)
168  do l1=1,m1
169  l2=idx(l1)
170  k1=map(l1,m1); k2=map(l1,m2); k3=map(l2,m1); k4=map(l2,m2)
171  if ((tr(l1).and.tr(m1)).or.((.not.tr(l1)).and.(.not.tr(m1)))) then
172  rh(k1)=dble(h(k1))+s(m1)*dble(h(k2))+s(l1)*(dble(h(k3))+s(m1)*dble(h(k4)))
173  else
174  t2=aimag(h(k2))
175  if (l1 > m2) t2=-t2
176  t3=aimag(h(k3))
177  if (l2 > m1) t3=-t3
178  t4=aimag(h(k4))
179  if (l2 > m2) t4=-t4
180  rh(k1)=aimag(h(k1))+s(m1)*t2+s(l1)*(t3+s(m1)*t4)
181  if (.not.tr(l1)) rh(k1)=-rh(k1)
182  end if
183  end do
184 end do
185 !-----------------------------!
186 ! real overlap matrix !
187 !-----------------------------!
188 ! ⟨APW|O|APW⟩
189 do j=1,ngp
190  k=(j-1)*nmatp+1
191  ro(k:k+j-1)=dble(o(k:k+j-1))
192 end do
193 ! ⟨APW|O|lo⟩
194 do m1=1,nlotot
195  j1=(ngp+m1-1)*nmatp
196  j2=(ngp+idx(m1)-1)*nmatp
197  z1=zp(m1); s1=s(m1)
198  if (tp(m1)) then
199  if (tr(m1)) then
200  ro(j1+1:j1+ngp)=dble(o(j1+1:j1+ngp)*z1)+s1*dble(o(j2+1:j2+ngp)*z1)
201  else
202  ro(j1+1:j1+ngp)=aimag(o(j1+1:j1+ngp)*z1)+s1*aimag(o(j2+1:j2+ngp)*z1)
203  end if
204  else
205  if (tr(m1)) then
206  ro(j1+1:j1+ngp)=dble(o(j1+1:j1+ngp))+s1*dble(o(j2+1:j2+ngp))
207  else
208  ro(j1+1:j1+ngp)=aimag(o(j1+1:j1+ngp))+s1*aimag(o(j2+1:j2+ngp))
209  end if
210  end if
211 end do
212 ! ⟨lo|O|lo⟩
213 do m1=1,nlotot
214  m2=idx(m1)
215  do l1=1,m1
216  l2=idx(l1)
217  k1=map(l1,m1); k2=map(l1,m2); k3=map(l2,m1); k4=map(l2,m2)
218  if ((tr(l1).and.tr(m1)).or.((.not.tr(l1)).and.(.not.tr(m1)))) then
219  ro(k1)=dble(o(k1))+s(m1)*dble(o(k2))+s(l1)*(dble(o(k3))+s(m1)*dble(o(k4)))
220  else
221  t2=aimag(o(k2))
222  if (l1 > m2) t2=-t2
223  t3=aimag(o(k3))
224  if (l2 > m1) t3=-t3
225  t4=aimag(o(k4))
226  if (l2 > m2) t4=-t4
227  ro(k1)=aimag(o(k1))+s(m1)*t2+s(l1)*(t3+s(m1)*t4)
228  if (.not.tr(l1)) ro(k1)=-ro(k1)
229  end if
230  end do
231 end do
232 ! solve the generalised eigenvalue problem for real symmetric matrices
233 ! enable MKL parallelism
234 call holdthd(maxthdmkl,nthd)
235 nts=mkl_set_num_threads_local(nthd)
236 ! diagonalise the matrix (use o_ as the work array)
237 call dsygvx(1,'V','I','U',nmatp,rh,nmatp,ro,nmatp,vl,vu,1,nstfv,evaltol,m,w, &
238  rv,nmatp,o_,n2,iwork,ifail,info)
239 nts=mkl_set_num_threads_local(0)
240 call freethd(nthd)
241 if (info /= 0) then
242  write(*,*)
243  write(*,'("Error(eveqnfvr): diagonalisation failed")')
244  write(*,'(" DSYGVX returned INFO = ",I0)') info
245  if (info > nmatp) then
246  i=info-nmatp
247  write(*,'(" The leading minor of the overlap matrix of order ",I0)') i
248  write(*,'(" is not positive definite")')
249  write(*,'(" Order of overlap matrix : ",I0)') nmatp
250  end if
251  write(*,*)
252  stop
253 end if
254 evalfv(1:nstfv)=w(1:nstfv)
255 ! reconstruct the complex eigenvectors
256 do j=1,nstfv
257  evecfv(1:ngp,j)=rv(1:ngp,j)
258  evecfv(ngp+1:nmatp,j)=0.d0
259  do l1=1,nlotot
260  i1=ngp+l1
261  i2=ngp+idx(l1)
262  t1=rv(i1,j)
263  if (tr(l1)) then
264  evecfv(i1,j)=evecfv(i1,j)+t1
265  evecfv(i2,j)=evecfv(i2,j)+s(l1)*t1
266  else
267  evecfv(i1,j)%im=evecfv(i1,j)%im-t1
268  evecfv(i2,j)%im=evecfv(i2,j)%im-s(l1)*t1
269  end if
270  end do
271  do l1=1,nlotot
272  if (tp(l1)) then
273  i1=ngp+l1
274  evecfv(i1,j)=evecfv(i1,j)*zp(l1)
275  end if
276  end do
277 end do
278 deallocate(rh)
279 call timesec(ts1)
280 !$OMP ATOMIC
281 timefv=timefv+ts1-ts0
282 
283 contains
284 
285 elemental integer function map(i,j)
286 implicit none
287 ! arguments
288 integer, intent(in) :: i,j
289 ! map from local-orbital indices to position in matrix
290 if (i <= j) then
291  map=ngp+i+(ngp+j-1)*nmatp
292 else
293  map=ngp+j+(ngp+i-1)*nmatp
294 end if
295 end function
296 
297 end subroutine
298 !EOC
299 
integer, dimension(maxspecies) nlorb
Definition: modmain.f90:786
integer, dimension(:,:,:), allocatable idxlo
Definition: modmain.f90:855
integer, dimension(maxatoms, maxspecies) idxas
Definition: modmain.f90:42
Definition: modomp.f90:6
integer maxthdmkl
Definition: modomp.f90:15
integer, dimension(:,:,:), allocatable ieqatom
Definition: modmain.f90:368
subroutine eveqnfvr(nmatp, ngp, vpc, h_, o_, evalfv, evecfv)
Definition: eveqnfvr.f90:10
real(8) evaltol
Definition: modmain.f90:917
integer, dimension(maxspecies) natoms
Definition: modmain.f90:36
subroutine timesec(ts)
Definition: timesec.f90:10
real(8) timefv
Definition: modmain.f90:1217
integer nspecies
Definition: modmain.f90:34
subroutine freethd(nthd)
Definition: modomp.f90:106
subroutine holdthd(nloop, nthd)
Definition: modomp.f90:78
elemental integer function map(i, j)
Definition: eveqnfvr.f90:286
integer, dimension(maxlorb, maxspecies) lorbl
Definition: modmain.f90:796
real(8), dimension(3, maxatoms, maxspecies) atposc
Definition: modmain.f90:54