def test_get_reference_year_total_capacity(self, reference_year, expected_output): model = Mock() plant1 = create_power_plant("plant1", 1990, "CCGT", 1200) plant2 = create_power_plant("plant2", 2010, "Onshore", 60) plant3 = create_power_plant("plant3", 1990, "Offshore", 120) plant4 = create_power_plant("plant4", 1980, "Coal", 120) agent1 = GenCo(1, model, "Test", 0.06, [plant1, plant2, plant3]) agent2 = GenCo(1, model, "Test", 0.06, [plant4]) model.year_number = 2018 agent1.operate_constructed_plants() agent2.operate_constructed_plants() agent1.dismantle_old_plants() agent2.dismantle_old_plants() schedule = Mock() schedule.agents = [agent1, agent2] model.schedule = schedule calculate_capacity = WorldPlantCapacity(model) assert calculate_capacity.get_reference_year_total_capacity( reference_year) == expected_output
def test_get_power_plants_running_in_reference_year( self, reference_year, expected_output): model = Mock() plant1 = create_power_plant("plant1", 1990, "CCGT", 1200) plant2 = create_power_plant("plant2", 2010, "Onshore", 60) plant3 = create_power_plant("plant3", 1990, "Offshore", 120) plant4 = create_power_plant("plant4", 1980, "Coal", 120) agent1 = GenCo(1, model, "Test", 0.06, [plant1, plant2, plant3]) agent2 = GenCo(1, model, "Test", 0.06, [plant4]) model.year_number = 2018 agent1.operate_constructed_plants() agent2.operate_constructed_plants() agent1.dismantle_old_plants() agent2.dismantle_old_plants() schedule = Mock() schedule.agents = [agent1, agent2] model.schedule = schedule calculate_capacity = WorldPlantCapacity(model) plant_list = calculate_capacity.get_power_plants_running_in_reference_year( reference_year) for plant, expected_name in zip(plant_list, expected_output): logger.debug("{}, {}".format(plant.name, expected_name)) assert plant.name == expected_name
def test_calculate_expected_yearly_outflow(self, calculate_latest_NPV, year, plant_type, capacity, expected_output): power_plant = create_power_plant("Test", year, plant_type, capacity) SHORT_RUN_MARGINAL_COST = 8.9 TOTAL_RUNNING_HOURS = 8752.42 TOTAL_YEARLY_INCOME = 1646133520 YEARLY_CAPITAL_COST = 514111666.67 yearly_outflow = calculate_latest_NPV._calculate_yearly_operation_cashflow(power_plant, SHORT_RUN_MARGINAL_COST, TOTAL_RUNNING_HOURS, TOTAL_YEARLY_INCOME, YEARLY_CAPITAL_COST) assert yearly_outflow == pytest.approx(expected_output)
def power_exchange(self): model = Mock() gen_co1 = GenCo(1, model, "Test", 0.06) gen_co1.plants = [create_power_plant("Test", )] gen_co1 = GenCo(1, model, "Test", 0.06) gen_co1 = GenCo(1, model, "Test", 0.06) gen_co1 = GenCo(1, model, "Test", 0.06) model.schedule.agents = [] power_exchange = PowerExchange(model) return power_exchange
def test_get_predicted_marginal_cost(self, plant_type, capacity, look_back_years, expected_output): model = Mock() model.step_number = 5 model.year_number = 2018 power_plant = create_power_plant("estimate_variable", model.year_number, plant_type, capacity) latest_market_data = LatestMarketData(model) assert latest_market_data.get_predicted_marginal_cost( power_plant, look_back_years) == approx(expected_output)
def test_check_if_operating_in_certain_year(self): power_plant = create_power_plant("test_plant", 2018, "CCGT", 1200) assert power_plant.check_if_operating_in_certain_year(2018, 2) == False assert power_plant.check_if_operating_in_certain_year(2018, 3) == False assert power_plant.check_if_operating_in_certain_year(2018, 4) == False assert power_plant.check_if_operating_in_certain_year(2018, 5) == False assert power_plant.check_if_operating_in_certain_year(2018, 6) == False assert power_plant.check_if_operating_in_certain_year(2018, 7) == True assert power_plant.check_if_operating_in_certain_year(2018, 8) == True assert power_plant.check_if_operating_in_certain_year(2018, 9) == True assert power_plant.check_if_operating_in_certain_year(2018, 10) == True assert power_plant.check_if_operating_in_certain_year(2018, 11) == True assert power_plant.check_if_operating_in_certain_year(2018, 12) == True assert power_plant.check_if_operating_in_certain_year(2018, 13) == True assert power_plant.check_if_operating_in_certain_year(2018, 14) == True assert power_plant.check_if_operating_in_certain_year(2018, 31) == True assert power_plant.check_if_operating_in_certain_year(2018, 32) == False assert power_plant.check_if_operating_in_certain_year(2018, 33) == False
def test_predict_load_curve_price(self): model = Mock() model.year_number = 2025 model.step_number = 6 model.Demand.segment_consumption = [52152, 45209, 42206, 39585, 37480, 35505, 34182, 33188, 32315, 31567, 30721, 29865, 28935, 27888, 26760, 25520, 24327, 23127, 21964, 17568] model.Demand.segment_hours = [8752.5, 8291.83, 7831.17, 7370.5, 6909.92, 6449.25, 5988.58, 5527.92, 5067.25, 4606.58, 4146, 3685.33, 3224.67, 2764, 2303.33, 1842.67, 1382.08, 921.42, 460.75, 0.08] plant1 = create_power_plant("plant1", 2016, "CCGT", 1200) plant2 = create_power_plant("plant2", 2015, "CCGT", 1200) plant3 = create_power_plant("plant3", 2014, "CCGT", 1200) plant4 = create_power_plant("plant4", 2020, "CCGT", 1200) plant5 = create_power_plant("plant5", 2021, "CCGT", 1200) plant6 = create_power_plant("plant6", 2035, "CCGT", 1200) plants = [plant1, plant2, plant3, plant4, plant5, plant6] all_variable_costs = [plant1.variable_o_and_m_per_mwh, plant2.variable_o_and_m_per_mwh, plant3.variable_o_and_m_per_mwh, plant4.variable_o_and_m_per_mwh, plant5.variable_o_and_m_per_mwh, plant6.variable_o_and_m_per_mwh] index_of_max_var_o_m_costs = np.argmax(all_variable_costs) plant_with_highest_o_m = plants[index_of_max_var_o_m_costs] gen_co1 = GenCo(1, model, "genco1", 0.02, 4) gen_co1.plants = [plant1, plant2] gen_co2 = GenCo(1, model, "genco2", 0.02, 4) gen_co2.plants = [plant3, plant4, plant5, plant6] model.schedule.agents = [gen_co1, gen_co2] predict_price_duration_curve = PredictPriceDurationCurve(model=model) predicted_price_duration_curve = predict_price_duration_curve.predict_price_duration_curve(1.1) assert predicted_price_duration_curve.accepted_price.iloc[0] == pytest.approx(plant_with_highest_o_m.variable_o_and_m_per_mwh + 18.977/plant_with_highest_o_m.efficiency+25.085*plant_with_highest_o_m.fuel.mwh_to_co2e_conversion_factor*(1/plant_with_highest_o_m.efficiency)) assert predicted_price_duration_curve.accepted_price.iloc[1] == pytest.approx(plant_with_highest_o_m.variable_o_and_m_per_mwh + 18.977/plant_with_highest_o_m.efficiency+25.085*plant_with_highest_o_m.fuel.mwh_to_co2e_conversion_factor*(1/plant_with_highest_o_m.efficiency)) assert predicted_price_duration_curve.accepted_price.iloc[2] == pytest.approx(plant_with_highest_o_m.variable_o_and_m_per_mwh + 18.977/plant_with_highest_o_m.efficiency+25.085*plant_with_highest_o_m.fuel.mwh_to_co2e_conversion_factor*(1/plant_with_highest_o_m.efficiency)) assert predicted_price_duration_curve.accepted_price.iloc[3] == pytest.approx(plant_with_highest_o_m.variable_o_and_m_per_mwh + 18.977/plant_with_highest_o_m.efficiency+25.085*plant_with_highest_o_m.fuel.mwh_to_co2e_conversion_factor*(1/plant_with_highest_o_m.efficiency)) assert predicted_price_duration_curve.accepted_price.iloc[4] == pytest.approx(plant_with_highest_o_m.variable_o_and_m_per_mwh + 18.977/plant_with_highest_o_m.efficiency+25.085*plant_with_highest_o_m.fuel.mwh_to_co2e_conversion_factor*(1/plant_with_highest_o_m.efficiency)) assert predicted_price_duration_curve.accepted_price.iloc[5] == pytest.approx(plant_with_highest_o_m.variable_o_and_m_per_mwh + 18.977/plant_with_highest_o_m.efficiency+25.085*plant_with_highest_o_m.fuel.mwh_to_co2e_conversion_factor*(1/plant_with_highest_o_m.efficiency)) assert predicted_price_duration_curve.accepted_price.iloc[6] == pytest.approx(plant_with_highest_o_m.variable_o_and_m_per_mwh + 18.977/plant_with_highest_o_m.efficiency+25.085*plant_with_highest_o_m.fuel.mwh_to_co2e_conversion_factor*(1/plant_with_highest_o_m.efficiency)) assert predicted_price_duration_curve.accepted_price.iloc[7] == pytest.approx(plant_with_highest_o_m.variable_o_and_m_per_mwh + 18.977/plant_with_highest_o_m.efficiency+25.085*plant_with_highest_o_m.fuel.mwh_to_co2e_conversion_factor*(1/plant_with_highest_o_m.efficiency)) assert predicted_price_duration_curve.accepted_price.iloc[8] == pytest.approx(plant_with_highest_o_m.variable_o_and_m_per_mwh + 18.977/plant_with_highest_o_m.efficiency+25.085*plant_with_highest_o_m.fuel.mwh_to_co2e_conversion_factor*(1/plant_with_highest_o_m.efficiency)) assert predicted_price_duration_curve.accepted_price.iloc[9] == pytest.approx(plant_with_highest_o_m.variable_o_and_m_per_mwh + 18.977/plant_with_highest_o_m.efficiency+25.085*plant_with_highest_o_m.fuel.mwh_to_co2e_conversion_factor*(1/plant_with_highest_o_m.efficiency))
def invest(self): # capacity_of_invested_plants = 0 lowest_upfront_cost = 0 down_payment = 0 counter = 0 total_capacity = 0 number_of_plants_to_purchase = 1 # while self.money > lowest_upfront_cost and total_capacity < 1500: while self.money > lowest_upfront_cost: # while number_of_plants_to_purchase > 0: # counter += 1 # if counter>3: # break # potential_plant_data = npv_calculation.get_positive_npv_plants_list() potential_plant_data = get_most_profitable_plants_by_npv( self.model, self.difference_in_discount_rate, self.look_back_period) # logger.info("potential_plant_data: {}".format(potential_plant_data)) if potential_plant_data: potential_plant_list = [] for plant_data in potential_plant_data: power_plant_trial = create_power_plant( "invested_plant", self.model.year_number, plant_data[1], plant_data[0]) potential_plant_list.append(power_plant_trial) lowest_upfront_cost = min( plant.get_upfront_costs() * elecsim.scenario.scenario_data.upfront_investment_costs for plant in potential_plant_list) else: return 1, False for plant_data in potential_plant_list: # power_plant_trial = create_power_plant("invested_plant", self.model.year_number, plant_data[1], plant_data[0]) power_plant_trial = create_power_plant("invested_plant", self.model.year_number, plant_data.plant_type, plant_data.capacity_mw) down_payment = power_plant_trial.get_upfront_costs( ) * elecsim.scenario.scenario_data.upfront_investment_costs number_of_plants_to_purchase = int(self.money / down_payment) if number_of_plants_to_purchase == 0: continue capacity_to_purchase = number_of_plants_to_purchase * power_plant_trial.capacity_mw if capacity_to_purchase > 20000: number_of_plants_to_purchase = int( 20000 / power_plant_trial.capacity_mw) power_plant_trial_group = create_power_plant_group( name="invested_plant_group", start_date=self.model.year_number, simplified_type=plant_data.plant_type, capacity=plant_data.capacity_mw, number_of_plants_to_purchase=number_of_plants_to_purchase) down_payment_of_plant_array = number_of_plants_to_purchase * down_payment # logger.info(create_power_plant.cache_info()) if self.money > down_payment_of_plant_array and number_of_plants_to_purchase >= 1: logger.debug( "investing in {}, company: {}, size: {}, number: {}, self.money: {}" .format(power_plant_trial_group.plant_type, self.name, power_plant_trial_group.capacity_mw, number_of_plants_to_purchase, self.money)) self.plants.append(power_plant_trial_group) self.money -= down_payment_of_plant_array total_capacity += power_plant_trial_group.capacity_mw if total_capacity > 400000: # 20000000: return 1, True break else: return 0, False
def test_calculate_yearly_loan_payment(self, calculate_latest_NPV, year, plant_type, capacity, expected_output): power_plant = create_power_plant("Test", year, plant_type, capacity) monthly_rate = get_yearly_payment(power_plant, 0.06) logger.debug("monthly_rate: {}".format(monthly_rate))
def test_calculate_expected_yearly_profit_per_mwh(self, calculate_latest_NPV, year, plant_type, capacity, expected_output): power_plant = create_power_plant("Test", year, plant_type, capacity) TOTAL_RUNNING_HOURS = 8752.42 YEARLY_OUTFLOW = 874963277.93 yearly_profit_per_mwh = calculate_latest_NPV._get_yearly_profit_per_mwh(power_plant=power_plant, total_running_hours=TOTAL_RUNNING_HOURS, yearly_cash_flow=YEARLY_OUTFLOW) assert yearly_profit_per_mwh == pytest.approx(expected_output, abs=0.01)
def test_calculate_expected_capital_cost(self, calculate_latest_NPV, year, plant_type, capacity, expected_output): power_plant = create_power_plant("Test", year, plant_type, capacity) yearly_capital_cost = calculate_latest_NPV._get_capital_outflow(power_plant) logger.debug(yearly_capital_cost) assert yearly_capital_cost == pytest.approx(expected_output)
def test_select_yearly_payback_payment_for_year(self, year, plant_type, capacity, expected_output): power_plant = create_power_plant("Test", year, plant_type, capacity) model = Mock() model.year_number=2020 select_yearly_payback_payment_for_year(power_plant, 0.6, model)
sorted_npv = npv_results.sort_values(by='npv_per_mw', ascending=False) logger.debug("sorted_npv: \n {}".format(sorted_npv)) return sorted_npv # @lru_cache(maxsize=10000) def calculate_npv(self, plant_type, plant_size): # Forecast segment prices <<<<<<< HEAD ======= >>>>>>> 5f3c373861c398621fed06ebb3fe989ceb1733a9 forecasted_segment_prices = self._get_price_duration_predictions() # logger.info("Forecasted price duration curve: {}".format(forecasted_segment_prices)) power_plant = create_power_plant("PowerPlantName", self.model.year_number, plant_type, plant_size) # Forecast marginal costs short_run_marginal_cost = self._get_predicted_marginal_cost(power_plant) logger.debug("short run marginal cost: {}".format(short_run_marginal_cost)) forecasted_segment_prices = self._clean_segment_prices(forecasted_segment_prices) logger.debug("forecasted_segment_prices: \n {}".format(forecasted_segment_prices)) self._get_profit_per_mwh(forecasted_segment_prices, short_run_marginal_cost) self._get_profit_per_segment(forecasted_segment_prices, power_plant=power_plant) self._get_total_hours_to_run(forecasted_segment_prices, power_plant) self._get_total_yearly_income(forecasted_segment_prices, power_plant)
def calculate_npv(self, plant_type, plant_size): # Forecast segment prices if self.price_curve_parameters is None: forecasted_segment_prices = self._get_price_duration_predictions() elif self.price_curve_parameters: forecasted_segment_prices = self.price_curve_parameters logger.debug( "forecasted_segment_prices: {}".format(forecasted_segment_prices)) if plant_type == "Nuclear" and self.model.nuclear_subsidy is not None: forecasted_segment_prices[ 'accepted_price'] = forecasted_segment_prices[ 'accepted_price'] + self.model.nuclear_subsidy logger.debug("Forecasted price duration curve: \n{}".format( forecasted_segment_prices)) power_plant = create_power_plant("PowerPlantName", self.model.year_number, plant_type, plant_size) # Forecast marginal costs short_run_marginal_cost = self._get_predicted_marginal_cost( power_plant) logger.debug( "short run marginal cost: {}".format(short_run_marginal_cost)) forecasted_segment_prices = self._clean_segment_prices( forecasted_segment_prices) logger.debug("forecasted_segment_prices: \n {}".format( forecasted_segment_prices)) self._get_profit_per_mwh(forecasted_segment_prices, short_run_marginal_cost) self._get_profit_per_segment(forecasted_segment_prices, power_plant=power_plant) self._get_total_hours_to_run(forecasted_segment_prices, power_plant) self._get_total_yearly_income(forecasted_segment_prices, power_plant) logger.debug("total_hours_predicted_to_run: \n {}".format( forecasted_segment_prices)) # total_profit_for_year = sum(forecasted_segment_prices['_total_profit_per_segment']) total_running_hours = sum( forecasted_segment_prices['_total_running_hours']) total_yearly_income = sum(forecasted_segment_prices['total_income']) logger.debug("total_yearly_income: {}".format(total_yearly_income)) yearly_capital_cost = self._get_capital_outflow(power_plant) logger.debug("yearly_capital_cost: {}".format(yearly_capital_cost)) yearly_operating_cash_flow = self._calculate_yearly_operation_cashflow( power_plant, short_run_marginal_cost, total_running_hours, total_yearly_income, yearly_capital_cost) total_cash_flow = yearly_capital_cost + yearly_operating_cash_flow logger.debug('total_cash_flow: {}'.format(total_cash_flow)) if power_plant.plant_type == "Nuclear": self.weighted_average_cost_capital = elecsim.scenario.scenario_data.nuclear_wacc + self.difference_in_discount_rate else: self.weighted_average_cost_capital = elecsim.scenario.scenario_data.non_nuclear_wacc + self.difference_in_discount_rate # logger.debug("cash_flow_wacc: {}".format(cash_flow_wacc)) logger.debug("discount rate: {}".format( self.weighted_average_cost_capital)) npv_power_plant = npv(self.weighted_average_cost_capital, total_cash_flow) logger.debug("npv_power_plant: {}".format(npv_power_plant)) NPVp = divide(npv_power_plant, (power_plant.capacity_mw * total_running_hours)) return NPVp
def initialize_gencos(self, financial_data, plant_data, gencos_rl): """ Creates generation company agents based on financial data and power plants owned. Estimates cost parameters of each power plant if data not for power plant not available. :param financial_data: Data containing information about generation company's financial status :param plant_data: Data containing information about generation company's plants owned, start year and name. """ financial_data = pd.merge(financial_data, plant_data, on="Company", how="inner") financial_data = financial_data[["Company", "cash_in_bank"]] # Initialising generator company data financial_data.cash_in_bank = financial_data.cash_in_bank.replace("nan", np.nan) financial_data.cash_in_bank = financial_data.cash_in_bank.fillna(0) companies_groups = plant_data.groupby("Company") company_financials = financial_data.groupby("Company") logger.info("Initialising generation companies with their power plants.") # Initialize generation companies with their respective power plants for gen_id, ((name, data), (_, financials)) in enumerate( zip(companies_groups, company_financials), 0 ): rl_bidding = False if financials.Company.iloc[0] != name: raise ValueError( "Company financials name ({}) and agent name ({}) do not match.".format( financials.Company.iloc[0], name ) ) elif financials.Company.iloc[0] in gencos_rl: rl_bidding = True gen_co = GenCo( unique_id=gen_id, model=self, difference_in_discount_rate=round(uniform(-0.03, 0.03), 3), look_back_period=randint(3, 7), name=name, money=financials.cash_in_bank.iloc[0], rl_bidding=rl_bidding, ) self.unique_id_generator += 1 # Add power plants to generation company portfolio # parent_directory = os.path.dirname(os.getcwd()) pickle_directory = ( "{}/../elecsim/data/processed/pickled_data/power_plants/".format( ROOT_DIR ) ) for plant in data.itertuples(): try: power_plant = pickle.load( open( "{}{}-{}.pickle".format( pickle_directory, plant.Name, plant.Start_date ), "rb", ) ) except (OSError, IOError, FileNotFoundError, EOFError) as e: logger.info("plant: {}".format(plant)) power_plant = create_power_plant( plant.Name, plant.Start_date, plant.Simplified_Type, plant.Capacity, ) pickle.dump( power_plant, open( "{}{}-{}.pickle".format( pickle_directory, plant.Name, plant.Start_date ), "wb", ), ) gen_co.plants.append(power_plant) logger.debug("Adding generation company: {}".format(gen_co.name)) self.schedule.add(gen_co) logger.info("Added generation companies.")