Skip to content

Commit 6283a45

Browse files
PatyHidalgostaadecker
authored andcommitted
Merge pull request #118 from staadecker/postprocess-fix
Cleanup and minor fixes to get_inputs post process
2 parents 4d98cd8 + 10b7cf5 commit 6283a45

11 files changed

+74
-93
lines changed

switch_model/tools/templates/config.yaml

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
# ------------------
88
# General config
99
# ------------------
10+
version: 3.0
1011
inputs_dir: inputs
1112

1213
# --------------------------------
@@ -17,7 +18,7 @@ get_inputs:
1718
schema: switch
1819

1920
# Scenario configuration
20-
scenario_id: <FILL_IN>
21+
scenario_id: 176
2122
# the following parameters are optional and will override the defaults for that scenario
2223
# this should only be used for preliminary exploration of scenarios or for testing
2324
# if a scenario is part of research, it should be included in the database as a row in the scenarios table.
@@ -42,20 +43,28 @@ get_inputs:
4243
# enable_planning_reserves:
4344
# generation_plant_technologies_scenario_id:
4445
# variable_o_m_cost_scenario_id:
45-
# add_storage was used by Martin when studying LDES
46-
# you likely don't need to use these parameters
47-
# they won't impact your runs
48-
# add_storage:
49-
# costs_scenario: 0
50-
# plants_scenario: 0
51-
# constant_scenario: 0
52-
# minimums_scenario: 0
53-
# When the following line is uncommented (regardless of its value) then only California load zones are kept
54-
# only_california: 0
55-
# When the following lines are uncommented all the Central_PV and Wind projects within the same load zone gets
56-
# aggregated into a single project. This helps reduce the model complexity.
57-
# cf_quantile is the percentile for the capacity factor to use. 1 will use the largest capacity factor
58-
# of all the available candidate plants, 0.5 will use the median plant and 0 will use the worst plant.
59-
# aggregate_projects_by_zone:
60-
# agg_techs: ["Central_PV"]
61-
# cf_method: "file" # Other options are "weighted_mean" and "95_quantile"
46+
# wind_to_solar_ratio:
47+
post_process_steps: # The following post process steps will be run in order
48+
# - add_storage # Used by Martin when studying LDES, likely shouldn't uncomment this line
49+
# - aggregate_candidate_projects
50+
- replace_plants_in_zone_all
51+
- create_graph_files
52+
# - energy_cost
53+
- fix_prebuild_conflict
54+
# - only_california
55+
# - reserve_technologies
56+
post_process_config:
57+
# add_storage was used by Martin when studying LDES you likely don't need to uncomment these parameters
58+
# add_storage:
59+
# costs_scenario: 0
60+
# plants_scenario: 0
61+
# constant_scenario: 0
62+
# minimums_scenario: 0
63+
64+
# When the following lines are uncommented all the Central_PV and Wind projects within the same load zone gets
65+
# aggregated into a single project. This helps reduce the model complexity.
66+
# cf_quantile is the percentile for the capacity factor to use. 1 will use the largest capacity factor
67+
# of all the available candidate plants, 0.5 will use the median plant and 0 will use the worst plant.
68+
# aggregate_candidate_projects:
69+
# agg_techs: ["Central_PV"]
70+
# cf_method: "file" # Other options are "weighted_mean" and "95_quantile"

switch_model/wecc/get_inputs/cli.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88
from switch_model.wecc.get_inputs.get_inputs import query_db
99
from switch_model.wecc.utilities import load_config
1010

11-
# from switch_model.wecc.get_inputs.post_process_steps import *
12-
# from switch_model.wecc.get_inputs.register_post_process import run_post_process, _registered_steps
13-
1411

1512
def main():
1613
timer = StepTimer()
@@ -68,14 +65,16 @@ def run_post_process(module):
6865
post_process = getattr(mod, "post_process")
6966

7067
# Get specific configuration for the post process if specified
71-
post_config = full_config.get(module, None)
68+
post_config = None
69+
if "post_process_config" in full_config and full_config["post_process_config"] is not None:
70+
post_config = full_config["post_process_config"].get(module, None)
7271

7372
# Run post process
74-
post_process(full_config, post_config)
73+
post_process(post_config)
7574

7675
# Run all post process specified, otherwise run single one
7776
if args.post_process_step is None:
78-
for module in full_config["post_process"]:
77+
for module in full_config["post_process_steps"]:
7978
run_post_process(module)
8079
else:
8180
run_post_process(getattr(args, "post_process_step"))

