使用Fortran计算Hall电导

 

整理用Fortran计算某一条能带的Hall电导,这里使用的QWZ模型。

整理用Fortran计算某一条能带的Hall电导,这里使用的QWZ模型。

前言

这里使用的是最简单的QWZ模型,其哈密顿量为

\[H = (m_0 - t_x \cos(k_x) - t_y \cos(k_y))\sigma_z + a_x \sin(k_x) \sigma_x + a_y * \sin(k_y) * sigma_y\]

程序实现上目前是分别计算每一条能带的Hall电导,而不是计算费米面以下电子贡献的电导。当化学势落在能隙中的时候,这里计算的Hall电导就是单独一条能带贡献,如果化学势与能带有交点,那么Hall电导的计算应该是考虑所有费米面以下的贡献,这里先不考虑这件事情。

代码

串行版

module code_param
    implicit none
    integer, parameter :: dp = kind(1.0d0)  ! 双精度
    real(dp),parameter::pi = acos(-1.0_dp)
    complex(dp),parameter::im = (0.,1.)                 !   Imagine unit  
    integer Nk,numk_bz
    real(dp),allocatable::BZklist(:,:)
    real(dp) m0,t1,ax,ay,mu
    real(dp) omega
    parameter(m0 = 1.0,t1 = 1.0,ax = 1.0,ay = 1.0,Nk = 1e2, mu = 0.0, omega = 1e-8)
end module code_param
!==============================================================================================================================================================
program chern_insulator_hall_conductance
    use code_param
    implicit none
    integer :: ik0
    real(dp) :: kx, ky, hall_conductance
    real(dp),external :: calculate_berry_curvature
    call squareBZ()  ! 构建布里渊区

    hall_conductance = 0.0

    ! 遍历 k 空间,计算 Berry 曲率并积分
    do ik0 = 1,size(BZklist,2)
        kx = BZklist(1,ik0)
        ky = BZklist(2,ik0)
        hall_conductance = hall_conductance + calculate_berry_curvature(kx,ky,1) * (pi/Nk)**2
    end do

    ! 输出结果
    write(*,"(A50,F15.6)")"Hall Conductance (in units of e^2/h): ", hall_conductance / (2.0 * pi)

end program chern_insulator_hall_conductance
!==============================================================================================================================================================
    function calculate_berry_curvature(kx,ky,ind_band)
    ! 计算某一条能带的 Berry 曲率的子程序
    use code_param
    implicit none
    integer,parameter::hn = 2  ! 哈密顿量维度
    integer ie1,ie2
    real(dp), intent(in) :: kx, ky
    integer, intent(in) :: ind_band
    real(dp) :: eigvals(hn),calculate_berry_curvature
    complex(dp) :: re1(hn), dHdkx(hn,hn), dHdky(hn,hn), Ham(hn,hn), eigvecs(hn,hn)
    complex(dp),external::Ave_Ham

    ! H = (m0 - tx cos(kx) - ty cos(ky))\sigma_z + ax sin(kx) \sigma_x + ay * sin(ky) * sigma_y
    Ham = 0.0
    Ham(1,1) = m0 - t1 * (cos(kx) + cos(ky)) - mu
    Ham(2,2) = -(m0 - t1 * (cos(kx) + cos(ky))) - mu
    Ham(1,2) = ax * sin(kx) - im * ay * sin(ky)
    Ham(2,1) = ax * sin(kx) + im * ay * sin(ky)
    
    ! 计算哈密顿量的特征值和特征向量
    eigvecs = 0.0
    eigvals = 0.0
    call diagonalize_hermitian_matrix(hn, Ham, eigvecs, eigvals)

    ! 构建哈密顿量对 kx 和 ky 的导数矩阵
    dHdkx = 0.0
    dHdky = 0.0

    !  DH_x
    dHdkx(1,1) = t1 * sin(kx)
    dHdkx(2,2) = -t1 * sin(kx)

    dHdkx(1,2) = ax * cos(kx) 
    dHdkx(2,1) = ax * cos(kx)
    
    !  DH_y
    dHdky(1,1) = t1 * sin(ky)
    dHdky(2,2) = -t1 * sin(ky)

    dHdky(1,2) = -im * ay * cos(ky)
    dHdky(2,1) = im * ay * cos(ky)

    ! 计算 Berry 曲率
    re1 = 0.0
    do ie1 = 1, hn   ! 索引能带
    do ie2 = 1, hn
        if (ie2 /= ie1) then
            re1(ie1) = re1(ie1) + (Ave_Ham(hn, eigvecs(:, ie1), dHdkx, eigvecs(:, ie2)) * &
                            Ave_Ham(hn, eigvecs(:, ie2), dHdky, eigvecs(:, ie1))) / &
                            ((eigvals(ie1) - eigvals(ie2))**2 + omega)  ! 添加正则项防止除零
        endif
    end do
    end do
    calculate_berry_curvature = 2 * aimag(re1(ind_band))
