Welcome to the Grimsel docs¶
Flexible energy system optimization framework based on relational input data.
Important
This documentation is work in progress.
Introductory example-¶
This example provides a minimal example of the modeling process with Grimsel, including the definition of the input tables.
Definition of the input data¶
First, all required input tables are explained and defined as pandas.Dataframes
. They are later written to csv files in order to be read by Grimsel. Input data in Grimsel is structured like a normalized database (see Input data structure). It is recommended to write input data to an appropriately constrained SQL schema to ensure consistency.
The def_node
table¶
The def_node
table contains the mapping between nd_id*s and node names *nd as well as all parameters which are indexed by the nodes only. In this simple example we define a single node Node1
with a certain CO2 price price_co2
(EUR/t). The node weight is used to scale nodes, e.g. to represent \(n\) households through a single household node. It serves as a factor in the objective function grimsel.core.constraints.add_objective_rules()
(all costs are scaled by node_weight), the supply constraint grimsel.core.constraints.add_supply_rules()
(power exchange between nodes is scaled accordingly), and the cross-border transmission capacity (grimsel.core.constraints.add_transmission_bounds_rules()
).
Note that Grimsel is agnostic with respect to physical units. The price on CO2 could be defined in different units as long as consistency with the other parameters (emission intensity etc.) is ensured.
Columns which don’t correspond to Grimsel parameter names are ignored. While this can cause mistakes, it is convenient to keep additional columns in the same tables for mmodifications of the model parameters (e.g. for future years, columns _yr2020 etc. in the plant_encar table, see Input data structure)
nd | nd_id | price_co2 | nd_weight | |
---|---|---|---|---|
0 | Node1 | 0 | 10 | 1 |
Important
The indices nd_id are best generated after the finalization of the table. The same holds for all other basic indices (power plants pp_id, fuels fl_id etc). It is good practice to never assume numerical indices as fixed, but to use translated names instead. The grimsel.core.auxiliary.maps.Maps
class provides convenience methods and attributes for this. For example, instead of referring to nd_id = 0
we would always use nd_id = mps.dict_nd['Node1']
instead (with mps
an instance of the Maps
class). Since the def_node table defines the node ids, the mapping between node names and ids is stored in the dictionary dict_nd
for translation of the node names in the other tables (see below).
The def_fuel
table¶
Every power plant in the broadest sense has a fuel. This includes fuel-less renewable generators (wind, solar), demand-like model components, and transmission between nodes. In this simple example we consider 3 concrete fuel types. The CO2 emission intensity parameter co2_int defines the specific emissions per unit of fuel energy content \(\mathrm{t_{CO_2}/MWh_{fl}}\).
Note
Abstract fuels which follow directly from the model structure (demand, curtailment, transmission) don’t have to be defined in the input table (though they can). They are automatically appended by the :module:`grimsel.core.autocomplete` module.
fl_id | fl | co2_int | |
---|---|---|---|
0 | 0 | natural_gas | 0.20 |
1 | 1 | hard_coal | 0.35 |
2 | 2 | solar | 0.00 |
The def_encar
table¶
Definition of produced energy carriers.
Note
In systems where a produced energy carrier can be consumed by other plants (e.g. electricity to produce heat), a column fl_id is required, which maps the output (e.g. electricity) carrier to the input (e.g. electricity) fuel.
ca_id | ca | |
---|---|---|
0 | 0 | EL |
The def_pp_type
table¶
This table defines the power plant type, which—similar to the fuel—groups power plants according to certain characteristics. Its purpose is filtering of model input and power plant aggregation for analysis. No parameters, variables, or constraints are associated with the power plant type.
pt_id | pt | |
---|---|---|
0 | 0 | GAS_LIN |
1 | 1 | SOLAR |
2 | 2 | HCO_ELC |
The def_plant
table¶
The def plant table defines the power plants. It establishes the link between the fuel ids, the power plant type ids, and the node ids with power plants. Furthermore, it assigns power plants to certain power plant subsets. In the example below, we define the subsets of
- fixed profile plants (wind, set_def_pr)
- dispatchable power plants (both gas plants and coal, set_def_pp)
- power plants with linear cost supply curve (ND1_GAS_LIN, set_def_lin); these plants require the definition of the supply curve coefficients (see the :ref:corresponding input table`<introductory_example_plant_encar>`).
- power plants whose capacity can be expanded/invested in (new gas and wind, set_def_add)
pp | pp_id | pt_id | nd_id | fl_id | set_def_pr | set_def_pp | set_def_lin | set_def_add | |
---|---|---|---|---|---|---|---|---|---|
0 | ND1_GAS_LIN | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
1 | ND1_GAS_NEW | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
2 | ND1_SOLAR | 2 | 1 | 0 | 2 | 1 | 0 | 0 | 1 |
3 | ND1_HCO_ELC | 3 | 2 | 0 | 1 | 0 | 1 | 0 | 0 |
The def_profile
table¶
This table assigns an id to the model’s temporal profiles, i.e. parameters which are defined for each time slot. In the example below this includes
- the demand (units \(\mathrm{MW}\))
- the wind supply profiles (capacity factors per time slot, unitless).
Other profiles not included in this example
- price profiles (e.g. to model households or micro-grids buying eletricity with time-dependencies of electricity tariffs)
- CHP profiles which define a lower bound of power production for certain power plants
pf_id | pf | |
---|---|---|
0 | 0 | SUPPLY_SOLAR |
1 | 1 | DMND_NODE1 |
The plant_encar
table¶
This table contains the main collection of power plant parameters. It is indexed by the power plant id and the energy carrier id. For example, a CHP plant might have different efficiencies for the production of heat and electricity. In the example below, only electricity is considered as an energy carrier.
The parameters included in the table below are defined in the grimsel.core.parameters.Parameters
documentation. Note that as of now Grimsel requires fixed cost annuities (e.g. \(EUR/MW/yr\)). In the example below they arae calculated a-priori.
pp_id | ca_id | supply_pf_id | pp_eff | factor_lin_0 | factor_lin_1 | cap_pwr_leg | fc_cp_ann | |
---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | None | NaN | 2.5 | 0.000208 | 0 | NaN |
1 | 1 | 0 | None | 0.6 | NaN | NaN | 0 | 69747.645581 |
2 | 2 | 0 | 0 | NaN | NaN | NaN | 0 | 130776.835465 |
3 | 3 | 0 | None | 0.4 | NaN | NaN | 5000 | NaN |
130776.83546527711
The node_encar
table¶
This table maps the demand profile for a certain energy carrier in a certain node to the corresponding profile id. In addition, grid losses depend on the node and the energy carrier. They would be defined in this table. Since they default to zero (see grimsel.core.parameters.Parameters
), they are omitted.
Note
While this column is not used in the model, the total demand per node and energy carrier (dmnd_sum) could be added to this table, to scale demand profiles according to the total demand during future years.
nd_id | ca_id | dmnd_pf_id | |
---|---|---|---|
0 | 0 | 0 | 1 |
The fuel_node_encar
table¶
The fuel cost is defined per fuel, node, and produced energy carrier. The indexing of this parameter by produced energy carrier is not necessarily meaningful, but no separate fuel_node
table exists as of now.
Other parameters defined in this table are listed in the parameter docs.
fl_id | nd_id | ca_id | vc_fl | |
---|---|---|---|---|
0 | 0 | 0 | 0 | 40 |
1 | 1 | 0 | 0 | 10 |
The profsupply
table¶
This table contains the supply profiles (see table def_profile) for each supply profile id and “each hour of the year” hy
. The hour of the year corresponds to the raw time resolution, which is defined and potentially reduced during the model call.
Note that no capacity constraints apply to plants with fixed profiles. Consequently, Grimsel would accept capacity factors > 1.
The
As always, units are implicitly defined by the input data. Another approach would be the definition of the profile in terms of \(\mathrm{MW}\) while keeping the capacities of the corresponding plants equal to 1.

