The Elk Code
 
Loading...
Searching...
No Matches
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:
9subroutine eveqnfvr(nmatp,ngp,vpc,h_,o_,evalfv,evecfv)
10! !USES:
11use modmain
12use modomp
13use, 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
35implicit none
36! arguments
37integer, intent(in) :: nmatp,ngp
38real(8), intent(in) :: vpc(3)
39real(8), target :: h_(*),o_(*)
40real(8), intent(out) :: evalfv(nstfv)
41complex(8), intent(out) :: evecfv(nmatmax,nstfv)
42! local variables
43integer is,ia,ja,jas,ilo
44integer n2,i,j,k,l,m
45integer i1,i2,j1,j2
46integer k1,k2,k3,k4
47integer l1,l2,m1,m2
48integer info,nthd,nts
49real(8) v(3),vl,vu
50real(8) s1,t1,t2,t3,t4
51real(8) ts0,ts1
52complex(8) z1
53! automatic arrays
54logical tr(nlotot),tp(nlotot)
55integer idx(nlotot),s(nlotot)
56integer iwork(5*nmatp),ifail(nmatp)
57real(8) w(nmatp)
58complex(8) zp(nlotot)
59! allocatable arrays and pointers
60real(8), allocatable :: rh(:)
61real(8), pointer, contiguous :: ro(:),rv(:,:)
62complex(8), pointer, contiguous :: h(:),o(:)
63call timesec(ts0)
64! reuse already allocated memory
65n2=nmatp**2
66call c_f_pointer(c_loc(h_),h,shape=[n2])
67call c_f_pointer(c_loc(o_),o,shape=[n2])
68call c_f_pointer(c_loc(h_),ro,shape=[n2])
69call c_f_pointer(c_loc(h_(n2+1)),rv,shape=[nmatp,nstfv])
70tp(1:nlotot)=.false.
71i=0
72do 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
136end do
137!---------------------------------!
138! real Hamiltonian matrix !
139!---------------------------------!
140allocate(rh(n2))
141! ⟨APW|H|APW⟩
142do j=1,ngp
143 k=(j-1)*nmatp+1
144 rh(k:k+j-1)=dble(h(k:k+j-1))
145end do
146! ⟨APW|H|lo⟩
147do 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
164end do
165! ⟨lo|H|lo⟩
166do 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
184end do
185!-----------------------------!
186! real overlap matrix !
187!-----------------------------!
188! ⟨APW|O|APW⟩
189do j=1,ngp
190 k=(j-1)*nmatp+1
191 ro(k:k+j-1)=dble(o(k:k+j-1))
192end do
193! ⟨APW|O|lo⟩
194do 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
211end do
212! ⟨lo|O|lo⟩
213do 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
231end do
232! solve the generalised eigenvalue problem for real symmetric matrices
233! enable MKL parallelism
234call holdthd(maxthdmkl,nthd)
235nts=mkl_set_num_threads_local(nthd)
236! diagonalise the matrix (use o_ as the work array)
237call 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)
239nts=mkl_set_num_threads_local(0)
240call freethd(nthd)
241if (info /= 0) then
242 write(*,*)
243 write(*,'("Error(eveqnfvr): diagonalisation failed")')
244 write(*,'(" DSYGVX returned INFO = ",I8)') info
245 if (info > nmatp) then
246 i=info-nmatp
247 write(*,'(" The leading minor of the overlap matrix of order ",I8)') i
248 write(*,'(" is not positive definite")')
249 write(*,'(" Order of overlap matrix : ",I8)') nmatp
250 end if
251 write(*,*)
252 stop
253end if
254evalfv(1:nstfv)=w(1:nstfv)
255! reconstruct the complex eigenvectors
256do 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
277end do
278deallocate(rh)
279call timesec(ts1)
280!$OMP ATOMIC
281timefv=timefv+ts1-ts0
282
283contains
284
285elemental integer function map(i,j)
286implicit none
287! arguments
288integer, intent(in) :: i,j
289! map from local-orbital indices to position in matrix
290if (i <= j) then
291 map=ngp+i+(ngp+j-1)*nmatp
292else
293 map=ngp+j+(ngp+i-1)*nmatp
294end if
295end function
296
297end subroutine
298!EOC
299
subroutine eveqnfvr(nmatp, ngp, vpc, h_, o_, evalfv, evecfv)
Definition eveqnfvr.f90:10
elemental integer function map(i, j)
Definition eveqnfvr.f90:286
real(8) evaltol
Definition modmain.f90:916
real(8), dimension(3, maxatoms, maxspecies) atposc
Definition modmain.f90:54
integer, dimension(maxspecies) natoms
Definition modmain.f90:36
integer, dimension(:,:,:), allocatable ieqatom
Definition modmain.f90:368
integer, dimension(:,:,:), allocatable idxlo
Definition modmain.f90:850
integer, dimension(maxatoms, maxspecies) idxas
Definition modmain.f90:42
real(8) timefv
Definition modmain.f90:1216
integer, dimension(maxspecies) nlorb
Definition modmain.f90:786
integer nspecies
Definition modmain.f90:34
integer, dimension(maxlorb, maxspecies) lorbl
Definition modmain.f90:796
integer maxthdmkl
Definition modomp.f90:15
subroutine holdthd(nloop, nthd)
Definition modomp.f90:78
subroutine freethd(nthd)
Definition modomp.f90:106
subroutine timesec(ts)
Definition timesec.f90:10