switch_model/wecc/get_inputs/post_process_steps/add_storage.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
the csvs in the inputs folder.
66
"""
77
import pandas as pd
8-
from switch_model.wecc.get_inputs.register_post_process import register_post_process
8+
from switch_model.wecc.get_inputs.register_post_process import post_process_step
99

1010

1111
def fetch_df(tab_name, key, config):
@@ -100,9 +100,7 @@ def drop_previous_candidate_storage():
100100
costs.to_csv("gen_build_costs.csv", index=False)
101101

102102

103-
@register_post_process(
104-
msg="Adding storage from Google Sheets",
105-
)
103+
@post_process_step(msg="Adding storage from Google Sheets")
106104
def post_process(config):
107105
# Drop previous candidate storage from inputs
108106
drop_previous_candidate_storage()

switch_model/wecc/get_inputs/post_process_steps/aggregate_candidate_projects.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717
import numpy as np
1818
import pandas as pd
1919

20-
from switch_model.wecc.get_inputs.register_post_process import register_post_process
20+
from switch_model.wecc.get_inputs.register_post_process import post_process_step
2121

2222

23-
@register_post_process(
24-
msg="Aggregating candidate projects by load zone for specified technologies",
23+
@post_process_step(
24+
msg="Aggregating candidate projects by load zone for specified technologies"
2525
)
26-
def post_process(config, func_config):
26+
def post_process(func_config):
2727
agg_techs = func_config["agg_techs"]
2828
cf_method = func_config["cf_method"]
2929
assert type(agg_techs) == list
@@ -51,7 +51,14 @@ def post_process(config, func_config):
5151
should_agg = df["gen_tech"].isin(agg_techs) & (~df[key].isin(predetermined))
5252
if cf_method == "file":
5353
# Filter out projects where we don't have a capacity factor
54-
zonal_cf = pd.read_csv("zonal_capacity_factors.csv", index_col=False)
54+
try:
55+
zonal_cf = pd.read_csv("zonal_capacity_factors.csv", index_col=False)
56+
except FileNotFoundError:
57+
raise Exception(
58+
"Post process step 'aggregate_candidate_projects' with method 'file'"
59+
" requires an external zonal_capacity_factors.csv to exist. This file can be generated"
60+
" using the scripts in zonal_capacity_factors.csv."
61+
)
5562
valid_proj = df.merge(
5663
zonal_cf[["gen_load_zone", "gen_tech"]].drop_duplicates(),
5764
on=["gen_load_zone", "gen_tech"],

switch_model/wecc/get_inputs/post_process_steps/create_graph_files.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import pandas as pd
22

3-
from switch_model.wecc.get_inputs.register_post_process import register_post_process
3+
from switch_model.wecc.get_inputs.register_post_process import post_process_step
44

55

6-
@register_post_process(msg="Creating graph files")
7-
def post_process(config, *args, **kwargs):
6+
@post_process_step(msg="Creating graph files")
7+
def post_process(_):
88
timepoints = pd.read_csv("timepoints.csv", index_col=False)
99
timeseries = pd.read_csv("timeseries.csv", index_col=False)
1010
timepoints = timepoints.merge(

switch_model/wecc/get_inputs/post_process_steps/energy_cost.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
# Third-party packages
66
import pandas as pd
77

8-
from switch_model.wecc.get_inputs.register_post_process import register_post_process
8+
from switch_model.wecc.get_inputs.register_post_process import post_process_step
99

1010

11-
@register_post_process(
11+
@post_process_step(
1212
msg="Change energy cost for storage candidate",
1313
)
14-
def post_process(config, func_config):
14+
def post_process(func_config):
1515

1616
percentage = int(func_config["percentage"]) / 100
1717
dtype = {"GENERATION_PROJECT": str}

switch_model/wecc/get_inputs/post_process_steps/fix_prebuild_conflict.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import pandas as pd
22

3-
from switch_model.wecc.get_inputs.register_post_process import register_post_process
3+
from switch_model.wecc.get_inputs.register_post_process import post_process_step
44

55

6-
@register_post_process(msg="Shifting 2020 pre-build years to 2019")
7-
def post_process(config, *args, **kwargs):
6+
@post_process_step(msg="Shifting 2020 pre-build years to 2019")
7+
def post_process(_):
88
"""
99
This post-processing step is necessary to pass the no_predetermined_bld_yr_vs_period_conflict BuildCheck.
1010
Basically we are moving all the 2020 predetermined build years to 2019 to avoid a conflict with the 2020 period.
@@ -15,9 +15,13 @@ def post_process(config, *args, **kwargs):
1515
return
1616

