Skip to content

Commit

Permalink
Add lots of tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Merrielle Ondreicka committed Nov 8, 2019
1 parent f205d75 commit 5c3b5a0
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 71 deletions.
72 changes: 71 additions & 1 deletion postreise/plot/multi/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,74 @@
'coal': sns.xkcd_rgb["light brown"],
'other inc. biomass': 'rebeccapurple',
'other': 'royalblue'
}
}
BASELINES = {
'Arizona': 4.567094,
'California': 81.0,
'Colorado': 11.039050999999999,
'Idaho': 2.5057110000000002,
'Montana Western': 2.28368,
'Nevada': 7.047959,
'New Mexico Western': 2.5586450000000003,
'Oregon': 7.509413,
'Utah': 2.798768,
'Washington': 96.129826,
'Wyoming': 5.9288989999999995,
'El Paso': 0.021684000000000002,
'Western': 223.369046}
CA_BASELINES = {
'Arizona': 4.567094,
'California': 48.954528,
'Colorado': 11.039050999999999,
'Idaho': 2.5057110000000002,
'Montana Western': 2.28368,
'Nevada': 7.047959,
'New Mexico Western': 2.5586450000000003,
'Oregon': 7.509413,
'Utah': 2.798768,
'Washington': 96.129826,
'Wyoming': 5.9288989999999995,
'El Paso': 0.021684000000000002,
'Western': 191.34526}
TARGETS = {
'Arizona': 14.556582999999998,
'California': 203.49599999999998,
'Colorado': 18.892801000000002,
'Idaho': 0.0,
'Montana Western': 2.248663,
'Nevada': 20.942648000000002,
'New Mexico Western': 9.613257,
'Oregon': 13.704619000000001,
'Utah': 6.94292,
'Washington': 95.334513,
'Wyoming': 0.0,
'El Paso': 0.0,
'Western': 385.732004}
CA_TARGETS = {
'Arizona': 58.22633199999999,
'California': 203.49599999999998,
'Colorado': 37.785602000000004,
'Idaho': 23.28269,
'Montana Western': 8.994652,
'Nevada': 25.131178,
'New Mexico Western': 11.535909,
'Oregon': 32.891086,
'Utah': 20.828761,
'Washington': 71.500885,
'Wyoming': 11.379466,
'El Paso': 0.0,
'Western': 505.052561}
DEMAND = {
'Arizona': 97.04388686,
'California': 339.16,
'Colorado': 62.97600378,
'Idaho': 38.80448402,
'Montana Western': 14.991087099999998,
'Nevada': 41.88529659,
'New Mexico Western': 19.22651448,
'Oregon': 54.81847715,
'Utah': 34.71460116,
'Washington': 119.16814099999999,
'Wyoming': 18.96577653,
'El Paso': 0.0,
'Western': 841.7542689999999}
2 changes: 0 additions & 2 deletions postreise/plot/multi/plot_bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
import matplotlib.pyplot as plt
import numpy as np

from collections import OrderedDict

from postreise.plot.multi.constants import ALL_RESOURCE_TYPES, RESOURCE_LABELS
from postreise.plot.multi.plot_helpers import handle_plot_inputs

Expand Down
35 changes: 10 additions & 25 deletions postreise/plot/multi/plot_helpers.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import pandas as pd
import matplotlib.pyplot as plt

from collections import OrderedDict
from postreise.plot.analyze_pg import AnalyzePG as apg
from powersimdata.scenario.scenario import Scenario

from postreise.plot.multi.constants import ZONES, SCENARIO_RESOURCE_TYPES
from postreise.plot.multi.constants import ZONES, SCENARIO_RESOURCE_TYPES, BASELINES, CA_BASELINES, TARGETS, CA_TARGETS, DEMAND

# Checks input validity for plotting code, fetches data if necessary
# param: interconnect: either 'Western' or 'Texas'
Expand All @@ -26,7 +25,7 @@ def handle_plot_inputs(interconnect, scenario_ids, custom_data):
if custom_data == None:
custom_data = {}

graph_data = OrderedDict(scenario_data, **custom_data)
graph_data = dict(scenario_data, **custom_data)
return (zone_list, graph_data)

# Checks input validity for shortfall plotting code, fetches data if necessary
Expand All @@ -42,9 +41,12 @@ def handle_plot_inputs(interconnect, scenario_ids, custom_data):
def handle_shortfall_inputs(interconnect, scenario_ids, custom_data, is_match_CA, baselines, targets, demand):
zone_list, graph_data = handle_plot_inputs(interconnect, scenario_ids, custom_data)

baselines = _fetch_baselines() if baselines == None else baselines
targets = _fetch_targets(is_match_CA) if targets == None else targets
demand = _fetch_demand() if demand == None else demand
if baselines == None:
baselines = CA_BASELINES if is_match_CA else BASELINES
if targets == None:
targets = CA_TARGETS if is_match_CA else TARGETS
if demand == None:
demand = DEMAND