end function calculate_berry_curvature
!==============================================================================================================================================================
function Ave_Ham(matdim,psi1,Ham,psi2)
    ! 计算  <psi_1|Ham|psi_2>
    use code_param
    implicit none
    integer i0,j0,matdim
    complex(dp) Ave_Ham,expectation,Ham(matdim,matdim),temp(matdim),psi1(matdim),psi2(matdim)
    expectation = 0.0
    do i0 = 1,matdim
        temp(i0) = 0.0
        do j0 = 1,matdim
            temp(i0) = temp(i0) + Ham(i0, j0) * psi2(j0)
        end do
    end do

    do i0 = 1,matdim
        expectation = expectation + conjg(psi1(i0)) * temp(i0)
    end do
    Ave_Ham = expectation
    return
end function 
!============================================================================================================================
subroutine squareBZ()
    ! 构建四方BZ
    use code_param
    integer ikx,iky,i0
    ! 对于四方点阵,BZ的点数可以直接确定
    numk_bz = (2 * Nk)**2   
    allocate(BZklist(2,numk_bz))
    i0 = 0
    open(30,file = "BZ.dat")
    do ikx = -Nk,Nk - 1
        do iky = -Nk,Nk - 1
            i0 = i0 + 1
            BZklist(1,i0) = pi * ikx/(1.0 * Nk)
            BZklist(2,i0) = pi * iky/(1.0 * Nk) 
            write(30,"(4F15.8)")BZklist(1,i0),BZklist(2,i0)
        end do
    end do
    close(30)
    return  
end subroutine
!==============================================================================================================================================================
subroutine diagonalize_Hermitian_matrix(matdim, matin, matout, mateigval)
    ! 厄米矩阵对角化
    ! matin 输入矩阵, matout 本征矢量, mateigval 本征值
    implicit none
    integer, parameter :: dp = kind(1.0d0)  ! 双精度
    integer, intent(in) :: matdim
    integer :: lda0, lwmax0, lwork, lrwork, liwork, info
    complex(dp), intent(in) :: matin(matdim, matdim)
    complex(dp), intent(out) :: matout(matdim, matdim)
    real(dp), intent(out) :: mateigval(matdim)
    complex(dp), allocatable :: work(:)
    real(dp), allocatable :: rwork(:)
    integer, allocatable :: iwork(:)
    !-----------------
    lda0 = matdim
    lwmax0 = 2 * matdim + matdim**2
    allocate(work(lwmax0))
    allocate(rwork(1 + 5 * matdim + 2 * matdim**2))
    allocate(iwork(3 + 5 * matdim))

    matout = matin
    lwork = -1
    liwork = -1
    lrwork = -1

    ! 初次调用 zheevd 获取最佳工作空间大小
    call zheevd('V', 'U', matdim, matout, lda0, mateigval, work, lwork, rwork, lrwork, iwork, liwork, info)

    ! 根据第一次调用的返回值重新调整工作空间大小
    lwork = min(2 * matdim + matdim**2, int(work(1)))
    lrwork = min(1 + 5 * matdim + 2 * matdim**2, int(rwork(1)))
    liwork = min(3 + 5 * matdim, iwork(1))

    ! 重新分配工作空间
    deallocate(work)
    allocate(work(lwork))
    deallocate(rwork)
    allocate(rwork(lrwork))
    deallocate(iwork)
    allocate(iwork(liwork))

    ! 第二次调用 zheevd 计算本征值和本征矢量
    call zheevd('V', 'U', matdim, matout, lda0, mateigval, work, lwork, rwork, lrwork, iwork, liwork, info)

    ! 错误处理
    if (info > 0) then
        open(11, file = "mes.dat", status = "unknown")
        write(11, *) 'The algorithm failed to compute eigenvalues.'
        close(11)
    end if

    return
