Skip to content

Commit 3e3a208

Browse files
authored
Merge pull request #88 from staadecker/improve_load_aug
Improve loading inputs and docs
2 parents 8362e91 + d0849d1 commit 3e3a208

File tree

27 files changed

+852
-943
lines changed

27 files changed

+852
-943
lines changed

README.md

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,41 @@
33
Welcome! This repository contains the SWITCH electricity planning model adapted for the
44
REAM research lab.
55

6-
For **an overview** of what SWITCH is and how it works, read [`docs/Overview.md`](./docs/Overiew.md).
6+
## Available documentation
77

8-
To discover **how to install, run or debug** the different components of Switch, read [`docs/Usage.md`](./docs/Usage.md)
8+
In `docs/`:
99

10-
To **see examples** of smaller SWITCH models, see the `examples/` folder.
10+
- [`Overview.md`](./docs/Overiew.md): An overview of what SWITCH is and how it works, read
1111

12-
To discover **how to contribute to the model**, read [`docs/Contribute.md`](/docs/Contribute.md)
12+
- [`Usage.md`](./docs/Usage.md): How to install, run or debug the different components of Switch
1313

14-
To **learn about our database** (e.g. how to connect to it and modify it), read [`docs/Database.md`](/docs/Database.md).
14+
- [`Developing Modules.md`](./docs/Developing%20Modules.md): How to create SWITCH modules from scratch
1515

16-
To **generate documentation**, run `pydoc -w switch_model` after having installed
16+
- [`Contribute.md`](/docs/Contribute.md): How to contribute code to the project.
17+
18+
- [`Graphs`](/docs/Graphs.md): How to create new graphs to analyze your results.
19+
20+
- [`Database.md`](/docs/Database.md): All about the REAM database (e.g. how to connect to it and modify it)
21+
22+
- [`Numerical Solvers.md`](/docs/Numerical%20Solvers.md): Information about numerical solvers, specifically Gurobi.
23+
24+
- [`Numerical Issues.md`](/docs/Numerical%20Issues.md): Information about detecting and resolving numerical issues.
25+
26+
Finally, you can generate documentation for the SWITCH modules by running `pydoc -w switch_model` after having installed
1727
SWITCH. This will build HTML documentation files from python doc strings which
1828
will include descriptions of each module, their intentions, model
1929
components they define, and what input files they expect.
2030

21-
To learn about **numerical solvers** read [`docs/Numerical Solvers.md`](/docs/Numerical%20Solvers.md)
31+
## Key folders
32+
33+
- [`/database`](/database) Folder containing SQL scripts and files that keep track of updates to our PostgreSQL database.
34+
35+
- [`/examples`](/examples) Folder with numerous examples of SWITCH projects often used for testing.
36+
37+
- [`/switch_model`](/switch_model) Folder containing all the source code for the SWITCH modules.
38+
39+
- [`/switch_model/wecc`](/switch_model/wecc) Folder containing modules specific to the REAM team.
40+
41+
- [`/switch_model/wecc/get_inputs`](/switch_model/wecc/get_inputs) Scripts that fetch the input data from the PostgreSQL database.
2242

23-
To learn about **numerical issues** read [`docs/Numerical Issues.md`](/docs/Numerical%20Issues.md)
43+
- [`/tests`](/tests) Folder containing tests for SWITCH. Can be run via `python run_tests.py`.

docs/Contribute.md

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Contributing Code
22

3-
This document describes the best practices for contributing code.
3+
You've made changes to the codebase and now you want to share them
4+
with the rest of the team! Here are the best practices for the process.
45

56
## The process
67

@@ -39,43 +40,6 @@ supposed to alter the results of the examples, you'll need
3940
to follow the instructions that appear on screen to suppress the errors
4041
produced by `python run_tests.py`.
4142

42-
## Contributing graphs
43+
## Important notes
4344