return zone_list, graph_data, baselines, targets, demand

Expand All @@ -59,7 +61,7 @@ def unit_conversion(val, change): return round(val/1000**change, 2)
# param zone_list: list(string) of zone names
# returns: formatted scenario data
def _get_scenario_data(scenario_ids, zone_list):
scenario_data = OrderedDict()
scenario_data = dict()
for id in scenario_ids:
data_chart, scenario_name = _get_data_chart_from_scenario(id, zone_list)
scenario_data[id] = _format_scenario_data(data_chart, scenario_name)
Expand Down Expand Up @@ -134,22 +136,5 @@ def _get_data_chart_from_csv(file_loc_1, file_loc_2, region, index='(in MW)'):
data.append(df.to_dict())

return data

# Imports baseline data from a locally stored csv
def _fetch_baselines():
baselines = {} # TODO import from csv
return baselines

# Imports target data from a locally stored csv
def _fetch_targets(is_match_CA):
if is_match_CA:
targets = {} # TODO import from csv
else:
targets = {} # TODO import from csv
return targets

# Imports demand data from a locally stored csv
def _fetch_demand():
demand = {} # TODO import from csv
return demand


2 changes: 0 additions & 2 deletions postreise/plot/multi/plot_pie.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
import matplotlib.pyplot as plt
import numpy as np

from collections import OrderedDict

from postreise.plot.multi.constants import ALL_RESOURCE_TYPES, RESOURCE_LABELS, RESOURCE_COLORS
from postreise.plot.multi.plot_helpers import handle_plot_inputs

Expand Down
51 changes: 30 additions & 21 deletions postreise/plot/multi/plot_shortfall.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
import matplotlib.pyplot as plt
import numpy as np

from collections import OrderedDict

from postreise.plot.multi.plot_helpers import handle_shortfall_inputs

