Skip to content

Support intermediate power constraints on groups of devices (flex-model group field)#2276

Open
Flix6x wants to merge 8 commits into
mainfrom
fix/intermediate-power-constraints
Open

Support intermediate power constraints on groups of devices (flex-model group field)#2276
Flix6x wants to merge 8 commits into
mainfrom
fix/intermediate-power-constraints

Conversation

@Flix6x

@Flix6x Flix6x commented Jul 10, 2026

Copy link
Copy Markdown
Member

Description

Adds support for intermediate power constraints: power limits on the aggregate flow of a group of devices, sitting between per-device power capacities and site-level (EMS) constraints. Closes #2092 (a hybrid inverter whose battery + PV children could jointly exceed the inverter's limit) and implements the flex-model-centric design from the discussion #1418 comment. Includes #2277.

Design

Device entries in a multi-device storage flex-model reference a group; the group's own flex-model entry constrains the group's aggregate power:

[
  {"sensor": 1, "power-capacity": "2 kW", "group": {"sensor": 5}},
  {"sensor": 2, "production-capacity": "2 kW", "consumption-capacity": "0 kW", "group": {"sensor": 5}},
  {"sensor": 5, "power-capacity": "2.5 kW"}
]
  • power-capacity on the group entry → hard constraint (both directions).
  • consumption-capacity / production-capacitysoft constraints, enforced via breach commitments with default breach prices (10000 currency/kW; no user-set group prices — consistent with the smart-defaults policy in Smarter commodity-context defaults and Commitment commodity field #2272).
  • Groups can be referenced by sensor ({"sensor": <id>}, shown above) or by asset ({"asset": <id>}). The asset variant is what DB-stored flex-models naturally produce, making the feature fully definable via an asset tree: store partial flex-models on the assets and trigger the parent with an empty flex-model.
  • Saving the group's schedule: sensor-referenced groups save the aggregate to the group power sensor; asset-referenced groups (which have no power sensor) save it via their consumption/production output sensors, following the standard conventions (consumption only → full profile consumption-positive; production only → full profile production-positive on save; both → clip-split into positive parts on each sensor). Either kind may define output sensors.
  • Nested groups are supported (cycles rejected); group members must share a commodity; groups require multi-device flex-models.

Implementation

Built entirely on the existing device-group solver machinery — hard bounds via ems_constraints/ems_constraint_groups (multi-commodity work, #1946) and soft bounds via grouped FlowCommitments (#1934). No optimizer changes.

  • Schema: new group field (sensor or asset reference, exactly one) on StorageFlexModelSchema and DBStorageFlexModelSchema; sensor variant validated to reference a power sensor.
  • MetaStorageScheduler._prepare: group entries split from device entries (validations: dangling refs, device-only fields on group entries, mixed commodities, cycles, single-sensor mode) and per-group hard/soft constraints built mirroring the site-level capacity/breach patterns.
  • UI: group added to the flex-model editor; the editor recommends the parent asset for a child's group field (one-click suggestion) and hints in both the parent's and children's editors when the parent's flex-model defines a power-capacity.
  • Docs: new "Intermediate power constraints" section in the scheduling feature docs, plus a new toy-example tutorial driven entirely by DB-stored flex-models.

Bug fixes along the way

  • Latent device-index misalignment in _prepare: per-device lists were built from the full flex-model list (including stock-only entries) instead of the filtered device models.
  • AssetTriggerSchema.check_flex_model_sensors raised KeyError on asset-only flex-model entries.
  • The freeze_server_now test fixture leaked its server_now monkeypatch into all subsequently run tests in the same process, causing order-dependent duplicate-key failures when scheduling jobs saved beliefs with identical frozen belief times.

Tests

  • Solver-level (test_group_constraints.py, 18 tests): the [FlexMeasures/Scheduler] Investigate Missing Parent-Child Physical Constraint Propagation #2092 inverter case with a control run proving the constraint binds, soft directional bounds + breach commitment costs, output-sensor saving in all three modes, nested/mixed-kind groups, cycle detection, validation errors, and a pure-DB-tree end-to-end test (all flex-models stored as asset attributes, scheduling triggered with an empty flex-model).
  • API-level: end-to-end trigger → job → beliefs on the group sensor equal the sum of member schedules; 422 for a group sensor outside the asset tree.
  • UI tests for the editor hints; schema tests for both reference variants.
  • Full serial regression (planning + schemas + UI + API schedule suites): 537 passed, 3 xfailed. Pre-commit and docs build clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TAad46Ayg86DHpL6nY54sX

Flix6x and others added 2 commits July 10, 2026 08:40
Add a new `group` field to the storage flex-model, letting device entries
reference a power sensor that represents a group of devices (e.g. a hybrid
inverter shared by a battery and PV). The group sensor's own flex-model entry
constrains the group's aggregate power:

- power-capacity: hard constraint (both directions)
- consumption-capacity / production-capacity: soft constraints, enforced via
  breach commitments with default breach prices (10000 <currency>/kW)

The group's scheduled aggregate power is saved to the group sensor. Nested
groups are supported (cycles rejected); groups require multi-device
flex-models and members must share a commodity.

Implemented on top of the existing device-group solver machinery
(ems_constraint_groups from the multi-commodity work, and grouped
FlowCommitments from PR #1934); no changes to the optimizer itself.

Also fixes a latent device-index misalignment in MetaStorageScheduler._prepare,
where per-device lists were built from the full flex-model list (including
stock-only entries) instead of the filtered device models.

Closes #2092

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TAad46Ayg86DHpL6nY54sX
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TAad46Ayg86DHpL6nY54sX
@read-the-docs-community

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

Copy link
Copy Markdown

Flix6x and others added 4 commits July 10, 2026 10:29
Add a new `group` field to the storage flex-model, letting device entries
reference a power sensor that represents a group of devices (e.g. a hybrid
inverter shared by a battery and PV). The group sensor's own flex-model entry
constrains the group's aggregate power:

- power-capacity: hard constraint (both directions)
- consumption-capacity / production-capacity: soft constraints, enforced via
  breach commitments with default breach prices (10000 <currency>/kW)

The group's scheduled aggregate power is saved to the group sensor. Nested
groups are supported (cycles rejected); groups require multi-device
flex-models and members must share a commodity.

Implemented on top of the existing device-group solver machinery
(ems_constraint_groups from the multi-commodity work, and grouped
FlowCommitments from PR #1934); no changes to the optimizer itself.

Also fixes a latent device-index misalignment in MetaStorageScheduler._prepare,
where per-device lists were built from the full flex-model list (including
stock-only entries) instead of the filtered device models.

Closes #2092

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TAad46Ayg86DHpL6nY54sX
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TAad46Ayg86DHpL6nY54sX
Signed-off-by: F.N. Claessen <claessen@seita.nl>
The UI-DB flex-model schema parity test requires every DBStorageFlexModelSchema
field to have UI support.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TAad46Ayg86DHpL6nY54sX
Signed-off-by: F.N. Claessen <claessen@seita.nl>
Flix6x and others added 2 commits July 10, 2026 12:22
… asset tree (#2277)

Extend the storage flex-model's group field to also accept {"asset": <id>},
so a group can be identified by an asset-keyed flex-model entry - the form
that DB-stored flex-models naturally produce. This makes intermediate power
constraints fully definable via an asset tree with stored flex-models, with
an empty flex-model in the scheduling trigger.

- Asset-referenced group entries define no power sensor of their own; the
  group's scheduled aggregate power is saved via the entry's consumption
  and/or production output sensors, following the usual output-sensor
  conventions (full profile on a single sensor; clip-split when both given).
- Sensor-referenced groups keep saving the aggregate to the group power
  sensor, and may now also define output sensors.
- The UI asset flex-model editor recommends the parent asset when editing a
  child's group field (one-click suggestion), and hints in both the parent's
  and children's editors when the parent's flex-model defines power-capacity.
- New tutorial: toy example for intermediate power constraints, driven
  entirely by DB-stored flex-models.

Bug fixes uncovered along the way:
- AssetTriggerSchema.check_flex_model_sensors raised KeyError on asset-only
  flex-model entries.
- The freeze_server_now test fixture leaked its server_now monkeypatch into
  all subsequently run tests in the same process, causing order-dependent
  duplicate-key failures when scheduling jobs saved beliefs with identical
  (frozen) belief times.


Claude-Session: https://claude.ai/code/session_01TAad46Ayg86DHpL6nY54sX

Signed-off-by: F.N. Claessen <claessen@seita.nl>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Remove references to code modules, tests and GitHub issues from the tutorial;
tutorials address FlexMeasures users, not developers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TAad46Ayg86DHpL6nY54sX
Signed-off-by: F.N. Claessen <claessen@seita.nl>
@Flix6x Flix6x changed the title Support intermediate power constraints on groups of devices Support intermediate power constraints on groups of devices (flex-model group field) Jul 10, 2026
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.

[FlexMeasures/Scheduler] Investigate Missing Parent-Child Physical Constraint Propagation

1 participant