Repository navigation
Conversation
…lipping it S2 lets a resource manager expect any usage, negative included, and says nothing about what happens when the storage cannot take it. FlexMeasures plans a forecast usage as forced, so a gain at a full storage, or a draw at an empty one the actuator cannot keep up with, left no feasible plan. The handler clipped negative usage to zero to avoid the first case. With a usage_correction_sensor_id and FlexMeasures v1.1.0 or newer, the handler now asks for a schedule with a correction instead: a second device on the storage's stock, on a commodity of its own, which may only move each step's expected usage towards zero. Its price is twice a bound on what a unit of stock can be worth to the scheduler, computed from a coherent set of prices the request carries: band breach prices of 10x, and a site capacity breach price of 100x, the highest absolute market price over the window. So it is used only where nothing physical keeps the plan within the hard bounds. A negative usage is then recorded and planned as stated. Where a correction cannot be priced or shared (no prices, a state-of-charge sensor with a resolution), the forecast is planned without its negative values, as before. The site configurator and the example server give each site a "usage correction" sensor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CcpawsJs74cSwFLXkz7ZwW Signed-off-by: F.N. Claessen <claessen@seita.nl>
- The stock was planned against every forecast on the usage sensor, while the correction's limits and the translation back came from the latest one only, so an older forecast's gain had no correction. The stock now gets its usage inline, from the same series. Before any forecast has arrived since the handler started, the plan goes without usage, since the sensor may hold negative usage recorded as stated. - A request with a commodity list made FlexMeasures ignore the site's stored electricity flex context: a contracted capacity or a peak price was lost. Those fields are carried into the electricity entry, and stored per-MW prices (peaks, commitments) go into the bound; one that is not a fixed price per MW leaves the plan without a correction. - A stored relax-capacity-constraints would make the correction's limits soft; device capacities are now kept hard in the correction path. - Efficiencies above one (a heat pump's COP, a storage that gains) no longer lower the bound. - The correction is opt-in for sites: FRBCSiteConfigurator(correct_usage=) and the example server's S2_CORRECT_USAGE, since it also replaces FlexMeasures' default breach prices with market-relative ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CcpawsJs74cSwFLXkz7ZwW Signed-off-by: F.N. Claessen <claessen@seita.nl>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CcpawsJs74cSwFLXkz7ZwW Signed-off-by: F.N. Claessen <claessen@seita.nl>
Coverage Report for CI Build 42532459987Warning No base build found for commit Coverage: 96.168%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsRequires a base build to compare against. How to fix this → Coverage Stats
💛 - Coveralls |
…s with The co-simulation's controller steers each home with peak prices it stores on the site as sensor references. The bound accepted only fixed prices per MW, so every plan fell back to planning without a correction, in the very setting the correction is for. A stored price on a sensor is now bounded by its highest absolute value over the window, read in the market's currency per MW, as the market prices are. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CcpawsJs74cSwFLXkz7ZwW Signed-off-by: F.N. Claessen <claessen@seita.nl>
The first co-simulation run with the correction on had every request refused with 422: the site's stored flex context holds aggregate-power, which FlexMeasures accepts only at the top level, and the request copied it into the electricity entry. Only the fields FlexMeasures' commodity flex-context schema lists are copied now; the others stay where FlexMeasures merges them in itself. Checked against FlexMeasures v1.1.0's API: the request this handler builds, against a stored context shaped like a co-simulation's (sensor peak prices and capacities, inflexible devices, aggregate-power), is accepted (202), and its job removes exactly the gain the hard top forces. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CcpawsJs74cSwFLXkz7ZwW Signed-off-by: F.N. Claessen <claessen@seita.nl>
Pricing the usage correction above a breach of the site's capacity forced the request to set its own, lower site breach price: at FlexMeasures' default, the correction price would exceed what HiGHS solves reliably. In a steered co-simulation, a site breach price low enough to keep the correction solvable made the houses ignore their steering capacity, and one high enough to steer made every house's schedule infeasible. The correction is now priced from the market and the fill-level band only, and the site's breach prices are left to the asset or FlexMeasures. A correction can then be cheaper than a site breach, but stays dearer than a breach of the band. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CcpawsJs74cSwFLXkz7ZwW Signed-off-by: F.N. Claessen <claessen@seita.nl>
…ed request FlexMeasures fills in its default site breach price (10000 per kW) only for a flex context without commodities. In a commodity entry, a site capacity without a breach price stays hard. A corrected request names its commodities, so a steered site capacity became hard, and a house whose inflexible load exceeded it had no feasible plan. The electricity entry now states that default where the site's capacity may be breached, unless the asset stores a breach price of its own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CcpawsJs74cSwFLXkz7ZwW Signed-off-by: F.N. Claessen <claessen@seita.nl>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #279 (base
dev/s2-frbc-complete), as asked in the review of #271. Merge #279 first.Why
S2 lets a resource manager expect any usage, negative included, and says nothing about what happens when the storage cannot take it. FlexMeasures plans a forecast usage as forced. So a gain at a full storage, or a draw at an empty one that the actuator cannot keep up with, leaves no feasible plan, and the storage gets no instruction. Until now the handler clipped negative usage to zero, which hid the first case and not the second.
What
With a
usage_correction_sensor_idand FlexMeasures v1.1.0 or newer,FRBCSimpleasks for a schedule with a correction of the usage forecast:A second device on the storage's stock (same state-of-charge sensor), on a commodity of its own, so it never touches the site's electricity. No instruction is ever sent for it.
Per step, it may only move the expected usage towards zero: give back up to the expected usage, or take away up to the expected gain. It works the same on both sides, since S2's fill levels do not say which bound is an overflow.
It is priced as a last resort: at twice an upper bound on what one MWh of stock can be worth to the scheduler. The request carries a coherent set of prices to make that bound finite and numerically sound:
soc_breach_price_factor);Device capacities are kept hard, so the correction cannot move a usage past zero.
A negative expected usage is then recorded and planned as stated. The usage is sent inline, from the same forecast as the correction's limits and the translation back into instructions.
Where a correction cannot be planned (prices unreadable, a state-of-charge sensor with a resolution, a stored price that cannot be bounded, a stored flex context with commodities), the forecast is planned without its negative values, as before, with a warning saying why.
It is opt-in:
FRBCSiteConfigurator(correct_usage=True), orS2_CORRECT_USAGE=1for the example server. That is because it replaces FlexMeasures' default band breach price (1000 EUR/kWh) with a market-relative one, which is the deployment's call. Handlers without the new sensor behave exactly as before.How the price was chosen
Probes against FlexMeasures v1.1.0 measured, per scenario, the correction price above which the scheduler stops using a correction it does not need. That threshold is what a MWh of stock is worth to the scheduler. Each matched one term of the bound:
With FlexMeasures' default breach prices, a dominant price was about 1e8 EUR/MWh, where HiGHS already returned over-corrected plans. With the coherent set, over a 24-hour window with prices from −120 to 450 EUR/MWh, the correction price is about 1.8e6 EUR/MWh:
Priced at the band's breach price instead, the correction replaced band breaches (9.24 vs 3.12 kWh) and corrected where nothing needed correcting.
Why the site's capacity breach is left out. Pricing the correction above a site breach needs the request to set a site breach price the solver can live with. In the co-simulation (below), a site breach price of 100× the market price kept the correction solvable but let the houses ignore their steering capacity, and 1000× pushed the correction price to 1.3e7 EUR/MWh, where HiGHS declared every house schedule infeasible (replays put the cliff between 0.7e7 and 1.3e7 for this house). So a correction can now be cheaper than a site breach, while it stays dearer than a band breach, which the plan still uses first.
FlexMeasures fills in its default site breach price only for a flex context without commodities; in a commodity entry, a site capacity without one stays hard. The request therefore states that default itself.
Evidence
relax-capacity-constraintswould soften the limits; and that efficiencies above one lowered the bound. All are fixed in the second commit, which also makes the correction opt-in.Co-simulation
One steered day, two houses, the community capacity policy, deterministic solver settings. Every run below had 0 degree-hours outside the comfort band.
D6 matches C1 on breach and peak. Cost differences between these runs are within what repeats of the same code showed on #279, so I draw no conclusion from them. One difference remains open: the community planner reports a planned residual breach of 2.419 kW at each step in D3 and D6, against at most 0.21 kW in C1, while the realized breach is the same.
🤖 Generated with Claude Code
https://claude.ai/code/session_01CcpawsJs74cSwFLXkz7ZwW