# Copyright (C) 2016 EDF
# All Rights Reserved
# This code is published under the GNU Lesser General Public License (GNU LGPL)
import numpy as np
import math
import utils.OneDimRegularSpaceGrid as rsg
import utils.OneDimData as data
import simulators.MeanRevertingSimulator as mrsim
import dp.OptimizeGasStorageSwitchingCost as ogssc
import StOptReg as reg
import StOptGrids
import dp.DynamicProgrammingByRegression as dyn
import unittest
import importlib

accuracyClose = 0.5


class ZeroFunction:
    
    def __init__(self):
        
        return None
    
    def set(self, a, b, c):
        
        return 0.
    
def testGasStorage() :
        
    # test MPI
    moduleMpi4Py=importlib.util.find_spec('mpi4py')
    if (moduleMpi4Py is not None):
       from mpi4py import MPI
       #########
       maxLevelStorage = 360000
       injectionRateStorage = 60000
       withdrawalRateStorage = 45000
       injectionCostStorage = 0.35
       withdrawalCostStorage = 0.35
       switchingCostStorage =  4.

       maturity = 1.
       nstep = 10

       # define a a time grid
       timeGrid = rsg.OneDimRegularSpaceGrid(np.zeros(1), maturity / nstep, nstep)
       futValues = np.zeros(nstep + 1)
       # periodicity factor
       iPeriod = 52

       for i in range(nstep + 1):
           futValues[i] = 50. + 20 * math.sin((math.pi * i * iPeriod) / nstep)

       # define the future curve
       futureGrid = data.OneDimData(timeGrid, futValues)
       # one dimensional factors
       nDim = 1
       sigma = np.zeros(nDim) + 0.94
       mr = np.zeros(nDim) + 0.29
       # number of simulations
       nbsimulOpt = 20000
       # grid
       #####
       nGrid = 40
       lowValues = np.zeros(1, dtype = float)
       step = np.zeros(1, dtype = float) + maxLevelStorage / nGrid
       nbStep = np.zeros(1, dtype = np.int32) + nGrid
       grid = StOptGrids.RegularSpaceGrid(lowValues, step, nbStep)

       # no actualization
       rate=0.
       # a backward simulator
       ######################
       bForward = False
       backSimulator = mrsim.MeanRevertingSimulator(futureGrid, sigma, mr, rate,maturity, nstep, nbsimulOpt, bForward)
       # optimizer
       ############
       tval = np.zeros(2)
       tval[0] = 0.
       tval[1] = 1.e30
       timeGrid = StOptGrids.OneDimSpaceGrid(tval)
       values = np.zeros(2, dtype = np.int32)
       values[0] = 3
       values[1] = 3
       regime = data.OneDimData(timeGrid, values)
       storage = ogssc.OptimizeGasStorageSwitchingCost(injectionRateStorage, withdrawalRateStorage, injectionCostStorage, withdrawalCostStorage, switchingCostStorage, regime)
       # regressor
       ##########
       nMesh = 4
       nbMesh = np.zeros(1, dtype = np.int32) + nMesh
       regressor = reg.LocalLinearRegression(nbMesh)
       # final value
       vFunction = ZeroFunction()

       # initial values
       initialStock = np.zeros(1) + maxLevelStorage
       initialRegime = 0 # here do nothing (no injection, no withdrawal)

       # Optimize
       ###########
       fileToDump = "CondExpGasSwiCost"
       # link the simulations to the optimizer
       storage.setSimulator(backSimulator)
       valueOptim = dyn.DynamicProgrammingByRegression(grid, storage, regressor, vFunction, initialStock, initialRegime, fileToDump)
       print("valOP", valueOptim)

class testGasStorageSwitchCostTest(unittest.TestCase):
         
    def test_gasStorageSwitchCost(self):
        
        testGasStorage()
    
if __name__ == '__main__':
    
    unittest.main()
