!****************************************************************************
!
!	MODULE:  Params
!
!	PURPOSE:  Declares and initializes global variables
!			 
!	AUTHOR:	 Ben Malin 
!
!	DATE:  11/2007
!****************************************************************************

module Params
  
  implicit none
  
  integer,parameter :: prec = selected_real_kind(15,307)
  real(prec),parameter :: pie = 3.1415926535897932
  
  !------------------------------
  !Number of 'state' variables
  !------------------------------
  integer,parameter :: N = COUNTRIES 	   !Number of countries  
  integer,parameter :: d = 2*COUNTRIES !2*N!   !Dimension of state space (capital and tech shock)
  integer,parameter :: q = 2*COUNTRIES+2 !d+2!   !In smolyak interpolation algorithm, lambda = q-d

  !----------------------
  !Parameters of model
  !----------------------
  real(prec),parameter :: gamma = 0.25	!Risk aversion parameter
  real(prec) :: xgamma = 1.0/gamma      !Intertemporal Elasticity of Substitution
  real(prec),parameter :: eta = 0.1     !Labor supply elasticity parameter
  real(prec) :: xeta = 1.0/eta          !Frisch elasticity of labor supply
  real(prec),parameter :: betah = 0.99	!Subjective discount factor
  real(prec),parameter :: alpha = 0.36	!Capital Share
  real(prec),parameter :: delta = 0.025	!Depreciation
  real(prec) :: kappa = 0.5		!Adjustment Cost parameter  ("phi" in paper)
  
  real(prec) :: A_tfp = (1-betah)/(alpha*betah)	 !Total Factor Productivity
  real(prec),parameter :: sigma = 0.01	 !var of tech. shock
  real(prec),parameter :: rho = 0.95     !Persistence of tech. shock
  
  real(prec),dimension(N) :: Pareto    !Pareto weights for each of N countries (set in Grid)

  real(prec) :: b   !Utility parameter for labor
  real(prec) :: Lfoc !Parameter in intratemporal first order condition
  real(prec) :: Lelast !Used in intratemporal first order condition
  
  !--------------------------------
  !Variables for grid subroutine
  !--------------------------------
  real(prec) :: kss	! deterministic steady state capital stock
  real(prec) :: kmax	! used to put upper bound on capital grid
  real(prec) :: kmin	! used to put lower bound on capital grid

  real(prec) :: lss	! deterministic steady state labor supply
  
  real(prec) :: zmax	! largest positive shock is e^(zmax)
  real(prec) :: zmin	! largest negative shock is e^(zmin)
  
  !--------------------------------------------
  !Weights used in formulas for interpolation 
  !--------------------------------------------
  integer :: coc1	!Used in weighted sum of cheb polynomials in Smolyak interpolation
  integer :: coc2	!coc1 is (d-1) choose 1 and coc2 is (d-1) choose 2
  
  !--------------------------------------------------------
  !Variables that hold coefficients of policy functions 
  !--------------------------------------------------------
  real(prec),dimension(d,2**(q-d)+1,N) :: CoeffsCons3	!Coeffs for 4th order polynomials for each of d dims
  real(prec),dimension(d,2**(q-d)+1,N) :: CoeffsCap3    !Coeffs for 4th order polynomials for each of d dims
  real(prec),dimension(d,2**(q-d)+1,N) :: CoeffsLab3    !Coeffs for 4th order polynomials for each of d dims
  real(prec),dimension(d,2**(q-d-1)+1,N) :: CoeffsCons1	!Coeffs for 2nd order polynomials for each of d dims
  real(prec),dimension(d,2**(q-d-1)+1,N) :: CoeffsCap1	!Coeffs for 2nd order polynomials for each of d dims
  real(prec),dimension(d,2**(q-d-1)+1,N) :: CoeffsLab1	!Coeffs for 2nd order polynomials for each of d dims
  real(prec),dimension(d-1,d,2**(q-d-1)+1,2**(q-d-1)+1,N) :: CoeffsCons2 !Coeffs for 2nd order tensor prods
  real(prec),dimension(d-1,d,2**(q-d-1)+1,2**(q-d-1)+1,N) :: CoeffsCap2	 !Coeffs for 2nd order tensor prods
  real(prec),dimension(d-1,d,2**(q-d-1)+1,2**(q-d-1)+1,N) :: CoeffsLab2	 !Coeffs for 2nd order tensor prods
  real(prec),dimension(N) :: yCons0		!Policy function (consumption) evaluated at point0
  real(prec),dimension(N) :: yCap0		!Policy function (capital) evaluated at point0
  real(prec),dimension(N) :: yLab0		!Policy function (labor) evaluated at point0
  
  !--------------------------------
  !General global variables
  !--------------------------------
  integer :: FOCi
  real(prec),dimension(N) :: SimConsumption, SimLabor, SimCapTom, SimOutput
  real(prec),dimension(N) :: SimCapital, shock
  real(prec),dimension(2*N) :: instate
  real(prec),dimension(4*N) :: Results
  
