子程序返回NaN。类变量问题?

时间:2014-02-05 19:55:14

标签: fortran90

我遇到了一个我编写的简单代码的问题。子程序能量应该计算系统的能量,并经常返回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

1 个答案:

答案 0 :(得分:0)

很抱歉带走你们的家伙,感谢你们看到这个。错误是在子程序移动中,我在定义xold,yold,zold之前指定了x(it)= xold,y(it)= yold,z(it)= zold。菜鸟错误!