Skip to content

Commit 7a0cab7

Browse files
pesapstaadecker
authored andcommitted
Merge pull request #110 from REAM-lab/feature/post_process
Refactoring and simplification of postprocess
2 parents 5b2af27 + d8b918f commit 7a0cab7

File tree

11 files changed

+364
-190
lines changed

11 files changed

+364
-190
lines changed

switch_model/wecc/get_inputs/cli.py

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
""" Script to retrieve the input data from the switch-wecc database and apply post-processing steps.
22
"""
33
import argparse
4+
import importlib
45
import os
56

67
from switch_model.utilities import query_yes_no, StepTimer
78
from switch_model.wecc.get_inputs.get_inputs import query_db
8-
from switch_model.wecc.get_inputs.register_post_process import run_post_process
99
from switch_model.wecc.utilities import load_config
10-
from switch_model.wecc.get_inputs.post_process_steps import *
10+
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
1113

1214

1315
def main():
@@ -21,23 +23,64 @@ def main():
2123
config.yaml specifies the scenario parameters.
2224
The environment variable DB_URL specifies the url to connect to the database. """,
2325
)
24-
parser.add_argument("--skip-cf", default=False, action='store_true',
25-
help="Skip creation variable_capacity_factors.csv. Useful when debugging and one doesn't"
26-
"want to wait for the command.")
27-
parser.add_argument("--post-process", default=None, help="Run only this post process step.")
28-
parser.add_argument("--overwrite", default=False, action='store_true',
29-
help="Overwrite previous input files without prompting to confirm.")
26+
parser.add_argument(
27+
"--skip-cf",
28+
default=False,
29+
action="store_true",
30+
help="Skip creation variable_capacity_factors.csv. Useful when debugging and one doesn't"
31+
"want to wait for the command.",
32+
)
33+
parser.add_argument(
34+
"--post-process-only",
35+
default=False,
36+
action="store_true",
37+
help="Run only post process steps.",
38+
)
39+
parser.add_argument(
40+
"--post-process-step", default=None, help="Run only this post process step."
41+
)
42+
parser.add_argument(
43+
"--overwrite",
44+
default=False,
45+
action="store_true",
46+
help="Overwrite previous input files without prompting to confirm.",
47+
)
3048
args = parser.parse_args() # Makes switch get_inputs --help works
3149

3250
# Load values from config.yaml
3351
full_config = load_config()
3452
switch_to_input_dir(full_config, overwrite=args.overwrite)
3553

36-
if args.post_process is None:
54+
if not args.post_process_only and args.post_process_step is None:
3755
query_db(full_config, skip_cf=args.skip_cf)
38-
print("Post-processing...")
39-
run_post_process(full_config, step_name=args.post_process)
40-
print(f"\nScript took {timer.step_time_as_str()} seconds to build input tables.")
56+
57+
print("\nRunning post processing...")
58+
59+
# Get location of post process scripts
60+
post_process_path = ".".join(__name__.split(".")[:-1]) + ".post_process_steps"
61+
62+
def run_post_process(module):
63+
""" Run a function from a given module """
64+
65+
# This uses python module syntax with a dot. Example: import foo.bar.test
66+
mod = importlib.import_module(f".{module}", post_process_path)
67+
68+
post_process = getattr(mod, "post_process")
69+
70+
# Get specific configuration for the post process if specified
71+
post_config = full_config.get(module, None)
72+
73+
# Run post process
74+
post_process(full_config, post_config)
75+
76+
# Run all post process specified, otherwise run single one
77+
if args.post_process_step is None:
78+
for module in full_config["post_process"]:
79+
run_post_process(module)
80+
else:
81+
run_post_process(getattr(args, "post_process_step"))
82+
83+
print(f"\nScript took {timer.step_time_as_str()} seconds.")
4184

4285

4386
def switch_to_input_dir(config, overwrite):
@@ -49,7 +92,7 @@ def switch_to_input_dir(config, overwrite):
4992
print("Inputs directory created.")
5093
else:
5194
if not overwrite and not query_yes_no(
52-
"Inputs directory already exists. Allow contents to be overwritten?"
95+
"Inputs directory already exists. Allow contents to be overwritten?"
5396
):
5497
raise SystemExit("User cancelled run.")
5598

switch_model/wecc/get_inputs/get_inputs.py

100755100644
Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from switch_model.wecc.utilities import connect
2222
from switch_model.version import __version__
2323

24+
2425
def write_csv_from_query(cursor, fname: str, headers: List[str], query: str):
2526
"""Create CSV file from cursor."""
2627
print(f"\t{fname}.csv... ", flush=True, end="")
@@ -334,7 +335,7 @@ def query_db(config, skip_cf):
334335
[
335336
"trans_capital_cost_per_mw_km",
336337
"trans_lifetime_yrs",
337-
"trans_fixed_om_fraction"
338+
"trans_fixed_om_fraction",
338339
],
339340
f"""
340341
SELECT trans_capital_cost_per_mw_km,
@@ -433,7 +434,7 @@ def query_db(config, skip_cf):
433434
"gen_self_discharge_rate",
434435
"gen_discharge_efficiency",
435436
"gen_land_use_rate",
436-
"gen_storage_energy_to_power_ratio"
437+
"gen_storage_energy_to_power_ratio",
437438
],
438439
f"""
439440
select
@@ -480,7 +481,12 @@ def query_db(config, skip_cf):
480481
write_csv_from_query(
481482
db_cursor,
482483
"gen_build_predetermined",
483-
["GENERATION_PROJECT", "build_year", "gen_predetermined_cap", "gen_predetermined_storage_energy_mwh"],
484+
[
485+
"GENERATION_PROJECT",
486+
"build_year",
487+
"gen_predetermined_cap",
488+
"gen_predetermined_storage_energy_mwh",
489+
],
484490
f"""select generation_plant_id, build_year, capacity as gen_predetermined_cap, gen_predetermined_storage_energy_mwh
485491
from generation_plant_existing_and_planned
486492
join generation_plant as t using(generation_plant_id)
@@ -529,7 +535,7 @@ def query_db(config, skip_cf):
529535
########################################################
530536
# FINANCIALS
531537

