This is rtc-tools-interface, a toolbox for user-interfaces for rtc-tools.
pip install rtc-tools-interface
The goal generator
can be used to automatically add goals based on a csv file. Currently, the following goal types are supported:
- range (default order is 2)
- minimization_path (default order is 1)
- maximization_path (default order is 1)
- range_rate_of_change (default order is 1)
For the range goals, the target need to be specified. This can either be a value, a parameter or a timeseries.
The required columns of the goal_table
are:
id
: A unique string for each goal.active
: Either0
or1
. If0
goal will not be used.state
: State (variable) on which the goal should act on.goal_type
: Choose from path goals:range
,minimization_path
,maximization_path
orrange_rate_of_change
.priority
: Priority of the goal.
And optional columns are:
function_min
: For goals of typerange
specify the minimum possible value for the selected state. If not specified, will be calculated using the bounds of thestate
(if available).function_max
: For goals of typerange
specify the maximum possible value for the selected state. If not specified, will be calculated using the bounds of thestate
(if available).function_nominal
: Approximate order of the state.target_data_type
: Eithervalue
,parameter
ortimeseries
.target_min
: Only for goals of typerange
: specify either a value or the name of the parameter/timeseries.target_max
: Only for goals of typerange
: specify either a value or the name of the parameter/timeseries.weight
: Weight of the goal.order
: Only for goals of typerange
, order of the goal.
To use to goal_generator, first import it as follows:
from rtctools_interface.optimization.goal_generator_mixin import GoalGeneratorMixin
and add the GoalGeneratorMixin
to your optimization problem class. It must be added before GoalProgrammingMixin
. Also, define the goal_table.csv
in the input folder of your problem.
- The
minimization_path
andmaximization_path
goals can be used to minimize/maximize the sum of astate
over all timesteps, but be careful with the order:- For a
maximization_path
goal, if the order is even, the goal is equal to the minimization_path goal, as the minus sign is squared out. - A
minimization_path
ormaximization_path
goal with an even order will try to bring the selectedstate
as close to 0 as possible, so not necessarily minimizing/maximizing it.
- For a
For each goal, this section will specify the equations that rtc-tools will add to the optimization problem. Note that rtc-tools will always minimize the objective function.
For the minimization_path goal, rtc-tools adds the following equation to the objective function of the specified priority
weight
(default is 1), order
(default is 1), state
. No constraints are added for this goal.
For the maximization_path goal, rtc-tools adds the following equation to the objective function of the specified priority
weight
(default is 1), order
(default is 1), state
. No constraints are added for this goal.
For the range goal, rtc-tools adds the following equation to the objective function of the specified priority
\begin{aligned}
g_{low}(\epsilon_t) \leq &x_t \leq g_{up}(\epsilon_t) \quad &\forall t\
0 \leq &\epsilon_t \leq 1 \quad &\forall t
\end{aligned}
$$
where
$$
\begin{aligned}
g_{low}(\epsilon_t) &:= (1-\epsilon_t) m_{t,target} + \epsilon_t m \
g_{up}(\epsilon_t) &:= (1-\epsilon_t) M_{t,target} + \epsilon_t M
\end{aligned}
$$
and weight
(default is 1), order
(default is 2), state
, target_min
and target_max
), function_min
and function_max
). The auxiliary variable
The range_rate_of_change goal can be used to set a target range on ramp rate. Like the range goal, one needs to set the target_min
and target_max
for that. Importantly for the range_rate_of_change goal, the supplied values are relative to the nominal of the function. So supplying a target_max
of 10
corresponds to the aim of having a maximum increase per timestep of 10% * nominal
, where the nominal automatically set to maximum rate of change
/2 or specified manually. To formulate the target of having a maximum increase and decrease by of 10% per timestep, one would set the target_min
to -10
and the target_max
to 10
.
The equations for the range_rate_of_change goal are almost the same as for the range goal, which can be found above. The only difference is that
See the table below for an example content of the goal_table.csv
.
id | state | active | goal_type | function_min | function_max | function_nominal | target_data_type | target_min | target_max | priority | weight | order |
---|---|---|---|---|---|---|---|---|---|---|---|---|
goal_1 | reservoir_1_waterlevel | 1 | range | 0 | 15 | 10 | value | 5.0 | 10.0 | 5 | ||
goal_2 | reservoir_2_waterlevel | 1 | range | 0 | 15 | 10 | timeseries | "target_series" | "target_series" | 10 | ||
goal_3 | electricity_cost | 1 | minimization_path | 20 |
For all goals defined with the goal generator this rtc-tools-interface module will also calculate performance metrics. By default, these performance metrics are saved to a .csv in the folder output/perfomance_metrics
, with one csv file per goal. With the class variable calculate_performance_metrics
this functionality can be disabled (by default it is enabled).
The calculated metrics are:
timeseries_sum
: The sum of the state variable over all timesteps.timeseries_min
: The minimum of the state variable.timeseries_max
: The maximum of the state variable.timeseries_avg
: The average of the state variable.max_difference
: The maximum difference in one timestep.mean_absolute_percentual_difference
: The mean of the absolute percentual difference per timestep over all timesteps (only for range goals).mean_absolute_difference
: The mean absolute difference per timestep of the state variable over all timesteps (only for range goals).
With the PlotMixin
one can easily make plots of the results of rtc-tools. This functionality can be used both for optimization and simulation problems. For optimization problems, use:
from rtctools_interface.optimization.plot_mixin import PlotMixin
and for simulation problems use:
from rtctools_interface.simulation.plot_mixin import PlotMixin
Then, add the PlotMixin
to your optimization/simulation problem class. For optimization problems, the PlotMixin can create a plot after each priority and/or a plot with the final results only.
By default, the PlotMixin
will make both. This can be changed by setting the class variables plot_results_each_priority
and plot_final_results
to either True
or False
in your problem class.
Furthermore, the PlotMixin can either create Plotly
plots and matplotlib
plots. The matplotlib
plots will be exported as png
, the Plotly figures as html
. By default, Plotly
is used. To change this, pass the keyword-argument plotting_library="matplotlib"
to the run_optimization_problem
function.
- In optimization mode, the plots for a particular priority will contain line segments with the results from the previous priority result. This makes it easy to see what changed from priority to priority.
- The
final_results
plot will show the result from the previous run. This allows for comparing results from different scenario's (like input timeseries or changes to the model). Note that is not possible to change the number of goals between two comparison runs. This feature currently only works with Plotly plots, where a dropdown is available to hide the previous results.
The following class variables can be set to change the behaviour of the PlotMixin:
plot_max_rows
: an integer number for the maximum number of rows (default is 4). The number of columns will be derived from that.plot_results_each_priority
: Only for optimization: boolean indicating whether the plots for each priority should be generated and saved. Default is True.plot_table_file
: path to plot table csv file. Default isinput\plot_table.csv
.
There are two types of plots that can be made with the PlotMixin
- Plots of arbitrary states, for example ones being optimized in a goal defined in Python.
- Plots based on goals in the goal_generator table (only applicable to optimization problems).
To add a plot for a goal in the goal_generator
table, one should add a row to the plot_table
with an id
equal to the id of the goal in the goal_generator
to be plotted. The specified_in
field should be set to goal_generator
. Rows of the plot_table
with specified_in
=goal_generator
but with an id
that does not occcur in the goal_table
, are ignored.
To add a plot for a custom state, it is not necessary to set the id
. However, by default no variables will be plotted. To do so, one needs to specify at least one variable.
The (only) required column of this plot_table
is:
y_axis_title
: A string for the y-axis (LaTeX allowed, between two$
).
And optional columns are:
id
: Required when a plot for a row in thegoal_table
should be created. Should be equal to the id in the correspondinggoal_table
.variables_style_1
: One or more state-names to be plotted, seperated by a comma.variables_style_2
: One or more state-names to be plotted, seperated by a comma. Fixed styling is applied for all variables defined here.variables_with_previous_result
: One or more state-names to be plotted, seperated by a comma. If available, the results for that variable at the previous priority optimization will also be shown.custom_title
: Custom title overwriting automatic title. Required for goals specified in python.specified_in
: Eithergoal_generator
orpython
. If equal togoal_generator
, the id field should be set.
The table could thus look like:
id | y_axis_title | variables_style_1 | variables_style_2 | variables_with_previous_result | custom_title | specified_in |
---|---|---|---|---|---|---|
goal_1 | Volume ( |
"PowerPlant1.QOut.Q" | goal_generator | |||
goal_2 | Volume ( |
"PowerPlant1.QOut.Q, PowerPlant2.QOut.Q" | goal_generator | |||
Volume ( |
electricity_cost | "Goal for minimizing electricity cost, at priority 10" | python |
After running the model, in your output folder the folder figures
containing the figures is created.
To run a closed loop experiment
one can use the run_optimization_problem_closed_loop
function
from rtctools_interface.closed_loop.runner
.
This function is a drop-in replacement for the run_optimization_problem
of rtc-tools.
The user needs to specify a ClosedLoopConfig
configuration
from rtctools_interface.closed_loop.config
to specify the time ranges for which to subsequentially solve the optimization problem.
Import ClosedLoopConfig
and run_optimization_problem_closed_loop
with:
from rtctools_interface.closed_loop.config import ClosedLoopConfig
from rtctools_interface.closed_loop.runner import run_optimization_problem_closed_loop
Create the file fixed_inputs.json
, in which you specify which variables in your
timeseries import are what we call 'fixed_inputs'. They are timeseries that the closed
loop runner should simply copy as they are, even if they contain only NaNs in a modelling
period.
The variables that are not mentioned in this list of fixed_inputs, and have only NaN's in a modelling period, are considered being 'initial values'. The closed loop runner will set the first timestep of each modelling period with the corresponding calculated value from the previous modelling period.
A ClosedLoopConfig
configuration can be created from a csv file or
from a given forecast timestep (time between each time range)
and optimization period (duration of each time range).
An option round_to_dates
can be used to round the start and end time of each range to a date,
i.e. the start time is rounded to the start of the day
and the end time is rounded to the end of a day.
Examples of creating a configuration are given below.
from datetime import timedelta
from rtctools_interface.closed_loop.config import ClosedLoopConfig
config_from_file = ClosedLoopConfig(
file="path/to/closed_loop_dates.csv",
round_to_dates=True
)
config_from_fixed_periods = ClosedLoopConfig.from_fixed_periods(
optimization_period=timedelta(days=3),
forecast_timestep=timedelta(days=2)
)
The CSV file closed_loop_dates.csv
has two columns start_date
and end_date
and looks as follows.
start_date, end_date
2024-05-19, 2024-05-23
2024-05-23, 2024-05-25
The run_optimization_problem_closed_loop
will solve the optimization problem
for each time range subseqentually.
It will use the final results from the previous run to set the initial values of the next run.
Note that this happens for:
- All variables available at the first time step in original timeseries_import, but not available at any timestep in the modelling period.
- All variables in the
initial_state.csv
(if the csv_mixin is used).
- The start time of the first time range should coincide with the start time of the input timeseries.
- The start time of the next time range should be less or equal to the end time of the current time range.
- Currently, only the initial values of the first time step in a given time range are set.
- The closed_loop runner only works in combination with the CSVMixin or the PIMixin. The CDFMixin is not supported.