end subroutine diagonalize_Hermitian_matrix

并行版

module code_param
    implicit none
    integer, parameter :: dp = kind(1.0d0)  ! 双精度
    real(dp),parameter::pi = acos(-1.0_dp)
    complex(dp),parameter::im = (0.,1.)                 !   Imagine unit  
    real(dp), parameter :: e0 = 1.602176634e-19_dp   ! 电子电荷 (C)
    real(dp), parameter :: hbar = 1.0545718e-34_dp  ! 约化普朗克常数 (J·s)
    integer Nk,numk_bz,num_mu
    real(dp),allocatable::BZklist(:,:)
    real(dp) m0,t1,ax,ay,mu,mu_Max
    real(dp) omega,delta_k
    parameter(t1 = 1.0,ax = 1.0,mu = 0.0,ay = 1.0,Nk = 1e3, omega = 1e-8, delta_k = 1e-5,num_mu = 100,mu_max = 3)
end module code_param
!==============================================================================================================================================================
program main
    use code_param
    use mpi
    implicit none
    integer numcore,indcore,ierr,nki,nkf   ! Parameter for MPI
    integer i0
    real(dp) temp,hall_conductance
    real(dp),external::calculate_Hall_conductance
    real(dp) da_mpi(num_mu),da_list(num_mu),hall_mpi(num_mu),hall_list(num_mu)
    !#######################################         并行计算设置      #######################################
    call MPI_INIT(ierr)     ! 初始化进程
    call MPI_COMM_RANK(MPI_COMM_WORLD, indcore, ierr) ! 得到本进程在通信空间中的rank值,即在组中的逻辑编号(该indcore为0到numcore-1间的整数,相当于进程的ID。)
    call MPI_COMM_SIZE(MPI_COMM_WORLD, numcore, ierr) !获得进程数量,用numcoer保存
    ! 并行循环分拆
    nki = floor(indcore * (1.0 * num_mu)/numcore) + 1
    nkf = floor((indcore + 1) * (1.0 * num_mu)/numcore)
    !#######################################         并行计算设置      #######################################
    call squareBZ()  ! 构建布里渊区
    do i0 = nki,nkf
        m0 = 2.0 * mu_max/num_mu * i0 - mu_max
        da_mpi(i0) = m0
        hall_mpi(i0) = calculate_Hall_conductance()
    end do
    call MPI_Barrier(MPI_COMM_WORLD,ierr)   ! 等所有核心都计算完成
    call MPI_Reduce(da_mpi, da_list, num_mu, MPI_DOUBLE_PRECISION, MPI_SUM, 0, MPI_COMM_WORLD,ierr)
    call MPI_Reduce(hall_mpi, hall_list, num_mu, MPI_DOUBLE_PRECISION, MPI_SUM, 0, MPI_COMM_WORLD,ierr)

    if(indcore.eq.0)then
        ! 数据读写
        open(30,file = "Hall-mu.dat")
        do i0 = 1,num_mu
            write(30,"(9F20.10)")da_list(i0),hall_list(i0)
        enddo
        close(30)
    endif
    call MPI_Finalize(ierr)

    ! hall_conductance = calculate_Hall_conductance()
    ! 输出结果
    ! write(*,"(A50,F15.6)")"Hall Conductance (in units of e^2/h): ", hall_conductance

