-
Notifications
You must be signed in to change notification settings - Fork 36
Rolling horizon #1327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rolling horizon #1327
Conversation
🤖 CompareMPS report✅ MPS files match |
Benchmark Results
Benchmark PlotsA plot of the benchmark results have been uploaded as an artifact to the workflow run for this PR. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1327 +/- ##
==========================================
- Coverage 98.61% 98.47% -0.14%
==========================================
Files 38 42 +4
Lines 1368 1511 +143
==========================================
+ Hits 1349 1488 +139
- Misses 19 23 +4 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
abelsiqueira
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@datejada, I've created a first draft of the rolling horizon implementation. I don't expect you to read everything, but I've marked a few interesting places, and we can discuss and go over the details if you have time.
I'm trying something with the profiles which hides the complexity in _profile_aggregate. This avoids changing the code everywhere and manually handling rolling horizon inside the model. I am still not sure whether this is efficient or not, but it's what I thought of so far.
I also have the following questions:
- Are there other places that will require rolling horizon? Are we trying to make it more generic than this? If so, how generic?
- I am not sure how to validate that the rolling horizon is working. I've created some random problem that possibly doesn't make a lot of sense. Do you have some Tulipa-compatible test? If not, maybe we can go over the TulipaBuilder implementation and see what comes out of it.
| return | ||
| end | ||
|
|
||
| function prepare_profiles_structure(connection) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@datejada, here I changed the defaults profiles structure to hold in parallel the values (as before) and the rolling horizon parameters (initially empty)
src/rolling-horizon.jl
Outdated
|
|
||
| function add_rolling_horizon_parameters!(connection, model, variables, profiles, window_length) | ||
| # Profiles | ||
| for (_, profile_object) in profiles.rep_period |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@datejada, here we initialise the profiles' rolling horizon variables
src/rolling-horizon.jl
Outdated
| @variable(model, [1:window_length] in JuMP.Parameter(0.0)) | ||
| end | ||
|
|
||
| # initial_storage_level |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@datejada, for the initial storage level, I have to create a table just for that.
src/rolling-horizon.jl
Outdated
| return | ||
| end | ||
|
|
||
| function update_rolling_horizon_profiles!(profiles, window_start, window_end) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@datejada, the straightforward update of the rolling horizon parameters
src/rolling-horizon.jl
Outdated
| return | ||
| end | ||
|
|
||
| function update_initial_storage_level!(param_initial_storage_level::TulipaVariable, connection) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@datejada, the not-so-straightforward update of the storage level.
| profile_object = profiles[tuple_key] | ||
|
|
||
| # Rolling horizon is inferred by the existence and non-emptyness of rolling_horizon_variables | ||
| is_rolling_horizon = | ||
| hasproperty(profile_object, :rolling_horizon_variables) && | ||
| length(profile_object.rolling_horizon_variables) > 0 | ||
|
|
||
| if is_rolling_horizon | ||
| profile_value = profile_object.rolling_horizon_variables | ||
| return agg_function(skipmissing(profile_value[time_block])) | ||
| else | ||
| profile_value = profile_object.values | ||
| return agg_function(skipmissing(profile_value[time_block])) | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@datejada, here's the trick with the profile. If is_rolling_horizon, we use the rolling horizon variables, otherwise use the actual values.
src/model-preparation.jl
Outdated
|
|
||
| # Completely separate calculation for inflows_profile_aggregation | ||
| if is_storage_level | ||
| # TODO: Fix this for rolling horizon |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@datejada, missed this. This is the one place that uses the profiles_rep_periods explicitly, which will probably require refactoring
test/test-case-studies.jl
Outdated
| # Rolling horizon | ||
| energy_problem = | ||
| TulipaEnergyModel.run_rolling_horizon(connection, 24 * 7, 48 * 7; show_log = false) | ||
| # @test energy_problem.objective_value ≈ 10000.0 atol = 1e-5 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to test the objective function of each one of the windows instead of the overall objective function
@abelsiqueira, thanks for the PR. It is starting to take shape 😃
Thanks again 😄 I like the changes |
|
Thanks for the initial review, @datejada. Some comments:
Thanks again for the review |
Great! Thanks for the reply. So:
Thanks! |
d1d2b3a to
4433c3c
Compare
9458b70 to
16b2a2a
Compare
|
📝 Check the documentation preview: https://tulipaenergy.github.io/TulipaEnergyModel.jl/previews/PR1327 |
16b2a2a to
41a0422
Compare
Implement ProfileWithRollingHorizon and make profiles.rep_period use
that instead of Vector{Float64}.
Change _profile_aggregate to dispatch on Vector{Float64} and
ProfileWithRollingHorizon.
These should allow the rolling horizon variables to be aggregated
the same way as the normal profiles.
Part of #1365
Implement run_rolling_horizon with the main idea. Use placeholders to specify places where a more complicated function needs to be called. Update the EnergyProblem structure to hold an inner EnergyProblem for the rolling horizon model. Part of #1365
Add ParametricOptInterface. Implement adding the rolling horizon parameters in src/rolling-horizon/create.jl. Update create_model to handle the rolling horizon parameters and wrap the solver in POI.Optimizer if it's rolling horizon. Part of #1365
Implement the update functions for rolling horizon and add them to the run_rolling_horizon function. Part of #1365
Add validation of input in the rolling horizon function. Add function to prepare the input to get in the rolling horizon and to get out. Add function to save the solution in the relevant tables. Part of #1365
Add tests of the various parts of rolling horizon. Part of #1365
Update src/constraints/storage.jl to use the initial_storage_level stored in the rolling horizon. Add test for the rolling horizon objective values to control future changes. Part of #1365
41a0422 to
e3bb910
Compare
|
@datejada, I've made the updates I commented yesterday, and I've squashed them in the existing commits. Now you can review them one commit at a time. The is a missing note that I mentioned from the docs: the solution of thermal and battery in RH vs no-RH were not equal. I though it was because of the ordering of the update of the initial value, but I've the code update and I also noticed that in the rolling horizon, we have only 1 storage asset, so there is no error in the ordering, because we have only 1 value. My understanding is that there isn't actually an issue, but what actually happens is that there are multiple solutions. One where you use the stored energy at time |
datejada
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed in-site after comments included from previous round.
Full PR with all rolling horizon commits (except for docs, see #1387 for that).
Changes:
ProfileWithRollingHorizonand makeprofiles.rep_perioduse that instead ofVector{Float64}.Vector{Float64}andProfileWithRollingHorizon.for the rolling horizon model.
to the run_rolling_horizon function.
Related issues
Closes #1365
Checklist