Rolling horizon dsm#804
Conversation
…o rolling_horizon_dsm
…o rolling_horizon_dsm Co-authored-by: Copilot <copilot@github.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #804 +/- ##
==========================================
+ Coverage 82.09% 83.09% +1.00%
==========================================
Files 56 56
Lines 9081 9518 +437
==========================================
+ Hits 7455 7909 +454
+ Misses 1626 1609 -17
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
maurerle
left a comment
There was a problem hiding this comment.
I did not review the dsm_load_shift.py - but all other files.
There are still a few things to do.
I guess that the way in which units are added to the DSMFlex is not that good, as the code seems to not know which parameters of the class exist.
The result is the need for various hasattr checks, as you never know if a param exists or is initialized.
I suggest using planning mode and a larger context window when using an LLM to help with this..
|
|
||
| # Set the congestion_indicator in the instance | ||
| # Delete the old component if it exists to avoid Pyomo warnings | ||
| if hasattr(instance, "congestion_indicator"): |
There was a problem hiding this comment.
I don't like this check - can't we test for something like instance.flexibility_measure == "congestion_management_flexibility" in which case the congestion_indicator is set?
This is more like a general thing
Co-authored-by: Copilot <copilot@github.com>
|
@Manish-Khanra please rebase/merge and fix the conflicts - then this can be merged :) |
|
| demand_value = self.steel_demand | ||
| if "_remaining_demand" in self.components: | ||
| demand_value = self.components["_remaining_demand"] | ||
| if hasattr(self, "_rh_window_remaining_demand"): |
There was a problem hiding this comment.
why not initialize _rh_window_remaining_demand in init instead of using hasattr here?
maurerle
left a comment
There was a problem hiding this comment.
Hi @Manish-Khanra I reviewed this PR with @reinecfi
we have some recommendations and changes requested.
If something is not easily understood, we can have a call as well.
| return "price_from_cleared_history" | ||
|
|
||
| # Otherwise treat as algorithm name and return as-is | ||
| return value |
There was a problem hiding this comment.
Shouldn't this happen automagically?
Via forecaster _registries:
assume/assume/common/forecaster.py
Line 657 in 7575332
I guess we currently can only decide if we want to use a self calculated forecast or the existing from forecasts_df.csv
This is still the case with this function (as forecasts_df is always preferred).
I wonder if this function is actually needed. @reinecfi
| market_prices=initial_market_prices | ||
| if initial_market_prices | ||
| else unit.get("market_prices"), |
There was a problem hiding this comment.
| market_prices=initial_market_prices | |
| if initial_market_prices | |
| else unit.get("market_prices"), | |
| market_prices=initial_market_prices or unit.get("market_prices"), |
what is market_prices here?
|
|
||
| if isinstance(price_update_resolved, pd.Series): | ||
| # Direct column: use as initial market prices | ||
| initial_market_prices["EOM"] = price_update_resolved |
There was a problem hiding this comment.
hardcoding "EOM" here does not look right?
But I guess this is consistently weird with the DSM unit and DSM forecaster as well.
| unit.optimisation_counter = 1 | ||
| if unit.horizon_mode == "rolling_horizon": | ||
| current_market_time = product_tuples[0][0] | ||
| did_reoptimize = unit._check_and_reoptimize_rolling_window( |
There was a problem hiding this comment.
This should be calling update_forecasts_if_needed instead.
This logic should then go into this update_forecasts_if_needed function.
But I think that we need to specify this further together with @reinecfi
…o rolling_horizon_dsm
This is still very different from other units and includes many workarounds.
| Returns: | ||
| dict: Updated forecast with adaptive prices learned from clearing history. | ||
| """ | ||
| unit = kwargs.get("unit") |
There was a problem hiding this comment.
where is this unit set when running this in the simulation (not in the test)
maurerle
left a comment
There was a problem hiding this comment.
Did you test that everything works well with your latest commit as intended?
I think that some relevant parts were removed there..? For example adding an "adaptive" forecast algorithm function.
The general idea is to keep the rolling horizon out of the loader_csv and implement the update function in the forecast_algorithm instead of the loader_csv so that it can be reused?
But maybe I am mistaken and this is intended?
…o rolling_horizon_dsm
@maurerle Yes removing the adaptive forecast algorithm was intentional. And you're right that it's a relevant piece, which is exactly why I am moving it to its own PR rather than dropping it. I originally added the adaptive update algorithm in the same commit as rolling horizon, but they are really two separate features. The adaptive algorithm is a forecast update mechanism that refreshes the price forecast for future use. Since rolling horizon doesnot depend on it, I have stashed the forecast algorithm to keep this PR focused on the rolling-horizon implementation and I will submit it as a dedicated PR. |
…Python versions other than 3.14
|
@maurerle The 3.14 checks fail because pypsa <= 0.35.2 (pinned in #808, see #807) becasue the network extra cant install on 3.14. Until the pin can be dropped, I have guarded the notebook 10 with pypsa + network test steps with if: matrix.python-version != '3.14'; 3.10/3.12 are unchanged. This notebook has its own fix now bu I dont know if this temporarily fix like this is appropriate. If not, could you please handle this part? |
Related Issue
Closes #804
If no issue exists, delete this line.
Description
This PR implements rolling-horizon optimization for the DSM units, enabling reactive bidding while maintaining inter-temporal feasibility. Previously, DSM units (steel plants, buildings, hydrogen plants, steam generation plants) optimized over the full simulation horizon. This feature allows units to re-optimize shorter look-ahead windows after each market round while carrying forward component states (e.g., storage SoC, operational status).
Checklist
docfolder updates etc.)Additional Notes (optional)
Key Features
dsm_optimisation_configwithhorizon_mode,look_ahead_horizon,commit_horizon, androlling_stepkeys