From 920cacbc3bb735e7b598ded8ee1b35d6f6a57065 Mon Sep 17 00:00:00 2001 From: dmuldrew Date: Tue, 3 Mar 2020 11:44:52 -0800 Subject: [PATCH 1/4] refactor: more intermediate output columns and input validation --- .../auto_capacity_scaling.py | 146 ++++++++++++++---- .../tests/test_object_persistence.py | 5 - .../tests/test_resource_target_manager.py | 4 - .../tests/test_target_manager_input.py | 11 +- 4 files changed, 126 insertions(+), 40 deletions(-) diff --git a/powersimdata/scaling/clean_capacity_scaling/auto_capacity_scaling.py b/powersimdata/scaling/clean_capacity_scaling/auto_capacity_scaling.py index d59f5e49b..48eff96b9 100644 --- a/powersimdata/scaling/clean_capacity_scaling/auto_capacity_scaling.py +++ b/powersimdata/scaling/clean_capacity_scaling/auto_capacity_scaling.py @@ -21,18 +21,32 @@ def set_next_sim_hours(next_sim_hours): def targets_from_data_frame(self, data_frame): for row in data_frame.itertuples(): - self.add_target(TargetManager(row.region_name, - row.ce_target_fraction, - row.ce_category, - row.total_demand, - row.external_ce_historical_amount, - row.solar_percentage)) + + if row.solar_percentage == 'None': + solar_percentage = None + else: + solar_percentage = row.solar_percentage + target = TargetManager(row.region_name, + row.ce_target_fraction, + row.ce_category, + row.total_demand, + row.external_ce_historical_amount, + solar_percentage) + if row.allowed_resources == '': + allowed_resources = ['solar', 'wind'] + else: + split_resources = row.allowed_resources.split(',') + allowed_resources = [x.strip() for x in split_resources] + target.set_allowed_resources(allowed_resources) + self.add_target(target) def add_target(self, target_manager_obj): """ Add target to strategy object :param target_manager_obj: target object to be added """ + assert (isinstance(target_manager_obj, TargetManager)), \ + "Input must be of TargetManager type" self.targets[target_manager_obj.region_name] = target_manager_obj @staticmethod @@ -70,22 +84,47 @@ def data_frame_of_next_capacities(self): """ target_capacities = [] for tar in self.targets: - solar_added_capacity, wind_added_capacity = \ - self.targets[tar].calculate_added_capacity() - # solar_added_capacity, wind_added_capacity = - # self.targets[tar].calculate_added_capacity_gen_constant() + if self.targets[tar].ce_target_fraction == 0: + solar_added_capacity, wind_added_capacity = (0, 0) + else: + solar_added_capacity, wind_added_capacity =\ + self.targets[tar].calculate_added_capacity() target_capacity = [ self.targets[tar].region_name, - self.targets[tar].resources['solar'].calculate_next_capacity( - solar_added_capacity), - self.targets[tar].resources['wind'].calculate_next_capacity( - wind_added_capacity)] + self.targets[tar].ce_target_fraction, + self.targets[tar].ce_target, + self.targets[tar].calculate_prev_ce_generation(), + self.targets[tar].calculate_ce_shortfall(), + solar_added_capacity, + wind_added_capacity, + self.targets[tar].resources['solar'].prev_capacity, + self.targets[tar].resources['wind'].prev_capacity, + self.targets[tar].resources[ + 'solar'].calculate_expected_cap_factor(), + self.targets[tar].resources[ + 'wind'].calculate_expected_cap_factor(), + self.targets[tar].resources[ + 'solar'].calculate_next_capacity(solar_added_capacity), + self.targets[tar].resources[ + 'wind'].calculate_next_capacity(wind_added_capacity)] target_capacities.append(target_capacity) - target_capacities_df = pd.DataFrame( - target_capacities, - columns=['region_name', - 'next_solar_capacity', - 'next_wind_capacity']) + + target_capacities_df = pd.DataFrame(target_capacities, + columns=[ + 'region_name', + 'ce_target_fraction', + 'ce_target', + 'previous_ce_generation', + 'clean_energy_shortfall', + 'solar_added_capacity', + 'wind_added_capacity', + 'solar_prev_capacity', + 'wind_prev_capacity', + 'solar_expected_cap_factor', + 'wind_expected_cap_factor', + 'next_solar_capacity', + 'next_wind_capacity']) + target_capacities_df = target_capacities_df.set_index('region_name') return target_capacities_df @@ -241,8 +280,6 @@ def calculate_capacity_scaling(self): solar_prev_capacity = self.calculate_total_capacity('solar') wind_prev_capacity = self.calculate_total_capacity('wind') solar_added, wind_added = self.calculate_total_added_capacity() - # solar_added, wind_added = - # self.calculate_total_added_capacity_gen_constant() solar_scaling = (solar_added / solar_prev_capacity) + 1 wind_scaling = (wind_added / wind_prev_capacity) + 1 @@ -259,15 +296,32 @@ def data_frame_of_next_capacities(self): for tar in self.targets: target_capacity = [ self.targets[tar].region_name, - self.targets[tar].resources['solar'].prev_capacity * + self.targets[tar].ce_target_fraction, + self.targets[tar].ce_target, + self.targets[tar].calculate_prev_ce_generation(), + self.targets[tar].calculate_ce_shortfall(), solar_scaling, - self.targets[tar].resources['wind'].prev_capacity * - wind_scaling] + wind_scaling, + self.targets[tar].resources['solar'].prev_capacity, + self.targets[tar].resources['wind'].prev_capacity, + self.targets[tar].resources[ + 'solar'].prev_capacity * solar_scaling, + self.targets[tar].resources[ + 'wind'].prev_capacity * wind_scaling] target_capacities.append(target_capacity) target_capacities_df = pd.DataFrame(target_capacities, columns=['region_name', + 'ce_target_fraction', + 'ce_target', + 'previous_ce_generation', + 'clean_energy_shortfall', + 'solar_scaling', + 'wind_scaling', + 'solar_prev_capacity', + 'wind_prev_capacity', 'next_solar_capacity', 'next_wind_capacity']) + target_capacities_df = target_capacities_df.set_index('region_name') return target_capacities_df @@ -284,6 +338,21 @@ def __init__(self, region_name, ce_target_fraction, ce_category, clean energy, etc. :param total_demand: total demand for region """ + assert (type(region_name) == str), "region_name must be a string" + assert (type(ce_category) == str), "ce_category must be a string" + assert (total_demand >= 0), "total_demand must be greater than zero" + assert (0 <= ce_target_fraction <= 1), "ce_target_fraction must be " \ + "between 0 and 1" + assert (external_ce_historical_amount >= 0), "external_ce_historical" \ + "_amount must be greater"\ + " than zero" + assert (type(solar_percentage) == float or + type(solar_percentage) == int or + solar_percentage is None), "solar_percentage must be" \ + " a number or None" + if type(solar_percentage) == float: + assert (0 <= solar_percentage <= 1), "solar_percentage must be " \ + "between 0 and 1" self.region_name = region_name self.ce_category = ce_category @@ -375,6 +444,8 @@ def add_resource(self, resource): Adds resource to TargetManager :param resource: resource to be added """ + assert (isinstance(resource, Resource)), "Input must be of Resource " \ + "type" self.resources[resource.name] = resource def get_resource(self, resource_name): @@ -452,13 +523,18 @@ def save_target_as_pickle(self): json_file.close() def __str__(self): - return json.dumps(json.loads(jsonpickle.encode(self)), indent=4, - sort_keys=True) + return json.dumps(json.loads( + jsonpickle.encode(self, unpicklable=False)), + indent=4, + sort_keys=True) class Resource: def __init__(self, name, prev_scenario_num): # todo: input validation + assert (type(name) == str), "name must be a string" + assert (type(prev_scenario_num) == int), "prev_scenario_num must be " \ + "and integer" self.name = name self.prev_scenario_num = prev_scenario_num self.no_congestion_cap_factor = None @@ -477,6 +553,12 @@ def set_capacity(self, no_congestion_cap_factor, prev_capacity, :param prev_capacity: capacity from scenario run :param prev_cap_factor: capacity factor from scenario run """ + assert (0 <= no_congestion_cap_factor <= 1), \ + "no_congestion_cap_factor must be between 0 and 1" + assert (0 <= prev_cap_factor <= 1),\ + "prev_cap_factor must be between 0 and 1" + assert (prev_capacity >= 0), "prev_capacity must be greater than zero" + self.no_congestion_cap_factor = no_congestion_cap_factor self.prev_capacity = prev_capacity self.prev_cap_factor = prev_cap_factor @@ -487,6 +569,8 @@ def set_generation(self, prev_generation): Set generation from scenario run :param prev_generation: generation from scenario run """ + assert (prev_generation >= 0), "prev_generation must be greater than "\ + "zero" self.prev_generation = prev_generation # todo: calculate directly from scenario results @@ -496,6 +580,8 @@ def set_curtailment(self, prev_curtailment): :param prev_curtailment: calculated curtailment from scenario run :return: """ + assert (prev_curtailment >= 0), "prev_curtailment must be greater " \ + "than zero" self.prev_curtailment = prev_curtailment def set_addl_curtailment(self, addl_curtailment): @@ -503,6 +589,8 @@ def set_addl_curtailment(self, addl_curtailment): Set additional curtailment to included in capacity calculations :param addl_curtailment: additional curtailment """ + assert (addl_curtailment >= 0), "addl_curtailment must be greater " \ + "than zero" self.addl_curtailment = addl_curtailment def calculate_expected_cap_factor(self): @@ -523,5 +611,7 @@ def calculate_next_capacity(self, added_capacity): return next_capacity def __str__(self): - return json.dumps(json.loads(jsonpickle.encode(self)), indent=4, - sort_keys=True) + return json.dumps(json.loads(jsonpickle.encode(self, + unpicklable=False + )), + indent=4, sort_keys=True) diff --git a/powersimdata/scaling/clean_capacity_scaling/tests/test_object_persistence.py b/powersimdata/scaling/clean_capacity_scaling/tests/test_object_persistence.py index cd63db71c..aa02d890d 100644 --- a/powersimdata/scaling/clean_capacity_scaling/tests/test_object_persistence.py +++ b/powersimdata/scaling/clean_capacity_scaling/tests/test_object_persistence.py @@ -3,11 +3,6 @@ import jsonpickle import json - -def test_can_pass(): - assert 1 == 1 - - def test_create_json_of_target_object(): # create Pacific pacific_solar = Resource('solar', 3) diff --git a/powersimdata/scaling/clean_capacity_scaling/tests/test_resource_target_manager.py b/powersimdata/scaling/clean_capacity_scaling/tests/test_resource_target_manager.py index dbd2b3917..2c6b54b1f 100644 --- a/powersimdata/scaling/clean_capacity_scaling/tests/test_resource_target_manager.py +++ b/powersimdata/scaling/clean_capacity_scaling/tests/test_resource_target_manager.py @@ -4,10 +4,6 @@ from unittest.mock import patch -def test_can_pass(): - assert 1 == 1 - - def test_expected_cap_factor(): solar = Resource('solar', 3) solar.set_capacity(0.25, 3700, 0.25) diff --git a/powersimdata/scaling/clean_capacity_scaling/tests/test_target_manager_input.py b/powersimdata/scaling/clean_capacity_scaling/tests/test_target_manager_input.py index b2d17fe8c..87eccf49a 100644 --- a/powersimdata/scaling/clean_capacity_scaling/tests/test_target_manager_input.py +++ b/powersimdata/scaling/clean_capacity_scaling/tests/test_target_manager_input.py @@ -1,7 +1,10 @@ from powersimdata.scaling.clean_capacity_scaling.auto_capacity_scaling \ import AbstractStrategyManager, TargetManager import pandas as pd -import pytest + + +def test_can_pass(): + assert 1 == 1 def test_create_targets_from_dataframe(): @@ -11,7 +14,8 @@ def test_create_targets_from_dataframe(): 'ce_target_fraction': [.25, .4], 'total_demand': [200000, 300000], 'external_ce_historical_amount': [0, 0], - 'solar_percentage': [.3, .6]} + 'solar_percentage':[.3, .6], + 'allowed_resources': ['solar', 'wind']} # future_data = {'total_demand': [200000, 300000], # 'external_ce_total_gen': [ 0, 0]} @@ -38,7 +42,8 @@ def test_populate_strategy_from_dataframe(): 'ce_target_fraction': [.25, .4], 'total_demand': [200000, 300000], 'external_ce_historical_amount': [0, 0], - 'solar_percentage': [.3, .6]} + 'solar_percentage':[.3, .6], + 'allowed_resources': ['solar', 'wind']} planning_dataframe = pd.DataFrame.from_dict(planning_data) strategy = AbstractStrategyManager() From baea5c3a1477be6e98e6d85a4322916071ea5f8e Mon Sep 17 00:00:00 2001 From: dmuldrew Date: Tue, 3 Mar 2020 15:14:05 -0800 Subject: [PATCH 2/4] chore: pep8 tweaks --- .../clean_capacity_scaling/tests/test_object_persistence.py | 1 + .../clean_capacity_scaling/tests/test_target_manager_input.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/powersimdata/scaling/clean_capacity_scaling/tests/test_object_persistence.py b/powersimdata/scaling/clean_capacity_scaling/tests/test_object_persistence.py index aa02d890d..0e180ee07 100644 --- a/powersimdata/scaling/clean_capacity_scaling/tests/test_object_persistence.py +++ b/powersimdata/scaling/clean_capacity_scaling/tests/test_object_persistence.py @@ -3,6 +3,7 @@ import jsonpickle import json + def test_create_json_of_target_object(): # create Pacific pacific_solar = Resource('solar', 3) diff --git a/powersimdata/scaling/clean_capacity_scaling/tests/test_target_manager_input.py b/powersimdata/scaling/clean_capacity_scaling/tests/test_target_manager_input.py index 87eccf49a..86edc5d27 100644 --- a/powersimdata/scaling/clean_capacity_scaling/tests/test_target_manager_input.py +++ b/powersimdata/scaling/clean_capacity_scaling/tests/test_target_manager_input.py @@ -14,7 +14,7 @@ def test_create_targets_from_dataframe(): 'ce_target_fraction': [.25, .4], 'total_demand': [200000, 300000], 'external_ce_historical_amount': [0, 0], - 'solar_percentage':[.3, .6], + 'solar_percentage' :[.3, .6], 'allowed_resources': ['solar', 'wind']} # future_data = {'total_demand': [200000, 300000], @@ -42,7 +42,7 @@ def test_populate_strategy_from_dataframe(): 'ce_target_fraction': [.25, .4], 'total_demand': [200000, 300000], 'external_ce_historical_amount': [0, 0], - 'solar_percentage':[.3, .6], + 'solar_percentage': [.3, .6], 'allowed_resources': ['solar', 'wind']} planning_dataframe = pd.DataFrame.from_dict(planning_data) From 8e9be7d87da77eab4f47c0b12d0d117009853ec9 Mon Sep 17 00:00:00 2001 From: dmuldrew Date: Tue, 3 Mar 2020 15:19:26 -0800 Subject: [PATCH 3/4] fix: error typo --- .../scaling/clean_capacity_scaling/auto_capacity_scaling.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powersimdata/scaling/clean_capacity_scaling/auto_capacity_scaling.py b/powersimdata/scaling/clean_capacity_scaling/auto_capacity_scaling.py index 48eff96b9..0c31395ca 100644 --- a/powersimdata/scaling/clean_capacity_scaling/auto_capacity_scaling.py +++ b/powersimdata/scaling/clean_capacity_scaling/auto_capacity_scaling.py @@ -534,7 +534,7 @@ def __init__(self, name, prev_scenario_num): # todo: input validation assert (type(name) == str), "name must be a string" assert (type(prev_scenario_num) == int), "prev_scenario_num must be " \ - "and integer" + "an integer" self.name = name self.prev_scenario_num = prev_scenario_num self.no_congestion_cap_factor = None From e68c0bb0316fdf56926554bc7d8382288008b970 Mon Sep 17 00:00:00 2001 From: dmuldrew Date: Tue, 3 Mar 2020 16:33:25 -0800 Subject: [PATCH 4/4] fix: pep8 space fix --- .../clean_capacity_scaling/tests/test_target_manager_input.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powersimdata/scaling/clean_capacity_scaling/tests/test_target_manager_input.py b/powersimdata/scaling/clean_capacity_scaling/tests/test_target_manager_input.py index 86edc5d27..5876a94c8 100644 --- a/powersimdata/scaling/clean_capacity_scaling/tests/test_target_manager_input.py +++ b/powersimdata/scaling/clean_capacity_scaling/tests/test_target_manager_input.py @@ -14,7 +14,7 @@ def test_create_targets_from_dataframe(): 'ce_target_fraction': [.25, .4], 'total_demand': [200000, 300000], 'external_ce_historical_amount': [0, 0], - 'solar_percentage' :[.3, .6], + 'solar_percentage': [.3, .6], 'allowed_resources': ['solar', 'wind']} # future_data = {'total_demand': [200000, 300000],