def test_local_dependency(): """Check that if all the production is local, the average price is equal to the local price.""" # Local production is equal to energy needs. There is no importation electric_production = baseline.production[['Coal', 'Gas' ]].loc[START_YEAR:END_YEAR + 1] useful_heat_rate = heat_rate[['Coal', 'Gas']] needed_production = pd.DataFrame(electric_production.values * useful_heat_rate.values, columns=useful_heat_rate.columns, index=useful_heat_rate.index) # Generate random international prices to test the independence of the result past_price_gas = [] past_price_coal = [] for _ in range(1970, 2016): past_price_coal.append(randint(1, 100)) for _ in range(1977, 2016): past_price_gas.append(randint(1, 100)) price_gas_compare = pd.DataFrame({'Price_Gas': past_price_gas}, index=range(1977, 2016)) price_coal_compare = pd.DataFrame({'Price_Coal': past_price_coal}, index=range(1970, 2016)) #Create the two objects to compare np.random.seed(0) fuel_1 = price_fuel(local_prices, price_gas, price_coal, needed_production, baseline) np.random.seed(0) fuel_2 = price_fuel(local_prices, price_gas_compare, price_coal_compare, needed_production, baseline) assert fuel_1.average_price["Gas"].all( ) == fuel_2.average_price["Gas"].all() assert fuel_1.average_price["Coal"].all( ) == fuel_2.average_price["Coal"].all()
def summary(self): """Summary of Coal and Gas supply and prices.""" milestones = [start_year, 2020, 2025, 2030, 2040, 2050] supply_coal = pd.DataFrame({ 'Coal imported': self.needed_importation['Coal'] / (10**8 * MBtu), 'Coal locally produced': self.loc_production['Coal'] / (10**8 * MBtu), 'Coal needs': self.needed_production['Coal'] / (10**8 * MBtu) }) prices_coal = pd.DataFrame({ 'Average coal price': self.average_price['Coal'] * MBtu, 'Local coal price': self.loc_prices['Coal'] * MBtu, 'Imported coal price': self.international_prices["Coal"] * MBtu }) supply_gas = pd.DataFrame({ 'Gas needs': self.needed_production['Gas'] / (10**8 * MBtu), 'Gas locally produced': self.loc_production['Gas'] / (10**8 * MBtu), 'Gas imported': self.needed_importation['Gas'] / (10**8 * MBtu) }) prices_gas = pd.DataFrame({ 'Average gas price': self.average_price['Gas'] * MBtu, 'Local gas price': self.loc_prices['Gas'] * MBtu, 'Imported gas price': self.international_prices["Gas"] * MBtu }) return ("\n Coal and Gas origin and prices for " + str(self.scenario) + '\n\n' "Coal supply (in E+8 MMBtu)\n" + str(supply_coal.loc[milestones].round()) + '\n\n' + "Coal prices (in $/MMBtu)\n" + str(prices_coal.loc[milestones].round()) + '\n\n' + "Gas supply (in E+8 MMBtu)\n" + str(supply_gas.loc[milestones].round()) + '\n\n' + "Gas prices (in $/MMBtu)\n" + str(prices_gas.loc[milestones].round()) + '\n\n')
def __init__(self, past_gas, past_coal): self.past_gas = past_gas self.past_coal = past_coal self.coef_cor = self.realized_pairwise_correlation() self.forecast_price = self.price_path() self.international_prices = pd.DataFrame({'Coal': self.forecast_price[1], 'Gas': self.forecast_price[0]}, index=range(start_year, end_year+1))
def summary(self): """Summary of Coal and Gas supply and prices.""" milestones = [START_YEAR, 2020, 2025, 2030, 2040, 2050] supply_coal = pd.DataFrame( { 'Domestic': self.loc_production['Coal'] / (10**8 * MBtu), 'Imported': self.needed_importation['Coal'] / (10**8 * MBtu), 'Total': self.needed_production['Coal'] / (10**8 * MBtu) }, columns=['Domestic', 'Imported', 'Total']) prices_coal = pd.DataFrame( { 'Domestic': self.loc_prices['Coal'] * MBtu, 'Imported': self.import_prices["Coal"] * MBtu, 'Average': self.average_price['Coal'] * MBtu }, columns=['Domestic', 'Imported', 'Average']) supply_gas = pd.DataFrame( { 'Domestic': self.loc_production['Gas'] / (10**8 * MBtu), 'Imported': self.needed_importation['Gas'] / (10**8 * MBtu), 'Total': self.needed_production['Gas'] / (10**8 * MBtu) }, columns=['Domestic', 'Imported', 'Total']) prices_gas = pd.DataFrame( { 'Domestic': self.loc_prices['Gas'] * MBtu, 'Imported': self.import_prices["Gas"] * MBtu, 'Average': self.average_price['Gas'] * MBtu }, columns=['Domestic', 'Imported', 'Average']) return ("\n Coal and Gas origin and prices for " + self.plan_name + '\n\n' "Coal supply (in E+8 MMBtu)\n" + str(supply_coal.loc[milestones].round(1)) + '\n\n' + "Coal prices (in $/MMBtu)\n" + str(prices_coal.loc[milestones].round(1)) + '\n\n' + "Gas supply (in E+8 MMBtu)\n" + str(supply_gas.loc[milestones].round(1)) + '\n\n' + "Gas prices (in $/MMBtu)\n" + str(prices_gas.loc[milestones].round(1)) + '\n\n')
def importation(self): """Calculate fuel quantities that have to be imported for the electric system.""" importation = pd.DataFrame(columns=['Coal', 'Gas'], index=self.index) importation["Coal"] = self.needed_production[ "Coal"] - self.loc_production["Coal"] importation[ "Gas"] = self.needed_production["Gas"] - self.loc_production["Gas"] #Importation needs < 0 means that there is not any importation. #Negative values are replaced by 0 importation[importation < 0] = 0 return importation
def __init__(self, past_gas, past_coal): self.past_gas = past_gas self.past_coal = past_coal self.coef_cor = self.realized_pairwise_correlation() self.forecast_price = self.price_path() self.import_prices = pd.DataFrame( { 'Coal': self.forecast_price[1], 'Gas': self.forecast_price[0] }, index=range(START_YEAR, END_YEAR + 1))
def needed_energy(self, plan): """Return the amount of heat energy from gas and coal needed for the plan (MBtu).""" electric_energy = plan.production[['Coal', 'Gas']].loc[START_YEAR:END_YEAR + 1] useful_heat_rate = heat_rate[['Coal', 'Gas']] needed_production = pd.DataFrame(electric_energy.values * useful_heat_rate.values, columns=useful_heat_rate.columns, index=useful_heat_rate.index) needed_production["Coal"] = needed_production["Coal"] * MBtu needed_production["Gas"] = needed_production["Gas"] * MBtu return needed_production
def test_international_dependency(): """Check that if all the production is imported, the average price is equal to the international price.""" # Local production is null production = [0] * (END_YEAR + 1 - START_YEAR) nul_production = pd.DataFrame({ 'Coal': production, 'Gas': production }, index=range(START_YEAR, END_YEAR + 1)) # Generate random local prices to test the independence of the result local_price_gas = [] local_price_coal = [] for _ in range(START_YEAR, END_YEAR + 1): local_price_gas.append(randint(0, 100)) local_price_coal.append(randint(0, 100)) local_prices_compare = pd.DataFrame( { 'Coal': local_price_coal, 'Gas': local_price_gas }, index=range(START_YEAR, END_YEAR + 1)) #Create the two objects to compare np.random.seed(0) fuel_1 = price_fuel(local_prices, price_gas, price_coal, nul_production, baseline) np.random.seed(0) fuel_2 = price_fuel(local_prices_compare, price_gas, price_coal, nul_production, baseline) assert fuel_1.average_price["Coal"].all( ) == fuel_2.average_price["Coal"].all() assert fuel_1.average_price["Gas"].all( ) == fuel_2.average_price["Gas"].all()
def needed_energy(self): """Get how much energy from gas and coal is needed for the scenario""" electric_production = self.scenario.production[[ 'Coal', 'Gas' ]].loc[start_year:end_year + 1] useful_heat_rate = heat_rate[['Coal', 'Gas']] needed_production = pd.DataFrame(electric_production.values * useful_heat_rate.values, columns=useful_heat_rate.columns, index=useful_heat_rate.index) needed_production["Coal"] = needed_production["Coal"] * MBtu needed_production["Gas"] = needed_production["Gas"] * MBtu return needed_production
def generate_parameters(self): """Generate parameters with different international prices forecasts at each run.""" updated_heat_price = pd.DataFrame(columns=heat_price.columns, index=heat_price.index) for fuel in SOURCES: if fuel == "Coal" or fuel == "Gas": updated_heat_price[fuel] = self.average_price[fuel] * MBtu else: updated_heat_price[fuel] = heat_price[fuel] updated_parameter = Parameter( DISCOUNT_RATE, plant_accounting_life, construction_cost[SOURCES], fixed_operating_cost[SOURCES], variable_operating_cost[SOURCES], heat_rate, updated_heat_price, EMISSION_FACTOR, capture_factor, CARBON_PRICE) return updated_parameter
def price_calculation(self): """Return Coal and Gas cost in USD/Btu, by weight-averaged domestic and import costs.""" #If there is not any importation, local price is considered average_price = pd.DataFrame(columns=['Coal', 'Gas'], index=self.index, dtype=float) average_price['Coal'] = np.where( self.needed_importation['Coal'] == 0, self.loc_prices['Coal'], (self.loc_production['Coal'] * self.loc_prices['Coal'] + self.needed_importation['Coal'] * self.import_prices['Coal']) / (self.needed_production['Coal'])) average_price['Gas'] = np.where( self.needed_importation['Gas'] == 0, self.loc_prices['Gas'], (self.loc_production['Gas'] * self.loc_prices['Gas'] + self.needed_importation['Gas'] * self.import_prices['Gas']) / (self.needed_production['Gas'])) return average_price
def generate_parameters(self): """Generate parameters with different international prices forecasts at each run""" updated_heat_price = pd.DataFrame(columns=heat_price.columns, index=heat_price.index) for fuel in sources: if fuel == "Coal" or fuel == "Gas": updated_heat_price[fuel] = self.average_price[fuel] * MBtu else: updated_heat_price[fuel] = heat_price[fuel] updated_parameter = Parameter( discount_rate, plant_accounting_life, construction_cost[sources], fixed_operating_cost[sources], variable_operating_cost[sources], heat_rate, updated_heat_price, emission_factor, capture_factor, carbon_price) return updated_parameter
def price_calculation(self): """Calculate the average fuel price (for Coal and Gas) in USD/Btu""" #If there is not any importation, local price is considered average_price = pd.DataFrame(columns=['Coal', 'Gas'], index=self.index, dtype=float) average_price['Coal'] = np.where( self.needed_importation['Coal'] == 0, self.loc_prices['Coal'], (self.loc_production['Coal'] * self.loc_prices['Coal'] + self.needed_importation['Coal'] * self.international_prices['Coal']) / (self.needed_production['Coal'])) average_price['Gas'] = np.where( self.needed_importation['Gas'] == 0, self.loc_prices['Gas'], (self.loc_production['Gas'] * self.loc_prices['Gas'] + self.needed_importation['Gas'] * self.international_prices['Gas']) / (self.needed_production['Gas'])) return average_price
def total(self): """Dataframe tabulating the key results.""" def bnUSD(cost): """Format as integer number of billion USD.""" return [round(cost * MUSD / GUSD), "bn USD"] d = pd.DataFrame() d["Power produced"] = [(self.total_production * GWh / TWh).round(), "Twh"] d["System LCOE"] = [round(self.lcoe * (MUSD / GWh) / (USD / MWh), 1), "USD/MWh"] d["Total cost"] = bnUSD(self.total_cost) d[" Construction"] = bnUSD(self.total_investment) d[" Fuel cost"] = bnUSD(self.total_fuel_cost) d[" O&M"] = bnUSD(self.total_fixed_om_cost + self.total_variable_OM_cost) d[" Salvage value"] = bnUSD(-self.total_salvage_value) d["CO2 emissions"] = [round(self.total_emissions, 1), "GtCO2eq"] d["CO2 capture"] = [round(self.total_capture, 1), "GtCO2"] d["CO2 cost"] = bnUSD(self.total_external_cost) d["Cost with CO2"] = bnUSD(self.total_cost + self.total_external_cost) d = d.transpose() d.columns = [str(self), 'Unit'] return d
def summary(self): """Summarize object contents, time series are defined by initial level and trend.""" summary = pd.DataFrame() s = self.plant_accounting_life[sources] s.name = "Plant accounting life (year)" summary = summary.append(s) s = self.emission_factor[sources] s.name = "Emission factor (gCO2eq/kWh)" summary = summary.append(s) s = self.capture_factor.loc[start_year, sources] s.name = "Capture factor (gCO2/kWh)" summary = summary.append(s) s = self.construction_cost.loc[start_year] s.name = "Overnight construction costs ($/kW)" summary = summary.append(s) s = self.construction_cost.diff().loc[start_year + 1] s.name = "Overnight construction costs trend ($/kW/y)" summary = summary.append(s) s = self.fixed_operating_cost.loc[start_year] s.name = "Fixed operating costs ($/kW)" summary = summary.append(s) s = self.fixed_operating_cost.diff().loc[start_year + 1] s.name = "Fixed operating costs trend ($/kW/yr)" summary = summary.append(s) s = self.variable_operating_cost.loc[start_year] s.name = "Variable operating costs ($/kWh)" summary = summary.append(s) s = self.heat_rate.loc[start_year] s.name = "Heat rate (Btu/kWh)" summary = summary.append(s) s = self.heat_price.loc[start_year] s.name = "Heat price ($/MBtu)" summary = summary.append(s) return (str(self) + '\n\n' + str(summary[sources].round(1)) + '\n\n' + "Carbon price ($/tCO2eq)\n" + str(self.carbon_price.loc[[start_year, 2030, 2040, 2050]]) + '\n\n' + "Discount rate: " + str(self.discount_rate))
def summary(self): """Summarize object contents, time series are defined by initial level and trend.""" summary = pd.DataFrame() s = self.plant_accounting_life[SOURCES] s.name = "Plant accounting life (year)" summary = summary.append(s) s = self.EMISSION_FACTOR[SOURCES] s.name = "Emission factor (gCO2eq/kWh)" summary = summary.append(s) s = self.capture_factor.loc[START_YEAR, SOURCES] s.name = "Capture factor (gCO2/kWh)" summary = summary.append(s) s = self.construction_cost.loc[START_YEAR] s.name = "Overnight construction costs ($/kW)" summary = summary.append(s) s = self.construction_cost.diff().loc[START_YEAR + 1] s.name = "Overnight construction costs trend ($/kW/y)" summary = summary.append(s) s = self.fixed_operating_cost.loc[START_YEAR] s.name = "Fixed operating costs ($/kW)" summary = summary.append(s) s = self.fixed_operating_cost.diff().loc[START_YEAR + 1] s.name = "Fixed operating costs trend ($/kW/yr)" summary = summary.append(s) s = self.variable_operating_cost.loc[START_YEAR] s.name = "Variable operating costs ($/kWh)" summary = summary.append(s) s = self.heat_rate.loc[START_YEAR] s.name = "Heat rate (Btu/kWh)" summary = summary.append(s) s = self.heat_price.loc[START_YEAR] s.name = "Heat price ($/MBtu)" summary = summary.append(s) return (str(self) + '\n\n' + str(summary[SOURCES].round(1)) + '\n\n' + "Carbon price ($/tCO2eq)\n" + str(self.CARBON_PRICE.loc[[START_YEAR, 2030, 2040, 2050]]) + '\n\n' + "Discount rate: " + str(self.DISCOUNT_RATE))
With CCS: CO2_captured = CO2_produced - CO2_emitted CO2_emitted = EMISSION_FACTOR_withCCS * production CO2_produced = CO2_factor_of_heat * heat_used CO2_produced = CO2_factor_of_heat * production * heat_rate_CCS CO2_produced = CO2_factor_of_heat * production * heat_rate_noCCS * (1 + energy_penalty) CO2_produced = production * EMISSION_FACTOR_noCCS * (1 + energy_penalty) CO2_captured = production * capture_factor capture_factor = EMISSION_FACTOR_noCCS * (1 + energy_penalty) - EMISSION_FACTOR_withCCS """ capture_factor = pd.DataFrame(index=YEARS) for fuel in SOURCES: capture_factor[fuel] = pd.Series(0, index=YEARS) # gCO2/ kWh capture_factor["CoalCCS"] = (EMISSION_FACTOR["Coal"] * (1 + energy_penalty) - EMISSION_FACTOR["CoalCCS"]) capture_factor["GasCCS"] = (EMISSION_FACTOR["Gas"] * (1 + energy_penalty) - EMISSION_FACTOR["GasCCS"]) capture_factor["BioCCS"] = (EMISSION_FACTOR["Biomass"] * (1 + energy_penalty) - EMISSION_FACTOR["BioCCS"]) # %% DISCOUNT_RATE = 0.06
#international_past_data["ini_year_Coal"] = 1960 #%%Monte Carlo characteristics : 35 forcasted prices from 2016 to 2050 for_values = end_year - start_year +1 #Collect of data international_prices_data = pd.read_csv(international_past_data["path_data"], index_col=0) international_prices_data.columns = ["Gas", "Coal"] x = np.array(international_prices_data.index) y_coal = np.array(international_prices_data.Coal) / (calorific_power["Coal_international"] * t) y_gas = np.array(international_prices_data.Gas) / MBtu price_gas = pd.DataFrame({'Price_Gas': international_prices_data['Gas']})\ .loc[international_past_data["ini_year_Gas"]:2016] / (MBtu) price_coal = pd.DataFrame({'Price_Coal': international_prices_data['Coal']})\ .loc[international_past_data["ini_year_Coal"]:2016]\ /(calorific_power["Coal_international"] * t) coal = [] gas = [] for j in range(len(price_coal)): coal.append(np.array(price_coal)[j][0]) for j in range(len(price_gas)): gas.append(np.array(price_gas)[j][0]) def x_function(prices): "Define a sequence used in correlation factor calculation" x_list = [] for i, n in enumerate(prices): if i < len(prices)-1:
With CCS: CO2_captured = CO2_produced - CO2_emitted CO2_emitted = emission_factor_withCCS * production CO2_produced = CO2_factor_of_heat * heat_used CO2_produced = CO2_factor_of_heat * production * heat_rate_CCS CO2_produced = CO2_factor_of_heat * production * heat_rate_noCCS * (1 + energy_penalty) CO2_produced = production * emission_factor_noCCS * (1 + energy_penalty) CO2_captured = production * capture_factor capture_factor = emission_factor_noCCS * (1 + energy_penalty) - emission_factor_withCCS """ capture_factor = pd.DataFrame(index=years) for fuel in sources: capture_factor[fuel] = pd.Series(0, index=years) # gCO2/ kWh capture_factor["CoalCCS"] = (emission_factor["Coal"] * (1 + energy_penalty) - emission_factor["CoalCCS"]) capture_factor["GasCCS"] = (emission_factor["Gas"] * (1 + energy_penalty) - emission_factor["GasCCS"]) capture_factor["BioCCS"] = (emission_factor["Biomass"] * (1 + energy_penalty) - emission_factor["BioCCS"]) #%% discount_rate = 0.06
x_gas = np.delete(x_coal, -1) y_gas = np.array(local_prices_data.Gas) / (MBtu) y_gas = np.delete(y_gas, -1) #interpolation of data with a langrangian polynom function_price_coal = lagrange(x_coal, y_coal) function_price_gas = lagrange(x_gas, y_gas) interpol_coal_price = [] interpol_gas_price = [] index = [] #Saving interpolating data #for i in range(2030-start_year+1): for i in range(start_year, end_year + 1): if i <= 2025: interpol_coal_price.append(function_price_coal(i)) interpol_gas_price.append(function_price_gas(i)) elif i <= 2030: interpol_coal_price.append(function_price_coal(i)) interpol_gas_price.append(interpol_gas_price[-1]) else: interpol_coal_price.append(interpol_coal_price[-1]) interpol_gas_price.append(interpol_gas_price[-1]) local_prices = pd.DataFrame( { 'Coal': interpol_coal_price, 'Gas': interpol_gas_price }, index=range(start_year, end_year + 1))
x = np.array(local_production_data.index) y_coal = np.array( local_production_data.Coal) * kt * calorific_power["Coal_local"] y_gas = np.array( local_production_data.Gas) * MM3 * calorific_power["Gas_local"] #interpolation of data with a langrangian polynom function_production_coal = lagrange(x, y_coal) function_production_gas = lagrange(x, y_gas) interpol_coal_production = [] interpol_gas_production = [] #Saving interpolating data for i in range(start_year, end_year + 1): if i <= 2030: interpol_coal_production.append(round(function_production_coal(i), 0)) interpol_gas_production.append(round(function_production_gas(i), 0)) else: interpol_coal_production.append(interpol_coal_production[-1]) interpol_gas_production.append(interpol_gas_production[-1]) local_production = pd.DataFrame( { 'Coal': interpol_coal_production, 'Gas': interpol_gas_production }, index=range(start_year, end_year + 1))
name=fuel) if VERBOSE: myplot(data, fuel, col, s, " (regression on " + str(len(data)) + ") ") return s # %% Construction costs def set_construction_cost(fuel, method): """Update the construction_cost dataframe for the fuel technology, using given method.""" construction_cost[fuel] = method(fuel, "OnghtCptlCostDolPerKw") construction_cost = pd.DataFrame(index=years) set_construction_cost("Coal", by_median) set_construction_cost("Gas", by_median) set_construction_cost("Oil", by_regression) set_construction_cost("BigHydro", by_regression) set_construction_cost("SmallHydro", by_median) set_construction_cost("Solar", by_regression) set_construction_cost("Biomass", by_median) # In Vietnam, wind power is near-shore set_construction_cost("Offshore", by_regression) set_construction_cost("Onshore", by_regression) construction_cost["Wind"] = (construction_cost["Offshore"] + construction_cost["Onshore"]) // 2
x = np.array(local_production_data.index) y_coal = np.array( local_production_data.Coal) * kt * CALORIFIC_POWER["Coal_local"] y_gas = np.array( local_production_data.Gas) * MM3 * CALORIFIC_POWER["Gas_local"] #interpolation of data with a langrangian polynom function_production_coal = lagrange(x, y_coal) function_production_gas = lagrange(x, y_gas) interpol_coal_production = [] interpol_gas_production = [] #Saving interpolating data for i in range(START_YEAR, END_YEAR + 1): if i <= 2030: interpol_coal_production.append(round(function_production_coal(i), 0)) interpol_gas_production.append(round(function_production_gas(i), 0)) else: interpol_coal_production.append(interpol_coal_production[-1]) interpol_gas_production.append(interpol_gas_production[-1]) local_production = pd.DataFrame( { 'Coal': interpol_coal_production, 'Gas': interpol_gas_production }, index=range(START_YEAR, END_YEAR + 1))
"Coal": 40, "Gas": 25, "Oil": 30, "BigHydro": 100, "SmallHydro": 60, "Biomass": 25, "Wind": 20, "Solar": 25, "CoalCCS": 40, "GasCCS": 25, "BioCCS": 25, "PumpedStorage": 100, "Import": 100 }) retirement = pd.DataFrame() for tech in plant_life.index: retirement[tech] = additions[tech].shift(plant_life[tech]) retirement.fillna(0, inplace=True) # Fix to meet PDP7A objective more precisely retirement.loc[2017, "BigHydro"] = 200 retirement.loc[2018, "BigHydro"] = 200 retirement.loc[2019, "BigHydro"] = 200 retirement.loc[2017, "Oil"] = 100 retirement.loc[2018, "Oil"] = 100 retirement.loc[2019, "Oil"] = 100
x_gas = np.delete(x_coal, -1) y_gas = np.array(local_prices_data.Gas) / (MBtu) y_gas = np.delete(y_gas, -1) #interpolation of data with a langrangian polynom FUNCTION_PRICE_COAL = lagrange(x_coal, y_coal) function_price_gas = lagrange(x_gas, y_gas) interpol_coal_price = [] interpol_gas_price = [] index = [] #Saving interpolating data #for i in range(2030-START_YEAR+1): for i in range(START_YEAR, END_YEAR + 1): if i <= 2025: interpol_coal_price.append(FUNCTION_PRICE_COAL(i)) interpol_gas_price.append(function_price_gas(i)) elif i <= 2030: interpol_coal_price.append(FUNCTION_PRICE_COAL(i)) interpol_gas_price.append(interpol_gas_price[-1]) else: interpol_coal_price.append(interpol_coal_price[-1]) interpol_gas_price.append(interpol_gas_price[-1]) local_prices = pd.DataFrame( { 'Coal': interpol_coal_price, 'Gas': interpol_gas_price }, index=range(START_YEAR, END_YEAR + 1))