end program main
!==============================================================================================================================================================
function calculate_Hall_conductance()
    use code_param
    implicit none
    integer :: ik0
    real(dp) :: kx, ky, re1, re2, calculate_Hall_conductance
    real(dp),external :: calculate_berry_curvature_v1
    real(dp),external :: calculate_berry_curvature_v2

    re1 = 0.0
    re2 = 0.0

    ! 遍历 k 空间,计算 Berry 曲率并积分
    do ik0 = 1,size(BZklist,2)
        kx = BZklist(1,ik0)
        ky = BZklist(2,ik0)
        ! re2 = re2 + calculate_berry_curvature_v1(kx,ky,1) * (pi/Nk)**2   !  我这里的步长上是  pi/Nk
        re1 = re1 + calculate_berry_curvature_v2(kx,ky,1) * (pi/Nk)**2   !  我这里的步长上是  pi/Nk
    end do
    calculate_Hall_conductance = re1/(2.0 * pi)
    ! 输出结果
    ! write(*,"(A50,F15.6)")"Hall Conductance (in units of e^2/h): ", re1/(2 * pi)

end function calculate_Hall_conductance
!==============================================================================================================================================================
    function calculate_berry_curvature_v1(kx,ky,ind_band)
    ! 计算某一条能带的 Berry 曲率的子程序
    ! 解析给出哈密顿量偏导
    use code_param
    implicit none
    integer,parameter::hn = 2  ! 哈密顿量维度
    integer ie1,ie2
    real(dp), intent(in) :: kx, ky
    integer, intent(in) :: ind_band
    real(dp) :: eigvals(hn),calculate_berry_curvature_v1
    complex(dp) :: re1(hn), dHdkx(hn,hn), dHdky(hn,hn), Ham(hn,hn), eigvecs(hn,hn)
    complex(dp),external::Ave_Ham

    ! H = (m0 - tx cos(kx) - ty cos(ky))\sigma_z + ax sin(kx) \sigma_x + ay * sin(ky) * sigma_y
    Ham = 0.0
    Ham(1,1) = m0 - t1 * (cos(kx) + cos(ky)) - mu
    Ham(2,2) = -(m0 - t1 * (cos(kx) + cos(ky))) - mu
    Ham(1,2) = ax * sin(kx) - im * ay * sin(ky)
    Ham(2,1) = ax * sin(kx) + im * ay * sin(ky)
    
    ! 计算哈密顿量的特征值和特征向量
    eigvecs = 0.0
    eigvals = 0.0
    call diagonalize_hermitian_matrix(hn, Ham, eigvecs, eigvals)

    ! 构建哈密顿量对 kx 和 ky 的导数矩阵
    dHdkx = 0.0
    dHdky = 0.0

    !  DH_x
    dHdkx(1,1) = t1 * sin(kx)
    dHdkx(2,2) = -t1 * sin(kx)

    dHdkx(1,2) = ax * cos(kx) 
    dHdkx(2,1) = ax * cos(kx)
    
    !  DH_y
    dHdky(1,1) = t1 * sin(ky)
    dHdky(2,2) = -t1 * sin(ky)

    dHdky(1,2) = -im * ay * cos(ky)
    dHdky(2,1) = im * ay * cos(ky)

    ! 计算 Berry 曲率
    re1 = 0.0
    do ie1 = 1, hn   ! 索引能带
    do ie2 = 1, hn
        if (ie2 /= ie1) then
            re1(ie1) = re1(ie1) + (Ave_Ham(hn, eigvecs(:, ie1), dHdkx, eigvecs(:, ie2)) * &
                            Ave_Ham(hn, eigvecs(:, ie2), dHdky, eigvecs(:, ie1))) / &
                            ((eigvals(ie1) - eigvals(ie2))**2 + omega)  ! 添加正则项防止除零
        endif
    end do
    end do
    calculate_berry_curvature_v1 = 2 * aimag(re1(ind_band))