1717
# Read two files that need modification
18-
gen_build_costs = pd.read_csv("gen_build_costs.csv", index_col=False)
18+
gen_build_costs = pd.read_csv(
19+
"gen_build_costs.csv", index_col=False, dtype={"GENERATION_PROJECT": object}
20+
)
1921
gen_build_predetermined = pd.read_csv(
20-
"gen_build_predetermined.csv", index_col=False
22+
"gen_build_predetermined.csv",
23+
index_col=False,
24+
dtype={"GENERATION_PROJECT": object},
2125
)
2226
# Save their size
2327
rows_prior = gen_build_costs.size, gen_build_predetermined.size

switch_model/wecc/get_inputs/post_process_steps/only_california.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
import pandas as pd
22

3-
from switch_model.wecc.get_inputs.register_post_process import register_post_process
3+
from switch_model.wecc.get_inputs.register_post_process import post_process_step
44
from switch_model.tools.drop import main as drop
55

66

7-
@register_post_process(
8-
name="only_california",
9-
msg="Dropping all the zones outside of California",
10-
priority=3,
11-
)
7+
@post_process_step(msg="Dropping all the zones outside of California")
128
def main(_):
139
df = pd.read_csv("load_zones.csv", index_col=False)
1410
df = df[df["LOAD_ZONE"].str.startswith("CA_")]

switch_model/wecc/get_inputs/post_process_steps/replace_plants_in_zone_all.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import pandas as pd
22

3-
from switch_model.wecc.get_inputs.register_post_process import register_post_process
3+
from switch_model.wecc.get_inputs.register_post_process import post_process_step
44

55

6-
@register_post_process(msg="Replacing _ALL_ZONES plants with a plant in each zone")
7-
def post_process(config, *args, **kwargs):
6+
@post_process_step(msg="Replacing _ALL_ZONES plants with a plant in each zone")
7+
def post_process(_):
88
"""
99
This post-process step replaces all the generation projects that have a load called
1010
_ALL_ZONES with a generation project for each load zone.

switch_model/wecc/get_inputs/post_process_steps/reserve_technologies.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,15 @@
66
# Third-party packages
77
import pandas as pd
88

9-
from switch_model.wecc.get_inputs.register_post_process import register_post_process
9+
from switch_model.wecc.get_inputs.register_post_process import post_process_step
1010

1111

12-
@register_post_process(
13-
name="no_fosill_reserve",
14-
msg="Aggregating candidate projects by load zone for specified technologies",
15-
only_with_config=True,
16-
priority=4,
12+
@post_process_step(
13+
msg="Removing fossil fuels from reserves.",
1714
)
18-
def post_process(config):
15+
def post_process(_):
1916
"""This function sets to zero the column that allows each candidate technology to
20-
proividee"""
17+
provide"""
2118

2219
fname = "generation_projects_info.csv"
2320
df = pd.read_csv(fname)
Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,18 @@
11
"""
2-
This file provides two functions
3-
4-
1. register_post_process(msg, enabled=True) which is a function decorator that allows registering a function
5-
as a post-process step.
6-
7-
2. run_post_process() which runs the registered post process steps.
8-
9-
These 2 functions are kept in a separate file to avoid cyclical dependencies.
2+
This file provides the decorator post_process_step(msg)
3+
which is a function decorator that ensures the post processing step is printed.
104
"""
115

126
from functools import wraps
13-
import functools
147

15-
_registered_steps = {}
168

17-
18-
def register_post_process(
9+
def post_process_step(
1910
msg=None,
2011
):
2112
"""
2213
Decorator that should be used to register a post-processing step.
2314
2415
@param msg The message to display while running this step.
25-
@param enabled Whether we should be using this step.
26-
@param name Name of the post processing step and of the config section
27-
@param only_with_config if True the step will only run if 'name' exists in the config file
28-
@param priority 0 is highest priority (runs first) and larger numbers are lower priority.
2916
"""
3017

3118
def decorator(func):
@@ -40,19 +27,3 @@ def wrapper(*args, **kwargs):
4027
return wrapper
4128

4229
return decorator
43-
44-
45-
def run_post_process(config, step_name=None):
46-
"""
47-
Run the post processing steps.
48-
49-
@param config The values from config.yaml (already parsed)
50-
@param step_name if step_name is None we run all the steps. If it's specified we only run that step.
51-
"""
52-
if step_name is None:
53-
for name, func in sorted(
54-
_registered_steps.items(), key=lambda s: s[1].priority
55-
):
56-
func(config.get(name, None))
57-
else:
58-
_registered_steps[step_name](config.get(step_name, None))

0 commit comments

Comments
 (0)