44-
Read [`docs/Graphs.md`](./Graphs.md) to see learn to add graphs.
45-
46-
## Modifying the database
47-
48-
Read [`docs/Database.md`](./Database.md) to learn about the database.
49-
50-
## Outputting results
51-
52-
Once the model is solved, the `post_solve()` function in each module is called.
53-
Within the `post_solve()` function you may
54-
55-
- Call `write_table()` to create
56-
a .csv file with data from the solution (see existing modules for examples).
57-
58-
- Call `add_info()` (from `utilities/result_info.py`) to add a line
59-
of information to the `outputs/info.txt` file. `add_info()` can also be added to `graph()`.
60-
61-
### Example
62-
63-
```python
64-
from switch_model.utilities.results_info import add_info
65-
from switch_model.reporting import write_table
66-
import os
67-
...
68-
def post_solve(instance, outdir):
69-
...
70-
# This will add the a line to info.txt in the outputs folder
71-
add_info("Some important value", instance.important_value)
72-
...
73-
# This will create my_table.csv
74-
write_table(
75-
instance,
76-
instance.TIMEPOINTS, # Set that the values function will iterate over
77-
output_file=os.path.join(outdir, "my_table.csv"),
78-
headings=("timepoint", "some value"),
79-
values=lambda m, t: (t, m.some_value[t])
80-
)
81-
```
45+
- If your change is modifying the database, make sure you've read [`Database.md`](./Database.md).

docs/Developing Modules.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
## Developing modules
2+
3+
Modules are the core elements of SWITCH. Each module defines a specific functionality for the model. For example,
4+
the `switch_model.generators.core.build` defines how generators are allowed to be built while `switch_model.timescales`
5+
defines how time is handled in SWITCH.
6+
7+
There are 3 important parts to any module.
8+
9+
1. `define_components(model)`: This function specifies the Pyomo Sets, Parameters, Variables and Expressions for the module
10+
as well as the input files that should be used. It's the first thing that gets called when you run `switch solve` as
11+
it creates the Pyomo model.
12+
13+
2. `post_solve()`: This function gets run after the solver has found the optimal solution. This is where you can output
14+
results to e.g. a csv file.
15+
16+
3. Functions with the `@graph(...)` decorator. These functions get called last and are responsible for creating graphs
17+
for analysis using the data from the csv files you created in `post_solve()`.
18+
19+
There are also a few other components that you may encounter:
20+
21+
- `load_inputs()`: This function is the old way of loading inputs from .csv files into the model. It gets called right
22+
after `define_components()`. Now the prefered way of loading inputs is by using `input_file=`
23+
(see next section for details).
24+
25+
- `define_dynamic_lists(model)` and `define_dynamic_components(model)`:
26+
Some modules need to define objects to be shared across multiple modules.
27+
The best example of this is `switch_model.balancing.load_zones` which
28+
allows different modules to add elements to a dynamic list that is defined
29+
in `define_dynamic_lists`. Then in `define_dynamic_components` it defines
30+
the energy balance constraint using the dynamic list. See the module for details.
31+
32+
## Writing `define_components()`
33+
34+
`define_components(mod)` takes in the model as an argument and is responsible
35+
for adding constraints, expressions, variables, sets or parameters to the model.
36+
37+
Sometimes Sets or Parameters should be initialized from an input csv file.
38+
If this is the case, add `input_file=` (and optionally `input_column`) to the
39+
set or parameter definition.
40+
41+
For example the following code snippet defines a Set and a parameter
42+
indexed over that set. Both the set and parameter are initialized from
43+
the `input.csv` file.
44+
45+
```python
46+
from pyomo.environ import *
47+
48+
49+
def define_components(mod):
50+
mod.SetA = Set(
51+
dimen=2,
52+
input_file="input.csv",
53+
)
54+
55+
mod.some_indexed_param = Param(
56+
mod.SetA,
57+
input_file="input.csv",
58+
input_column="param1" # only specify when the name of the column in the csv is not the same as the component name
59+
)
60+
```
61+
62+
## Writing `post_solve()`
63+
64+
Once the model is solved, the `post_solve()` function in each module is called. Within the `post_solve()` function you
65+
may
66+
67+
- Call `write_table()` to create a .csv file with data from the solution (see existing modules for examples).
68+
69+
- Call `add_info()` (from `utilities/result_info.py`) to add a line of information to the `outputs/info.txt`
70+
file. `add_info()` can also be added to `graph()`.
71+
72+
### Example
73+
74+
```python
75+
from switch_model.utilities.results_info import add_info
76+
from switch_model.reporting import write_table
77+
import os
78+
79+
...
80+
81+
82+
def post_solve(instance, outdir):
83+
...
84+
# This will add the a line to info.txt in the outputs folder
85+
add_info("Some important value", instance.important_value)
86+
...
87+
# This will create my_table.csv
88+
write_table(
89+
instance,
90+
instance.TIMEPOINTS, # Set that the values function will iterate over
91+
output_file=os.path.join(outdir, "my_table.csv"),
92+
headings=("timepoint", "some value"),
93+
values=lambda m, t: (t, m.some_value[t])
94+
)
95+
```

