我遇到了一个我编写的简单代码的问题。子程序能量应该计算系统的能量,并经常返回NaN。这样做的原因是因为值dd,粒子之间的距离变为零,我不知道为什么。我对Fortran比较新,我相信它可能与我如何传递类变量有关,这就是我来到这里的原因。代码和模块如下。
模块开始从输入文件定义类和读取值并打印到屏幕。
module get_started
implicit none
type input
integer :: np
integer :: istart
integer :: mceq,mcsteps
integer :: nsample, nadjust
double precision :: rcut,rcut2,rv,rv2,rcrv2
double precision :: maxd
double precision :: vol,box,hbox
double precision :: eps,sig
double precision :: dens
double precision :: temp
end type input
contains
subroutine init(param)
implicit none
type(input) :: param
open(unit=1,file='input')
read(1,*)param%rcut
read(1,*)param%np ! system's size
read(1,*)param%dens ! thermodynamical conditions
read(1,*)param%temp
read(1,*)param%istart
read(1,*)param%maxd
read(1,*)param%mceq,param%mcsteps
read(1,*)param%nsample
read(1,*)param%nadjust
param%eps = 1.0d0
param%sig = 1.0d0
param%rcut2 = param%rcut*param%rcut
param%rv = 1.1*param%rcut
param%rv2 = param%rv*param%rv
param%rcrv2 = (param%rv-param%rcut) * (param%rv-param%rcut)
param%vol = param%np/param%dens
param%box = param%vol**(1.0d0/3.0d0)
param%hbox = param%hbox/2
return
end subroutine init
subroutine print_input(param)
implicit none
type(input):: param
print*
print*,' A Monte Carlo program for Lennard-Jones particles'
print*,' -------------------------------------------------'
print*,' Lennard-Jones parameters:'
print*,' np=',param%np
print*,' eps= ',param%eps
print*,' sig= ',param%sig
print*,' rcut= ',param%rcut
print*,' rv =',param%rv
print*,' rv2 =',param%rv2
print*
print*,' Simulation box length: ',param%box
print*,' Volume : ',param%vol
print*,' Number density : ',param%dens
print*,' Temperature : ',param%temp
print*
print*
print*,' maxd : ',param%maxd
print*,' # eq steps : ',param%mceq
print*,' # MC steps : ',param%mcsteps
print*,' Sampling freq : ',param%nsample
print*,' Adjusting freq : ',param%nadjust
print*
return
end subroutine print_input
end module get_started
模块位置初始化粒子的位置
module position
use get_started
implicit none
integer:: numpd
double precision ::gsize
integer :: i,j,k
integer :: flag
contains
subroutine init_position(param,x,y,z,flag)
implicit none
type(input),intent(in) :: param
double precision :: x(param%np),y(param%np),z(param%np)
integer :: counter,flag
numpd = ceiling(param%np**(1.0d0/3.0d0))
print*,'numpd',numpd
print*,'box',param%box
gsize = param%box/numpd
print*,'gsize',gsize
if(flag.eq.0) then
counter =1
do i=1,numpd
do j=1,numpd
do k=1,numpd
if(counter.le.param%np)then
y(counter) = i*gsize
z(counter) = j*gsize
x(counter) = k*gsize
endif
counter = counter+1
enddo
enddo
enddo
else if(flag.eq.1) then
do i=1,param%np
x(i) = ran()*param%box
y(i) = ran()*param%box
z(i) = ran()*param%box
enddo
end if
open(unit=2,file='posit.dat')
do i =1,param%np
write(2,*)x(i),y(i),z(i)
enddo
close(unit=2)
return
end subroutine init_position
end module position
模块modmove_energy是所有操作所在的位置。在此模块中,包含应用蒙特卡洛移动(拾取粒子,随机位移,接受或拒绝移动)的子程序以及能量计算(这是错误所在的位置)。能量中的变量dd经常为非相同粒子返回零,从而导致NaN误差。
module modmove_energy
use get_started
contains
! note random generator function
subroutine move(potential,param,x,y,z,ar)
implicit none
integer :: ar,it,step
type(input),intent(in) :: param
double precision :: potential
double precision :: x(param%np),y(param%np),z(param%np)
double precision :: xold,yold,zold,drxold,dryold,drzold
double precision :: dr2
double precision :: uold,unew,delta
double precision :: alpha,beta,gamma
it = int(ran()*param%np)+1
call energy(uold,x,y,z,param)
alpha =param%maxd*(ran()-0.5)
beta =param%maxd*(ran()-0.5)
gamma =param%maxd*(ran()-0.5)
x(it) = x(it) + alpha
y(it) = y(it) + beta
z(it) = z(it) + gamma
if (x(it) > param%box) then
x(it)=x(it)-param%box
elseif (x(it) < 0.d0) then
x(it)=x(it)+param%box
endif
if (y(it) > param%box) then
y(it)=y(it)-param%box
else if (y(it) < 0.d0) then
y(it)=y(it)+param%box
endif
if (z(it) > param%box) then
z(it)=z(it)-param%box
else if (z(it) < 0.d0) then
z(it)=z(it)+param%box
endif
call energy(unew,x,y,z,param)
delta = unew-uold
if (delta < 0.) then
potential=potential+delta
ar=1
elseif (exp(-delta/(param%temp)) >= ran()) then
potential=potential+delta
ar=1
else
x(it)=xold
y(it)=yold
z(it)=zold
ar=0
endif
end subroutine move
subroutine energy(u,x,y,z,param)
implicit none
integer :: np,it
type(input),intent(in):: param
double precision :: u
double precision,intent(in) :: x(param%np),y(param%np),z(param%np)
integer :: i,j
double precision :: ddx,ddy,ddz,dd
u=0.0e0
do i=1,param%np-1
do j=i+1,param%np
ddx=x(i)-x(j)
ddy=y(i)-y(j)
ddz=z(i)-z(j)
if (ddx > param%hbox) ddx=ddx-param%box
if (ddy > param%hbox) ddy=ddy-param%box
if (ddz > param%hbox) ddz=ddz-param%box
if (ddx < -param%hbox) ddx=ddx+param%box
if (ddy < -param%hbox) ddy=ddy+param%box
if (ddz < -param%hbox) ddz=ddz+param%box
dd=sqrt(ddx*ddx+ddy*ddy+ddz*ddz)
if (dd <= param%rcut) then
u = u + ( (param%sig/dd)**12 - (param%sig/dd)**6 )
endif
enddo
enddo
u=u*4.0*param%eps
return
end subroutine energy
end module modmove_energy
最后,主程序如下
program lennard
use get_started
use position
use modmove_energy
implicit none
integer :: step,ar
integer :: seed1,seed2
type(input) :: param
double precision, allocatable :: x(:),y(:),z(:)
double precision :: potential
seed1 = 2*int(secnds(0.0))
seed2 = 1+seed1
call srand(seed2)
call init(param)
call print_input(param)
allocate (x(param%np),y(param%np),z(param%np))
call init_position(param,x,y,z,0)
do step=1,param%mceq
call move(potential,param,x,y,z,ar)
! print*,potential
enddo
stop
end program lennard
答案 0 :(得分:0)
很抱歉带走你们的家伙,感谢你们看到这个。错误是在子程序移动中,我在定义xold,yold,zold之前指定了x(it)= xold,y(it)= yold,z(it)= zold。菜鸟错误!