end function calculate_berry_curvature_v1
!==============================================================================================================================================================
function calculate_berry_curvature_v2(kx,ky,ind_band)
    ! 计算某一条能带的 Berry 曲率的子程序
    ! 数值差分计算哈密顿量偏导
    use code_param
    implicit none
    integer,parameter::hn = 2  ! 哈密顿量维度
    integer ie1,ie2
    real(dp), intent(in) :: kx, ky
    integer, intent(in) :: ind_band
    real(dp) :: eigvals(hn),calculate_berry_curvature_v2
    complex(dp) :: re1(hn), dHdkx(hn,hn), dHdky(hn,hn), Ham(hn,hn), eigvecs(hn,hn)
    complex(dp),external::Ave_Ham

    call matset(kx,ky,Ham)
    call DH_kxky(kx,ky,dHdkx,dHdky)
    ! 计算哈密顿量的特征值和特征向量
    eigvecs = 0.0
    eigvals = 0.0
    call diagonalize_hermitian_matrix(hn, Ham, eigvecs, eigvals)

    ! 计算 Berry 曲率
    re1 = 0.0
    do ie1 = 1, hn   ! 索引能带
    do ie2 = 1, hn
        if (ie2 /= ie1) then
            re1(ie1) = re1(ie1) + (Ave_Ham(hn, eigvecs(:, ie1), dHdkx, eigvecs(:, ie2)) * &
                            Ave_Ham(hn, eigvecs(:, ie2), dHdky, eigvecs(:, ie1))) / &
                            ((eigvals(ie1) - eigvals(ie2))**2 + omega)  ! 添加正则项防止除零
        endif
    end do
    end do
    calculate_berry_curvature_v2 = 2 * aimag(re1(ind_band))

end function calculate_berry_curvature_v2
!==============================================================================================================================================================
subroutine matset(kx,ky,Ham)
    use code_param
    implicit none
    integer,parameter::hn = 2  ! 哈密顿量维度
    real(dp) kx,ky
    complex(dp) :: Ham(hn,hn)
    ! H = (m0 - tx cos(kx) - ty cos(ky))\sigma_z + ax sin(kx) \sigma_x + ay * sin(ky) * sigma_y
    Ham = 0.0
    Ham(1,1) = m0 - t1 * (cos(kx) + cos(ky)) - mu
    Ham(2,2) = -(m0 - t1 * (cos(kx) + cos(ky))) - mu
    Ham(1,2) = ax * sin(kx) - im * ay * sin(ky)
    Ham(2,1) = ax * sin(kx) + im * ay * sin(ky)
    return
end subroutine
!==============================================================================================================================================================
subroutine DH_kxky(kx,ky,Ham_dkx,Ham_dky)
    use code_param
    implicit none
    integer,parameter::hn = 2  ! 哈密顿量维度
    real(dp) kx,ky
    complex(dp) :: Ham_pk(hn,hn),Ham_mk(hn,hn),Ham_dkx(hn,hn),Ham_dky(hn,hn)
    call matset(kx + delta_k,ky,Ham_pk)
    call matset(kx - delta_k,ky,Ham_mk)
    Ham_dkx = (Ham_pk - Ham_mk)/(2.0 * delta_k)

    call matset(kx,ky + delta_k,Ham_pk)
    call matset(kx,ky - delta_k,Ham_mk)
    Ham_dky = (Ham_pk - Ham_mk)/(2.0 * delta_k)
    return
end subroutine
!==============================================================================================================================================================
function Ave_Ham(matdim,psi1,Ham,psi2)
    ! 计算  <psi_1|Ham|psi_2>
    use code_param
    implicit none
    integer i0,j0,matdim
    complex(dp) Ave_Ham,expectation,Ham(matdim,matdim),temp(matdim),psi1(matdim),psi2(matdim)
    expectation = 0.0
    do i0 = 1,matdim
        temp(i0) = 0.0
        do j0 = 1,matdim
            temp(i0) = temp(i0) + Ham(i0, j0) * psi2(j0)
        end do
    end do

    do i0 = 1,matdim
        expectation = expectation + conjg(psi1(i0)) * temp(i0)
    end do
    Ave_Ham = expectation
    return
end function 
!============================================================================================================================
subroutine squareBZ()
    ! 构建四方BZ
    use code_param
    integer ikx,iky,i0
    ! 对于四方点阵,BZ的点数可以直接确定
    numk_bz = (2 * Nk)**2   
    allocate(BZklist(2,numk_bz))
    i0 = 0
    open(30,file = "BZ.dat")
    do ikx = -Nk,Nk - 1
        do iky = -Nk,Nk - 1
            i0 = i0 + 1
            BZklist(1,i0) = pi * ikx/(1.0 * Nk)
            BZklist(2,i0) = pi * iky/(1.0 * Nk) 
            write(30,"(4F15.8)")BZklist(1,i0),BZklist(2,i0)
        end do
    end do
    close(30)
    return  
