Fortran语言中二维Ising模型的相变
我正在使用Metropolis Montecarlo算法研究二维伊辛模型。当我绘制平均磁化强度与温度的关系图时,相变应该在2.5K左右,但我的相变在0.5到1.0之间。但是用python编写的类似代码给出了正确的结果 输出: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(:)
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
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该评论建议将所有子程序和函数放入模块中。