Writing input tables to disk¶
All tables are saved as csv files. This is currently the input data format of choice. PostgreSQL input support needs to be fixed.
<grimsel.core.model_base.ModelBase at 0x7f6c6df4b798>
Setting up the model instance¶
The model instance (class grimsel.core.model_base.ModelBase
) is intialized through the grimsel.core.model_loop.ModelLoop
class. The ModelLoop manages model variations and initializes the IO class, which reads and writes the model input and output data. Note that because of this setup, the ModelBase class cannot be initialized on its own in a meaningful way, since it lacks the features of reading and writing data.
The model parameter is only the time slot structure: Here we specify that the input data has 730 (1 month) time resolution, and that we want to construct the model with the same number of time slots: (730, 730)
. Alternatively, we could lower the time resolution to any multiple of the original time resolution, e.g. (730, 730*2)
.
The IO class is initialized using the following parameters:
data_path
: location of the input (csv) filesoutput_target
: one of (fastparquet
,psql
,hdf5
); current,fastparquet
is the format of choice, the others require fixingcl_out
: output collection; here: path for parquet files; parquet files are written separately by variable and model run; alternatively PostgreSQL schema (ifoutput_target == psql
) or HDF5 file namedev_mode: True
skips confirmation prompt prior to overwriting existing output files
The nsteps
list is the main parameter defining the model variations. In this example, we want to vary the CO2 price for 5 values of equal spacing (swco
). In adddition, the installation of new gas power plants is allowed or not (2 discrete value swnewgas
). The prefix sw
(“sweep”) is a convention and not strictly necessary.
For convenience, we can define appropriate dictionaries with clearer names for the envisioned model modifications:
The CO2 price will be scaled between 0 and a maximum. Therefore, no such names definitions are necessary.
Initializing the ModelLoop
class results in the following:
- Initialization of a
ModelBase
instance, which subclasses the Pyomo Model class, holds all model components, and performs single model runs - Initialization of a
grimsel.core.io.IO
instance, which takes care of input data reading and output data writing - The creation of the
ModelLoop.def_run
table (see below) - call the
grimsel.core.io.IO.read_model_data()
method - call the
grimsel.core.model_base.ModelBase.init_maps()
method which creates agrimsel.core.auxiliary.maps.Maps
instance (see below) - call the
grimsel.core.model_base.ModelBase.map_to_time_res()
method which handles all functionalities related to time mapping and - call the
grimsel.core.io.IO.write_runtime_tables()
method, which writes model tables which where generated during model creation - call the
grimsel.core.model_base.ModelBase.get_setlst()
method - call the
grimsel.core.model_base.ModelBase.define_sets()
method - call the
grimsel.core.model_base.ModelBase.add_parameters()
method - call the
grimsel.core.model_base.ModelBase.define_variables()
method - call the
grimsel.core.model_base.ModelBase.add_all_constraints()
method - call the
grimsel.core.model_base.ModelBase.init_solver()
method - call the
grimsel.core.io.IO.init_output_tables()
method
The ml.df_def_run table¶
The model runs to be performed are summarized in the ml.df_def_run table. By default it contains all combinations of model parameter variations defined in the nhours parameter:
run_id | swco_id | swnewgas_id | swco | swnewgas | swco_vl | swnewgas_vl | |
---|---|---|---|---|---|---|---|
0 | 0 | 0.0 | 0.0 | 0.00 | 0.0 | NaN | NaN |
1 | 1 | 1.0 | 0.0 | 0.25 | 0.0 | NaN | NaN |
2 | 2 | 2.0 | 0.0 | 0.50 | 0.0 | NaN | NaN |
3 | 3 | 3.0 | 0.0 | 0.75 | 0.0 | NaN | NaN |
4 | 4 | 4.0 | 0.0 | 1.00 | 0.0 | NaN | NaN |
5 | 5 | 0.0 | 1.0 | 0.00 | 1.0 | NaN | NaN |
6 | 6 | 1.0 | 1.0 | 0.25 | 1.0 | NaN | NaN |
7 | 7 | 2.0 | 1.0 | 0.50 | 1.0 | NaN | NaN |
8 | 8 | 3.0 | 1.0 | 0.75 | 1.0 | NaN | NaN |
9 | 9 | 4.0 | 1.0 | 1.00 | 1.0 | NaN | NaN |
This table can be filtered to reduce the number of model. For example, if we are primarily interested in the default case including new gas power plants, we could selectively reduce the resolution of the CO2 price variation:
run_id | swco_id | swnewgas_id | swco | swnewgas | swco_vl | swnewgas_vl | |
---|---|---|---|---|---|---|---|
0 | 0 | 0.0 | 0.0 | 0.00 | 0.0 | NaN | NaN |
1 | 1 | 1.0 | 0.0 | 0.25 | 0.0 | NaN | NaN |
2 | 2 | 2.0 | 0.0 | 0.50 | 0.0 | NaN | NaN |
3 | 3 | 3.0 | 0.0 | 0.75 | 0.0 | NaN | NaN |
4 | 4 | 4.0 | 0.0 | 1.00 | 0.0 | NaN | NaN |
5 | 5 | 0.0 | 1.0 | 0.00 | 1.0 | NaN | NaN |
6 | 6 | 2.0 | 1.0 | 0.50 | 1.0 | NaN | NaN |
7 | 7 | 4.0 | 1.0 | 1.00 | 1.0 | NaN | NaN |
Autocompletion¶
Grimsel treats demand, curtailment, and transmission as power plants. To avoid the tedious task of defining these components in the input tables in a consistent manner, Grimsel autocompletes them in all relevant tables. This can be thought of as an additional step between the input data and the tables stored by the ModelBase class. For example, the df_def_plant
table contains two additional entries, which where not included in the original input data. Node1_DMND_FLEX
is curtailment, which allows for overproduction Node1
.
pp | pp_id | pt_id | nd_id | fl_id | set_def_pr | set_def_pp | set_def_lin | set_def_add | set_def_dmd | set_def_curt | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | ND1_GAS_LIN | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0.0 | 0.0 |
1 | ND1_GAS_NEW | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0.0 | 0.0 |
2 | ND1_SOLAR | 2 | 1 | 0 | 2 | 1 | 0 | 0 | 1 | 0.0 | 0.0 |
3 | ND1_HCO_ELC | 3 | 2 | 0 | 1 | 0 | 1 | 0 | 0 | 0.0 | 0.0 |
0 | Node1_DMND_FLEX | 4 | 4 | 0 | 3 | 0 | 0 | 0 | 0 | 0.0 | 1.0 |
1 | Node1_DMND | 5 | 5 | 0 | 4 | 0 | 0 | 0 | 0 | 1.0 | 0.0 |
Defining the model modifications¶
The model is modfiied prior to each run in accordance with the table def_run
described above. The actual modifications are typically implemented in a helper class with one method per parameter change. An example is shown below.
The structure of these methods is always similar:
The current run_id steps are retrieved: For any time step, the
ModelLoop.dct_step
attribute contains the value of the def_run table’s step columns (swco, swnewgas).>>> ml.select_run(2) >>> ml.dct_step {'swco': 0.5, 'swnewgas': 0.0}
In the CO2 price example, this is the scaling factor by which the maximum CO2 price is multiplied. In the gas plant example, this is the key for the name dictionary defined above:
dict_swnewgas[self.ml.dct_step['swnewgas']]
The model components are modified. In the CO2 price example, the new values are applied to the corresponding parameter. Note that these parameters are Pyomo objects (since the ModelBase class subclasses the Pyomo.ConcreteModel). Possible ways to modify these objects are described in the Pyomo documentation. In the gas plant example, the
cap_pwr_new
variable is set to zero and fixed. In this way any investment in gas plants is inhibited.The entries of the ModelLoop.dct_vl dictionary are defined. This step is important. This dictionary is used to fill the
NaN
columnsswco_vl
andswnewgas_vl
in the def_run table above. They are the names by which the model runs are identified in the analysis.
More advanced parameter modifications might make use of past model runs, e.g. to keep production profiles fixed at a default value. For this purpose, the model results can be accessed as described below.
Defining a model run function¶
Finally, a function performing a single model run is defined. This function takes the run_id
as an input and
- sets the internal ModelLoop run_id
- resets parameters and variables (if applicable)
- calls the
ModelLoopModifier
methods - calls the
ModelLoop.perform_model_run
method
Perform all model runs¶
While the run_model
function can be called for single run ids, its purpose is to be passed to the grimsel.run_parallel`()
or grimsel.run_sequential`()
function. This loops
Solver script file=/tmp/tmphcd1ykej.cplex.script
Solver script file=/tmp/tmplt0h4uzr.cplex.script
Solver script file=/tmp/tmpyjn9vmux.cplex.script
Solver script file=/tmp/tmp3nyr47uo.cplex.script
Solver log file: '/tmp/tmpwrxd9xmv.cplex.log'
Solver log file: '/tmp/tmp_ndycne5.cplex.log'
Solver log file: '/tmp/tmpeti0ofif.cplex.log'
Solver log file: '/tmp/tmp_nqdr5v1.cplex.log'
Solver script file=/tmp/tmp1ju__ibs.cplex.script
Solver solution file: '/tmp/tmpk1dur59q.cplex.sol'
Solver solution file: '/tmp/tmp4iwh4_rx.cplex.sol'
Solver solution file: '/tmp/tmp8xsu7vd4.cplex.sol'
Solver log file: '/tmp/tmp0rmcug2k.cplex.log'
Solver solution file: '/tmp/tmpzili5a4q.cplex.sol'
Solver solution file: '/tmp/tmpy0h91d2q.cplex.sol'
Solver script file=/tmp/tmptolmq9pl.cplex.script
Solver problem files: ('/tmp/tmpkjz0o0fh.pyomo.lp',)
Solver problem files: ('/tmp/tmpbry7jorl.pyomo.lp',)
Solver problem files: ('/tmp/tmptc6kcgqe.pyomo.lp',)
Solver problem files: ('/tmp/tmprko9u04m.pyomo.lp',)
Solver script file=/tmp/tmpyaq61fx1.cplex.script
Solver log file: '/tmp/tmpxo0tg2ul.cplex.log'
Solver solution file: '/tmp/tmpaunft7wo.cplex.sol'
Solver problem files: ('/tmp/tmpm6fx6wav.pyomo.lp',)
Solver log file: '/tmp/tmp1caa3m41.cplex.log'
Solver problem files: ('/tmp/tmpf8ke8lg1.pyomo.lp',)
Solver solution file: '/tmp/tmpoblonf22.cplex.sol'
Solver problem files: ('/tmp/tmpdroipib7.pyomo.lp',)
Solver script file=/tmp/tmpm5qdoeuc.cplex.script
Solver log file: '/tmp/tmpg8g7hzw9.cplex.log'
Solver solution file: '/tmp/tmpzlzwsptn.cplex.sol'
Solver problem files: ('/tmp/tmpv0je2h0d.pyomo.lp',)
Running Grimsel¶
Grimsel is instantiated most conventiently through the grimsel.core.model_loop.ModelLoop
class. This class takes care of data input/output (through the grimsel.core.io
class), model initialization (grimsel.core.model_base
class), as well as parameter variation/scenario management. This tutorial provides a step-by-description how the model is initialized and run.
Note that this assumes the availability of a self-consistent set of input data. These data consist in either a PostgreSQL schema of normalized tables or a set of CSV files with the same structure (see the example files included with Grimsel on Github). The structure of the required input data is further explained in the corresponding section.
Basic imports¶
- The
grimsel.core.model_loop
module contains theModelLoop
class which puts it all together. - The
grimsel.core.ModelBase
class is imported to access itsgrimsel.core.model_base.ModelBase.get_constraint_groups()
method (see below). This allows to define project-specific global configuration parameters (e.g. related to database connection and input file locations). - The grimsel_config module assumes the existence of a config_local.py file in the current working directory.
- The logger is defined in the Grimsel
__init__
file. The module levellogger
instance can be used to set the global logging level. Please refer to the documentation of thelogging
module for further details.
Defining model parameters¶
The model parameters are collected in a dictionary mkwargs
. They are passed to the ModelLoop
initializer as dictionary and serve as keyword arguments to initialize the grimsel.core.model_base.ModelBase
class.
slct_encar
: Which energy carriers to include. Any subset of the entries in the def_encar input table’s ca column. All input tables are filtered accordingly.slct_node
: Which nodes to include. Any subset of the entries in the def_node input table’s nd column. All input tables are filtered accordingly. In the example, two country-nodes[CH0, DE0]
and two household-nodes[SFH_AA, SFH_AB]
are included.nhours
: Original and target time resolution of all profiles in the selected nodes. The value pairs correspond to thefreq
andnhours
parameters of thegrimsel.auxiliary.timemap.TimeMap
class. In the example, the country nodes have 1 hour time resolution. ForCH0
, this remains explicitly unchanged:(1, 1)
.SFH_AA
andSFH_AB
have 15 minute inpute data time resolution which is maintained forSFH_AA
(0.25, 0.25)
and averaged to 30 minutes forSFH_AB
:(0.25, 0.5)
. In principle, any combination of time resolutions is possible. However,grimsel.auxiliary.timemap.TimeMap
throws an error if the target time resolutionfreq
is not a multiple of the input data time resolutionnhours
.slct_pp_type
: Which power plant types to include. Any subset of the entries in the def_pp_type input table’s pt column. All input tables are filtered accordingly. An empty list implies no filtering, i.e. all power plant types included in the input data are used.skip_runs
: If set toTrue
, no model runs are performed and only the constructed model parameters are written to the output data. Occasionally useful.tm_filt
: The parameter of thegrimsel.auxiliary.timemap.TimeMap
class. In the example we limit the temporal scope of the model to the first day of four selected months. All input profiles are filtered accordingly.
Warning
The time filtering makes use of the grimsel.auxiliary.timemap
class which defaults to the 2015 year structure. This might be import to keep in mind in case certain days of the week are selected.
constraint_groups
: The constraint groups are the methods of thegrimsel.core.constraints.Constraints
class whose name follows the patternadd_*_rules
. Through this model parameter it is possible to select a subset of the active constraints (e.g. to investigate infeasibilities). For convenience, thegrimsel.core.model_base.ModelBase.get_constraint_groups()
class method allows to select all constraint groups except for those specified by itsexcl
parameter. The example below demonstrates the case where all constraint groups except for thechp
constraints are selected. If the model is constructed with this selection, the methodgrimsel.core.constraints.add_hydro_rules()
will not be called.
['capacity_calculation',
'capacity_constraint',
'charging_level',
'chp',
'energy_aggregation',
'energy_constraint',
'monthly_total',
'objective',
'ramp_rate',
'supply',
'transmission_bounds',
'variables',
'yearly_cost']
Defining input/output parameters¶
The input/output parameters are collected in a dictionary iokwargs
. They are passed to the ModelLoop
initializer as dictionary and serve as keyword arguments to the grimsel.core.io.IO
__init__
class.
Data input parameters
sc_inp
: Name of the input PostgreSQL schema if data is to be read from the database.data_path
: Name of the path holding the input data CSV files if applicable.
Data output parameters
output_target
: One of'hdf5'
(write to hdf5 file) or'psql'
(write to PostgreSQL database).cl_out
: Name of the output table collection. This could either be a PostgreSQL schema or an hdf5 file.no_output
: IfTrue
, no output is written to selected target, but only the model runs are performed.resume_loop
: Resume the model runs at a certainrun_id
. If this isFalse
(default), the output table collection (file or database schema) is re-initialized.replace_runs_if_exist
: By default, ifresume_loop
is an integer, all output data withrun_id >= resume_loop
is deleted prior to the first model run. Ifreplace_runs_if_exist
isTrue
, individual model runs are replaced instead.
General parameters
dev_mode
: Re-initialize the output data target without the default warning.sql_connector
: Instance of thegrimsel.auxiliary.sqlutils.aux_sql_func.SqlConnector
class. This is only required if either the input reading or model output writing makes use of a database connection.
Defining model loop parameters¶
Apart from the iokwkargs
and mkwargs
dictionaries, the ModelLoop
class’ only parameter is the nsteps list:
It defines the steps of parameter variations/scenarios and hence the model runs. In this example, 3 steps of both a swco
axis and a swfy
axis are defined, e.g. to vary the |CO2| emission price and the future years separately. The third item of each tuple (numpy functions) specify whether the corresponding axis values are defined as
- equally spaced steps between 0 and 1 (
np.linspace
); this might be convenient e.g. if the emission price is to varied between 0 and an upper maximum, e.g. 100. In this case the resulting swco loop value can just be used as a multiplicator. - n steps (
np.arange
), e.g. to select discrete values (years, scenarios, etc) from a dictionary{0: 'yr2015', 1: 'yr2020', 3: 'yr2030'}
Then, the ModelLoop
instance is constructed as follows:
Calling the grimsel.core.model_loop.ModelLoop.init_run_table()
method generates a table with all combinations of the steps specified through the nsteps
parameter above:
run_id | swco_id | swfy_id | swco | swfy | swco_vl | swfy_vl | |
---|---|---|---|---|---|---|---|
0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | NaN | NaN |
1 | 1 | 1.0 | 0.0 | 0.5 | 0.0 | NaN | NaN |
2 | 2 | 2.0 | 0.0 | 1.0 | 0.0 | NaN | NaN |
3 | 3 | 0.0 | 1.0 | 0.0 | 1.0 | NaN | NaN |
4 | 4 | 1.0 | 1.0 | 0.5 | 1.0 | NaN | NaN |
5 | 5 | 2.0 | 1.0 | 1.0 | 1.0 | NaN | NaN |
6 | 6 | 0.0 | 2.0 | 0.0 | 2.0 | NaN | NaN |
7 | 7 | 1.0 | 2.0 | 0.5 | 2.0 | NaN | NaN |
8 | 8 | 2.0 | 2.0 | 1.0 | 2.0 | NaN | NaN |
The run_id column is the unique integer index, the *_id columns are unique step ids for each axis, the columns bearing the axes names without suffix are the results of the step type specified in the nsteps
parameter (np.arange
or np.linspace
). Finally, the *_vl columns are actual names of the model run variations and are set later.
For detailed parameter studies this table gets quite large. It is typically filtered to limited the model runs:
run_id | swco_id | swfy_id | swco | swfy | swco_vl | swfy_vl | |
---|---|---|---|---|---|---|---|
0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 | NaN | NaN |
1 | 1 | 1.0 | 0.0 | 0.5 | 0.0 | NaN | NaN |
2 | 2 | 0.0 | 1.0 | 0.0 | 1.0 | NaN | NaN |
3 | 3 | 1.0 | 1.0 | 0.5 | 1.0 | NaN | NaN |
4 | 4 | 2.0 | 1.0 | 1.0 | 1.0 | NaN | NaN |
5 | 5 | 0.0 | 2.0 | 0.0 | 2.0 | NaN | NaN |
6 | 6 | 1.0 | 2.0 | 0.5 | 2.0 | NaN | NaN |
Note that the run_id column is automatically reset for any change to this table.
Model setup¶
A sequence of method calls is used to read the input data and to set up the model instance:
The grimsel.core.io.IO.read_model_data
method reads the model data from the selected data source and adds all tables to the grimsel.core.model_base.ModelBase
instance.
The method grimsel.core.model_base.ModelBase.init_maps()
uses the input table to generate a grimsel.auxiliary.maps.Maps
object. This is based on the def_*
tables and serves primarily to convert ids to names and vice versa (of nodes, power plants, profiles, etc).
The method grimsel.core.model_base.ModelBase.map_to_time_res()
takes care of all model aspects related to the selected time resolution:
- It maps all input profiles to the desired model time resolution as specified by the
nhours
parameter (see above). This results in a set of attributes likeml.m.df_profdmnd_soy
(equivalent for the other profile tables) which are filtered according to thetm_filt
parameter and have potentially reduced time resolution. - It generates the required tables to define the transmission between nodes, especially concerning the mapping of time slots for inter-nodal energy transmission between nodes with different time resolution.
The method grimsel.core.io.write_runtime_tables()
writes input and runtime tables to the output data container. Runtime tables are time maps between model time slots and hours of the year.
Sets up the pyomo set objects as attributes of the
:class:grimsel.core.model_base.ModelBase
class.
The method :func:grimsel.core.sets.define_sets
generates all
necessary pyomo set objects.
The method :func:grimsel.core.sets.get_setlst
generates a dictionary
ml.m.setlst
with the most basic sets, especially those defined by
the set_def_* columns of the ml.m.df_def_plant
input table:
[57, 60, 102, 103]
{57: 'DE_HYD_STO', 60: 'CH_HYD_STO', 102: 'SFH_AA_STO', 103: 'SFH_AB_STO'}
Adds all parameter, variable, and constraint attributes to the model (see grimsel.core.parameters
, grimsel.core.variables
, and grimsel.core.constraints
, ).
The method grimsel.core.model_base.ModelBase.init_solver()
initializes a pyomo SolverFactory instance. Note that assumption on the CPLEX executable are hardcoded here in dependence on the operating system. If this doesn’t work, manual manipulation is required.
grimsel.core.io.IO.init_output_tables()
generates the output table handler objects grimsel.core.io.CompIO
and initializes the SQL tables (if applicable).
Generating a model loop modifier¶
Loop over model runs¶
Basic model data access¶
Grimsel default model structure¶
Grimsel provides a flexible framework for the definition of energy optimization models. The included default case corresponds to a typical national-scale dispatch model. This section describes the mathematical formulation of the default model. It is defined by its sets, variables, parameters, and constraints. The sets and parameter values are defined by the input tables.
Todo
This section mixes the mathematical model formulation and the Python module documentation. This should better be separated.