From f602c55989372cc28bea8d57377ae4fd49d7cab8 Mon Sep 17 00:00:00 2001 From: Julen-ia Date: Mon, 4 Jun 2018 11:33:42 +0200 Subject: [PATCH] Included modified routines for the calculation of second k-space derivatives of Hamiltonian and position operator. Included option for including the Wannier centres into the exponentials of the Fourier sums (so-called tight-binding convention). Included option for considering a small broadening parameter when computing denominators that contain energy differences, numerically needed for the sums over virtual states involved in the calculation of the shift current. --- src/postw90/postw90_common.F90 | 464 +++++++++++++++++++++++++++++++++ src/postw90/wan_ham.F90 | 143 +++++++++- 2 files changed, 606 insertions(+), 1 deletion(-) diff --git a/src/postw90/postw90_common.F90 b/src/postw90/postw90_common.F90 index d9e00b2de..a2cee35f4 100644 --- a/src/postw90/postw90_common.F90 +++ b/src/postw90/postw90_common.F90 @@ -35,6 +35,7 @@ module w90_postw90_common public :: nrpts, rpt_origin, v_matrix, ndegen, irvec, crvec public :: num_int_kpts_on_node, int_kpts, weight public :: pw90common_kmesh_spacing + public :: pw90common_fourier_R_to_k_new_second_d, pw90common_fourier_R_to_k_new_second_d_TB_conv, pw90common_fourier_R_to_k_vec_dadb, pw90common_fourier_R_to_k_vec_dadb_TB_conv ! AAM PROBABLY REMOVE THIS ! This 'save' statement could probably be ommited, since this module @@ -301,6 +302,9 @@ subroutine pw90common_wanint_param_dist call comms_bcast(wanint_kpoint_file,1) call comms_bcast(dis_win_min,1) call comms_bcast(dis_win_max,1) + call comms_bcast(sc_eta,1) + call comms_bcast(sc_w_thr,1) + call comms_bcast(sc_phase_conv,1) ! ---------------------------------------------- ! ! New input variables in development @@ -819,6 +823,215 @@ subroutine pw90common_fourier_R_to_k_new(kpt,OO_R,OO,OO_dx,OO_dy,OO_dz) end subroutine pw90common_fourier_R_to_k_new + !=========================================================! + subroutine pw90common_fourier_R_to_k_new_second_d(kpt,OO_R,OO,OO_da,OO_dadb) + !=======================================================! + ! ! + !! For OO: + !! $$O_{ij}(k) = \sum_R e^{+ik.R}.O_{ij}(R)$$ + !! For $$OO_{dx,dy,dz}$$: + !! $$\sum_R [i.R_{dx,dy,dz}.e^{+ik.R}.O_{ij}(R)]$$ + !! where R_{x,y,z} are the Cartesian components of R + !! For $$OO_{dx1,dy1,dz1;dx2,dy2,dz2}$$: + !! $$-\sum_R [R_{dx1,dy1,dz1}.R_{dx2,dy2,dz2}.e^{+ik.R}.O_{ij}(R)]$$ + !! where R_{xi,yi,zi} are the Cartesian components of R + ! ! + !=======================================================! + + use w90_constants, only : dp,cmplx_0,cmplx_i,twopi + use w90_parameters, only : timing_level,num_kpts,kpt_latt, num_wann, use_ws_distance + use w90_ws_distance, only : irdist_ws, wdist_ndeg, ws_translate_dist + + implicit none + + ! Arguments + ! + real(kind=dp) :: kpt(3) + complex(kind=dp), dimension(:,:,:), intent(in) :: OO_R + complex(kind=dp), optional, dimension(:,:), intent(out) :: OO + complex(kind=dp), optional, dimension(:,:,:), intent(out) :: OO_da + complex(kind=dp), optional, dimension(:,:,:,:), intent(out) :: OO_dadb + + integer :: ir, i,j,ideg, a, b + real(kind=dp) :: rdotk + complex(kind=dp) :: phase_fac + + if(use_ws_distance) CALL ws_translate_dist(nrpts, irvec) + + if(present(OO)) OO=cmplx_0 + if(present(OO_da)) OO_da=cmplx_0 + if(present(OO_dadb)) OO_dadb=cmplx_0 + do ir=1,nrpts +! [lp] Shift the WF to have the minimum distance IJ, see also ws_distance.F90 + if(use_ws_distance)then + do j=1,num_wann + do i=1,num_wann + do ideg = 1,wdist_ndeg(j,i,ir) + + rdotk=twopi*dot_product(kpt(:),real(irdist_ws(:,ideg,i,j,ir),dp)) + phase_fac=cmplx(cos(rdotk),sin(rdotk),dp)/real(ndegen(ir)*wdist_ndeg(i,j,ir),dp) + if(present(OO)) OO(i,j)=OO(i,j)+phase_fac*OO_R(i,j,ir) + if(present(OO_da)) then + do a=1,3 + OO_da(i,j,a)=OO_da(i,j,a)+cmplx_i*crvec(a,ir)*phase_fac*OO_R(i,j,ir) + enddo + endif + if(present(OO_dadb)) then + do a=1,3 + do b=1,3 + OO_dadb(i,j,a,b)=OO_dadb(i,j,a,b)-& + crvec(a,ir)*crvec(b,ir)*phase_fac*OO_R(i,j,ir) + enddo + enddo + end if + + enddo + enddo + enddo + else +! [lp] Original code, without IJ-dependent shift: + rdotk=twopi*dot_product(kpt(:),irvec(:,ir)) + phase_fac=cmplx(cos(rdotk),sin(rdotk),dp)/real(ndegen(ir),dp) + if(present(OO)) OO(:,:)=OO(:,:)+phase_fac*OO_R(:,:,ir) + if(present(OO_da)) then + do a=1,3 + OO_da(:,:,a)=OO_da(:,:,a)+cmplx_i*crvec(a,ir)*phase_fac*OO_R(:,:,ir) + enddo + endif + if(present(OO_dadb)) then + do a=1,3 + do b=1,3 + OO_dadb(:,:,a,b)=OO_dadb(:,:,a,b)-& + crvec(a,ir)*crvec(b,ir)*phase_fac*OO_R(:,:,ir) + enddo + enddo + end if + endif + enddo + + end subroutine pw90common_fourier_R_to_k_new_second_d + + subroutine pw90common_fourier_R_to_k_new_second_d_TB_conv(kpt,OO_R,oo_a_R,OO,OO_da,OO_dadb) + !=======================================================! + ! modified version of pw90common_fourier_R_to_k_new_second_d, includes wannier centres in + ! the exponential inside the sum (so called TB convention) + ! + !! For OO: + !! $$O_{ij}(k) = \sum_R e^{+ik.(R+tau_ij)}.O_{ij}(R)$$ + !! For $$OO_{dx,dy,dz}$$: + !! $$\sum_R [i.(R+tau_ij)_{dx,dy,dz}.e^{+ik.(R+tau_ij)}.O_{ij}(R)]$$ + !! where R_{x,y,z} are the Cartesian components of R + !! For $$OO_{dx1,dy1,dz1;dx2,dy2,dz2}$$: + !! $$-\sum_R [(R+tau_ij)_{dx1,dy1,dz1}.(R+tau_ij)_{dx2,dy2,dz2}.e^{+ik.(R+tau_ij)}.O_{ij}(R)]$$ + !! where {xi,yi,zi} denote the Cartesian components and + ! tau_ij = tau_j - tau_i, being tau_i=<0i|r|0i> the individual wannier centres + !=======================================================! + + use w90_constants, only : dp,cmplx_0,cmplx_i,twopi + use w90_parameters, only : timing_level,num_kpts,kpt_latt, num_wann, use_ws_distance, wannier_centres, recip_lattice + use w90_ws_distance, only : irdist_ws, wdist_ndeg, ws_translate_dist + use w90_utility, only : utility_cart_to_frac + + implicit none + + ! Arguments + ! + real(kind=dp) :: kpt(3) + complex(kind=dp), dimension(:,:,:), intent(in) :: OO_R + complex(kind=dp), optional, dimension(:,:), intent(out) :: OO + complex(kind=dp), optional, dimension(:,:,:), intent(out) :: OO_da + complex(kind=dp), optional, dimension(:,:,:,:), intent(out) :: OO_dadb + complex(kind=dp), dimension(:,:,:,:), intent(in) :: oo_a_R + + integer :: ir, i,j,ideg, a, b + real(kind=dp) :: rdotk + complex(kind=dp) :: phase_fac + real(kind=dp) :: local_wannier_centres(3,num_wann), wannier_centres_frac(3,num_wann) + real(kind=dp) :: r_sum(3) + + r_sum = 0.d0 + + if(use_ws_distance) CALL ws_translate_dist(nrpts, irvec) + + ! calculate wannier centres in cartesian + local_wannier_centres(:,:) = 0.d0 + do j = 1,num_wann + do ir=1,nrpts + if ((irvec(1,ir).eq.0).and.(irvec(2,ir).eq.0).and.(irvec(3,ir).eq.0)) then + local_wannier_centres(1,j) = real(oo_a_R(j,j,ir,1)) + local_wannier_centres(2,j) = real(oo_a_R(j,j,ir,2)) + local_wannier_centres(3,j) = real(oo_a_R(j,j,ir,3)) + endif + enddo + enddo + ! rotate wannier centres from cartesian to fractional coordinates + wannier_centres_frac(:,:) = 0.d0 + do ir = 1,num_wann + call utility_cart_to_frac(local_wannier_centres(:,ir),wannier_centres_frac(:,ir),recip_lattice) + enddo + + + if(present(OO)) OO=cmplx_0 + if(present(OO_da)) OO_da=cmplx_0 + if(present(OO_dadb)) OO_dadb=cmplx_0 + do ir=1,nrpts +! [lp] Shift the WF to have the minimum distance IJ, see also ws_distance.F90 + if(use_ws_distance)then + do j=1,num_wann + do i=1,num_wann + do ideg = 1,wdist_ndeg(j,i,ir) + + rdotk=twopi*dot_product(kpt(:),real(irdist_ws(:,ideg,i,j,ir)+wannier_centres_frac(:,j)-wannier_centres_frac(:,i),dp)) + phase_fac=cmplx(cos(rdotk),sin(rdotk),dp)/real(ndegen(ir)*wdist_ndeg(i,j,ir),dp) + if(present(OO)) OO(i,j)=OO(i,j)+phase_fac*OO_R(i,j,ir) + if(present(OO_da)) then + do a=1,3 + OO_da(i,j,a)=OO_da(i,j,a)+cmplx_i*(crvec(a,ir)+local_wannier_centres(a,j)-local_wannier_centres(a,i))*phase_fac*OO_R(i,j,ir) + enddo + endif + if(present(OO_dadb)) then + do a=1,3 + do b=1,3 + OO_dadb(i,j,a,b)=OO_dadb(i,j,a,b)-& + (crvec(a,ir)+local_wannier_centres(a,j)-local_wannier_centres(a,i))*& + (crvec(b,ir)+local_wannier_centres(b,j)-local_wannier_centres(b,i))*phase_fac*OO_R(i,j,ir) + enddo + enddo + end if + + enddo + enddo + enddo + else +! [lp] Original code, without IJ-dependent shift: + do j=1,num_wann + do i=1,num_wann + r_sum(:) = real(irvec(:,ir))+wannier_centres_frac(:,j)-wannier_centres_frac(:,i) + rdotk=twopi*dot_product(kpt(:),r_sum(:)) + phase_fac=cmplx(cos(rdotk),sin(rdotk),dp)/real(ndegen(ir),dp) + if(present(OO)) OO(i,j)=OO(i,j)+phase_fac*OO_R(i,j,ir) + if(present(OO_da)) then + do a=1,3 + OO_da(i,j,a)=OO_da(i,j,a)+cmplx_i*(crvec(a,ir)+local_wannier_centres(a,j)-local_wannier_centres(a,i))*phase_fac*OO_R(i,j,ir) + enddo + endif + if(present(OO_dadb)) then + do a=1,3 + do b=1,3 + OO_dadb(i,j,a,b)=OO_dadb(i,j,a,b)-& + (crvec(a,ir)+local_wannier_centres(a,j)-local_wannier_centres(a,i))*& + (crvec(b,ir)+local_wannier_centres(b,j)-local_wannier_centres(b,i))*phase_fac*OO_R(i,j,ir) + enddo + enddo + end if + enddo + enddo + endif + enddo + + end subroutine pw90common_fourier_R_to_k_new_second_d_TB_conv + + ! ***NEW*** ! !=========================================================! @@ -904,6 +1117,257 @@ subroutine pw90common_fourier_R_to_k_vec(kpt,OO_R,OO_true,OO_pseudo) end subroutine pw90common_fourier_R_to_k_vec + !=========================================================! + subroutine pw90common_fourier_R_to_k_vec_dadb(kpt,OO_R,OO_da,OO_dadb) + !====================================================================! + ! ! + !! For $$OO_{ij;dx,dy,dz}$$: + !! $$O_{ij;dx,dy,dz}(k) = \sum_R e^{+ik.R} O_{ij;dx,dy,dz}(R)$$ + !! For $$OO_{ij;dx1,dy1,dz1;dx2,dy2,dz2}$$: + !! $$O_{ij;dx1,dy1,dz1;dx2,dy2,dz2}(k) = \sum_R e^{+ik.R} i.R_{dx2,dy2,dz2} + !! .O_{ij;dx1,dy1,dz1}(R)$$ + ! ! + !====================================================================! + + use w90_constants, only : dp,cmplx_0,cmplx_i,twopi + use w90_parameters, only : num_kpts,kpt_latt, num_wann, use_ws_distance + use w90_ws_distance, only : irdist_ws, wdist_ndeg, ws_translate_dist + + implicit none + + ! Arguments + ! + real(kind=dp) :: kpt(3) + complex(kind=dp), dimension(:,:,:,:), intent(in) :: OO_R + complex(kind=dp), optional, dimension(:,:,:), intent(out) :: OO_da + complex(kind=dp), optional, dimension(:,:,:,:), intent(out) :: OO_dadb + + integer :: ir, i,j,ideg,a,b + real(kind=dp) :: rdotk + complex(kind=dp) :: phase_fac + + if(use_ws_distance) CALL ws_translate_dist(nrpts, irvec) + if(present(OO_da)) OO_da=cmplx_0 + if(present(OO_dadb)) OO_dadb=cmplx_0 + do ir=1,nrpts +! [lp] Shift the WF to have the minimum distance IJ, see also ws_distance.F90 + if(use_ws_distance)then + do j=1,num_wann + do i=1,num_wann + do ideg = 1,wdist_ndeg(j,i,ir) + + rdotk=twopi*dot_product(kpt(:),real(irdist_ws(:,ideg,i,j,ir),dp)) + phase_fac=cmplx(cos(rdotk),sin(rdotk),dp)/real(ndegen(ir)*wdist_ndeg(i,j,ir),dp) + rdotk=twopi*dot_product(kpt(:),irvec(:,ir)) + phase_fac=cmplx(cos(rdotk),sin(rdotk),dp)/real(ndegen(ir),dp) + if(present(OO_da)) then + OO_da(i,j,1)=OO_da(i,j,1)+phase_fac*OO_R(i,j,ir,1) + OO_da(i,j,2)=OO_da(i,j,2)+phase_fac*OO_R(i,j,ir,2) + OO_da(i,j,3)=OO_da(i,j,3)+phase_fac*OO_R(i,j,ir,3) + endif + if(present(OO_dadb)) then + do a=1,3 + do b=1,3 + OO_dadb(i,j,a,b)=OO_dadb(i,j,a,b)+cmplx_i*crvec(b,ir)*phase_fac*OO_R(i,j,ir,a) + enddo + enddo + endif + + enddo + enddo + enddo + else +! [lp] Original code, without IJ-dependent shift: + rdotk=twopi*dot_product(kpt(:),irvec(:,ir)) + phase_fac=cmplx(cos(rdotk),sin(rdotk),dp)/real(ndegen(ir),dp) + if(present(OO_da)) then + OO_da(:,:,1)=OO_da(:,:,1)+phase_fac*OO_R(:,:,ir,1) + OO_da(:,:,2)=OO_da(:,:,2)+phase_fac*OO_R(:,:,ir,2) + OO_da(:,:,3)=OO_da(:,:,3)+phase_fac*OO_R(:,:,ir,3) + endif + if(present(OO_dadb)) then + do a=1,3 + do b=1,3 + OO_dadb(:,:,a,b)=OO_dadb(:,:,a,b)+cmplx_i*crvec(b,ir)*phase_fac*OO_R(:,:,ir,a) + enddo + enddo + endif + endif + enddo + + end subroutine pw90common_fourier_R_to_k_vec_dadb + + !=========================================================! + subroutine pw90common_fourier_R_to_k_vec_dadb_TB_conv(kpt,OO_R,OO_da,OO_dadb) + !====================================================================! + ! ! + ! modified version of pw90common_fourier_R_to_k_vec_dadb, includes wannier centres in + ! the exponential inside the sum (so called TB convention) + ! + !! For $$OO_{ij;dx,dy,dz}$$: + !! $$O_{ij;dx,dy,dz}(k) = \sum_R e^{+ik.(R+tau_ij)} O_{ij;dx,dy,dz}(R)$$ + !! For $$OO_{ij;dx1,dy1,dz1;dx2,dy2,dz2}$$: + !! $$O_{ij;dx1,dy1,dz1;dx2,dy2,dz2}(k) = \sum_R e^{+ik.(R+tau_ij)} i.(R+tau_ij)_{dx2,dy2,dz2} + !! .O_{ij;dx1,dy1,dz1}(R)$$ + ! with tau_ij = tau_j - tau_i, being tau_i=<0i|r|0i> the individual wannier centres + ! ! + !====================================================================! + + use w90_constants, only : dp,cmplx_0,cmplx_i,twopi + use w90_parameters, only : num_kpts,kpt_latt, num_wann, use_ws_distance, wannier_centres, recip_lattice + use w90_ws_distance, only : irdist_ws, wdist_ndeg, ws_translate_dist + use w90_utility, only : utility_cart_to_frac + + implicit none + + ! Arguments + ! + real(kind=dp) :: kpt(3) + complex(kind=dp), dimension(:,:,:,:), intent(in) :: OO_R + complex(kind=dp), optional, dimension(:,:,:), intent(out) :: OO_da + complex(kind=dp), optional, dimension(:,:,:,:), intent(out) :: OO_dadb + + integer :: ir, i,j,ideg,a,b + real(kind=dp) :: rdotk + complex(kind=dp) :: phase_fac + real(kind=dp) :: local_wannier_centres(3,num_wann), wannier_centres_frac(3,num_wann) + real(kind=dp) :: r_sum(3) + + r_sum = 0.d0 + + if(use_ws_distance) CALL ws_translate_dist(nrpts, irvec) + if(present(OO_da)) OO_da=cmplx_0 + if(present(OO_dadb)) OO_dadb=cmplx_0 + + + ! calculate wannier centres in cartesian + local_wannier_centres(:,:) = 0.d0 + do j = 1,num_wann + do ir=1,nrpts + if ((irvec(1,ir).eq.0).and.(irvec(2,ir).eq.0).and.(irvec(3,ir).eq.0)) then + local_wannier_centres(1,j) = real(OO_R(j,j,ir,1)) + local_wannier_centres(2,j) = real(OO_R(j,j,ir,2)) + local_wannier_centres(3,j) = real(OO_R(j,j,ir,3)) + endif + enddo + enddo + ! rotate wannier centres from cartesian to fractional coordinates + wannier_centres_frac(:,:) = 0.d0 + do ir = 1,num_wann + call utility_cart_to_frac(local_wannier_centres(:,ir),wannier_centres_frac(:,ir),recip_lattice) + enddo + + +! print *, 'wannier_centres_frac' +! do ir = 1,num_wann +! print *, wannier_centres_frac(:,ir) +! enddo +! stop +! +! print *, 'crvec' +! do ir = 1,nrpts +! print *, crvec(:,ir) +! enddo +! stop +! print *, 'wannier_centres' +! do ir = 1,num_wann +! print *, wannier_centres(:,ir) +! enddo +! stop + + + + + do ir=1,nrpts +! [lp] Shift the WF to have the minimum distance IJ, see also ws_distance.F90 + if(use_ws_distance)then + do j=1,num_wann + do i=1,num_wann + do ideg = 1,wdist_ndeg(j,i,ir) + + rdotk=twopi*dot_product(kpt(:),real(irdist_ws(:,ideg,i,j,ir)+wannier_centres_frac(:,j)-wannier_centres_frac(:,i),dp)) + phase_fac=cmplx(cos(rdotk),sin(rdotk),dp)/real(ndegen(ir)*wdist_ndeg(i,j,ir),dp) +! rdotk=twopi*dot_product(kpt(:),irvec(:,ir)) +! phase_fac=cmplx(cos(rdotk),sin(rdotk),dp)/real(ndegen(ir),dp) + if(present(OO_da)) then + ! if we are at the origin and at the same band, then the + ! matrix element is zero in this convention + if ((irvec(1,ir).eq.0).and.(irvec(2,ir).eq.0).and.(irvec(3,ir).eq.0).and.(i.eq.j)) then + cycle + else + OO_da(i,j,1)=OO_da(i,j,1)+phase_fac*OO_R(i,j,ir,1) + OO_da(i,j,2)=OO_da(i,j,2)+phase_fac*OO_R(i,j,ir,2) + OO_da(i,j,3)=OO_da(i,j,3)+phase_fac*OO_R(i,j,ir,3) + endif + endif + if(present(OO_dadb)) then + ! same skip as before + if ((irvec(1,ir).eq.0).and.(irvec(2,ir).eq.0).and.(irvec(3,ir).eq.0).and.(i.eq.j)) then + cycle + else + do a=1,3 + do b=1,3 + OO_dadb(i,j,a,b)=OO_dadb(i,j,a,b)+cmplx_i*(crvec(b,ir)+local_wannier_centres(b,j)-local_wannier_centres(b,i))*phase_fac*OO_R(i,j,ir,a) + enddo + enddo + endif + endif + + enddo + enddo + enddo + else +! [lp] Original code, without IJ-dependent shift: + do j =1,num_wann + do i=1,num_wann + r_sum(:) = real(irvec(:,ir))+wannier_centres_frac(:,j)-wannier_centres_frac(:,i) + rdotk=twopi*dot_product(kpt(:),r_sum(:)) + phase_fac=cmplx(cos(rdotk),sin(rdotk),dp)/real(ndegen(ir),dp) + if(present(OO_da)) then + ! if we are at the origin and at the same band, then the + ! matrix element is zero in this convention + if ((irvec(1,ir).eq.0).and.(irvec(2,ir).eq.0).and.(irvec(3,ir).eq.0).and.(i.eq.j)) then + OO_da(i,j,1)=OO_da(i,j,1)+phase_fac*(OO_R(i,j,ir,1)-local_wannier_centres(1,j)) + OO_da(i,j,2)=OO_da(i,j,2)+phase_fac*(OO_R(i,j,ir,2)-local_wannier_centres(2,j)) + OO_da(i,j,3)=OO_da(i,j,3)+phase_fac*(OO_R(i,j,ir,3)-local_wannier_centres(3,j)) +! print *, 'OO_R(i,j,ir,1)', OO_R(i,j,ir,1) +! print *, 'local_wannier_centres(1,j)', local_wannier_centres(1,j) +! print *, 'OO_R(i,j,ir,2)', OO_R(i,j,ir,2) +! print *, 'local_wannier_centres(2,j)', local_wannier_centres(2,j) + cycle + else + OO_da(i,j,1)=OO_da(i,j,1)+phase_fac*OO_R(i,j,ir,1) + OO_da(i,j,2)=OO_da(i,j,2)+phase_fac*OO_R(i,j,ir,2) + OO_da(i,j,3)=OO_da(i,j,3)+phase_fac*OO_R(i,j,ir,3) + endif + endif + if(present(OO_dadb)) then + ! same skip as before + if ((irvec(1,ir).eq.0).and.(irvec(2,ir).eq.0).and.(irvec(3,ir).eq.0).and.(i.eq.j)) then + do a=1,3 + do b=1,3 + OO_dadb(i,j,a,b)=OO_dadb(i,j,a,b)+cmplx_i*(crvec(b,ir)+local_wannier_centres(b,j)-local_wannier_centres(b,i))*phase_fac*& + ( OO_R(i,j,ir,a)-local_wannier_centres(a,j) ) + enddo + enddo +! cycle + else + do a=1,3 + do b=1,3 + OO_dadb(i,j,a,b)=OO_dadb(i,j,a,b)+cmplx_i*(crvec(b,ir)+local_wannier_centres(b,j)-local_wannier_centres(b,i))*phase_fac*OO_R(i,j,ir,a) + enddo + enddo + endif + endif + enddo + enddo + endif + enddo + + end subroutine pw90common_fourier_R_to_k_vec_dadb_TB_conv + + + !===========================================================! ! PRIVATE PROCEDURES ! !===========================================================! diff --git a/src/postw90/wan_ham.F90 b/src/postw90/wan_ham.F90 index 078f6d1a7..efb5c3418 100644 --- a/src/postw90/wan_ham.F90 +++ b/src/postw90/wan_ham.F90 @@ -21,8 +21,9 @@ module w90_wan_ham private - public :: wham_get_D_h, wham_get_eig_deleig + public :: wham_get_D_h, wham_get_eig_deleig, wham_get_eig_deleig_TB_conv, wham_get_D_h_P_value public :: wham_get_occ_mat_list, wham_get_eig_UU_HH_JJlist + public :: wham_get_eig_UU_HH_AA_sc, wham_get_eig_UU_HH_AA_sc_TB_conv contains @@ -109,6 +110,52 @@ subroutine wham_get_D_h(delHH,UU,eig,D_h) end subroutine wham_get_D_h + subroutine wham_get_D_h_P_value(delHH,UU,eig,D_h) + !=========================================! + ! ! + !! Compute D^H_a=UU^dag.del_a UU (a=x,y,z) + !! using Eq.(24) of WYSV06 + ! and prescription for energy denominator + ! from BK81 + ! ! + !=========================================! + + ! TO DO: Implement version where energy denominators only connect + ! occupied and empty states. In this case probably do not need + ! to worry about avoiding small energy denominators + + use w90_constants, only : dp,cmplx_0 + use w90_parameters, only : num_wann,sc_eta + use w90_utility, only : utility_rotate + + ! Arguments + ! + complex(kind=dp), dimension(:,:,:), intent(in) :: delHH + complex(kind=dp), dimension(:,:), intent(in) :: UU + real(kind=dp), dimension(:), intent(in) :: eig + complex(kind=dp), dimension(:,:,:), intent(out) :: D_h + + complex(kind=dp), allocatable :: delHH_bar_i(:,:) + integer :: n,m,i + real(kind=dp) :: deltaE + + + allocate(delHH_bar_i(num_wann,num_wann)) + D_h=cmplx_0 + deltaE = 0.d0 + do i=1,3 + delHH_bar_i(:,:)=utility_rotate(delHH(:,:,i),UU,num_wann) + do m=1,num_wann + do n=1,num_wann + if(n==m) cycle + deltaE = eig(m)-eig(n) + D_h(n,m,i)=delHH_bar_i(n,m)*(deltaE/(deltaE**(2)+sc_eta**(2))) + end do + end do + enddo + + end subroutine wham_get_D_h_P_value + subroutine wham_get_JJp_JJm_list(delHH,UU,eig,JJp_list,JJm_list,occ) !===============================================! @@ -378,6 +425,34 @@ subroutine wham_get_eig_deleig(kpt,eig,del_eig,HH,delHH,UU) end subroutine wham_get_eig_deleig + subroutine wham_get_eig_deleig_TB_conv(kpt,eig,del_eig,delHH,UU) + ! modified version of wham_get_eig_deleig for the TB convention + ! avoids recalculating delHH and UU, works with input values + + !! Given a k point, this function returns eigenvalues E and + !! derivatives of the eigenvalues dE/dk_a, using wham_get_deleig_a + ! + use w90_parameters, only: num_wann + use w90_get_oper, only: HH_R, get_HH_R + use w90_postw90_common, only : pw90common_fourier_R_to_k + use w90_utility, only : utility_diagonalize + + real(kind=dp), dimension(3), intent(in) :: kpt + !! the three coordinates of the k point vector (in relative coordinates) + real(kind=dp), intent(out) :: del_eig(num_wann,3) + real(kind=dp), intent(in) :: eig(num_wann) + complex(kind=dp), dimension(:,:,:), intent(in) :: delHH + !! the delHH matrix (derivative of H) at kpt + complex(kind=dp), dimension(:,:), intent(in) :: UU + !! the rotation matrix that gives the eigenvectors of HH + + call wham_get_deleig_a(del_eig(:,1),eig,delHH(:,:,1),UU) + call wham_get_deleig_a(del_eig(:,2),eig,delHH(:,:,2),UU) + call wham_get_deleig_a(del_eig(:,3),eig,delHH(:,:,3),UU) + + end subroutine wham_get_eig_deleig_TB_conv + + subroutine wham_get_eig_UU_HH_JJlist(kpt,eig,UU,HH,JJp_list,JJm_list,occ) !========================================================! @@ -420,4 +495,70 @@ subroutine wham_get_eig_UU_HH_JJlist(kpt,eig,UU,HH,JJp_list,JJm_list,occ) end subroutine wham_get_eig_UU_HH_JJlist + subroutine wham_get_eig_UU_HH_AA_sc_TB_conv(kpt,eig,UU,HH,HH_da,HH_dadb) + !========================================================! + ! ! + ! modified version of wham_get_eig_UU_HH_AA_sc, calls routines + ! satisfying the TB phase convention + ! ! + !========================================================! + + use w90_parameters, only : num_wann + use w90_get_oper, only : HH_R,get_HH_R,AA_R,get_AA_R + use w90_postw90_common, only : pw90common_fourier_R_to_k_new_second_d, pw90common_fourier_R_to_k_new_second_d_TB_conv + use w90_utility, only : utility_diagonalize + + real(kind=dp), dimension(3), intent(in) :: kpt + real(kind=dp), intent(out) :: eig(num_wann) + complex(kind=dp), dimension(:,:), intent(out) :: UU + complex(kind=dp), dimension(:,:), intent(out) :: HH + complex(kind=dp), dimension(:,:,:), intent(out) :: HH_da + complex(kind=dp), dimension(:,:,:,:), intent(out) :: HH_dadb + + integer :: i + + call get_HH_R + call get_AA_R + + call pw90common_fourier_R_to_k_new_second_d_TB_conv(kpt,HH_R,AA_R,OO=HH,& + OO_da=HH_da(:,:,:),& + OO_dadb=HH_dadb(:,:,:,:)) + call utility_diagonalize(HH,num_wann,eig,UU) + + end subroutine wham_get_eig_UU_HH_AA_sc_TB_conv + + + + subroutine wham_get_eig_UU_HH_AA_sc(kpt,eig,UU,HH,HH_da,HH_dadb) + !========================================================! + ! ! + !! Wrapper routine used to reduce number of Fourier calls + ! ! + !========================================================! + + use w90_parameters, only : num_wann + use w90_get_oper, only : HH_R,get_HH_R + use w90_postw90_common, only : pw90common_fourier_R_to_k_new_second_d + use w90_utility, only : utility_diagonalize + + real(kind=dp), dimension(3), intent(in) :: kpt + real(kind=dp), intent(out) :: eig(num_wann) + complex(kind=dp), dimension(:,:), intent(out) :: UU + complex(kind=dp), dimension(:,:), intent(out) :: HH + complex(kind=dp), dimension(:,:,:), intent(out) :: HH_da + complex(kind=dp), dimension(:,:,:,:), intent(out) :: HH_dadb + + integer :: i + + call get_HH_R + + call pw90common_fourier_R_to_k_new_second_d(kpt,HH_R,OO=HH,& + OO_da=HH_da(:,:,:),& + OO_dadb=HH_dadb(:,:,:,:)) + call utility_diagonalize(HH,num_wann,eig,UU) + + end subroutine wham_get_eig_UU_HH_AA_sc + + + end module w90_wan_ham