# plot_shortfall: Plots any number of scenarios with two columns per scenario
Expand Down Expand Up @@ -33,6 +31,8 @@ def plot_shortfall(interconnect, scenario_ids=None, custom_data=None, is_match_C
_construct_shortfall_visuals(zone, ax_data, shortfall_pct_list, targets[zone], is_match_CA)
print(f'\nDone\n')

# returns: dictionary of data to visualize { '2016 NREL': {'2016 Renewables': 100, 'Simulated increase in renewables': 30, 'Missed target': 10 }, ...}
# and a list of shortfall percentages to show on the graph
def _construct_shortfall_ax_data(zone, scenarios, is_match_CA, baseline, target, demand):
ax_data = {}
shortfall_pct_list = []
Expand All @@ -54,36 +54,28 @@ def _construct_shortfall_ax_data(zone, scenarios, is_match_CA, baseline, target,

return ax_data, shortfall_pct_list

def _get_total_generated_renewables(zone, resource_data, is_match_CA):
CA_extras = 32045472

resource_types = ['wind', 'solar', 'geothermal']
total_renewables = [resource_data[resource] if resource in resource_data.keys() else 0 for resource in resource_types].sum()

# Scenario data does not include Extras for California so we add them back in
if zone == 'California':
total_renewables += CA_extras
# Washington's goals also include "clean energy", i.e. nuclear and hydro
if zone == 'Washington' and not is_match_CA:
total_renewables += resource_data['hydro'] + resource_data['nuclear']

return total_renewables

# Western has unique needs for data construction
# there are special rules around calculating shortfall when a scenario is collaborative vs. when it's independent.
# returns: dictionary of data to visualize { '2016 NREL': {'2016 Renewables': 100, 'Simulated increase in renewables': 30, 'Missed target': 10 }, ...}
# and a list of shortfall percentages to show on the graph
def _construct_shortfall_data_for_western(scenarios, is_match_CA, has_collaborative_scenarios, baseline, targets, demand):
ax_data = {}
shortfall_pct_list = []

for s_id, scenario in scenarios.items():
zone_list = scenario['gen']['data'].keys()
zone_list.remove('Western')
zone_list = list(scenario['gen']['data'].keys())
if 'Western' in zone_list:
zone_list.remove('Western')
renewables_by_zone = {zone: _get_total_generated_renewables(zone, scenario['gen']['data'][zone], is_match_CA) for zone in zone_list}

if s_id in has_collaborative_scenarios:
# When states can collaborate they make up for each other's shortfall
if has_collaborative_scenarios != None and s_id in has_collaborative_scenarios:
total_renewables = sum(renewables_by_zone.values())
shortfall = shortfall = max(0, round(targets['Western'] - total_renewables, 2))
else:
# When the zones do not collaborate, zones with extra renewables can't help zones with shortfall
shortfall = sum([max(0, round(targets['Western'] - renewables_by_zone[zone], 2)) for zone in zone_list])
# thus the shortfall is the sum of the shortfall from every state
shortfall = sum([max(0, round(targets[zone] - renewables_by_zone[zone], 2)) for zone in zone_list])
# total_renewables here is meaningless in terms of the shortfall so we fudge it to match the target line
total_renewables = targets['Western'] - shortfall

Expand All @@ -97,6 +89,23 @@ def _construct_shortfall_data_for_western(scenarios, is_match_CA, has_collaborat

return ax_data, shortfall_pct_list

# returns the sum of all the renewable energy generated in a zone
def _get_total_generated_renewables(zone, resource_data, is_match_CA):
CA_extras = 32.045472

resource_types = ['wind', 'solar', 'geothermal']
total_renewables = sum([resource_data[resource] if resource in resource_data.keys() else 0 for resource in resource_types])

# Scenario data does not include Extras for California so we add them back in
if zone == 'California':
total_renewables += CA_extras
# Washington's goals also include "clean energy", i.e. nuclear and hydro
if zone == 'Washington' and not is_match_CA:
resource_types = ['hydro', 'nuclear']
total_renewables += sum([resource_data[resource] if resource in resource_data.keys() else 0 for resource in resource_types])

return total_renewables

def _construct_shortfall_visuals(zone, ax_data, shortfall_pct_list, target, is_match_CA):
df = pd.DataFrame(ax_data).T
ax = df.plot.bar(stacked=True, color=['darkgreen', 'yellowgreen', 'salmon'], figsize=(10, 8), fontsize=16)
Expand Down
30 changes: 27 additions & 3 deletions postreise/plot/multi/test/mock_graph_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,31 @@
}
}

_MORE_MOCK_DATA = {
'87': {
'Arizona': {'solar': 17.0},
'Colorado': {'ng': 12.0, 'solar': 3.0, 'hydro': 10.0},
'Oregon': {'wind': 7.0, 'hydro': 5.0},
'Western': {'solar': 20.0, 'wind': 7.0, 'ng': 12.0, 'hydro': 15}
},
'2016_nrel': {
'Arizona': {'solar': 15.0},
'Colorado': {'ng': 14.0, 'solar': 5.0, 'hydro': 10.0},
'Oregon': {'wind': 11.0, 'hydro': 5.0},
'Western': {'solar': 20.0, 'wind': 11.0, 'ng': 14.0, 'hydro': 15}
}
}

# Factory for creating mock graph data
# will eventually have parameters to customize the data returned
def create_mock_graph_data():
return _MOCK_GRAPH_DATA
# param: more_gen - adds more robust data to mock data generation
# will eventually have more parameters to customize the data returned
def create_mock_graph_data(more_gen=False):
if more_gen == False:
return _MOCK_GRAPH_DATA
else:
copy_graph_data = _MOCK_GRAPH_DATA.copy()
for scenario, data in _MORE_MOCK_DATA.items():
copy_graph_data[scenario]['gen']['data'] = data
return copy_graph_data


24 changes: 22 additions & 2 deletions postreise/plot/multi/test/test_plot_helpers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytest
from pprint import pprint

from postreise.plot.multi.constants import ZONES
from postreise.plot.multi.constants import ZONES, BASELINES, CA_BASELINES, TARGETS, CA_TARGETS, DEMAND
from postreise.plot.multi.test.mock_graph_data import create_mock_graph_data
from postreise.plot.multi.test.mock_data_chart import create_mock_data_chart
from postreise.plot.multi.plot_helpers import handle_plot_inputs, handle_shortfall_inputs, _format_scenario_data, unit_conversion
Expand All @@ -14,7 +15,25 @@ def test_handle_plot_inputs():
assert zone_list == ZONES['Western']
assert graph_data == mock_graph_data

def test_handle_shortfall_inputs():
def test_handle_shortfall_inputs_where_is_match_CA_is_false():
mock_graph_data = create_mock_graph_data()
zone_list, graph_data, baselines, targets, demand = handle_shortfall_inputs('Western', None, mock_graph_data, False, None, None, None)
assert zone_list == ZONES['Western']
assert graph_data == mock_graph_data
assert baselines == BASELINES
assert targets == TARGETS
assert demand == DEMAND

def test_handle_shortfall_inputs_where_is_match_CA_is_true():
mock_graph_data = create_mock_graph_data()
zone_list, graph_data, baselines, targets, demand = handle_shortfall_inputs('Western', None, mock_graph_data, True, None, None, None)
assert zone_list == ZONES['Western']
assert graph_data == mock_graph_data
assert baselines == CA_BASELINES
assert targets == CA_TARGETS
assert demand == DEMAND

def test_handle_shortfall_inputs_with_baseline_target_and_demand_params():
mock_graph_data = create_mock_graph_data()
dummy_baselines = {'b': 1}
dummy_targets = {'t': 2}
Expand Down Expand Up @@ -44,3 +63,4 @@ def test_unit_conversion_increase_by_2():

def test_unit_conversion_decrease_by_1():
assert unit_conversion(0.32, -1) == 320.00

Loading

0 comments on commit 5c3b5a0

Please sign in to comment.