Observed
In a community co-simulation, a CEM sent a storage flex-model with an explicit production-capacity: 0 kW for a heat pump (derived from its S2 operation modes — the device physically cannot produce). Under a tight site capacity (1 kW for one slot, via capacity tightening), the StorageScheduler scheduled −1.764 kW of production from the heat pump.
Why this is legal today
relax-constraints defaults to True and auto-injects default breach prices (device: 100 EUR/kW, site: 10 000 EUR/kW). In storage.py, a device's production_capacity — even an explicit 0 — only becomes a hard bound (derivative min = 0) when production_breach_price is None; otherwise it becomes a soft FlowCommitment, and the hard bound stays at the symmetric -power-capacity fallback. With the device breach 100× cheaper than the site breach, 'producing' from the heat pump is the LP's rational move. The only opt-out is the is_strictly_non_positive sensor attribute.
Proposal
Treat an explicitly provided zero directional capacity as a physical statement, not an economic one: keep it hard regardless of relax-constraints/breach prices (or equivalently, auto-infer is_strictly_non_positive/non_negative when a directional capacity is explicitly 0). Relaxation semantics would then apply only to non-zero (economic) capacity limits — consistent with the smart-defaults policy of #2272, where breach prices exist to soften limits, not to un-declare impossibilities.
Workaround in the meantime: set is_strictly_non_positive on consumption-only device sensors (applied in our S2 CEM).
🤖 Generated with Claude Code
https://claude.ai/code/session_01LQFkeGxDwErydUV5ZmHmki
Observed
In a community co-simulation, a CEM sent a storage flex-model with an explicit
production-capacity: 0 kWfor a heat pump (derived from its S2 operation modes — the device physically cannot produce). Under a tight site capacity (1 kW for one slot, via capacity tightening), theStorageSchedulerscheduled −1.764 kW of production from the heat pump.Why this is legal today
relax-constraintsdefaults toTrueand auto-injects default breach prices (device: 100 EUR/kW, site: 10 000 EUR/kW). Instorage.py, a device'sproduction_capacity— even an explicit 0 — only becomes a hard bound (derivative min = 0) whenproduction_breach_priceisNone; otherwise it becomes a softFlowCommitment, and the hard bound stays at the symmetric-power-capacityfallback. With the device breach 100× cheaper than the site breach, 'producing' from the heat pump is the LP's rational move. The only opt-out is theis_strictly_non_positivesensor attribute.Proposal
Treat an explicitly provided zero directional capacity as a physical statement, not an economic one: keep it hard regardless of relax-constraints/breach prices (or equivalently, auto-infer
is_strictly_non_positive/non_negativewhen a directional capacity is explicitly 0). Relaxation semantics would then apply only to non-zero (economic) capacity limits — consistent with the smart-defaults policy of #2272, where breach prices exist to soften limits, not to un-declare impossibilities.Workaround in the meantime: set
is_strictly_non_positiveon consumption-only device sensors (applied in our S2 CEM).🤖 Generated with Claude Code
https://claude.ai/code/session_01LQFkeGxDwErydUV5ZmHmki