contains
  
  !*************************
  !** Primative Functions **
  !*************************
  
  !-------------------------------------------------------
  ! function Ucc
  !
  !	2nd Derivative of (CRRA) utility function with
  !	coefficient of relative risk aversion 1/gamma
  !
  ! Inputs:	c -- real, consumption 
  ! Returns:	real -- U"(c) 
  !
  !-------------------------------------------------------
  
  function Ucc(c)
    implicit none
    real(prec) :: Ucc
    real(prec), intent(in) :: c
    real(prec) :: epsilon
    
    epsilon = (10.0)**(-6)
    
    if (c < epsilon) then
       print*, 'c is below lower bound in the function Ucc, c = ', c	
       !pause
       Ucc = -xgamma * epsilon**(-xgamma - 1.0)
    else
       Ucc = -xgamma * c**(-xgamma - 1.0)
    end if
    
  end function Ucc
  
  !---------------------------------------------------
  ! function Uc
  !
  !	(CRRA) marginal utility function with
  !	coefficient of relative risk aversion 1/gamma
  !
  ! Inputs:	c -- real, consumption 
  ! Returns:	real, marginal utility 
  !
  !---------------------------------------------------
  
  function Uc(c)
    implicit none
    real(prec) :: Uc
    real(prec), intent(in) :: c
    real(prec) :: epsilon
    
    epsilon = (10.0)**(-6)
    
    if (c < epsilon) then
       print*, 'c is below lower bound in the function Uc, c = ', c
       pause
       Uc = epsilon**(-xgamma) + Ucc(epsilon) * (c - epsilon)
    else
       Uc = c**(-xgamma)
    end if
    
  end function Uc
  
  !-------------------------------------------------------
  ! function Ull
  !
  !	2nd Derivative of (CRRA) utility function wrt
  !	labor
  !
  ! Inputs:	lab -- real, labor supply 
  ! Returns:	real -- U"(lab) 
  !
  !-------------------------------------------------------
  
  function Ull(lab)
    implicit none
    real(prec) :: Ull
    real(prec), intent(in) :: lab
    real(prec) :: epsilon
    
    epsilon = (10.0)**(-6)
    
    if (lab < epsilon) then
       print*, 'lab below lower bound in the function Ull, lab = ', lab	
       !pause
       Ull = -b * xeta * epsilon**(xeta - 1.0)
    else
       Ull = -b * xeta * lab**(xeta - 1.0)
    end if
    
  end function Ull
  
  !--------------------------------------------------------
  ! function UlUc
  !
  !	Marginal Rate of Substitution between consumption 
  !     and labor
  !
  ! Inputs:	c -- real, consumption
  !             lab -- real, labor supply
  ! Returns:	real, marginal rate of substitution
  !
  !--------------------------------------------------------
  
  function UlUc(c,lab)
    implicit none
    
    real(prec) :: UlUc	
    real(prec), intent(in) :: c
    real(prec), intent(in) :: lab
    real(prec) :: epsilon
    
    epsilon = (10.0)**(-6)
    
    if (c < epsilon .and. lab < epsilon) then
       print*, "Error - consumption below lower bound in UlUc, c = ", c
       print*, "Error - labor below lower bound in UlUc, l = ", lab
       pause
       UlUc = -1.0 * (-b * epsilon**(xeta) + Ull(epsilon) * (lab - epsilon)) * &
            & (epsilon**(-xgamma) + Ucc(epsilon) * (c - epsilon))**(-1.0)
    elseif (c < epsilon .and. lab >= epsilon) then
       print*, "Error - consumption below lower bound in UlUc, c = ", c
       pause
       UlUc = b * lab**(xeta)  * &
            & (epsilon**(-xgamma) + Ucc(epsilon) * (c - epsilon))**(-1.0)
    elseif (c >= epsilon .and. lab < epsilon) then
       print*, "Error - labor below lower bound in UlUc, l = ", lab
       pause
       UlUc = -1.0 * (-b * epsilon**(xeta) + Ull(epsilon) * (lab - epsilon)) * &
            & c**(xgamma)
    else
       UlUc = b * lab**(xeta) * c**(xgamma)
    end if

  end function UlUc

  !------------------------------------------------------------------------------------
  ! function F
  !
  !	Production Function - Takes country-specific capital stock and 
  !	technology shock and returns output.
  !
  ! Inputs:	capital -- real, capital level
  !             lab -- real, labor supply
  !	        sh -- real, technological shock   
  ! Returns:	real, output
  !
  !------------------------------------------------------------------------------------
  
  function F(capital,lab,sh)
    implicit none
    real(prec) :: F
    real(prec), intent(in) :: capital,lab,sh
    real(prec) :: epsilon
    
    epsilon = (10.0)**(-6)
    
    if (capital >= epsilon .and. lab >= epsilon) then
       F =  A_tfp * exp(sh) * capital**alpha * lab**(1.0-alpha)
    elseif (capital < epsilon .and. lab >= epsilon) then
       print*, "Error - Capital Stock is negative in F, cap = ", capital 
       pause
       F = 0
    elseif (capital >= epsilon .and. lab < epsilon) then
       print*, "Error - Labor is negative in F, lab = ", lab 
       pause
       F = 0
    else
       print*, "Error - Capital Stock is negative in F, cap = ", capital 
       print*, "Error - Labor is negative in F, lab = ", lab 
       pause
       F = 0
    end if
    
  end function F
  
  !----------------------------------------------------------------------------
  ! function Fk
  !
  !	Marginal Product of Capital - Takes country specific capital stock and 
  !	technology shock and returns mpk.
  !
  ! Inputs:	capital -- real, capital level
  !             lab -- real, labor supply
  !		sh -- real, technological shock   
  ! Returns:	real, mpk
  !
  !----------------------------------------------------------------------------
  
  function Fk(capital,lab,sh)
    implicit none
    real(prec) :: Fk
    real(prec), intent(in) :: capital,lab,sh
    real(prec) :: epsilon
    
    epsilon = (10.0)**(-6)
    
    if (capital >= epsilon .and. lab >= epsilon) then
       Fk =  alpha * A_tfp * exp(sh) * (capital/lab)**(alpha-1.0)
    elseif (capital < epsilon .and. lab >= epsilon) then
       print*, "Error - Capital Stock is negative in Fk, cap = ", capital  
       pause
       Fk =  alpha * A_tfp * exp(sh) * epsilon**(alpha-1.0) * lab**(1.0-alpha)
    elseif (capital >= epsilon .and. lab < epsilon) then
       print*, "Error - Labor Supply is negative in Fk, lab = ", lab  
       pause
       Fk =  alpha * A_tfp * exp(sh) * capital**(alpha-1.0) * epsilon**(1.0-alpha)
    else
       print*, "Error - Capital Stock is negative in Fk, cap = ", capital  
       print*, "Error - Labor Supply is negative in Fk, lab = ", lab  
       pause
       Fk =  alpha * A_tfp * exp(sh) * epsilon**(alpha-1.0) * epsilon**(1.0-alpha)
    end if
    
  end function Fk
  
  !----------------------------------------------------------------------------
  ! function Fl
  !
  !	Marginal Product of Labor - Takes country specific capital stock and 
  !	technology shock and returns mpl.
  !
  ! Inputs:	capital -- real, capital level
  !             lab -- real, labor supply
  !		sh -- real, technological shock   
  ! Returns:	real, mpl
  !
  !----------------------------------------------------------------------------
  
  function Fl(capital,lab,sh)
    implicit none
    real(prec) :: Fl
    real(prec), intent(in) :: capital,lab,sh
    real(prec) :: epsilon
    
    epsilon = (10.0)**(-6)
    
    if (capital >= epsilon .and. lab >= epsilon) then
       Fl = (1.0-alpha) * A_tfp * exp(sh) * (capital/lab)**(alpha) 
    elseif (capital < epsilon .and. lab >= epsilon) then
       print*, "Error - Capital Stock is negative in Fl, cap = ", capital  
       pause
       Fl = (1.0-alpha) * A_tfp * exp(sh) * epsilon**(alpha) * lab**(-alpha)
    elseif (capital >= epsilon .and. lab < epsilon) then
       print*, "Error - Labor Supply is negative in Fl, lab = ", lab  
       pause
       Fl = (1.0-alpha) * A_tfp * exp(sh) * capital**(alpha) * epsilon**(-alpha)
    else
       print*, "Error - Capital Stock is negative in Fl, cap = ", capital  
       print*, "Error - Labor Supply is negative in Fl, lab = ", lab  
       pause
       Fl = (1.0-alpha) * A_tfp * exp(sh) * epsilon**(alpha) * epsilon**(-alpha)
    end if
    
  end function Fl
  
end module Params
