feat: multi-commodity operation modes (per-commodity ranges + no-load flow)#2335
Open
Flix6x wants to merge 2 commits into
Open
feat: multi-commodity operation modes (per-commodity ranges + no-load flow)#2335Flix6x wants to merge 2 commits into
Flix6x wants to merge 2 commits into
Conversation
… flow) Generalise operation modes (#2278) so that a mode can carry, in addition to the device's own signed power band, per-commodity power ranges plus a per-commodity fixed no-load flow, matching S2's FRBC.OperationModeElement. The device scheduler ties the commodities affinely through a single continuous operation-mode factor per (banded device, band, time step), gated by the existing device_band binary. When a mode is active the factor sweeps the device's own power between its band min/max and every coupled commodity between its own (min, max) in lockstep: the range minima are the fixed no-load flows (gated by the binary), the shared factor supplies the marginal part. This natively expresses a unit-committed affine cogeneration unit (off + affine-on gas/heat), with a minimum level when on. Min up/down time is out of scope. Single-commodity operation modes are untouched (new machinery is only built for devices that declare commodity ranges). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016MLCUiSdXDqDBmg8GbYp1B Signed-off-by: F.N. Claessen <claessen@seita.nl>
Documentation build overview
7 files changed ·
|
Reconcile multi-commodity operation modes with the base-branch review change that renamed the operation-mode power range to sign-explicit consumption-range / production-range keys and added _operation_mode_signed_band. - OperationModeSchema: keep the base's consumption_range/production_range fields, check_ranges validator and _operation_mode_signed_band helper; drop the old power_range field/validator; keep commodity_power_ranges + uniqueness check. - CommodityPowerRangeSchema: make per-commodity ranges sign-explicit too (consumption-range and/or production-range), with the same non-negative / through-zero validation. - storage.py: factor out a shared _signed_range_endpoints core reused by both _operation_mode_signed_band (device's own band) and a new _operation_mode_commodity_bands, which derives each commodity's directional (factor-0, factor-1) signed endpoints aligned to the device's operation-mode factor. - linear_optimization.py: clarify that device_mode_commodity_ranges carries signed (c0, c1) factor-extreme endpoints (sign resolved upstream), not (min, max). - tests: express the cogeneration unit sign-explicitly (electricity and heat as production, gas as consumption), driven through the schema + helpers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016MLCUiSdXDqDBmg8GbYp1B Signed-off-by: F.N. Claessen <claessen@seita.nl>
Member
Author
|
Reconciled with the base-branch review change (sign-explicit
|
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.
What
Generalises operation modes (#2278) so that a single mode can carry, on top of the device's own signed power band, per-commodity power ranges plus a per-commodity fixed (no-load) flow. This matches the S2 FRBC model (
FRBC.OperationModeElement.power_ranges, a list — one range per commodity_quantity — where today's FlexMeasures version collapses to a single commodity), and lets a unit-committed affine cogeneration unit be expressed natively:[0, 0], gas[0, 0], heat[0, 0](no no-load fuel)[Pmin, Pmax], and — tied affinely — gas = no-load base + proportional, heat = no-load base + proportionalDesign route for the affine tie (route b, S2-faithful)
Two routes were on the table:
This PR takes route (b). Rationale:
power_rangesdirectly, and a singleoperation_mode_factor(0..1) interpolates every commodity's power simultaneously within its range. That interpolation is the affine tie. We model exactly this: a continuous factorlambda in [0, 1]per (banded device, band, time step), gated by the existingdevice_bandbinary, sets the banded device's own power topmin + lambda*(pmax-pmin)and each coupled commodity tocmin + lambda*(cmax-cmin). The range minima are the per-commodity fixed no-load flows (gated by the binary); the shared factor moves the marginal parts in lockstep.Trade-off vs. the coupling route: route (a)/coupling keeps the marginal ratio in one place (the coupling between ports) and can express couplings that exist independently of operation modes, but it needs that feature to land first and splits a cogeneration unit's description across two mechanisms. Route (b) keeps a mode's full multi-commodity behaviour in one object (closer to S2 and easier to reason about for unit commitment), at the cost of duplicating a ratio if the same physical coupling is also modelled elsewhere. Both are being prototyped so we can compare them for a release.
Schema shape
OperationModeSchemagains an optionalcommodity-power-ranges: a list of{"commodity": <str>, "power-range": [<low>, <high>]}(newCommodityPowerRangeSchema), mirroring S2's per-commoditypower_ranges. Endpoints are ordered factor-0 → factor-1 (not min/max), so the factor-0 endpoint is the no-load flow. Duplicate commodities are rejected. Single-commodityoperation-modesare unchanged.Scheduler wiring
device_schedulergains an optionaldevice_mode_commodity_rangesparameter (parallel todevice_power_bands). New Pyomo pieces (flexmeasures/data/models/planning/linear_optimization.py): thedevice_mode_factorvariable, its gatefactor <= device_band, the primary-power interpolation equality, and the per-commodity interpolation equality. Machinery is only built for devices that actually declare commodity ranges, so existing single-commodity behaviour is untouched.Test
test_operation_modes.pyadds a cogeneration unit expressed via multi-commodity operation modes:0.2 + 1.0*Pand heat =0.1 + 0.5*P(incl. no-load bases);1*0.4 + 1*0.4 + 10*0.4 = 4.8+ gas2*(0.6*3) = 3.6= 8.4.Existing single-commodity operation-mode cases stay green;
test_scheduling.pyadds schema load / duplicate-commodity validation tests.Scope
Min up/down time (minimum on/off durations) is out of scope for this prototype.