Pre-existing bug (not a linopy-v1 semantics issue) — surfaced while making the clustered-storage tests robust for #729.
Symptom
A Storage created with a numeric initial_charge_state but the default cluster_mode='intercluster_cyclic' (or 'cyclic') does not pin the initial SOC. The value is silently dropped, leaving the absolute SOC level unconstrained (degenerate).
fx.Storage('S', capacity_in_flow_hours=50, initial_charge_state=0.5, ...) # default cluster_mode='intercluster_cyclic'
# after clustering+solve: charge_state can be all-zero — initial_charge_state=0.5 had no effect
Location
flixopt/components.py:1415 (InterclusterStorageModel._add_intercluster_linking):
if self.element.cluster_mode == 'intercluster_cyclic':
self.add_constraints(soc_boundary[0] == soc_boundary[n], short_name='cyclic') # initial_charge_state NOT applied
else:
# only here is initial_charge_state pinned
The same applies to the base StorageModel 'cyclic' mode (_add_initial_final_constraints skips initial/final for independent/cyclic).
Root cause
In cyclic modes the level is tied start==end but never anchored to initial_charge_state, so the LP is degenerate in the absolute SOC level. A user who sets initial_charge_state gets no error/warning that it was ignored.
Impact
Proposed fix (needs a design decision)
Either (a) warn/error when initial_charge_state is set together with a cyclic cluster_mode (it is contradictory), or (b) honor it by anchoring soc_boundary[0] == initial_charge_state in addition to (or instead of) the cyclic tie. Option (a) is the smaller, safer change.
Severity
Correctness/UX (silent parameter drop) + solution degeneracy. Objective and flow rates remain correct.
Pre-existing bug (not a linopy-v1 semantics issue) — surfaced while making the clustered-storage tests robust for #729.
Symptom
A
Storagecreated with a numericinitial_charge_statebut the defaultcluster_mode='intercluster_cyclic'(or'cyclic') does not pin the initial SOC. The value is silently dropped, leaving the absolute SOC level unconstrained (degenerate).Location
flixopt/components.py:1415(InterclusterStorageModel._add_intercluster_linking):The same applies to the base
StorageModel'cyclic'mode (_add_initial_final_constraintsskips initial/final forindependent/cyclic).Root cause
In cyclic modes the level is tied start==end but never anchored to
initial_charge_state, so the LP is degenerate in the absolute SOC level. A user who setsinitial_charge_stategets no error/warning that it was ignored.Impact
test_storage_cyclic_charge_discharge_patternandtest_expanded_storageassert non-unique values (fixed to assert determinate dynamics in fix: compatibility with linopy v1 arithmetic semantics #729; see [test robustness] Cyclic-cluster storage tests assert a non-unique (degenerate) SOC level #733).Proposed fix (needs a design decision)
Either (a) warn/error when
initial_charge_stateis set together with a cycliccluster_mode(it is contradictory), or (b) honor it by anchoringsoc_boundary[0] == initial_charge_statein addition to (or instead of) the cyclic tie. Option (a) is the smaller, safer change.Severity
Correctness/UX (silent parameter drop) + solution degeneracy. Objective and flow rates remain correct.