Skip to content

Balance internal commodity nodes (heat/steam networks) via first-class balance groups#2279

Closed
Flix6x wants to merge 3 commits into
feat/chpfrom
feat/commodity-balance-groups
Closed

Balance internal commodity nodes (heat/steam networks) via first-class balance groups#2279
Flix6x wants to merge 3 commits into
feat/chpfrom
feat/commodity-balance-groups

Conversation

@Flix6x

@Flix6x Flix6x commented Jul 10, 2026

Copy link
Copy Markdown
Member

Description

Stacked on #2218. Completes the missing piece of the CHP/factory work: scheduling a multi-commodity factory end-to-end through StorageScheduler.compute().

  • device_scheduler gains a balance_groups argument: each group lists the devices of an internal commodity node (a heat or steam network without a grid connection) whose stock-side flows must sum to zero at every time step. This replaces the earlier workaround of overlapping stock groups with a min=max=0 "reference device" (which never worked automatically from a flex-model — see the investigation notes on dev/simulate-factory).
  • The StorageScheduler derives balance groups from the flex-config: a non-electricity commodity without energy prices in the flex-context is treated as an internal node (previously this raised Missing consumption price). Electricity still requires a price.
  • Converters are described in the flex-model as one entry per commodity port, tied together by a coupling group — so per-commodity balance groups are disjoint and no overlapping group tricks are needed.
  • Added changelog item in documentation/changelog.rst

How to test

pytest flexmeasures/data/models/planning/tests/test_commitments.py -k factory_chp_dispatch
pytest flexmeasures/data/models/planning/tests/test_storage.py -k factory_chp_dispatch_through_storage_scheduler

The engine-level factory test is parametrized to run in both modes (reference-device stock groups and balance groups) and must produce identical dispatch. The new StorageScheduler test drives the full factory (CHP + gas boiler + e-heater + steamer meeting a fixed 15 kW steam demand from an inflexible sensor) purely from a flex-model and flex-context.

Further Improvements

  • An explicit named-node concept in the flex-context (e.g. multiple heat networks per site) is a possible future extension; for now one internal node per commodity suffices.
  • A first-class 'converter' flex-model shorthand that expands into port devices + a coupling group could reduce verbosity.

Related Items

Stacked on #2218; continues the work explored on dev/simulate-factory (#2113-era factory simulation).

🤖 Generated with Claude Code

https://claude.ai/code/session_016MLCUiSdXDqDBmg8GbYp1B

Flix6x and others added 2 commits July 10, 2026 18:52
Adds a balance_groups argument to device_scheduler: each group lists the
devices of an internal commodity node (e.g. a heat or steam network without
a grid connection) whose stock-side flows must sum to zero at every time
step. This replaces the reference-device min=max=0 stock-group workaround
used by the factory scenario, which is now tested in both modes.

The StorageScheduler derives balance groups from the flex-config: a
non-electricity commodity without energy prices becomes an internal node
(previously this raised 'Missing consumption price'). Together with
coupling groups (one flex-model entry per converter port), this makes the
factory scenario (CHP + gas boiler + e-heater meeting a fixed steam demand)
schedulable end-to-end through StorageScheduler.compute().

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016MLCUiSdXDqDBmg8GbYp1B
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016MLCUiSdXDqDBmg8GbYp1B
@Flix6x Flix6x mentioned this pull request Jul 10, 2026
2 tasks
@read-the-docs-community

read-the-docs-community Bot commented Jul 10, 2026

Copy link
Copy Markdown

…terms

A device can sit in both a commodity balance group (via its commodity) and
a shared-stock group (via its state-of-charge sensor), e.g. a steamer that
discharges a heat buffer to produce steam. Its derivative efficiencies and
stock delta (e.g. the buffer's soc-usage losses assigned to it) describe
the stock-side conversion and must not leak into the commodity balance:
what crosses the node is the device's power flow (ems_power).

Found while running the Sappi factory scenario, where the heat buffer's
soc-usage drain was distorting the steam balance.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016MLCUiSdXDqDBmg8GbYp1B
@Flix6x

Flix6x commented Jul 10, 2026

Copy link
Copy Markdown
Member Author

Pushed a fix from real-world testing (a paper-mill factory scenario): the node balance now sums plain ems_power instead of stock-side terms. A device can sit in both a stock group (via state-of-charge, e.g. a steamer discharging a heat buffer) and a commodity balance group (via its commodity) — its derivative efficiencies and the buffer's soc-usage/stock-delta assigned to it describe the stock-side conversion and must not leak into the commodity balance. That leak made a realistic scenario (buffer with standing losses) infeasible.

Heads-up for the #2272 interaction: #2272's smart defaults fill a zero consumption-price into price-free commodity contexts, which defeats this PR's priceless-commodity internal-node detection when both are merged. The fix (tested on a local merge of both branches) is to record durably on the context whether any price field was user-given (a prices_are_defaulted flag set in fill_grid_connection_defaults) and let _prepare treat all-defaulted prices as 'no prices'. It needs code from both PRs, so I'll open it as a small follow-up once the second of the two lands — the commit is ready.

🤖 Generated with Claude Code

@Flix6x

Flix6x commented Jul 11, 2026

Copy link
Copy Markdown
Member Author

Superseded by #2289 after a commit-message cleanup (force-pushes to this branch are blocked by repository rules).

@Flix6x Flix6x closed this Jul 11, 2026
@Flix6x
Flix6x deleted the feat/commodity-balance-groups branch July 11, 2026 12:53
Flix6x added a commit that referenced this pull request Jul 16, 2026
PR #2279 was closed in favour of #2289, which carries the feature now.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015qxM7UZ5wHTz3ftz1Mf9yy
Signed-off-by: F.N. Claessen <felix@seita.nl>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant