Skip to content

Commit c92d93c

Browse files
committed
Merge remote-tracking branch 'rael/wecc' into wind_to_solar_ratio
2 parents c11826c + e99b869 commit c92d93c

File tree

85 files changed

+3675
-1536
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+3675
-1536
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,6 @@ SWITCH. This will build HTML documentation files from python doc strings which
1818
will include descriptions of each module, their intentions, model
1919
components they define, and what input files they expect.
2020

21-
To learn about **numerical solvers** read [`docs/Numerical Solvers.md`](/docs/Numerical%20Solvers.md)
21+
To learn about **numerical solvers** read [`docs/Numerical Solvers.md`](/docs/Numerical%20Solvers.md)
22+
23+
To learn about **numerical issues** read [`docs/Numerical Issues.md`](/docs/Numerical%20Issues.md)

REAM Model Changelog.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# REAM Model Breaking Changes
2+
3+
This file specifies the breaking changes that we have done to the model.
4+
A breaking change is any change that would change the results of previously
5+
completed runs.
6+
7+
## List of breaking changes to model
8+
9+
Changes are listed from oldest (first line) to newest (last line of table).
10+
11+
| PR | Month | Change description |
12+
| ---- | --- | ---------------------|
13+
| #12 | March 2021 | Use the middle of the period instead of the start as the cutoff for retirement and predetermined buildout. |
14+
| #15 | March 2021 | Fix bug where storage costs where being over-counted. |
15+
| #36 | May 2021 | Correct inputs to only list transmission lines in one direction. |
16+
| #56 | June 2021 | Convert 2020 predetermined build years to 2019 in `get_inputs.py` to avoid conflicts with 2020 period. |
17+
| #57 | June 2021 | Specify predetermined storage energy capacity in inputs (previously left unspecified). |
18+
| #68 | June 2021 | Change financial params to 2018 dollars & 5% interest rate. Start using terrain multipliers (which now include the economic multiplier). |
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
####################
3+
Add generation plants groups
4+
5+
Date applied:
6+
Description:
7+
This script adds the option to specify generation plant groups.
8+
The generation groups are specified in the table generation_plant_group.
9+
Plants are assigned to a group by adding them to the many-to-many table generation_plant_group_member.
10+
Groups are assigned to a generation_plant_scenario_id by specifying them in generation_plant_scenario_group_member
11+
#################
12+
*/
13+
14+
CREATE TABLE switch.generation_plant_group
15+
(
16+
generation_plant_group_id serial NOT NULL,
17+
description text NOT NULL,
18+
name character varying(30) NOT NULL,
19+
PRIMARY KEY (generation_plant_group_id)
20+
);
21+
22+
COMMENT ON TABLE switch.generation_plant_group
23+
IS 'This table specifies all the generation plant groups. Every group has a set of generation plants (see generation_plant_group_member). Groups can be assigned to a generation_plant_scenario (see generation_plant_scenario_group_member).';
24+
25+
CREATE TABLE switch.generation_plant_group_member
26+
(
27+
generation_plant_group_id integer,
28+
generation_plant_id integer,
29+
PRIMARY KEY (generation_plant_group_id, generation_plant_id)
30+
);
31+
32+
ALTER TABLE switch.generation_plant_group_member
33+
ADD CONSTRAINT generation_plant_group_member_group_id_fkey
34+
FOREIGN KEY (generation_plant_group_id)
35+
REFERENCES switch.generation_plant_group (generation_plant_group_id);
36+
37+
ALTER TABLE switch.generation_plant_group_member
38+
ADD CONSTRAINT generation_plant_group_member_generation_plant_id_fkey
39+
FOREIGN KEY (generation_plant_id)
40+
REFERENCES switch.generation_plant (generation_plant_id);
41+
42+
COMMENT ON TABLE switch.generation_plant_group_member
43+
IS 'This table is a many-to-many table that specifies the generation plants that are associated with a generation group.';
44+
45+
CREATE TABLE switch.generation_plant_scenario_group_member
46+
(
47+
generation_plant_scenario_id integer,
48+
generation_plant_group_id integer,
49+
PRIMARY KEY (generation_plant_scenario_id, generation_plant_group_id)
50+
);
51+
52+
ALTER TABLE switch.generation_plant_scenario_group_member
53+
ADD CONSTRAINT generation_plant_scenario_group_member_scenario_id_fkey
54+
FOREIGN KEY (generation_plant_scenario_id)
55+
REFERENCES switch.generation_plant_scenario (generation_plant_scenario_id);
56+
57+
ALTER TABLE switch.generation_plant_scenario_group_member
58+
ADD CONSTRAINT generation_plant_scenario_group_member_group_id_fkey
59+
FOREIGN KEY (generation_plant_group_id)
60+
REFERENCES switch.generation_plant_group (generation_plant_group_id);
61+
62+
COMMENT ON TABLE switch.generation_plant_scenario_group_member
63+
IS 'This table is a many-to-many table that specifies which generation plant groups belong to which generation plant scenarios';
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
####################
3+
Add column gen_store_energy_to_power_ratio
4+
5+
Date applied: 2021-06-18
6+
Description:
7+
This script adds a column to the generation_plant
8+
table called gen_storage_energy_to_power_ratio specifying
9+
the storage duration
10+
#################
11+
*/
12+
13+
ALTER TABLE switch.generation_plant ADD COLUMN gen_storage_energy_to_power_ratio real;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
####################
3+
Add transmission options
4+
5+
Date applied: 2021-06-23
6+
Description:
7+
Adds two rows to table transmission_base_capital_cost_scenario_id
8+
1. A scenario where transmission costs are zero.
9+
2. A scenario where transmission costs are infinity (building not allowed).
10+
#################
11+
*/
12+
13+
INSERT INTO switch.transmission_base_capital_cost (transmission_base_capital_cost_scenario_id,
14+
trans_capital_cost_per_mw_km, description)
15+
VALUES (3, 'Infinity', 'For scenarios where building transmission is forbidden.');
16+
17+
INSERT INTO switch.transmission_base_capital_cost (transmission_base_capital_cost_scenario_id,
18+
trans_capital_cost_per_mw_km, description)
19+
VALUES (4, 0, 'For scenarios where transmission is unlimited.');
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
####################
3+
Add transmission options
4+
5+
Date applied: 2021-06-29
6+
Description:
7+
Adds an extra scenario to the database for a 10x increase in transmission costs.
8+
#################
9+
*/
10+
11+
INSERT INTO switch.transmission_base_capital_cost (transmission_base_capital_cost_scenario_id,
12+
trans_capital_cost_per_mw_km, description)
13+
VALUES (5, 9600, '10x the costs of scenario #2. Approximates the no TX case.');

docs/Contribute.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ procedure.
1414
3. Once your changes are final and ready to be added to the switch main
1515
branch, create a pull request on Github.
1616

17-
4. Get someone to review and then merge your changes on Github.
17+
4. If your change is a breaking change add it to `REAM Model Changelog.md`.
18+
19+
5. Get someone to review and then merge your changes on Github.
1820

1921
For more information read [this excellent guide](https://guides.github.com/introduction/flow/) (5 min read).
2022

docs/Database.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ their strong points. DBVisualizer can also create a graph of all the relationshi
2121
tables.
2222

2323
Further, it is often useful to read the comments on tables (PGAdmin: right-click table -> Properties)
24-
as they sometimes give details on the tables role. Finally, if the table is used in [`get_inputs.py`](/switch_model/wecc/get_inputs.py)
24+
as they sometimes give details on the tables role. Finally, if the table is used in [`get_inputs.py`](/switch_model/wecc/get_inputs/get_inputs.py)
2525
one can discover what it does by looking at how get_inputs.py uses the table to generate the SWITCH inputs.
2626

2727
## Connecting to the database

docs/Graphs.md

Lines changed: 132 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -18,92 +18,128 @@ and `ca_policies` have already been solved).
1818

1919
## Adding new graphs
2020

21-
Graphs can be defined in any module by adding the following function to the file.
22-
21+
New graphs can be added with the `@graph(...)` annotation.
2322
```python
24-
def graph(tools):
23+
from switch_model.tools.graph import graph
24+
25+
@graph(
26+
name="my_custom_graph",
27+
title="An example plot",
28+
note="Some optional note to add below the graph",
29+
# Other options are possible see code documentation
30+
)
31+
def my_graphing_function(tools):
2532
# Your graphing code
2633
...
2734
```
2835

29-
In `graph()` you can use the `tools` object to create graphs. Here are some important methods.
30-
31-
- `tools.get_dataframe(csv=filename)` will return a pandas dataframe for the file called `filename`. You can also
32-
specify `folder=tools.folders.INPUTS` to load a csv from the inputs directory.
33-
34-
- `tools.get_new_axes(out, title, note)` will return a matplotlib axes. This should be the axes used while
35-
graphing. `out` is the name of the `.png` file that will be created with this graph. `title` and `note` are optional
36-
and will be the title and footnote for the graph.
37-
38-
- `tools.pd`, `tools.sns`, `tools.np`, `tools.mplt` are references to the pandas, seaborn, numpy and matplotlib
39-
libraries. This is useful if your graphing code needs to access these libraries since it doesn't require adding an
36+
In `my_graphing_function()` you can use the `tools` object to create graphs. Here are some important methods.
37+
38+
- `tools.get_dataframe(filename)` will return a pandas dataframe for the file called `filename`. You can also
39+
specify `from_inputs=True` to load a csv from the inputs directory.
40+
41+
- `tools.get_axes()` or `tools.get_figure()` will return a matplotlib axes or figure
42+
that should be used while graphing. When possible, always use `get_axes` instead of `get_figure` since
43+
this allows plots from different scenarios to share the same figure.
44+
45+
- `tools.save_figure(fig)`. Some libraries (e.g. plotnine)
46+
always generate their own figures. In this case we can add the figure
47+
to our outputs with this function. When possible, use `tools.get_axes()` instead.
48+
49+
- `tools.pd`, `tools.sns`, `tools.np`, `tools.mplt`, `tools.pn` are references to the pandas, seaborn, numpy, matplotlib
50+
and plotnine graphing libraries. This is useful if your graphing code needs to access these libraries since it doesn't require adding an
4051
import to your file.
4152

42-
- `tools.add_gen_type_column(df)` adds a column called `gen_type` to a dataframe with columns
43-
`gen_tech` and `gen_energy_source`. `gen_type` is a user-friendly name for the technology (e.g. Nuclear instead of
44-
Uranium). The mapping of `gen_energy_source` and `gen_tech` to `gen_type` is defined in
45-
a `inputs/graph_tech_types.csv`. If this file isn't present, a default mapping will be used. You can also use other
46-
mappings found in `graph_tech_types.csv` by specifying `map_name=` when calling `add_gen_type_column()`.
47-
53+
- `tools.transform` is a reference to a `TransformTools` object that provides
54+
useful helper methods for modyfing a dataframe for graphing. Full documentation
55+
can be found in the `TransformTools` class but some examples include.
56+
57+
- `tools.transform.build_year(df)` which will convert build years that aren't
58+
a period to the string `Pre-existing`.
59+
60+
- `tools.transform.gen_type(df)` which adds a column called `gen_type` to the dataframe.
61+
`gen_type` is a user-friendly name for the technology (e.g. Nuclear instead of
62+
Uranium) and is determined using the mappings in `inputs/graph_tech_types.csv`.
63+
64+
- `tools.transform.timestamp(df)`: which adds columns such as the hour, the timestamp in datetime format
65+
in the correct timezone, etc.
66+
67+
- `tools.transform.load_zone(df)`: Adds a column called 'region' to the dataframe which
68+
normally corresponds to the load zone state.
69+
4870
- `tools.get_colors()` returns a mapping of `gen_type` to its color. This is useful for graphing and can normally be
49-
passed straight to `color=` in standard plotting libraries. You can also specify a different color mapping using a
50-
similar process to above (`map_name=`)
71+
passed straight to `color=` in standard plotting libraries. The color mapping is based on `inputs/graph_tech_colors.csv`.
5172

5273
## Adding a comparison graph
5374

54-
By default, `tools.get_dataframe` will return the data for only one scenario (the one you are graphing).
55-
56-
Sometimes, you may wish to create a graph that compares multiple scenarios. To do this create a function
57-
called `compare`.
75+
Sometimes you may want to create graphs that compare data from multiple scenarios.
76+
To do this, add `supports_multi_scenario=True` inside the `@graph()` decorator.
5877

5978
```python
60-
def compare(tools):
61-
# Your graphing code
62-
...
79+
from switch_model.tools.graph import graph
80+
81+
@graph(
82+
name="my_custom_comparison_graph",
83+
title="My Comparison plot",
84+
supports_multi_scenario=True,
85+
# Instead of supports_multi_scenario, you can use
86+
# requires_multi_scenario if you want the graphing function
87+
# to *only* be run when we have multiple scenarios.
88+
# requires_multi_scenario=True,
89+
)
90+
def my_graphing_comparison_function(tools):
91+
# Read data from all the scenarios
92+
df = tools.get_dataframe("some_file.csv")
93+
# Plot data
94+
...
6395
```
6496