532-
#updated from $2016 and 7%
538+
# updated from $2016 and 7%
533539
write_csv(
534540
[[2018, 0.05, 0.05]],
535541
"financials",
@@ -591,7 +597,7 @@ def query_db(config, skip_cf):
591597
WHERE time_sample_id = {time_sample_id}
592598
AND study_timeframe_id = {study_timeframe_id}
593599
ORDER BY 1;
594-
"""
600+
""",
595601
)
596602

597603
write_csv_from_query(
@@ -655,7 +661,7 @@ def query_db(config, skip_cf):
655661
where period!=0
656662
group by period
657663
order by 1;
658-
"""
664+
""",
659665
)
660666

661667
########################################################
@@ -679,7 +685,7 @@ def query_db(config, skip_cf):
679685
where period!=0
680686
group by load_zone, period
681687
order by 1, 2;
682-
"""
688+
""",
683689
)
684690
modules.append("switch_model.policies.rps_unbundled")
685691

@@ -901,11 +907,17 @@ def ca_policies(db_cursor, scenario_params):
901907
write_csv_from_query(
902908
db_cursor,
903909
"ca_policies",
904-
['PERIOD', 'ca_min_gen_timepoint_ratio', 'ca_min_gen_period_ratio', 'carbon_cap_tco2_per_yr_CA'],
905-
query
910+
[
911+
"PERIOD",
912+
"ca_min_gen_timepoint_ratio",
913+
"ca_min_gen_period_ratio",
914+
"carbon_cap_tco2_per_yr_CA",
915+
],
916+
query,
906917
)
907918

908-
modules.append('switch_model.policies.CA_policies')
919+
modules.append("switch_model.policies.CA_policies")
920+
909921

910922
def planning_reserves(db_cursor, scenario_params):
911923
# reserve_capacity_value.csv specifies the capacity factors that should be used when calculating
@@ -917,7 +929,7 @@ def planning_reserves(db_cursor, scenario_params):
917929
write_csv_from_query(
918930
db_cursor,
919931
"reserve_capacity_value",
920-
["GENERATION_PROJECT","timepoint","gen_capacity_value"],
932+
["GENERATION_PROJECT", "timepoint", "gen_capacity_value"],
921933
f"""
922934
select
923935
generation_plant_id,
@@ -954,7 +966,11 @@ def planning_reserves(db_cursor, scenario_params):
954966
write_csv_from_query(
955967
db_cursor,
956968
"planning_reserve_requirements",
957-
["PLANNING_RESERVE_REQUIREMENT", "prr_cap_reserve_margin", "prr_enforcement_timescale"],
969+
[
970+
"PLANNING_RESERVE_REQUIREMENT",
971+
"prr_cap_reserve_margin",
972+
"prr_enforcement_timescale",
973+
],
958974
"""
959975
SELECT
960976
planning_reserve_requirement, prr_cap_reserve_margin, prr_enforcement_timescale

switch_model/wecc/get_inputs/post_process_steps/add_storage.py

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

1110

@@ -17,16 +16,16 @@ def fetch_df(tab_name, key, config):
1716
"constants": 0,
1817
"plants": 889129113,
1918
"costs": 1401952285,
20-
"minimums": 1049456965
19+
"minimums": 1049456965,
2120
}
2221
SHEET_ID = "1SJrj039T1T95NLTs964VQnsfZgo2QWCo29x2ireVYcU"
2322

2423
gid = TAB_NAME_GID[tab_name]
2524
url = f"https://docs.google.com/spreadsheet/ccc?key={SHEET_ID}&output=csv&gid={gid}"
2625

27-
df: pd.DataFrame = pd.read_csv(url, index_col=False) \
28-
.replace("FALSE", False) \
29-
.replace("TRUE", True)
26+
df: pd.DataFrame = (
27+
pd.read_csv(url, index_col=False).replace("FALSE", False).replace("TRUE", True)
28+
)
3029

