## Developing modules Modules are the core elements of SWITCH. Each module defines a specific functionality for the model. For example, the `switch_model.generators.core.build` defines how generators are allowed to be built while `switch_model.timescales` defines how time is handled in SWITCH. There are 3 important parts to any module. 1. `define_components(model)`: This function specifies the Pyomo Sets, Parameters, Variables and Expressions for the module as well as the input files that should be used. It's the first thing that gets called when you run `switch solve` as it creates the Pyomo model. 2. `post_solve()`: This function gets run after the solver has found the optimal solution. This is where you can output results to e.g. a csv file. 3. Functions with the `@graph(...)` decorator. These functions get called last and are responsible for creating graphs for analysis using the data from the csv files you created in `post_solve()`. There are also a few other components that you may encounter: - `load_inputs()`: This function is the old way of loading inputs from .csv files into the model. It gets called right after `define_components()`. Now the prefered way of loading inputs is by using `input_file=` (see next section for details). - `define_dynamic_lists(model)` and `define_dynamic_components(model)`: Some modules need to define objects to be shared across multiple modules. The best example of this is `switch_model.balancing.load_zones` which allows different modules to add elements to a dynamic list that is defined in `define_dynamic_lists`. Then in `define_dynamic_components` it defines the energy balance constraint using the dynamic list. See the module for details. ## Writing `define_components()` `define_components(mod)` takes in the model as an argument and is responsible for adding constraints, expressions, variables, sets or parameters to the model. Sometimes Sets or Parameters should be initialized from an input csv file. If this is the case, add `input_file=` (and optionally `input_column`) to the set or parameter definition. For example the following code snippet defines a Set and a parameter indexed over that set. Both the set and parameter are initialized from the `input.csv` file. ```python from pyomo.environ import * def define_components(mod): mod.SetA = Set( dimen=2, input_file="input.csv", ) mod.some_indexed_param = Param( mod.SetA, input_file="input.csv", input_column="param1" # only specify when the name of the column in the csv is not the same as the component name ) ``` ## Writing `post_solve()` Once the model is solved, the `post_solve()` function in each module is called. Within the `post_solve()` function you may - Call `write_table()` to create a .csv file with data from the solution (see existing modules for examples). - Call `add_info()` (from `utilities/result_info.py`) to add a line of information to the `outputs/info.txt` file. `add_info()` can also be added to `graph()`. ### Example ```python from switch_model.utilities.results_info import add_info from switch_model.reporting import write_table import os ... def post_solve(instance, outdir): ... # This will add the a line to info.txt in the outputs folder add_info("Some important value", instance.important_value) ... # This will create my_table.csv write_table( instance, instance.TIMEPOINTS, # Set that the values function will iterate over output_file=os.path.join(outdir, "my_table.csv"), headings=("timepoint", "some value"), values=lambda m, t: (t, m.some_value[t]) ) ```