switch_model/balancing/demand_response/simple.py

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88
demand shifting. This does not include a Shed Service (curtailment of load),
99
nor a Shimmy Service (fast dispatch for load following or regulation).
1010
11+
INPUT FILE FORMAT
12+
Import demand response-specific data from an input directory.
13+
14+
dr_data.csv
15+
LOAD_ZONE, TIMEPOINT, dr_shift_down_limit, dr_shift_up_limit
1116
"""
1217

1318
import os
@@ -52,10 +57,12 @@ def define_components(mod):
5257
mod.LOAD_ZONES, mod.TIMEPOINTS,
5358
default= 0.0,
5459
within=NonNegativeReals,
60+
input_file="dr_data.csv",
5561
validate=lambda m, value, z, t: value <= m.zone_demand_mw[z, t])
5662
mod.dr_shift_up_limit = Param(
5763
mod.LOAD_ZONES, mod.TIMEPOINTS,
5864
default= float('inf'),
65+
input_file="dr_data.csv",
5966
within=NonNegativeReals)
6067
mod.ShiftDemand = Var(
6168
mod.LOAD_ZONES, mod.TIMEPOINTS,
@@ -75,20 +82,3 @@ def define_components(mod):
7582
mod.Distributed_Power_Withdrawals.append('ShiftDemand')
7683
except AttributeError:
7784
mod.Zone_Power_Withdrawals.append('ShiftDemand')
78-
79-
80-
def load_inputs(mod, switch_data, inputs_dir):
81-
"""
82-
83-
Import demand response-specific data from an input directory.
84-
85-
dr_data.csv
86-
LOAD_ZONE, TIMEPOINT, dr_shift_down_limit, dr_shift_up_limit
87-
88-
"""
89-
90-
switch_data.load_aug(
91-
optional=True,
92-
filename=os.path.join(inputs_dir, 'dr_data.csv'),
93-
autoselect=True,
94-
param=(mod.dr_shift_down_limit, mod.dr_shift_up_limit))

switch_model/balancing/electric_vehicles/simple.py

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
of each timeseries they must be charged at some specific level according
1212
to users necessity.
1313
14+
INPUT FILE FORMAT
15+
Import virtual batteries specific location and power limits
16+
from an input directory.
17+
18+
ev_limits.tab
19+
LOAD_ZONES, TIMEPOINT, ev_cumulative_charge_upper_mwh,
20+
ev_cumulative_charge_upper_mwh, ev_charge_limit_mw
1421
"""
1522

1623
import os
@@ -68,16 +75,19 @@ def define_components(mod):
6875
mod.ev_charge_limit_mw = Param(
6976
mod.LOAD_ZONES, mod.TIMEPOINTS,
7077
default = float('inf'),
78+
input_file="ev_limits.csv",
7179
within=NonNegativeReals)
7280

7381
mod.ev_cumulative_charge_upper_mwh = Param(
7482
mod.LOAD_ZONES, mod.TIMEPOINTS,
7583
default = 0.0,
84+
input_file="ev_limits.csv",
7685
within=NonNegativeReals)
7786

7887
mod.ev_cumulative_charge_lower_mwh = Param(
7988
mod.LOAD_ZONES, mod.TIMEPOINTS,
8089
default = 0.0,
90+
input_file="ev_limits.csv",
8191
within=NonNegativeReals)
8292

8393
mod.EVCharge = Var(
@@ -112,23 +122,3 @@ def define_components(mod):
112122
mod.Distributed_Power_Withdrawals.append('EVCharge')
113123
else:
114124
mod.Zone_Power_Withdrawals.append('EVCharge')
115-
116-
117-
118-
def load_inputs(mod, switch_data, inputs_dir):
119-
"""
120-
121-
Import virtual batteries specific location and power limits
122-
from an input directory.
123-
124-
ev_limits.tab
125-
LOAD_ZONES, TIMEPOINT, ev_cumulative_charge_upper_mwh,
126-
ev_cumulative_charge_upper_mwh, ev_charge_limit_mw
127-
128-
"""
129-
130-
switch_data.load_aug(
131-
optional=True,
132-
filename=os.path.join(inputs_dir, 'ev_limits.tab'),
133-
autoselect=True,
134-
param=(mod.ev_cumulative_charge_lower_mwh, mod.ev_cumulative_charge_upper_mwh, mod.ev_charge_limit_mw))

0 commit comments

Comments
 (0)