1!
2! Copyright (C) 2006 Quantum ESPRESSO group
3! This file is distributed under the terms of the
4! GNU General Public License. See the file `License'
5! in the root directory of the present distribution,
6! or http://www.gnu.org/copyleft/gpl.txt .
7!
8!---------------------------------------------------------------
9subroutine test_bessel ( )
10  !---------------------------------------------------------------
11  !
12  !     diagonalization of the pseudo-atomic hamiltonian
13  !     in a basis of spherical Bessel functions: j_l (qr)
14  !     with zero boundary conditions at the border R:
15  !     j_l (q_l R) = 0
16  !     The basis sets contains all q_l's up to a kinetic
17  !     energy cutoff Ecut, such that q^2 <= Ecut (in Ry a.u.)
18  !     rm is the radius R of the box
19  !
20  use io_global, only : stdout
21  use kinds, only : dp
22  use constants, only: pi
23  use ld1inc, only: lmax, lmx, grid
24  use ld1inc, only: ecutmin, ecutmax, decut, rm
25  !
26  implicit none
27  !
28  real(kind=dp), parameter :: eps = 1.0d-4
29  real(kind=dp) ::  ecut   ! kinetic-energy cutoff (equivalent to PW)
30  !
31  real(kind=dp), allocatable :: q(:,:) ! quantized momenta in the spherical box
32  !
33  integer :: nswx, &            ! max number of quantized momenta q
34             nsw (0:lmx), &     ! number of q such that q^2 < Ecut
35             mesh_, &           ! mesh_ is such that r (mesh_) <= R
36             ncut, nc
37  !
38  if ( ecutmin < eps .or. ecutmax < eps .or. ecutmax < ecutmin + eps .or. &
39       decut < eps .or. rm < 5.0_dp ) return
40  !
41  write (stdout, "(/,5x,14('-'), ' Test with a basis set of Bessel functions ',&
42       & 10('-'),/)")
43  !
44  write (stdout, "(5x,'Box size (a.u.) : ',f6.1)" ) rm
45  ncut = nint ( ( ecutmax-ecutmin ) / decut ) + 1
46  !
47  !  we redo everything for each cutoff: not really a smart implementation
48  !
49  do nc = 1, ncut
50     !
51     ecut = ecutmin + (nc-1) * decut
52     !
53     !   estimated max number of q needed for all values of l
54     !
55     nswx = int ( sqrt ( ecut*rm**2/pi**2 ) ) + lmax + 1
56     !
57     !   find grid point mesh_ such that r(mesh_) < R
58     !   note that mesh_ must be odd to perform simpson integration
59     !
60     do mesh_ = 1, grid%mesh
61        if ( grid%r(mesh_) >= rm ) go to 20
62     end do
63     call errore ('test_bessel','r(mesh) < Rmax', mesh_)
6420   continue
65     mesh_ = 2 * ( (mesh_-1) / 2 ) + 1
66     !
67     !   find quantized momenta q
68     !
69     allocate ( q ( nswx, 0:lmax ) )
70     call q_fill ( nswx, lmax, rm, ecut, nsw, q )
71     !
72     !   fill and diagonalize Kohn-Sham pseudo-hamiltonian
73     !
74     write (stdout, "(/5x,'Cutoff (Ry) : ',f6.1)" ) ecut
75     call h_diag ( mesh_, nswx, nsw, lmax, q )
76     !
77     deallocate ( q )
78     !
79  end do
80  !
81  write (stdout, "(/,5x,14('-'), ' End of Bessel function test ',24('-'),/)")
82  !
83end subroutine test_bessel
84!
85!-----------------------------------------------------------------------
86subroutine q_fill ( nswx, lmax, rm, ecut, nsw, q )
87  !-----------------------------------------------------------------------
88  !
89  !   find quantized momenta in a box of radius R = rm
90  !
91  use kinds, only : dp
92  use constants, only : pi
93  implicit none
94  integer, intent(in) :: nswx, lmax
95  real(kind=dp), intent(in)  :: rm, ecut
96  integer, intent(out) :: nsw(0:lmax)
97  real(kind=dp), intent(out) :: q(nswx,0:lmax)
98  !
99  integer :: i, l, iret
100  real(kind=dp), parameter :: eps=1.0d-10
101  real(kind=dp), external :: find_root
102  !
103  !   l = 0 : j_0 (qR)=0  =>  q_i = i * (2pi/R)
104  !
105  do i = 1, nswx
106     q(i,0) = i*pi
107  end do
108  !
109  !   l > 0 : zeros for j_l (x) are found between two consecutive
110  !           zeros for j_{l-1} (x)
111  !
112  do l = 1, lmax
113     do i = 1, nswx-l
114        q(i,l) = find_root ( l, q(i,l-1), q(i+1,l-1), eps, iret )
115        if (iret /= 0)  call errore('q_fill','root not found',l)
116     end do
117  end do
118  !
119  do l = 0, lmax
120     do i = 1, nswx-l
121        q (i,l) = q(i,l) / rm
122        if ( q(i,l)**2 > ecut ) then
123           nsw(l) = i-1
124           goto 20
125        endif
126     enddo
127     call errore('q_fill','nswx is too small',nswx)
12820   continue
129  end do
130  !
131  return
132end subroutine q_fill
133!
134!-----------------------------------------------------------------------
135function find_root   ( l, xt1, xt2, eps, iret )
136  ! ----------------------------------------------------------------------
137  !
138  use kinds, only : dp
139  implicit none
140  !
141  integer, intent (in) :: l
142  real(kind=dp), intent (in) :: xt1, xt2, eps
143  !
144  integer, intent (out) :: iret
145  real(kind=dp) :: find_root
146  !
147  real(kind=dp) :: x1, x2, x0, f1, f2, f0
148  !
149  x1 = MIN (xt1, xt2)
150  x2 = MAX (xt1, xt2)
151  !
152  call sph_bes ( 1, 1.0_dp, x1, l, f1 )
153  call sph_bes ( 1, 1.0_dp, x2, l, f2 )
154  !
155  iret = 0
156  !
157  if ( sign(f1,f2) == f1 ) then
158     find_root = 0.0_dp
159     iret = 1
160     return
161  end if
162!
163  do while ( abs(x2-x1) > eps )
164     x0 = 0.5*(x1+x2)
165     call sph_bes ( 1, 1.0_dp, x0, l, f0 )
166     if ( sign(f0,f1) == f0 ) then
167        x1 = x0
168        f1 = f0
169     else
170        x2 = x0
171        f2 = f0
172     end if
173  end do
174  !
175  find_root = x0
176  !
177  return
178end function find_root
179!
180!-----------------------------------------------------------------------
181subroutine h_diag  ( mesh_, nswx, nsw, lmax, q )
182  !-----------------------------------------------------------------------
183  !
184  ! diagonalize the radial Kohn-Sham hamiltonian
185  ! in the basis of spherical bessel functions
186  ! Requires the self-consistent potential from a previous calculation!
187  !
188  use io_global, only : stdout
189  use kinds, only : dp
190  use ld1inc, only: lmx, grid
191  use ld1inc, only: nbeta, betas, qq, ddd, vpstot, vnl, lls, jjs, &
192       nspin, rel, pseudotype
193  implicit none
194  !
195  ! input
196  integer, intent (in) :: mesh_, lmax, nswx, nsw(0:lmx)
197  real(kind=dp), intent (in) :: q(nswx,0:lmax)
198  ! local
199  real(kind=dp), allocatable :: &
200       h(:,:), s(:,:),     & ! hamiltonian and overlap matrix
201       chi (:,:), enl (:), & ! eigenvectors and eigenvalues
202       s0(:),              & ! normalization factors for jl(qr)
203       betajl(:,:),        & ! matrix elements for beta
204       betajl_(:,:),       & ! work space:  \sum_m D_lm beta_m
205       vaux (:), jlq (:,:), work (:) ! more work space
206  real(kind=dp), external :: int_0_inf_dr
207  real(kind=dp) :: j
208  character(len=2), dimension (2) :: spin = (/ 'up', 'dw' /)
209  integer :: n_states = 3, l, n, m, nb, mb, ind, is, nj
210  !
211  !
212  allocate ( h (nswx, nswx), s0(nswx), chi (nswx, n_states), enl(nswx) )
213  allocate ( jlq ( mesh_, nswx ), work (mesh_), vaux (mesh_) )
214  if ( pseudotype > 2 ) allocate ( s(nswx, nswx) )
215  !
216  write(stdout,"( 20x,3(7x,'N = ',i1) )" ) (n, n=1,n_states)
217  !
218  do l=0,lmax
219     !
220     !  nj: number of j-components in fully relativistic case
221     !
222     if ( rel == 2 .and. l > 0  ) then
223        nj=2
224     else
225        nj=1
226     endif
227     !
228     do n = 1, nsw(l)
229        !
230        call sph_bes ( mesh_, grid%r, q(n,l), l, jlq(1,n) )
231        !
232        !  s0 = < j_l(qr) | j_l (qr) >
233        !
234        work (:) = ( jlq(:,n) * grid%r(1:mesh_) ) ** 2
235        s0(n) = sqrt ( int_0_inf_dr ( work, grid, mesh_, 2*l+2 ) )
236        !
237     end do
238     !
239     !    vaux is the local + scf potential ( + V_l for semilocal PPs)
240     !    note that nspin = 2 only for lsda; nspin = 1 in all other cases
241     !
242     do is  = 1, nspin
243        !
244        do ind = 1, nj
245           !
246           if ( rel == 2 .and. l > 0 ) then
247              j = l + (ind-1.5_dp) ! this is J=L+S
248           else if ( rel == 2 .and. l == 0 ) then
249              j = 0.5_dp
250           else
251              j = 0.0_dp
252           end if
253           !
254           if (pseudotype == 1) then
255              vaux(:) = vpstot (1:mesh_, is) + vnl (1:mesh_, l, ind)
256           else
257              vaux(:) = vpstot (1:mesh_, is)
258              allocate ( betajl ( nswx, nbeta ), betajl_ ( nswx, nbeta ) )
259           endif
260           !
261           h (:,:) = 0.0_dp
262           !
263           do n = 1, nsw(l)
264              !
265              !  matrix elements for vaux
266              !
267              do m = 1, n
268                 work (:) = jlq(:,n) * jlq(:,m) * vaux(1:mesh_) * grid%r2(1:mesh_)
269                 h(m,n) = int_0_inf_dr ( work, grid, mesh_, 2*l+2 ) &
270                      / s0(n) / s0(m)
271              end do
272              !
273              !    kinetic energy
274              !
275              h(n,n) =  h(n,n) + q(n,l)**2
276              !
277              !    betajl(q,n) = < beta_n | j_l(qr) >
278              !
279              if ( pseudotype > 1 ) then
280                 do nb = 1, nbeta
281                    if ( lls (nb) == l .and.  abs(jjs (nb) - j) < 0.001_8 ) then
282                       work (:) = jlq(:,n) * betas( 1:mesh_, nb ) * grid%r(1:mesh_)
283                       betajl (n, nb) = 1.0_dp / s0(n) * &
284                            int_0_inf_dr ( work, grid, mesh_, 2*l+2 )
285                    end if
286                 end do
287              end if
288           end do
289           !
290           !  separable PP
291           !
292           if ( pseudotype > 1 ) then
293              !
294              !    betajl_(q,m) = \sum_n D_mn * < beta_n | j_l(qr) >
295              !
296              betajl_ (:,:) = 0.0_dp
297              do mb = 1, nbeta
298                 if ( lls (mb) == l .and. abs(jjs (mb) - j) < 0.001_8 ) then
299                    do nb = 1, nbeta
300                       if ( lls (nb) == l .and. abs(jjs (nb) - j) < 0.001_8 ) then
301                          betajl_ (:, mb) = betajl_ (:, mb) + &
302                               ddd (mb,nb,is) * betajl (:, nb)
303                       end if
304                    end do
305                 end if
306              end do
307              !
308              !    matrix elements for nonlocal (separable) potential
309              !
310              do n = 1, nsw(l)
311                 do m = 1, n
312                    do nb = 1, nbeta
313                       if ( lls (nb) == l .and. abs(jjs (nb) - j) < 0.001_8 ) then
314                          h(m,n) = h(m,n) + betajl_ (m, nb) * betajl (n, nb)
315                       end if
316                    end do
317                 end do
318              end do
319              !
320              !  US PP
321              !
322              if ( pseudotype > 2 ) then
323                 !
324                 !    betajl_(q,m) = \sum_n D_mn * < beta_n | j_l(qr) >
325                 !
326                 betajl_ (:,:) = 0.0_dp
327                 do mb = 1, nbeta
328                    if ( lls (mb) == l .and. abs(jjs (mb) - j) < 0.001_8 ) then
329                       do nb = 1, nbeta
330                          if ( lls (nb) == l .and. &
331                               abs(jjs (nb) - j) < 0.001_8 ) then
332                             betajl_ (:, mb) = betajl_ (:, mb) + &
333                                  qq (mb,nb) * betajl (:, nb)
334                          end if
335                       end do
336                    end if
337                 end do
338                 !
339                 !    overlap matrix S
340                 !
341                 s (:,:) = 0.0_dp
342                 do n = 1, nsw(l)
343                    do m = 1, n
344                       do nb = 1, nbeta
345                          if ( lls (nb) == l .and. &
346                               abs(jjs (nb) - j) < 0.001_8 ) then
347                             s(m,n) = s(m,n) + betajl_ (m, nb) * betajl (n, nb)
348                          end if
349                       end do
350                    end do
351                    s(n,n) = s(n,n) + 1.0_dp
352                 end do
353              end if
354              !
355              deallocate ( betajl_, betajl )
356              !
357           end if
358           !
359           if ( pseudotype > 2 ) then
360              call rdiags ( nsw(l), h, s, nswx, n_states, enl, chi, nswx)
361           else
362              call rdiagd ( nsw(l), h, nswx, n_states, enl, chi, nswx)
363           end if
364           !
365           if ( nspin == 2 ) then
366              write(stdout, &
367                  "( 5x,'E(L=',i1,',spin ',a2,') =',4(f10.4,' Ry') )" ) &
368                   l, spin(is), (enl(n), n=1,n_states)
369           else if ( rel == 2 ) then
370              write(stdout, &
371                  "( 5x,'E(L=',i1,',J=',f3.1,') =',4(f10.4,' Ry') )" ) &
372                   l, j, (enl(n), n=1,n_states)
373           else
374              write(stdout, &
375                  "( 5x,'E(L=',i1,') =',5x,4(f10.4,' Ry') )" ) &
376                   l, (enl(n), n=1,n_states)
377           end if
378        end do
379        !
380     end do
381  end do
382  !
383  if ( pseudotype > 2 ) deallocate ( s )
384  deallocate ( vaux, work, jlq )
385  deallocate ( enl, chi, s0, h )
386  !
387  return
388end subroutine h_diag
389!
390!------------------------------------------------------------------
391subroutine rdiagd ( n, h, ldh, m, e, v, ldv )
392  !------------------------------------------------------------------
393  !
394  !     LAPACK driver for eigenvalue problem H*x = ex
395  !
396  use kinds, only : dp
397  implicit none
398  !
399  integer, intent (in) :: &
400       n,      & ! dimension of the matrix to be diagonalized
401       ldh,    & ! leading dimension of h, as declared in the calling pgm
402       m,      & ! number of roots to be searched
403       ldv       ! leading dimension of the v matrix
404  real(kind=dp), intent (inout) :: &
405       h(ldh,n) ! matrix to be diagonalized, UPPER triangle
406                ! DESTROYED ON OUTPUT
407  real(kind=dp), intent (out) :: e(m), v(ldv,m) ! eigenvalues and eigenvectors
408  !
409  integer :: mo, lwork, info
410  integer, allocatable :: iwork(:), ifail(:)
411  real(kind=dp)  :: vl, vu
412  real(kind=dp), allocatable  :: work(:)
413  !
414  lwork = 8*n
415  allocate ( work (lwork), iwork(5*n), ifail(n) )
416  v (:,:) = 0.0_dp
417  !
418  call DSYEVX ( 'V', 'I', 'U', n, h, ldh, vl, vu, 1, m, 0.0_dp, mo, e,&
419               v, ldv, work, lwork, iwork, ifail, info )
420  !
421  if ( info > 0) then
422     call errore('rdiagd','failed to converge',info)
423  else if(info < 0) then
424     call errore('rdiagd','illegal arguments',-info)
425  end if
426  deallocate ( ifail, iwork, work )
427  !
428  return
429end subroutine rdiagd
430!
431!----------------------------------------------------------------------------
432SUBROUTINE rdiags( n, h, s, ldh, m, e, v, ldv )
433  !----------------------------------------------------------------------------
434  !
435  !     LAPACK driver for generalized eigenvalue problem H*x = e S*x
436  !
437  use kinds, only : dp
438  IMPLICIT NONE
439  !
440  integer, intent (in) :: &
441       n,      & ! dimension of the matrix to be diagonalized
442       ldh,    & ! leading dimension of h, as declared in the calling pgm
443       m,      & ! number of roots to be searched
444       ldv       ! leading dimension of the v matrix
445  real(kind=dp), intent (inout) :: &
446       h(ldh,n), & ! matrix to be diagonalized, UPPER triangle
447       s(ldh,n)    ! overlap matrix - both destroyed on output
448  !
449  real(kind=dp), intent (out) :: e(m), v(ldv,m) ! eigenvalues and eigenvectors
450  !
451  ! ... LOCAL variables
452  !
453  integer :: mo, lwork, info
454  integer, allocatable :: iwork(:), ifail(:)
455  real(kind=dp), allocatable  :: work(:)
456
457  lwork = 8 * n
458  allocate ( work (lwork), iwork(5*n), ifail(n) )
459  v (:,:) = 0.0_dp
460  !
461  CALL DSYGVX( 1, 'V', 'I', 'U', n, h, ldh, s, ldh, &
462       0.0_dp, 0.0_dp, 1, m, 0.0_dp, mo, e, v, ldh, work, lwork, &
463       iwork, ifail, info )
464  !
465  if ( info > n) then
466     call errore('rdiags','failed to converge (factorization)',info-n)
467  else if(info > 0) then
468     call errore('rdiags','failed to converge: ',info)
469  else if(info < 0) then
470     call errore('rdiags','illegal arguments',-info)
471  end if
472  deallocate ( ifail, iwork, work )
473  !
474  return
475  !
476END SUBROUTINE rdiags
477