!-*- mode: F90 -*-! !------------------------------------------------------------! ! Copyright (C) 2026 Wannier Developer Group ! ! ! ! This library is free software; you can redistribute it ! ! and/or modify it under the terms of the GNU Lesser General ! ! Public License as published by the Free Software ! ! Foundation; either version 2.1 of the License, or (at your ! ! option) any later version. ! ! ! ! This library is distributed in the hope that it will be ! ! useful,but WITHOUT ANY WARRANTY; without even the implied ! ! warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ! ! PURPOSE. See the GNU Lesser General Public License for ! ! more details. ! ! ! ! You should have received a copy of the GNU Lesser General ! ! Public License along with this library; if not, see ! ! <https://www.gnu.org/licenses/>. ! ! ! ! The webpage of the Wannier90 code is ! ! <https://www.wannier.org>. ! ! ! ! The Wannier90 code is hosted on GitHub ! ! <https://github.com/wannier-developers/wannier90> ! !------------------------------------------------------------! ! ! ! w90_wan_ham: Hamiltonian operations in Wannier basis ! ! ! !------------------------------------------------------------! module w90_wan_ham !! This module contain operations on the Hamiltonian in the WF basis use w90_constants, only: dp use w90_error, only: w90_error_type, set_error_alloc, set_error_dealloc, set_error_fatal, & set_error_input, set_error_fatal, set_error_file implicit none private public :: wham_get_D_h public :: wham_get_D_h_P_value public :: wham_get_eig_deleig public :: wham_get_eig_deleig_TB_conv public :: wham_get_eig_UU_HH_AA_sc public :: wham_get_eig_UU_HH_AA_sc_TB_conv public :: wham_get_eig_UU_HH_JJlist public :: wham_get_occ_mat_list contains !================================================! subroutine wham_get_D_h_a(delHH_a, UU, eig, ef, D_h_a, num_wann) !================================================! ! !! Compute D^H_a=UU^dag.del_a UU (a=alpha,beta), !! using Eq.(24) of WYSV06 ! !================================================! use w90_constants, only: dp, cmplx_0 use w90_utility, only: utility_rotate use w90_postw90_common, only: pw90common_get_occ ! arguments complex(kind=dp), intent(in) :: delHH_a(:, :) complex(kind=dp), intent(in) :: UU(:, :) complex(kind=dp), intent(out) :: D_h_a(:, :) real(kind=dp), intent(in) :: eig(:) real(kind=dp), intent(in) :: ef integer, intent(in) :: num_wann ! local variables complex(kind=dp), allocatable :: delHH_a_bar(:, :) real(kind=dp) :: occ(num_wann) integer :: n, m call pw90common_get_occ(ef, eig, occ, num_wann) allocate (delHH_a_bar(num_wann, num_wann)) delHH_a_bar = utility_rotate(delHH_a, UU, num_wann) do m = 1, num_wann do n = 1, num_wann if (occ(n) > 0.999_dp .and. occ(m) < 0.001_dp) then D_h_a(n, m) = delHH_a_bar(n, m)/(eig(m) - eig(n)) else D_h_a(n, m) = cmplx_0 end if end do end do D_h_a = D_h_a - conjg(transpose(D_h_a)) end subroutine wham_get_D_h_a !================================================! subroutine wham_get_D_h(delHH, D_h, UU, eig, num_wann) !================================================! ! !! Compute D^H_a=UU^dag.del_a UU (a=x,y,z) !! using Eq.(24) of WYSV06 ! !================================================! ! 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_utility, only: utility_rotate ! arguments complex(kind=dp), intent(in) :: delHH(:, :, :) complex(kind=dp), intent(in) :: UU(:, :) complex(kind=dp), intent(out) :: D_h(:, :, :) real(kind=dp), intent(in) :: eig(:) integer, intent(in) :: num_wann ! local variables complex(kind=dp), allocatable :: delHH_bar_i(:, :) integer :: n, m, i allocate (delHH_bar_i(num_wann, num_wann)) D_h = cmplx_0 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 .or. abs(eig(m) - eig(n)) < 1.0e-7_dp) cycle D_h(n, m, i) = delHH_bar_i(n, m)/(eig(m) - eig(n)) end do end do end do end subroutine wham_get_D_h !================================================! subroutine wham_get_D_h_P_value(pw90_berry, delHH, D_h, UU, eig, num_wann) !================================================! ! !! 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_postw90_types, only: pw90_berry_mod_type !sc_eta use w90_utility, only: utility_rotate ! arguments type(pw90_berry_mod_type), intent(in) :: pw90_berry integer, intent(in) :: num_wann real(kind=dp), intent(in) :: eig(:) complex(kind=dp), intent(in) :: delHH(:, :, :) complex(kind=dp), intent(in) :: UU(:, :) complex(kind=dp), intent(out) :: D_h(:, :, :) ! local variables 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) + pw90_berry%sc_eta**(2))) end do end do end do end subroutine wham_get_D_h_P_value !================================================! subroutine wham_get_JJp_JJm_list(delHH, UU, eig, JJp_list, JJm_list, num_wann, & fermi_energy_list, occ) !================================================! ! ! ! Compute JJ^+_a and JJ^-_a (a=Cartesian index) ! ! for a list of Fermi energies ! ! ! ! This routine is a replacement for ! ! wham_get_JJp_list and wham_getJJm_list. ! ! It computes both lists at once in a more ! ! efficient manner. ! ! ! ! Tsirkin: added the optional occ parameter ! ! ! !================================================! use w90_constants, only: dp, cmplx_0, cmplx_i use w90_utility, only: utility_rotate_new ! arguments real(kind=dp), allocatable, intent(in) :: fermi_energy_list(:) integer, intent(in) :: num_wann real(kind=dp), intent(in) :: eig(:) real(kind=dp), intent(in), optional, dimension(:) :: occ complex(kind=dp), intent(inout) :: delHH(:, :) complex(kind=dp), intent(in) :: UU(:, :) complex(kind=dp), intent(out) :: JJm_list(:, :, :) complex(kind=dp), intent(out) :: JJp_list(:, :, :) ! local variables integer :: n, m, ife, nfermi_loc real(kind=dp) :: fe if (present(occ)) then nfermi_loc = 1 else nfermi_loc = 0 if (allocated(fermi_energy_list)) nfermi_loc = size(fermi_energy_list) end if call utility_rotate_new(delHH, UU, num_wann) do ife = 1, nfermi_loc fe = fermi_energy_list(ife) do m = 1, num_wann do n = 1, num_wann if (present(occ)) then if (occ(m) < 0.5_dp .and. occ(n) > 0.5_dp) then JJm_list(n, m, ife) = cmplx_i*delHH(n, m)/(eig(m) - eig(n)) JJp_list(m, n, ife) = cmplx_i*delHH(m, n)/(eig(n) - eig(m)) else JJm_list(n, m, ife) = cmplx_0 JJp_list(m, n, ife) = cmplx_0 end if else if (eig(n) > fe .and. eig(m) < fe) then JJp_list(n, m, ife) = cmplx_i*delHH(n, m)/(eig(m) - eig(n)) JJm_list(m, n, ife) = cmplx_i*delHH(m, n)/(eig(n) - eig(m)) else JJp_list(n, m, ife) = cmplx_0 JJm_list(m, n, ife) = cmplx_0 end if end if end do end do call utility_rotate_new(JJp_list(:, :, ife), UU, num_wann, reverse=.true.) call utility_rotate_new(JJm_list(:, :, ife), UU, num_wann, reverse=.true.) end do end subroutine wham_get_JJp_JJm_list !================================================! subroutine wham_get_occ_mat_list(fermi_energy_list, f_list, g_list, UU, num_wann, error, comm, & eig, occ) !================================================! ! !! Occupation matrix f, and g=1-f !! for a list of Fermi energies ! Tsirkin: !now optionally either eig or occ parameters may be supplied ! (Changed consistently the calls from the Berry module) !================================================! use w90_constants, only: dp, cmplx_0, cmplx_1 use w90_postw90_common, only: pw90common_get_occ use w90_comms, only: w90_comm_type ! arguments type(w90_error_type), allocatable, intent(out) :: error type(w90_comm_type), intent(in) :: comm real(kind=dp), allocatable, intent(in) :: fermi_energy_list(:) integer, intent(in) :: num_wann real(kind=dp), intent(in), optional :: eig(:) real(kind=dp), intent(in), optional :: occ(:) complex(kind=dp), intent(in) :: UU(:, :) complex(kind=dp), intent(out) :: f_list(:, :, :) complex(kind=dp), intent(out) :: g_list(:, :, :) ! local variables integer :: n, m, i, if, nfermi_loc real(kind=dp), allocatable :: occ_list(:, :) if (present(occ)) then nfermi_loc = 1 else nfermi_loc = 0 if (allocated(fermi_energy_list)) nfermi_loc = size(fermi_energy_list) end if allocate (occ_list(num_wann, nfermi_loc)) if (present(occ) .and. present(eig)) then call set_error_input(error, 'occ_list and eig cannot be both arguments in get_occ_mat_list', & comm) return elseif (.not. present(occ) .and. .not. present(eig)) then call set_error_input(error, 'either occ_list or eig must be passed as arguments to get_occ_mat_list', comm) return end if if (present(occ)) then occ_list(:, 1) = occ(:) else do if = 1, nfermi_loc call pw90common_get_occ(fermi_energy_list(if), eig, occ_list(:, if), num_wann) end do end if f_list = cmplx_0 do if = 1, nfermi_loc do n = 1, num_wann do m = 1, num_wann do i = 1, num_wann f_list(n, m, if) = f_list(n, m, if) & + UU(n, i)*occ_list(i, if)*conjg(UU(m, i)) end do g_list(n, m, if) = -f_list(n, m, if) if (m == n) g_list(n, n, if) = g_list(n, n, if) + cmplx_1 end do end do end do end subroutine wham_get_occ_mat_list !================================================! subroutine wham_get_deleig_a(deleig_a, eig, delHH_a, UU, num_wann, pw90_band_deriv_degen, & error, comm) !================================================! ! !! Band derivatives dE/dk_a ! !================================================! use w90_constants, only: dp !, cmplx_0, cmplx_i use w90_utility, only: utility_diagonalize, utility_rotate, utility_rotate_diag use w90_postw90_types, only: pw90_band_deriv_degen_type use w90_comms, only: w90_comm_type ! arguments type(pw90_band_deriv_degen_type), intent(in) :: pw90_band_deriv_degen integer, intent(in) :: num_wann real(kind=dp), intent(in) :: eig(num_wann) real(kind=dp), intent(out) :: deleig_a(num_wann) complex(kind=dp), intent(in) :: delHH_a(:, :) complex(kind=dp), intent(in) :: UU(:, :) type(w90_error_type), allocatable, intent(out) :: error type(w90_comm_type), intent(in) :: comm ! local variables integer :: i, degen_min, degen_max, dim real(kind=dp) :: diff complex(kind=dp), allocatable :: delHH_bar_a(:, :), U_deg(:, :) allocate (delHH_bar_a(num_wann, num_wann)) allocate (U_deg(num_wann, num_wann)) if (pw90_band_deriv_degen%use_degen_pert) then delHH_bar_a = utility_rotate(delHH_a, UU, num_wann) ! Assuming that the energy eigenvalues are stored in eig(:) in ! increasing order (diff >= 0) i = 0 do i = i + 1 if (i > num_wann) exit if (i + 1 <= num_wann) then diff = eig(i + 1) - eig(i) else ! i-th is the highest band, and it is non-degenerate diff = pw90_band_deriv_degen%degen_thr + 1.0_dp end if if (diff < pw90_band_deriv_degen%degen_thr) then ! Bands i and i+1 are degenerate degen_min = i degen_max = degen_min + 1 ! See if any higher bands are in the same degenerate group do if (degen_max + 1 > num_wann) exit diff = eig(degen_max + 1) - eig(degen_max) if (diff < pw90_band_deriv_degen%degen_thr) then degen_max = degen_max + 1 else exit end if end do ! Bands from degen_min to degen_max are degenerate. Diagonalize ! the submatrix in Eq.(31) YWVS07 over this degenerate subspace. ! The eigenvalues are the band gradients dim = degen_max - degen_min + 1 call utility_diagonalize(delHH_bar_a(degen_min:degen_max, degen_min:degen_max), dim, & deleig_a(degen_min:degen_max), U_deg(1:dim, 1:dim), error, comm) if (allocated(error)) return ! Scanned bands up to degen_max i = degen_max else ! Use non-degenerate form [Eq.(27) YWVS07] for current (i-th) band deleig_a(i) = real(delHH_bar_a(i, i), dp) end if end do else ! Use non-degenerate form for all bands deleig_a(:) = real(utility_rotate_diag(delHH_a(:, :), UU, num_wann), dp) end if end subroutine wham_get_deleig_a !================================================! subroutine wham_get_eig_deleig(dis_manifold, kpt_latt, pw90_band_deriv_degen, ws_region, & print_output, wannier_data, ws_distance, wigner_seitz, delHH, HH, & HH_R, u_matrix, UU, v_matrix, del_eig, eig, eigval, kpt, & real_lattice, scissors_shift, mp_grid, num_bands, num_kpts, & num_wann, num_valence_bands, effective_model, have_disentangled, & seedname, stdout, timer, error, comm) !================================================! ! !! Given a k point, this function returns eigenvalues E and !! derivatives of the eigenvalues dE/dk_a, using wham_get_deleig_a ! !================================================! use w90_constants, only: dp use w90_postw90_types, only: pw90_band_deriv_degen_type, wigner_seitz_type use w90_comms, only: w90_comm_type, mpirank use w90_constants, only: dp, cmplx_0 use w90_get_oper, only: get_HH_R use w90_types, only: dis_manifold_type, print_output_type, wannier_data_type, & ws_region_type, ws_distance_type, timer_list_type use w90_postw90_common, only: pw90common_fourier_R_to_k_new_second_d, & pw90common_fourier_R_to_k use w90_utility, only: utility_diagonalize implicit none ! arguments type(dis_manifold_type), intent(in) :: dis_manifold real(kind=dp), intent(in) :: kpt_latt(:, :) type(pw90_band_deriv_degen_type), intent(in) :: pw90_band_deriv_degen type(print_output_type), intent(in) :: print_output type(ws_region_type), intent(in) :: ws_region type(w90_comm_type), intent(in) :: comm type(wannier_data_type), intent(in) :: wannier_data type(wigner_seitz_type), intent(inout) :: wigner_seitz type(ws_distance_type), intent(inout) :: ws_distance type(timer_list_type), intent(inout) :: timer type(w90_error_type), allocatable, intent(out) :: error integer, intent(in) :: num_wann, num_kpts, num_bands, num_valence_bands integer, intent(in) :: mp_grid(3) integer, intent(in) :: stdout real(kind=dp), intent(in) :: kpt(3)!! the three coordinates of the k point vector (in relative coordinates) real(kind=dp), intent(out) :: eig(num_wann)!! the calculated eigenvalues at kpt real(kind=dp), intent(out) :: del_eig(num_wann, 3) !! the calculated derivatives of the eigenvalues at kpt [first component: band; second component: 1,2,3 !! for the derivatives along the three k directions] real(kind=dp), intent(in) :: eigval(:, :) real(kind=dp), intent(in) :: real_lattice(3, 3) real(kind=dp), intent(in) :: scissors_shift complex(kind=dp), intent(out) :: HH(:, :) !! the Hamiltonian matrix at kpt complex(kind=dp), intent(out) :: delHH(:, :, :) !! the delHH matrix (derivative of H) at kpt complex(kind=dp), intent(out) :: UU(:, :) !! the rotation matrix that gives the eigenvectors of HH complex(kind=dp), intent(in) :: u_matrix(:, :, :), v_matrix(:, :, :) complex(kind=dp), allocatable, intent(inout) :: HH_R(:, :, :) ! <0n|r|Rm> character(len=50), intent(in) :: seedname logical, intent(in) :: have_disentangled logical, intent(in) :: effective_model ! I call it to be sure that it has been called already once, ! and that HH_R contains the actual matrix. ! Further calls should return very fast. call get_HH_R(dis_manifold, kpt_latt, print_output, wigner_seitz, HH_R, u_matrix, v_matrix, & eigval, real_lattice, scissors_shift, num_bands, num_kpts, num_wann, & num_valence_bands, effective_model, have_disentangled, seedname, ws_distance, ws_region, & stdout, timer, error, comm) if (allocated(error)) return call pw90common_fourier_R_to_k(ws_region, wannier_data, ws_distance, wigner_seitz, HH, HH_R, & kpt, real_lattice, mp_grid, 0, num_wann, error, comm) if (allocated(error)) return call utility_diagonalize(HH, num_wann, eig, UU, error, comm) if (allocated(error)) return call pw90common_fourier_R_to_k(ws_region, wannier_data, ws_distance, wigner_seitz, & delHH(:, :, 1), HH_R, kpt, real_lattice, mp_grid, 1, num_wann, & error, comm) if (allocated(error)) return call pw90common_fourier_R_to_k(ws_region, wannier_data, ws_distance, wigner_seitz, & delHH(:, :, 2), HH_R, kpt, real_lattice, mp_grid, 2, num_wann, & error, comm) if (allocated(error)) return call pw90common_fourier_R_to_k(ws_region, wannier_data, ws_distance, wigner_seitz, & delHH(:, :, 3), HH_R, kpt, real_lattice, mp_grid, 3, num_wann, & error, comm) if (allocated(error)) return call wham_get_deleig_a(del_eig(:, 1), eig, delHH(:, :, 1), UU, num_wann, & pw90_band_deriv_degen, error, comm) if (allocated(error)) return call wham_get_deleig_a(del_eig(:, 2), eig, delHH(:, :, 2), UU, num_wann, & pw90_band_deriv_degen, error, comm) if (allocated(error)) return call wham_get_deleig_a(del_eig(:, 3), eig, delHH(:, :, 3), UU, num_wann, & pw90_band_deriv_degen, error, comm) if (allocated(error)) return end subroutine wham_get_eig_deleig !================================================! subroutine wham_get_eig_deleig_TB_conv(pw90_band_deriv_degen, delHH, UU, eig, del_eig, num_wann, & error, comm) !================================================! ! 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_postw90_types, only: pw90_band_deriv_degen_type use w90_comms, only: w90_comm_type ! arguments type(pw90_band_deriv_degen_type), intent(in) :: pw90_band_deriv_degen type(w90_error_type), allocatable, intent(out) :: error type(w90_comm_type), intent(in) :: comm integer, intent(in) :: num_wann real(kind=dp), intent(out) :: del_eig(num_wann, 3) real(kind=dp), intent(in) :: eig(num_wann) complex(kind=dp), intent(in) :: delHH(:, :, :) !! the delHH matrix (derivative of H) at kpt complex(kind=dp), intent(in) :: UU(:, :) !! the rotation matrix that gives the eigenvectors of HH call wham_get_deleig_a(del_eig(:, 1), eig, delHH(:, :, 1), UU, num_wann, & pw90_band_deriv_degen, error, comm) if (allocated(error)) return call wham_get_deleig_a(del_eig(:, 2), eig, delHH(:, :, 2), UU, num_wann, & pw90_band_deriv_degen, error, comm) if (allocated(error)) return call wham_get_deleig_a(del_eig(:, 3), eig, delHH(:, :, 3), UU, num_wann, & pw90_band_deriv_degen, error, comm) if (allocated(error)) return end subroutine wham_get_eig_deleig_TB_conv !================================================! subroutine wham_get_eig_UU_HH_JJlist(dis_manifold, fermi_energy_list, kpt_latt, ws_region, & print_output, wannier_data, ws_distance, wigner_seitz, HH, & HH_R, JJm_list, JJp_list, u_matrix, UU, v_matrix, eig, & eigval, kpt, real_lattice, scissors_shift, mp_grid, & num_bands, num_kpts, num_wann, num_valence_bands, & effective_model, have_disentangled, seedname, stdout, & timer, error, comm, occ) !================================================! ! !! Wrapper routine used to reduce number of Fourier calls ! Added the optional occ parameter ! !================================================! use w90_constants, only: dp use w90_postw90_common, only: pw90common_fourier_R_to_k_new_second_d, & pw90common_fourier_R_to_k_new use w90_get_oper, only: get_HH_R use w90_utility, only: utility_diagonalize use w90_types, only: print_output_type, wannier_data_type, dis_manifold_type, & ws_region_type, ws_distance_type, timer_list_type use w90_comms, only: w90_comm_type, mpirank use w90_postw90_types, only: wigner_seitz_type implicit none ! arguments type(dis_manifold_type), intent(in) :: dis_manifold real(kind=dp), allocatable, intent(in) :: fermi_energy_list(:) real(kind=dp), intent(in) :: kpt_latt(:, :) type(print_output_type), intent(in) :: print_output type(ws_region_type), intent(in) :: ws_region type(w90_comm_type), intent(in) :: comm type(wannier_data_type), intent(in) :: wannier_data type(wigner_seitz_type), intent(inout) :: wigner_seitz type(ws_distance_type), intent(inout) :: ws_distance type(timer_list_type), intent(inout) :: timer type(w90_error_type), allocatable, intent(out) :: error integer, intent(in) :: num_wann, num_kpts, num_bands, num_valence_bands integer, intent(in) :: mp_grid(3) integer, intent(in) :: stdout real(kind=dp), intent(in) :: kpt(3), real_lattice(3, 3) real(kind=dp), intent(out) :: eig(:) real(kind=dp), intent(in) :: eigval(:, :) real(kind=dp), intent(in) :: scissors_shift real(kind=dp), intent(in), optional :: occ(:) complex(kind=dp), intent(out) :: UU(:, :) complex(kind=dp), intent(out) :: HH(:, :) complex(kind=dp), intent(out) :: JJp_list(:, :, :, :) complex(kind=dp), intent(out) :: JJm_list(:, :, :, :) complex(kind=dp), intent(in) :: u_matrix(:, :, :), v_matrix(:, :, :) complex(kind=dp), allocatable, intent(inout) :: HH_R(:, :, :) ! <0n|r|Rm> character(len=50), intent(in) :: seedname logical, intent(in) :: have_disentangled logical, intent(in) :: effective_model ! local variables integer :: i complex(kind=dp), allocatable :: delHH(:, :, :) call get_HH_R(dis_manifold, kpt_latt, print_output, wigner_seitz, HH_R, u_matrix, v_matrix, & eigval, real_lattice, scissors_shift, num_bands, num_kpts, num_wann, & num_valence_bands, effective_model, have_disentangled, seedname, ws_distance, ws_region, & stdout, timer, error, comm) if (allocated(error)) return allocate (delHH(num_wann, num_wann, 3)) call pw90common_fourier_R_to_k_new(ws_region, wannier_data, ws_distance, wigner_seitz, HH_R, & kpt, real_lattice, mp_grid, num_wann, error, comm, OO=HH, & OO_dx=delHH(:, :, 1), OO_dy=delHH(:, :, 2), & OO_dz=delHH(:, :, 3)) if (allocated(error)) return call utility_diagonalize(HH, num_wann, eig, UU, error, comm) if (allocated(error)) return do i = 1, 3 if (present(occ)) then call wham_get_JJp_JJm_list(delHH(:, :, i), UU, eig, JJp_list(:, :, :, i), & JJm_list(:, :, :, i), num_wann, fermi_energy_list, occ=occ) else call wham_get_JJp_JJm_list(delHH(:, :, i), UU, eig, JJp_list(:, :, :, i), & JJm_list(:, :, :, i), num_wann, fermi_energy_list) end if end do end subroutine wham_get_eig_UU_HH_JJlist !================================================! subroutine wham_get_eig_UU_HH_AA_sc_TB_conv(pw90_berry, dis_manifold, kmesh_info, kpt_latt, & ws_region, print_output, wannier_data, ws_distance, & wigner_seitz, AA_R, HH, HH_da, HH_dadb, HH_R, & u_matrix, UU, v_matrix, eig, eigval, kpt, & real_lattice, scissors_shift, mp_grid, & num_bands, num_kpts, num_wann, num_valence_bands, & effective_model, have_disentangled, seedname, & stdout, timer, error, comm) !================================================! ! ! modified version of wham_get_eig_UU_HH_AA_sc, calls routines ! satisfying the TB phase convention ! !================================================! use w90_constants, only: dp use w90_get_oper, only: get_HH_R, get_AA_R_effective, get_AA_R use w90_postw90_common, only: pw90common_fourier_R_to_k_new_second_d_TB_conv use w90_types, only: print_output_type, wannier_data_type, dis_manifold_type, & kmesh_info_type, ws_region_type, ws_distance_type, timer_list_type use w90_utility, only: utility_diagonalize use w90_postw90_types, only: pw90_berry_mod_type, wigner_seitz_type use w90_comms, only: w90_comm_type, mpirank implicit none ! arguments type(pw90_berry_mod_type), intent(in) :: pw90_berry type(dis_manifold_type), intent(in) :: dis_manifold type(kmesh_info_type), intent(in) :: kmesh_info real(kind=dp), intent(in) :: kpt_latt(:, :) type(print_output_type), intent(in) :: print_output type(ws_region_type), intent(in) :: ws_region type(w90_comm_type), intent(in) :: comm type(wannier_data_type), intent(in) :: wannier_data type(wigner_seitz_type), intent(inout) :: wigner_seitz type(ws_distance_type), intent(inout) :: ws_distance type(timer_list_type), intent(inout) :: timer type(w90_error_type), allocatable, intent(out) :: error integer, intent(in) :: num_wann, num_kpts, num_bands, num_valence_bands integer, intent(in) :: mp_grid(3) integer, intent(in) :: stdout real(kind=dp), intent(out) :: eig(num_wann) real(kind=dp), intent(in) :: eigval(:, :) real(kind=dp), intent(in) :: kpt(3), real_lattice(3, 3) real(kind=dp), intent(in) :: scissors_shift complex(kind=dp), intent(out) :: UU(:, :) complex(kind=dp), intent(out) :: HH(:, :) complex(kind=dp), intent(out) :: HH_da(:, :, :) complex(kind=dp), intent(out) :: HH_dadb(:, :, :, :) complex(kind=dp), intent(in) :: u_matrix(:, :, :), v_matrix(:, :, :) complex(kind=dp), allocatable, intent(inout) :: HH_R(:, :, :) ! <0n|r|Rm> complex(kind=dp), allocatable, intent(inout) :: AA_R(:, :, :, :) ! <0n|r|Rm> character(len=50), intent(in) :: seedname logical, intent(in) :: have_disentangled logical, intent(in) :: effective_model call get_HH_R(dis_manifold, kpt_latt, print_output, wigner_seitz, HH_R, u_matrix, v_matrix, & eigval, real_lattice, scissors_shift, num_bands, num_kpts, num_wann, & num_valence_bands, effective_model, have_disentangled, seedname, ws_distance, ws_region, & stdout, timer, error, comm) if (allocated(error)) return if (effective_model) then call get_AA_R_effective(print_output, AA_R, HH_R, wigner_seitz%nrpts, num_wann, seedname, & stdout, timer, error, comm) else call get_AA_R(pw90_berry, dis_manifold, kmesh_info, kpt_latt, print_output, wannier_data, AA_R, & v_matrix, eigval, wigner_seitz, ws_distance, ws_region, num_bands, num_kpts, & num_wann, have_disentangled, seedname, stdout, timer, error, comm) end if if (allocated(error)) return call pw90common_fourier_R_to_k_new_second_d_TB_conv(kpt, HH_R, AA_R, num_wann, ws_region, & wannier_data, real_lattice, mp_grid, & ws_distance, wigner_seitz, error, comm, & OO=HH, OO_da=HH_da(:, :, :), & OO_dadb=HH_dadb(:, :, :, :)) if (allocated(error)) return call utility_diagonalize(HH, num_wann, eig, UU, error, comm) if (allocated(error)) return end subroutine wham_get_eig_UU_HH_AA_sc_TB_conv subroutine wham_get_eig_UU_HH_AA_sc(dis_manifold, kpt_latt, ws_region, print_output, & wannier_data, ws_distance, wigner_seitz, HH, HH_da, HH_dadb, & HH_R, u_matrix, UU, v_matrix, eig, eigval, kpt, & real_lattice, scissors_shift, mp_grid, num_bands, num_kpts, & num_wann, num_valence_bands, effective_model, & have_disentangled, seedname, stdout, timer, error, comm) !================================================! ! !! Wrapper routine used to reduce number of Fourier calls ! !================================================! use w90_constants, only: dp use w90_get_oper, only: get_HH_R use w90_postw90_common, only: pw90common_fourier_R_to_k_new_second_d use w90_utility, only: utility_diagonalize use w90_comms, only: w90_comm_type, mpirank use w90_types, only: print_output_type, wannier_data_type, dis_manifold_type, & ws_region_type, ws_distance_type, timer_list_type use w90_postw90_types, only: wigner_seitz_type implicit none ! arguments type(dis_manifold_type), intent(in) :: dis_manifold real(kind=dp), intent(in) :: kpt_latt(:, :) type(print_output_type), intent(in) :: print_output type(ws_region_type), intent(in) :: ws_region type(w90_comm_type), intent(in) :: comm type(wannier_data_type), intent(in) :: wannier_data type(wigner_seitz_type), intent(inout) :: wigner_seitz type(ws_distance_type), intent(inout) :: ws_distance type(timer_list_type), intent(inout) :: timer type(w90_error_type), allocatable, intent(out) :: error integer, intent(in) :: num_wann, num_kpts, num_bands, num_valence_bands integer, intent(in) :: mp_grid(3) integer, intent(in) :: stdout real(kind=dp), intent(out) :: eig(num_wann) real(kind=dp), intent(in) :: eigval(:, :) real(kind=dp), intent(in) :: kpt(3), real_lattice(3, 3) real(kind=dp), intent(in) :: scissors_shift complex(kind=dp), intent(out) :: UU(:, :) complex(kind=dp), intent(out) :: HH(:, :) complex(kind=dp), intent(out) :: HH_da(:, :, :) complex(kind=dp), intent(out) :: HH_dadb(:, :, :, :) complex(kind=dp), intent(in) :: u_matrix(:, :, :), v_matrix(:, :, :) complex(kind=dp), allocatable, intent(inout) :: HH_R(:, :, :) ! <0n|r|Rm> character(len=50), intent(in) :: seedname logical, intent(in) :: have_disentangled logical, intent(in) :: effective_model call get_HH_R(dis_manifold, kpt_latt, print_output, wigner_seitz, HH_R, u_matrix, v_matrix, & eigval, real_lattice, scissors_shift, num_bands, num_kpts, num_wann, & num_valence_bands, effective_model, have_disentangled, seedname, ws_distance, ws_region, & stdout, timer, error, comm) if (allocated(error)) return call pw90common_fourier_R_to_k_new_second_d(kpt, HH_R, num_wann, ws_region, wannier_data, & real_lattice, mp_grid, ws_distance, wigner_seitz, & error, comm, OO=HH, OO_da=HH_da(:, :, :), & OO_dadb=HH_dadb(:, :, :, :)) if (allocated(error)) return call utility_diagonalize(HH, num_wann, eig, UU, error, comm) if (allocated(error)) return end subroutine wham_get_eig_UU_HH_AA_sc end module w90_wan_ham