State transition patterns model changes between discrete states and link them to continuous variables. These patterns are essential for modeling startup/shutdown events, switching behavior, and controlled changes in system operation.
For a binary state variable
Two binary variables track the transitions:
-
$s^\text{on}(t) \in {0, 1}$ : equals 1 when switching from off to on -
$s^\text{off}(t) \in {0, 1}$ : equals 1 when switching from on to off
The state change equals the difference between switch-on and switch-off:
With:
-
$s(t)$ being the binary state variable -
$s_\text{prev}$ being the state before the optimization period -
$s^\text{on}(t), s^\text{off}(t)$ being the switch variables
Behavior:
- Off → On (
$s(t-1)=0, s(t)=1$ ):$s^\text{on}(t)=1, s^\text{off}(t)=0$ - On → Off (
$s(t-1)=1, s(t)=0$ ):$s^\text{on}(t)=0, s^\text{off}(t)=1$ - No change:
$s^\text{on}(t)=0, s^\text{off}(t)=0$
A state cannot switch on and off simultaneously:
This ensures:
- At most one switch event per time step
- No simultaneous on/off switching
Implementation: [BoundingPatterns.state_transition_bounds()][flixopt.modeling.BoundingPatterns.state_transition_bounds]
When a continuous variable should only change when certain switch events occur, continuous transition bounds link the variable changes to binary switches.
With:
-
$v(t)$ being the continuous variable -
$v_\text{prev}$ being the value before the optimization period -
$\Delta v^\text{max}$ being the maximum allowed change -
$s^\text{on}(t), s^\text{off}(t) \in {0, 1}$ being switch binary variables
Behavior:
- When
$s^\text{on}(t) = 0$ and$s^\text{off}(t) = 0$ : forces$v(t) = v(t-1)$ (no change) - When
$s^\text{on}(t) = 1$ or$s^\text{off}(t) = 1$ : allows change up to$\pm \Delta v^\text{max}$
Implementation: [BoundingPatterns.continuous_transition_bounds()][flixopt.modeling.BoundingPatterns.continuous_transition_bounds]
This pattern models a level variable that can increase or decrease, with changes controlled by binary variables. This is useful for inventory management, capacity adjustments, or gradual state changes.
The level evolves based on increases and decreases:
With:
-
$\ell(t)$ being the level variable -
$\ell_\text{init}$ being the initial level -
$\ell^\text{inc}(t)$ being the increase in level at time$t$ (non-negative) -
$\ell^\text{dec}(t)$ being the decrease in level at time$t$ (non-negative)
Changes are bounded and controlled by binary variables:
With:
-
$\Delta \ell^\text{max}$ being the maximum change per time step -
$b^\text{inc}(t), b^\text{dec}(t) \in {0, 1}$ being binary control variables
Simultaneous increase and decrease are prevented:
This ensures:
- Level can only increase OR decrease (or stay constant) in each time step
- No simultaneous contradictory changes
Implementation: [BoundingPatterns.link_changes_to_level_with_binaries()][flixopt.modeling.BoundingPatterns.link_changes_to_level_with_binaries]
Track startup and shutdown events to apply costs:
# Create switch variables
switch_on, switch_off = modeling.state_transition_bounds(
state_variable=on_state,
previous_state=previous_on_state
)
# Apply costs to switches
startup_cost = switch_on * startup_cost_per_event
shutdown_cost = switch_off * shutdown_cost_per_eventRestrict the number of state changes:
# Track all switches
switch_on, switch_off = modeling.state_transition_bounds(
state_variable=on_state
)
# Limit total switches
model.add_constraint(
(switch_on + switch_off).sum() <= max_switches
)Model systems where capacity can be incrementally adjusted:
# Level represents installed capacity
level_var, increase, decrease, inc_binary, dec_binary = \
modeling.link_changes_to_level_with_binaries(
initial_level=current_capacity,
max_change=max_capacity_change_per_period
)
# Constrain total increases
model.add_constraint(increase.sum() <= max_total_expansion)These patterns are used in:
OnOffParameters- Startup/shutdown tracking and costs- Operating mode switching with transition costs
- Investment planning with staged capacity additions
- Inventory management with controlled stock changes