Fortran语言中二维Ising模型的相变

Fortran语言中二维Ising模型的相变,fortran,physics,montecarlo,Fortran,Physics,Montecarlo,我正在使用Metropolis Montecarlo算法研究二维伊辛模型。当我绘制平均磁化强度与温度的关系图时,相变应该在2.5K左右,但我的相变在0.5到1.0之间。但是用python编写的类似代码给出了正确的结果 输出: program ising_model implicit none integer, allocatable, dimension(:,:) :: lattice real, allocatable, dimension(:)

我正在使用Metropolis Montecarlo算法研究二维伊辛模型。当我绘制平均磁化强度与温度的关系图时,相变应该在2.5K左右,但我的相变在0.5到1.0之间。但是用python编写的类似代码给出了正确的结果

输出:

program ising_model
    implicit none
    integer,  allocatable, dimension(:,:)   :: lattice
    real, allocatable, dimension(:)         :: mag
    integer                                 :: row, col, dim, mcs, sweeps, relax_sweeps
    real                                    :: j, dE, B, temp, rval

    ! specify the file name
    open(12,file='myoutput.txt')

    ! square - lattice specification
    dim = 25

    ! coupling constant
    j = 1.0

    ! magnetic field
    B = 0.0

    ! number of montecarlo simulations
    mcs = 100

    ! sparse averaging
    relax_sweeps = 50

    allocate(lattice(dim, dim))
    allocate(mag(mcs + relax_sweeps))
    call spin_array(dim, lattice)
    !call outputarray(dim, lattice)

    temp = 0.1
    do while (temp .le. 5.0)
        mag = 0
        do sweeps =  1, mcs + relax_sweeps
            ! One complete sweep
            do row = 1, dim
                do col = 1, dim
                    call EnergyCal(row, col, j, B, lattice, dim, dE)
                    call random_number(rval)
                    if (dE .le. 0) then
                        lattice(row,col) = -1 * lattice(row,col)
                    elseif (exp(-1 * dE / temp) .ge. rval) then
                        lattice(row,col) = -1 * lattice(row,col)
                    else
                        lattice(row,col) = +1 * lattice(row,col)
                    end if
                end do
            end do
            mag(sweeps) = abs(sum(lattice))/float((dim * dim))
        end do
        write(12,*) temp, sum(mag(relax_sweeps:))/float(mcs + relax_sweeps)
        temp = temp + 0.01
    end do
    !print*,''
    !call outputarray(dim, lattice)
end program ising_model

!--------------------------------------------------------------
!   subroutine to print array
!--------------------------------------------------------------
subroutine outputarray(dim, array)
    implicit none
    integer                         :: col, row, dim, id
    integer, dimension(dim, dim)    :: array
    do row = 1, dim
        write(*,10) (array(row,col), col = 1, dim)
10  format(100i3)
    end do
end subroutine outputarray

!--------------------------------------------------------------
!   subroutine to fill the square lattice with spin randomly
!--------------------------------------------------------------
subroutine spin_array(dim, array)
    implicit none
    integer                         :: dim, row, col
    real                            :: rval
    integer, dimension(dim, dim)    :: array
    do row = 1, dim
        do col = 1, dim
            call random_number(rval)
            if (rval .ge. 0.5) then
                array(row, col) = +1
            else
                array(row, col) = -1
            end if
        end do
    end do
end subroutine spin_array

!--------------------------------------------------------------
!   subroutine to calculate energy
!--------------------------------------------------------------
subroutine EnergyCal(row, col, j, B, array, dim, dE)
    implicit none
    integer, intent(in)                         :: row, col, dim
    real, intent(in)                            :: j, B
    integer                                     :: left, right, top, bottom
    integer, dimension(dim, dim), intent(in)    :: array
    real, intent(out)                           :: dE

    if (row == 1) then
        top = dim
    else 
        top = row - 1
    end if 

    if (row == dim) then
        bottom = 1
    else 
        bottom = row - 1
    end if

    if (col == 1) then
        left = dim
    else 
        left = col - 1
    end if

    if (col == dim) then
        right = 1
    else 
        right = col - 1
    end if

    dE = 2 * j * array(row, col) * ((array(top, col) + array(bottom, col) + &
            array(row, left) + array(row, right)) + B * sum(array))
