|
| 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 | +``` |
0 commit comments