program ising
  implicit none
  integer, parameter :: lmax=100
  real(kind(1.d0)), parameter :: JJ = 1.d0
  real(kind(1.d0)), external :: rndm
  real(kind(1.d0)) :: Etot, Hlocal, deltaE, beta
  real(kind(1.d0)) :: avgE, avgE2, avgM, avgM2, varE, varM
  integer :: L, M, icycle, Ncycle, k, ibeta, Nbeta
  integer :: i, j, ileft, iright, jup, jdown
  integer :: sigma(0:lmax,0:lmax)
  logical :: hot_start
  
  call set_rndm_seed(9879879)
  write (*,'(a,$)') " lattice size (L) >> "
  read (*,*) L
  write (*,*) L
  if (L>lmax) stop " L > lmax"
  if (L.le.0) stop " L .le. 0"
  write (*,'(a,$)') " hot start ? (T/F)>> "
  read (*,*) hot_start
  write (*,*) hot_start
! cold start
  sigma(0:L-1,0:L-1) = 1
! hot start
  if (hot_start) then
     do i=0,L-1
        do j=0,L-1
           if (rndm() > 0.5d0) sigma(i,j) = -1
        end do
     end do
  end if
! magnetization
  call magnetization(sigma,L,lmax,M)
  write (*,*) ' Starting magnetization = ', M
! Energy
  call energy(sigma,L,lmax,JJ,Etot)
  write (*,*) ' Starting energy = ', Etot

  write (*,'(a,$)') " Ncycle, Nbeta >> "
  read(*,*) Ncycle, Nbeta
  write(*,*) Ncycle, Nbeta

  write (*,*) "       beta,    Temp,     avgM/L2,    avgE/L2,    varM/L2,    varE/L2"
  do ibeta = 1, Nbeta

  read (*,*) beta
  avgM = 0.d0
  avgM2= 0.d0
  avgE = 0.d0
  avgE2= 0.d0
  do icycle = 1, Ncycle
     do k=1,L*L
        i = L*rndm()
        j = L*rndm()
        ileft  = mod(i+1,L)
        iright = i-1; if (iright<0) iright = iright + L
        jup    = mod(j+1,L)
        jdown  = j-1; if (jdown <0) jdown  = jdown  + L
        Hlocal = JJ * ( sigma(i,jup)    + sigma(i,jdown) + &
                        sigma(iright,j) + sigma(ileft,j) )
        deltaE = + 2 * Hlocal * sigma(i,j)
        if ( rndm() < exp( -beta * deltaE) ) then
           M = M - 2 * sigma(i,j)
           Etot = Etot + deltaE
           sigma(i,j) = - sigma(i,j)
!           call check_energy(sigma,L,lmax,JJ,Etot)
        end if
     end do 
     avgM = avgM + abs(M)
     avgE = avgE + Etot
     avgM2= avgM2+ M * M
     avgE2= avgE2+ Etot * Etot
  end do 
  avgM = avgM / Ncycle
  varM = avgM2/ Ncycle - avgM * avgM
  avgE = avgE / Ncycle
  varE = avgE2/ Ncycle - avgE * avgE

  write (*,'(6f12.4)') beta, 1.d0/beta, avgM/L/L,avgE/L/L,varM/L/L,varE/L/L

  end do

  stop
end program ising

subroutine magnetization(sigma,L,lmax,M)
   implicit none
   integer, intent(in) :: L, lmax, sigma(0:lmax,0:lmax)
   integer, intent(out):: M
   integer :: i,j
   M = 0
   do i=0,L-1
      do j=0,L-1
         M = M + sigma(i,j)
      end do
   end do
   return
end subroutine magnetization

subroutine energy(sigma,L,lmax,JJ,Etot)
   implicit none
   integer, intent(in) :: L, lmax, sigma(0:lmax,0:lmax)
   real(kind(1.d0)), intent(in) :: JJ
   real(kind(1.d0)), intent(out) :: Etot
   integer :: i,j, ileft, iright,jup,jdown
   real(kind(1.d0)):: Hlocal
   Etot = 0.d0
   do i=0,L-1
      do j=0,L-1
         ileft  = mod(i+1,L)
         iright = i-1; if (iright<0) iright = iright + L
         jup    = mod(j+1,L)
         jdown  = j-1; if (jdown <0) jdown  = jdown  + L
         Hlocal = JJ * ( sigma(i,jup)    + sigma(i,jdown) + &
                         sigma(iright,j) + sigma(ileft,j) )
         Etot = Etot - 0.5 * Hlocal * sigma(i,j)
! the factor 1/2 is because pair of interacting sites are counted only once
      end do
   end do
   return
end subroutine energy 

subroutine check_energy(sigma,L,lmax,JJ,Etot)
   implicit none
   integer, intent(in) :: L, lmax, sigma(0:lmax,0:lmax)
   real(kind(1.d0)), intent(in) :: JJ
   real(kind(1.d0)), intent(in) :: Etot
   real(kind(1.d0)), parameter :: small = 1.d-6
   real(kind(1.d0)) :: Enew
  
   call energy(sigma,L,lmax,JJ,Enew)
   if (abs(Enew-Etot) < small ) return
   write (*,*) Enew, Etot
   stop ' Energy calculation is not coinsistent'

end subroutine check_energy 