end subroutine EnergyCal
  • 晶格尺寸=25 x 25
  • 蒙特卡洛模拟的数量=100
  • 温度:0.1-5.0
  • 外磁场B=0
  • Fortran代码:

    program ising_model
        implicit none
        integer,  allocatable, dimension(:,:)   :: lattice
        real, allocatable, dimension(:)         :: mag
        integer                                 :: row, col, dim, mcs, sweeps, relax_sweeps
        real                                    :: j, dE, B, temp, rval
    
        ! specify the file name
        open(12,file='myoutput.txt')
    
        ! square - lattice specification
        dim = 25
    
        ! coupling constant
        j = 1.0
    
        ! magnetic field
        B = 0.0
    
        ! number of montecarlo simulations
        mcs = 100
    
        ! sparse averaging
        relax_sweeps = 50
    
        allocate(lattice(dim, dim))
        allocate(mag(mcs + relax_sweeps))
        call spin_array(dim, lattice)
        !call outputarray(dim, lattice)
    
        temp = 0.1
        do while (temp .le. 5.0)
            mag = 0
            do sweeps =  1, mcs + relax_sweeps
                ! One complete sweep
                do row = 1, dim
                    do col = 1, dim
                        call EnergyCal(row, col, j, B, lattice, dim, dE)
                        call random_number(rval)
                        if (dE .le. 0) then
                            lattice(row,col) = -1 * lattice(row,col)
                        elseif (exp(-1 * dE / temp) .ge. rval) then
                            lattice(row,col) = -1 * lattice(row,col)
                        else
                            lattice(row,col) = +1 * lattice(row,col)
                        end if
                    end do
                end do
                mag(sweeps) = abs(sum(lattice))/float((dim * dim))
            end do
            write(12,*) temp, sum(mag(relax_sweeps:))/float(mcs + relax_sweeps)
            temp = temp + 0.01
        end do
        !print*,''
        !call outputarray(dim, lattice)
    end program ising_model
    
    !--------------------------------------------------------------
    !   subroutine to print array
    !--------------------------------------------------------------
    subroutine outputarray(dim, array)
        implicit none
        integer                         :: col, row, dim, id
        integer, dimension(dim, dim)    :: array
        do row = 1, dim
            write(*,10) (array(row,col), col = 1, dim)
    10  format(100i3)
        end do
    end subroutine outputarray
    
    !--------------------------------------------------------------
    !   subroutine to fill the square lattice with spin randomly
    !--------------------------------------------------------------
    subroutine spin_array(dim, array)
        implicit none
        integer                         :: dim, row, col
        real                            :: rval
        integer, dimension(dim, dim)    :: array
        do row = 1, dim
            do col = 1, dim
                call random_number(rval)
                if (rval .ge. 0.5) then
                    array(row, col) = +1
                else
                    array(row, col) = -1
                end if
            end do
        end do
    end subroutine spin_array
    
    !--------------------------------------------------------------
    !   subroutine to calculate energy
    !--------------------------------------------------------------
    subroutine EnergyCal(row, col, j, B, array, dim, dE)
        implicit none
        integer, intent(in)                         :: row, col, dim
        real, intent(in)                            :: j, B
        integer                                     :: left, right, top, bottom
        integer, dimension(dim, dim), intent(in)    :: array
        real, intent(out)                           :: dE
    
        if (row == 1) then
            top = dim
        else 
            top = row - 1
        end if 
    
        if (row == dim) then
            bottom = 1
        else 
            bottom = row - 1
        end if
    
        if (col == 1) then
            left = dim
        else 
            left = col - 1
        end if
    
        if (col == dim) then
            right = 1
        else 
            right = col - 1
        end if
    
        dE = 2 * j * array(row, col) * ((array(top, col) + array(bottom, col) + &
                array(row, left) + array(row, right)) + B * sum(array))
    end subroutine EnergyCal
    

    在哪些地方,我可以使用任何内置函数(如周期性边界条件)减少代码行数并提高模拟速度?

    感谢@Ian Bush提供有关错误的提示。 我完全搞砸了我的周期边界条件,这个代码应该是

    ! periodic boundry condtions
        left = col - 1
        if (col .eq. 1) left = dim
    
        right = col + 1
        if (col .eq. dim) right = 1
    
        top = row - 1
        if (row .eq. 1) top = dim
    
        bottom = row + 1
        if (row .eq. dim) bottom = 1
    


    30多年科学编码的头号秘诀:如果你得到了错误的答案,不要担心速度。除此之外,您还必须更详细地告诉我们您想要实现的目标-伊辛模型对这里的大多数人来说几乎毫无意义。30多年科学编码的第二个技巧:始终在打开所有运行时检查的情况下进行开发。如果我使用gfortran并使用-fcheck=all进行编译并在文件Ising.f90 Fortran运行时错误:数组“array”的维度1的索引“0”低于1的下限“您已经搞糟了边界条件”。因为这看起来像是家庭作业,我只想说,除非你是我的学生,否则我会因为在每个子程序的调用点没有一个作用域中的接口而失败一个基本上不错的代码,始终使用模块或包含的子程序,其原因与使用隐式无的原因完全相同-请参阅我对@IanBush的回答谢谢您的帮助。我不明白你最后的评论。任何消息来源都将不胜感激。我在这方面还是个新手Fortran@147875该评论建议将所有子程序和函数放入模块中。