3130
if "description" in df.columns:
3231
df = df.drop("description", axis=1)
@@ -43,17 +42,16 @@ def filer_by_scenario(df, scenario_column, config):
4342
if scenario_column in config:
4443
scenario = config[scenario_column]
4544
else:
46-
scenario = input(f"Which scenario do you want for '{scenario_column}' (default 0) : ")
45+
scenario = input(
46+
f"Which scenario do you want for '{scenario_column}' (default 0) : "
47+
)
4748
scenario = int(scenario) if scenario != "" else 0
4849
df = df[df[scenario_column] == scenario]
4950
return df.drop(scenario_column, axis=1)
5051

5152

5253
def cross_join(df1, df2):
53-
return df1.assign(key=1).merge(
54-
df2.assign(key=1),
55-
on="key"
56-
).drop("key", axis=1)
54+
return df1.assign(key=1).merge(df2.assign(key=1), on="key").drop("key", axis=1)
5755

5856

5957
def add_to_csv(filename, to_add, primary_key=None, append=True):
@@ -83,8 +81,12 @@ def drop_previous_candidate_storage():
8381

8482
gen = pd.read_csv("generation_projects_info.csv", index_col=False)
8583
# Find generation projects that are both storage and not predetermined (i.e. candidate)
86-
predetermined_gen = pd.read_csv("gen_build_predetermined.csv", index_col=False)["GENERATION_PROJECT"]
87-
should_drop = (gen["gen_tech"] == STORAGE_TECH) & ~gen["GENERATION_PROJECT"].isin(predetermined_gen)
84+
predetermined_gen = pd.read_csv("gen_build_predetermined.csv", index_col=False)[
85+
"GENERATION_PROJECT"
86+
]
87+
should_drop = (gen["gen_tech"] == STORAGE_TECH) & ~gen["GENERATION_PROJECT"].isin(
88+
predetermined_gen
89+
)
8890
# Find projects that we should drop (candidate storage)
8991
gen_to_drop = gen[should_drop]["GENERATION_PROJECT"]
9092

@@ -99,30 +101,46 @@ def drop_previous_candidate_storage():
99101

100102

101103
@register_post_process(
102-
name="add_storage",
103104
msg="Adding storage from Google Sheets",
104-
only_with_config=True,
105-
priority=1 # Increased priority (default is 2) so that it always runs before replace_plants_in_zone_all.py
106105
)
107-
def main(config):
106+
def post_process(config):
108107
# Drop previous candidate storage from inputs
109108
drop_previous_candidate_storage()
110109

111110
# Get the generation storage plants from Google Sheet
112-
gen_projects = fetch_df("constants", "constant_scenario", config).set_index("param_name").transpose()
113-
gen_projects = cross_join(gen_projects, fetch_df("plants", "plants_scenario", config))
111+
gen_projects = (
112+
fetch_df("constants", "constant_scenario", config)
113+
.set_index("param_name")
114+
.transpose()
115+
)
116+
gen_projects = cross_join(
117+
gen_projects, fetch_df("plants", "plants_scenario", config)
118+
)
114119

115120
# Append the storage plants to the inputs
116-
add_to_csv("generation_projects_info.csv", gen_projects, primary_key="GENERATION_PROJECT")
121+
add_to_csv(
122+
"generation_projects_info.csv", gen_projects, primary_key="GENERATION_PROJECT"
123+
)
117124

118125
# Create min_per_tech.csv
119126
min_projects = fetch_df("minimums", "minimums_scenario", config)
120-
add_to_csv("min_per_tech.csv", min_projects, primary_key=["gen_tech", "period"], append=False)
127+
add_to_csv(
128+
"min_per_tech.csv",
129+
min_projects,
130+
primary_key=["gen_tech", "period"],
131+
append=False,
132+
)
121133

122134
# Get the plant costs from GSheets and append to costs
123135
storage_costs = fetch_df("costs", "costs_scenario", config)
124-
storage_costs = storage_costs[storage_costs["GENERATION_PROJECT"].isin(gen_projects["GENERATION_PROJECT"])]
125-
add_to_csv("gen_build_costs.csv", storage_costs, primary_key=["GENERATION_PROJECT", "build_year"])
136+
storage_costs = storage_costs[
137+
storage_costs["GENERATION_PROJECT"].isin(gen_projects["GENERATION_PROJECT"])
138+
]
139+
add_to_csv(
140+
"gen_build_costs.csv",
141+
storage_costs,
142+
primary_key=["GENERATION_PROJECT", "build_year"],
143+
)
126144

127145
# Create add_storage_info.csv
128146
pd.DataFrame([config]).transpose().to_csv("add_storage_info.csv", header=False)
@@ -132,9 +150,9 @@ def main(config):
132150
gen_type.columns = ["gen_tech", "energy_source"]
133151
gen_type["map_name"] = "default"
134152
gen_type["gen_type"] = "Storage"
135-
pd.concat([
136-
pd.read_csv("graph_tech_types.csv", index_col=False), gen_type
137-
]).to_csv("graph_tech_types.csv", index=False)
153+
pd.concat([pd.read_csv("graph_tech_types.csv", index_col=False), gen_type]).to_csv(
154+
"graph_tech_types.csv", index=False
155+
)
138156

139157

140158
if __name__ == "__main__":

0 commit comments

Comments
 (0)