end subroutine
!==============================================================================================================================================================
subroutine diagonalize_Hermitian_matrix(matdim, matin, matout, mateigval)
    ! 厄米矩阵对角化
    ! matin 输入矩阵, matout 本征矢量, mateigval 本征值
    implicit none
    integer, parameter :: dp = kind(1.0d0)  ! 双精度
    integer, intent(in) :: matdim
    integer :: lda0, lwmax0, lwork, lrwork, liwork, info
    complex(dp), intent(in) :: matin(matdim, matdim)
    complex(dp), intent(out) :: matout(matdim, matdim)
    real(dp), intent(out) :: mateigval(matdim)
    complex(dp), allocatable :: work(:)
    real(dp), allocatable :: rwork(:)
    integer, allocatable :: iwork(:)
    !-----------------
    lda0 = matdim
    lwmax0 = 2 * matdim + matdim**2
    allocate(work(lwmax0))
    allocate(rwork(1 + 5 * matdim + 2 * matdim**2))
    allocate(iwork(3 + 5 * matdim))

    matout = matin
    lwork = -1
    liwork = -1
    lrwork = -1

    ! 初次调用 zheevd 获取最佳工作空间大小
    call zheevd('V', 'U', matdim, matout, lda0, mateigval, work, lwork, rwork, lrwork, iwork, liwork, info)

    ! 根据第一次调用的返回值重新调整工作空间大小
    lwork = min(2 * matdim + matdim**2, int(work(1)))
    lrwork = min(1 + 5 * matdim + 2 * matdim**2, int(rwork(1)))
    liwork = min(3 + 5 * matdim, iwork(1))

    ! 重新分配工作空间
    deallocate(work)
    allocate(work(lwork))
    deallocate(rwork)
    allocate(rwork(lrwork))
    deallocate(iwork)
    allocate(iwork(liwork))

    ! 第二次调用 zheevd 计算本征值和本征矢量
    call zheevd('V', 'U', matdim, matout, lda0, mateigval, work, lwork, rwork, lrwork, iwork, liwork, info)

    ! 错误处理
    if (info > 0) then
        open(11, file = "mes.dat", status = "unknown")
        write(11, *) 'The algorithm failed to compute eigenvalues.'
        close(11)
    end if

    return
end subroutine diagonalize_Hermitian_matrix

png

绘图代码

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rcParams
import os
import matplotlib.gridspec as gridspec

plt.rc('font', family='Times New Roman')
config = {
"font.size": 30,
"mathtext.fontset":'stix',
"font.serif": ['SimSun'],
}
rcParams.update(config) # Latex 字体设置
#----------------------------------------------------------
def plot_hall():
    dataname = "Hall-mu.dat"
    picname = os.path.splitext(dataname)[0] + ".png"
    da = np.loadtxt(dataname) 
    plt.figure(figsize = (10,10))
    plt.scatter(da[:,0],da[:,1], s = 20,c = "b")
    plt.xlabel(r"$m_0$")
    plt.ylabel(r"$\sigma_{xy}(e^2/\hbar)$")
    # plt.xlim(0,Umax)
    plt.tick_params(direction = 'in' ,axis = 'x',width = 0,length = 10)
    plt.tick_params(direction = 'in' ,axis = 'y',width = 0,length = 10)
    
    # plt.axis('scaled')
    ax = plt.gca()
    ax.locator_params(axis='x', nbins = 5)  # x 轴最多显示 3 个刻度
    ax.locator_params(axis='y', nbins = 5)  # y 轴最多显示 3 个刻度
    ax.spines["bottom"].set_linewidth(1.5)
    ax.spines["left"].set_linewidth(1.5) 
    ax.spines["right"].set_linewidth(1.5)
    ax.spines["top"].set_linewidth(1.5)
    # plt.show()
    plt.savefig(picname, dpi = 100,bbox_inches = 'tight')
    plt.close()
#------------------------------------------------------------
if __name__=="__main__":
    plot_hall()

所有文件可以点击这里下载.

公众号

相关内容均会在公众号进行同步,若对该Blog感兴趣,欢迎关注微信公众号。

QR Code

Email

yxli406@gmail.com