!!------------------------------------------------------------------------
! $Id: american_mc.f90,v 1.2 1997/12/19 21:15:03 scott Exp $
!!Written by Scott A. Klasky
!!Copyright Scott A. Klasky, Geoffrey Fox, Mike Boughton, Scott McGuire
!! and NPAC, Syracuse University
!!Program to calculate American options
!!
!!First attempt: 10,19,1997-
!!Modified 10/21/1997 by Scott V. McGuire
!!   NOTES: Limitations on this program include the following:
!!          Only made to work with 1 underlying (will change data structures
!!          later).
!!------------------------------------------------------------------------

!! Want to define the Data structure before we begin, because this will 
!! make it much easier to code with the proper data structure.

program american
  use PATHS
  use MOD_INT
  use input_params
  implicit none

  type (PATH),dimension(:,:),save,allocatable    :: eta,sorteta
  real*8,dimension(:,:),save,allocatable         :: payoff, stockprice
  real*8,dimension(:,:),save,allocatable         :: sortpayoff 
  integer,dimension(:,:),save,allocatable        :: sort_order,sort_orderi
  real*8,dimension(:),save,allocatable           :: min_energy 

  type (PATH),dimension(:,:),save,allocatable    :: etac,sortetac
  real*8,dimension(:,:),save,allocatable         :: payoffc, stockpricec
  real*8,dimension(:,:),save,allocatable         :: sortpayoffc
  integer,dimension(:,:),save,allocatable        :: sort_orderc,sort_orderci
  real*8,dimension(:),save,allocatable           :: min_energyc
	real*8,dimension(:),save,allocatable           :: cab,cabc


  integer                                        :: max_nn, ipot, jpot
  integer                                        :: max_iter
  integer                                        :: ntime, npath, nn
  integer                                        :: tl, ol, iter, otl
  integer,parameter                              :: max_params = 30
  real*8,dimension(max_params)                   :: params
  character*10,parameter                         :: fname="path.stock"
  real*8                                         :: total_energy

  real*8                                         :: energy, oldenergy
  real*8                                         :: newenergy,oldpe,oldke,newpe
  real*8                                         :: newke,deltae
  real*8                                         :: spin_new 
  real*8                                         :: r1
  real*8,parameter                               :: HALF = 0.5d0
  integer,parameter                              :: SEED = 100

  real*8                                         :: paymax,pay1d
  real*8                                         :: temp
  integer                                        :: anealing,path0
  integer                                        :: tnum
  integer                                        :: flips
  integer                                        :: annealing
  real*8                                         :: r,sss
  integer                                        :: i,j
  integer                                        :: jiter, ool, j1iter, olsave
  integer                                        :: accept,reject 
  real*8                                         :: avgpayoff
  integer                                        :: spin_total,ispin
  integer                                        :: olstart