65-
If you call `tools.get_dataframe(...)` from within `compare`, then
66-
`tools.get_dataframe` will return a dataframe containing the data from *all*
67-
the scenarios. The dataframe will contain a column called `scenario` to indicate which rows correspond to which
68-
scenarios. You can then use this column to create a graph comparing the different scenarios (still
69-
using `tools.get_new_axes`).
97+
Now everytime you call `tools.get_dataframe(filename)`, data for *all* the scenarios
98+
gets returned. The way this works is that the
99+
returned dataframe will contain a column called `scenario_name`
100+
to indicate which rows correspond to which scenarios.
101+
You can then use this column to create a graph comparing the different scenarios (still
102+
using `tools.get_axes`).
70103

71-
At this point, when you run `switch compare`, your `compare(tools)` function will be called and your comparison graph
104+
At this point, when you run `switch compare`, your `my_graphing_comparison_function` function will be called and your comparison graph
72105
will be generated.
73106

74107
## Example
75108

76109
In this example we create a graph that shows the power capacity during each period broken down by technology.
77110

78111
```python
112+
from switch_model.tools.graph import graph
113+
114+
@graph(
115+
"capacity_per_period",
116+
title="Capacity per period"
117+
)
79118
def graph(tools):
80-
# Get a dataframe of gen_cap.csv
81-
gen_cap = tools.get_dataframe(csv="gen_cap")
82-
83-
# Add a 'gen_type' column to your dataframe
84-
gen_cap = tools.add_gen_type_column(gen_cap)
85-
86-
# Aggregate the generation capacity by gen_type and PERIOD
87-
capacity_df = gen_cap.pivot_table(
88-
index='PERIOD',
89-
columns='gen_type',
90-
values='GenCapacity',
91-
aggfunc=tools.np.sum,
92-
fill_value=0 # Missing values become 0
93-
)
94-
95-
# Get a new pair of axis to plot onto
96-
ax = tools.get_new_axes(out="capacity_per_period")
97-
98-
# Plot
99-
capacity_df.plot(
100-
kind='bar',
101-
ax=ax, # Notice we pass in the axis
102-
stacked=True,
103-
ylabel="Capacity Online (MW)",
104-
xlabel="Period",
105-
color=tools.get_colors(len(capacity_df.index))
106-
)
119+
# Get a dataframe of gen_cap.csv
120+
df = tools.get_dataframe("gen_cap.csv")
121+
122+
# Add a 'gen_type' column to your dataframe
123+
df = tools.transform.gen_type(df)
124+
125+
# Aggregate the generation capacity by gen_type and PERIOD
126+
df = df.pivot_table(
127+
index='PERIOD',
128+
columns='gen_type',
129+
values='GenCapacity',
130+
aggfunc=tools.np.sum,
131+
fill_value=0 # Missing values become 0
132+
)
133+
134+
# Plot
135+
df.plot(
136+
kind='bar',
137+
ax=tools.get_axes(),
138+
stacked=True,
139+
ylabel="Capacity Online (MW)",
140+
xlabel="Period",
141+
color=tools.get_colors(len(df.index))
142+
)
107143
```
108144

109145
Running `switch graph` would run the `graph()` function above and create
@@ -112,3 +148,37 @@ Running `switch graph` would run the `graph()` function above and create
112148
Running `switch compare` would create `capacity_per_period.png` containing
113149
your plot side-by-side with the same plot but for the scenario you're comparing to.
114150

151+
### Testing your graphs
152+
153+
To test your graphs, you can run `switch graph` or `switch compare`. However,
154+
this takes quite some time. If you want to test just one graphing function
155+
you can run `switch graph/compare -f FIGURE`. This will run only the graphing function
156+
you've defined. Here `FIGURE` should be the name of the graph (the first
157+
argument in `@graph()`, so `capacity_per_period` in the example above).
158+
159+
### Creating graphs outside of SWITCH
160+
161+
Sometimes you may want to create graphs but don't want to permently add
162+
them to the switch code. To do this create the following Python file anywhere
163+
on your computer.
164+
165+
```python
166+
from switch_model.tools.graph import graph
167+
from switch_model.tools.graph.cli_graph import main as graph
168+
169+
@graph(
170+
...
171+
)
172+
def my_first_graph(tools):
173+
...
174+
175+
@graph(
176+
...
177+
)
178+
def my_second_graph(tools):
179+
...
180+
181+
if __name__=="__main__":
182+
graph(["--ignore-modules-txt"])
183+
```
184+

0 commit comments

Comments
 (0)