! coarse grid variables
	integer                                        :: npathc
	integer                                        :: olc

  !! read in the parameters (Stock Price, Strike price, etc.
  !! read in the data from the european MC code
  !! Next sort the list in the Stock Price Dimension
  !! Next find the nearest neighbor list
  !! Set up the initial spins
  !! Find the initial energy of the system

	

  call random_seed(SEED)

  call read_params(max_params,params)

  !! allocate the memory
  ntime = int(params(P_NTIME))
  npath = int(params(P_NPATH))
  npathc= int( 1 + (int(params(P_NPATH))/2))
  nn    = int(params(P_NNN))

  allocate ( eta(ntime,npath),sorteta(ntime,npath) ) 
  allocate ( payoff(ntime,npath) ) 
  allocate ( stockprice(ntime,npath) ) 
  allocate ( sort_order(ntime,npath) )
  allocate ( sort_orderi(ntime,npath) )
  allocate ( sortpayoff(ntime,npath) )

  allocate ( cab(ntime) )

! coarse grid
  allocate ( etac(ntime,npathc),sortetac(ntime,npathc) ) 
  allocate ( payoffc(ntime,npathc) ) 
  allocate ( stockpricec(ntime,npathc) ) 
  allocate ( sort_orderc(ntime,npathc) )
  allocate ( sort_orderci(ntime,npathc) )
  allocate ( sortpayoffc(ntime,npathc) )
  allocate ( cabc(ntime) )


  do  tl = 1 , ntime 
     do ol = 1 , npath 
        allocate(eta(tl,ol)%nns(nn)) 
        allocate(eta(tl,ol)%nng(nn)) 
        allocate(eta(tl,ol)%nnt(nn)) 
        allocate(eta(tl,ol)%nni(nn)) 
        allocate(eta(tl,ol)%nnj(nn)) 
        allocate(sorteta(tl,ol)%nns(nn)) 
        allocate(sorteta(tl,ol)%nng(nn)) 
        allocate(sorteta(tl,ol)%nnt(nn)) 
        allocate(sorteta(tl,ol)%nni(nn)) 
        allocate(sorteta(tl,ol)%nnj(nn)) 
     end do !ol
  end do !tl

  do  tl = 1 , ntime 
     do olc = 1 , npathc
        allocate(etac(tl,olc)%nns(nn)) 
        allocate(etac(tl,olc)%nng(nn)) 
        allocate(etac(tl,olc)%nnt(nn)) 
        allocate(etac(tl,olc)%nni(nn)) 
        allocate(etac(tl,olc)%nnj(nn)) 
        allocate(sortetac(tl,olc)%nns(nn)) 
        allocate(sortetac(tl,olc)%nng(nn)) 
        allocate(sortetac(tl,olc)%nnt(nn)) 
        allocate(sortetac(tl,olc)%nni(nn)) 
        allocate(sortetac(tl,olc)%nnj(nn)) 
     end do !olc
  end do !tl

  allocate (min_energy(int(params(P_ANNEALS))))
  allocate (min_energyc(int(params(P_ANNEALS))))

  call read_data(fname,max_params,params,stockprice)
  open(20,file='am.out')

  write(20,*) 'input parameters:'
  do tl = 1, max_params
     write(20,*) tl,params(tl)
  end do

  call sort_stock(max_params,params,stockprice,sort_order,sort_orderi,payoff)

  call calculate_payoff(max_params,params,payoff,sortpayoff)
  call find_nearest_neighbor_list(max_params,params,sortpayoff,eta)
  call initialize_spins(max_params,params,sortpayoff,eta)

  avgpayoff = 0
  do jpot=1,int(params(P_NPATH))
     do ipot=1,int(params(P_NTIME))
        if (eta(ipot,sort_order(ipot,jpot))%spin == 1) then
           avgpayoff = avgpayoff +  payoff(ipot,sort_order(ipot,jpot))
           exit
        end if
     end do !ipot
  end do !jpot
  avgpayoff = avgpayoff / params(P_NPATH)

  jiter = 0



!   do otl = int(params(P_NTIME))-1, int(params(P_NTIME))-1,-1 
    do otl = int(params(P_NTIME))-1, 1,-1 

!			call set_up_coarse_grid(int(params(P_NPATH)),otl,params,sort_orderi, &
!                              cabc,sortpayoff, &
!                              sortpayoffc,sort_orderc,sort_orderci,etac)

			
!			olsave =  grid_solve(int((1+int(params(P_NPATH)))/2),otl,params, &
!                           sortpayoff,eta, sort_order,sort_orderi)
!
!      write(6,*) 'olsave=',olsave
!			cab(otl) = sortpayoff(otl,olsave)
!			write(6,*) otl
			olsave =  grid_solve(int(params(P_NPATH)),otl,params,sortpayoff,eta, &
                           sort_order,sort_orderi)

      write(6,*) 'olsave=',olsave
			cab(otl) = sortpayoff(otl,olsave)
		  eta(otl,:)%spin = 0
		  eta(otl,1:olsave-1)%spin = 1
		
	end do !otl

  avgpayoff = 0.0d0
  do jpot=1,int(params(P_NPATH))
     do ipot=1,int(params(P_NTIME))
        if (eta(ipot,sort_order(ipot,jpot))%spin == 1) then
           avgpayoff = avgpayoff +  sortpayoff(ipot,sort_order(ipot,jpot))
           exit
        end if
     end do !ipot
  end do !jpot
  avgpayoff = avgpayoff / params(P_NPATH)

  call dump_dat1d("Boundary",otl,1.0d0*(ntime-otl),max_params,params, &
                  sortpayoff,eta)
	write(6,*) avgpayoff
	write(20,*) avgpayoff
  close(20)
end program american
