# Storage Constraints¶

**Storage State Rule**: The constraint storage state rule is the main storage
constraint and it defines the storage energy content of a storage \(s\) in
a site \(v\) in support timeframe \(y\) at a timestep \(t\). This
constraint calculates the storage energy content at a timestep \(t\) by
adding or subtracting differences, such as ingoing and outgoing energy, to/from
a storage energy content at a previous timestep \(t-1\) multiplied by 1
minus the self-discharge rate \(d_{yvs}\) (which is scaled exponentially
with the timestep size \(\Delta t\)). Here ingoing energy is given by the
product of the variable storage input commodity flow
\(\epsilon_{yvst}^\text{in}\) and the parameter storage efficiency during
charge \(e_{yvs}^\text{in}\). Outgoing energy is given by the variable
storage output commodity flow \(\epsilon_{yvst}^\text{out}\) divided by the
parameter storage efficiency during discharge \(e_{yvs}^\text{out}\). The
mathematical explanation of this rule is given in Energy Storage.

In script `storage.py`

the constraint storage state rule is defined and
calculated by the following code fragment:

```
m.def_storage_state = pyomo.Constraint(
m.tm, m.sto_tuples,
rule=def_storage_state_rule,
doc='storage[t] = (1 - selfdischarge) * storage[t-1] + input * eff_in - output / eff_out')
```

```
def def_storage_state_rule(m, t, stf, sit, sto, com):
return (m.e_sto_con[t, stf, sit, sto, com] ==
m.e_sto_con[t - 1, stf, sit, sto, com] *
(1 - m.storage_dict['discharge']
[(stf, sit, sto, com)]) ** m.dt.value +
m.e_sto_in[t, stf, sit, sto, com] *
m.storage_dict['eff-in'][(stf, sit, sto, com)] -
m.e_sto_out[t, stf, sit, sto, com] /
m.storage_dict['eff-out'][(stf, sit, sto, com)])
```

**Storage Power Rule**: The constraint storage power rule defines the variable
total storage power \(\kappa_{yvs}^\text{p}\). The variable total storage
power is defined by the constraint as the sum of the parameter storage power
installed \(K_{vs}^\text{p}\) and the variable new storage power
\(\hat{\kappa}_{yvs}^\text{p}\). The mathematical explanation of this rule
is given in Energy Storage.

In script `storage.py`

the constraint storage power rule is defined and
calculated by the following code fragment:

```
m.def_storage_power = pyomo.Constraint(
m.sto_tuples,
rule=def_storage_power_rule,
doc='storage power = inst-cap + new power')
```

```
def def_storage_power_rule(m, stf, sit, sto, com):
if m.mode['int']:
if (sit, sto, com, stf) in m.inst_sto_tuples:
if (min(m.stf), sit, sto, com) in m.sto_const_cap_p_dict:
cap_sto_p = m.storage_dict['inst-cap-p'][
(min(m.stf), sit, sto, com)]
else:
cap_sto_p = (
sum(m.cap_sto_p_new[stf_built, sit, sto, com]
for stf_built in m.stf
if (sit, sto, com, stf_built, stf) in
m.operational_sto_tuples) +
m.storage_dict['inst-cap-p'][(min(m.stf), sit, sto, com)])
else:
cap_sto_p = (
sum(m.cap_sto_p_new[stf_built, sit, sto, com]
for stf_built in m.stf
if (sit, sto, com, stf_built, stf)
in m.operational_sto_tuples))
else:
if (stf, sit, sto, com) in m.sto_const_cap_p_dict:
cap_sto_p = m.storage_dict['inst-cap-p'][(stf, sit, sto, com)]
else:
cap_sto_p = (m.cap_sto_p_new[stf, sit, sto, com] +
m.storage_dict['inst-cap-p'][(stf, sit, sto, com)])
return cap_sto_p
```

**Storage Capacity Rule**: The constraint storage capacity rule defines the
variable total storage size \(\kappa_{yvs}^\text{c}\). The variable total
storage size is defined by the constraint as the sum of the parameter storage
content installed \(K_{vs}^\text{c}\) and the variable new storage size
\(\hat{\kappa}_{yvs}^\text{c}\). The mathematical explanation of this rule
is given in Energy Storage.

In script `storage.py`

the constraint storage capacity rule is defined and
calculated by the following code fragment:

```
m.def_storage_capacity = pyomo.Constraint(
m.sto_tuples,
rule=def_storage_capacity_rule,
doc='storage capacity = inst-cap + new capacity')
```

```
def def_storage_capacity_rule(m, stf, sit, sto, com):
if m.mode['int']:
if (sit, sto, com, stf) in m.inst_sto_tuples:
if (min(m.stf), sit, sto, com) in m.sto_const_cap_c_dict:
cap_sto_c = m.storage_dict['inst-cap-c'][
(min(m.stf), sit, sto, com)]
else:
cap_sto_c = (
sum(m.cap_sto_c_new[stf_built, sit, sto, com]
for stf_built in m.stf
if (sit, sto, com, stf_built, stf) in
m.operational_sto_tuples) +
m.storage_dict['inst-cap-c'][(min(m.stf), sit, sto, com)])
else:
cap_sto_c = (
sum(m.cap_sto_c_new[stf_built, sit, sto, com]
for stf_built in m.stf
if (sit, sto, com, stf_built, stf) in
m.operational_sto_tuples))
else:
if (stf, sit, sto, com) in m.sto_const_cap_c_dict:
cap_sto_c = m.storage_dict['inst-cap-c'][(stf, sit, sto, com)]
else:
cap_sto_c = (m.cap_sto_c_new[stf, sit, sto, com] +
m.storage_dict['inst-cap-c'][(stf, sit, sto, com)])
return cap_sto_c
```

**Storage Input by Power Rule**: The constraint storage input by power rule
limits the variable storage input commodity flow
\(\epsilon_{yvst}^\text{in}\). This constraint restricts a storage
\(s\) in a site \(v\) and support timeframe \(y\) at a timestep
\(t\) from having more input power than the storage power capacity. The
constraint states that the variable \(\epsilon_{yvst}^\text{in}\) must be
less than or equal to the variable total storage power
\(\kappa_{yvs}^\text{p}\), scaled by the size of the timesteps
\(\Delta t\). The mathematical explanation of this rule is given in
Energy Storage.

In script `storage.py`

the constraint storage input by power rule is defined
and calculated by the following code fragment:

```
m.res_storage_input_by_power = pyomo.Constraint(
m.tm, m.sto_tuples,
rule=res_storage_input_by_power_rule,
doc='storage input <= storage power')
```

```
def res_storage_input_by_power_rule(m, t, stf, sit, sto, com):
return (m.e_sto_in[t, stf, sit, sto, com] <= m.dt *
m.cap_sto_p[stf, sit, sto, com])
```

**Storage Output by Power Rule**: The constraint storage output by power rule
limits the variable storage output commodity flow
\(\epsilon_{yvst}^\text{out}\). This constraint restricts a storage
\(s\) in a site \(v\) and support timeframe \(y\) at a timestep
\(t\) from having more output power than the storage power capacity. The
constraint states that the variable \(\epsilon_{yvst}^\text{out}\) must be
less than or equal to the variable total storage power
\(\kappa_{yvs}^\text{p}\), scaled by the size of the timesteps
\(\Delta t\). The mathematical explanation of this rule is given in
Energy Storage.

In script `storage.py`

the constraint storage output by power rule is defined
and calculated by the following code fragment:

```
m.res_storage_output_by_power = pyomo.Constraint(
m.tm, m.sto_tuples,
rule=res_storage_output_by_power_rule,
doc='storage output <= storage power')
```

```
def res_storage_output_by_power_rule(m, t, stf, sit, sto, co):
return (m.e_sto_out[t, stf, sit, sto, co] <= m.dt *
m.cap_sto_p[stf, sit, sto, co])
```

**Storage State by Capacity Rule**: The constraint storage state by capacity
rule limits the variable storage energy content
\(\epsilon_{yvst}^\text{con}\). This constraint restricts a storage
\(s\) in a site \(v\) and support timeframe \(y\) at a timestep
\(t\) from having more storage content than the storage content capacity.
The constraint states that the variable \(\epsilon_{yvst}^\text{con}\) must
be less than or equal to the variable total storage size
\(\kappa_{yvs}^\text{c}\). The mathematical explanation of this rule is
given in Energy Storage.

In script `storage.py`

the constraint storage state by capacity rule is defined
and calculated by the following code fragment.

```
m.res_storage_state_by_capacity = pyomo.Constraint(
m.t, m.sto_tuples,
rule=res_storage_state_by_capacity_rule,
doc='storage content <= storage capacity')
```

```
def res_storage_state_by_capacity_rule(m, t, stf, sit, sto, com):
return (m.e_sto_con[t, stf, sit, sto, com] <=
m.cap_sto_c[stf, sit, sto, com])
```

**Storage Power Limit Rule**: The constraint storage power limit rule limits
the variable total storage power \(\kappa_{yvs}^\text{p}\). This contraint
restricts a storage \(s\) in a site \(v\) and support timeframe
\(y\) from having more total power output capacity than an upper bound and
having less than a lower bound. The constraint states that the variable total
storage power \(\kappa_{yvs}^\text{p}\) must be greater than or equal to
the parameter storage power lower bound \(\underline{K}_{yvs}^\text{p}\)
and less than or equal to the parameter storage power upper bound
\(\overline{K}_{yvs}^\text{p}\). The mathematical explanation of this rule
is given in Energy Storage.

In script `storage.py`

the constraint storage power limit rule is defined and
calculated by the following code fragment:

```
m.res_storage_power = pyomo.Constraint(
m.sto_tuples,
rule=res_storage_power_rule,
doc='storage.cap-lo-p <= storage power <= storage.cap-up-p')
```

```
def res_storage_power_rule(m, stf, sit, sto, com):
return (m.storage_dict['cap-lo-p'][(stf, sit, sto, com)],
m.cap_sto_p[stf, sit, sto, com],
m.storage_dict['cap-up-p'][(stf, sit, sto, com)])
```

**Storage Capacity Limit Rule**: The constraint storage capacity limit rule
limits the variable total storage size \(\kappa_{yvs}^\text{c}\). This
constraint restricts a storage \(s\) in a site \(v\) and support
timeframe \(y\) from having more total storage content capacity than an
upper bound and having less than a lower bound. The constraint states that the
variable total storage size \(\kappa_{yvs}^\text{c}\) must be greater than
or equal to the parameter storage content lower bound
\(\underline{K}_{yvs}^\text{c}\) and less than or equal to the parameter
storage content upper bound \(\overline{K}_{yvs}^\text{c}\). The
mathematical explanation of this rule is given in Energy Storage.

In script `storage.py`

the constraint storage capacity limit rule is defined
and calculated by the following code fragment:

```
m.res_storage_capacity = pyomo.Constraint(
m.sto_tuples,
rule=res_storage_capacity_rule,
doc='storage.cap-lo-c <= storage capacity <= storage.cap-up-c')
```

```
def res_storage_capacity_rule(m, stf, sit, sto, com):
return (m.storage_dict['cap-lo-c'][(stf, sit, sto, com)],
m.cap_sto_c[stf, sit, sto, com],
m.storage_dict['cap-up-c'][(stf, sit, sto, com)])
```

**Initial and Final Storage State Rule**:
The constraint initial and final storage state rule defines and restricts the
variable storage energy content \(\epsilon_{yvst}^\text{con}\) of a storage
\(s\) in a site \(v\) and support timeframe \(y\) at the initial
timestep \(t_1\) and at the final timestep \(t_N\). There are two
distinct cases:

- The initial and final storage states are specified by a value of the parameter \(I_{yvs}\) between 0 and 1.
- \(I_{yvs}\) is not specified (e.g. by setting it ‘#NV’ in the input sheet). In this case the initial and final storage state are still equal but variable.

In case 1 the constraints are written in the following way:

Initial storage state: Initial storage represents the storage state in a storage at the beginning of the simulation. The variable storage energy content \(\epsilon_{yvst}^\text{con}\) at the initial timestep \(t_1\) is defined by this constraint. The constraint states that the variable \(\epsilon_{yvst_1}^\text{con}\) must be equal to the product of the variable total installed storage capacity \(\kappa_{yvs}^\text{c}\) and initial and final state of charge \(I_{yvs}\).

Final storage state: Final storage represents the storage state in a storage at the end of the simulation. The variable storage energy content \(\epsilon_{yvst}^\text{con}\) at the final timestep \(t_N\) is restricted by this constraint. The constraint states that the variable \(\epsilon_{yvst_N}^\text{con}\) must be greater than or equal to the product of the variable total installed storage capacity \(\kappa_{yvs}^\text{c}\) and initial and final state of charge \(I_{yvs}\). The mathematical explanation of this rule is given in Energy Storage.

In script `storage.py`

the constraint initial and final storage state rule is
then defined and calculated by the following code fragment:

```
m.def_initial_storage_state = pyomo.Constraint(
m.sto_init_bound_tuples,
rule=def_initial_storage_state_rule,
doc='storage content initial == and final >= storage.init * capacity')
```

In case 2 the constraint becomes a lot easier, since the initial and final state are simply compared to each other by the following inequality:

In script `storage.py`

the constraint initial and final storage state rule is
then defined and calculated by the following code fragment:

```
m.res_storage_state_cyclicity = pyomo.Constraint(
m.sto_tuples,
rule=res_storage_state_cyclicity_rule,
doc='storage content initial <= final, both variable')
```

**Storage Energy to Power Ratio Rule**:
For certain type of storage technologies, the power and energy capacities cannot
be independently sized but are dependent to each other. Hence, the constraint
storage energy to power ratio rule sets a linear dependence between the
capacities through a user-defined “energy to power ratio”
\(k_{yvs}^\text{E/P}\). It has to be noted that this constraint is only
active for the storages with a positive value under the column “ep-ratio” in
the input file, and when this value is not given, the power and energy
capacities can be sized independently. The mathematical explanation of this
rule is given in Energy Storage.

In script `storage.py`

the constraint storage energy to power rule is
then defined and calculated by the following code fragment:

```
m.def_storage_energy_power_ratio = pyomo.Constraint(
m.sto_en_to_pow_tuples,
rule=def_storage_energy_power_ratio_rule,
doc='storage capacity = storage power * storage E2P ratio')
```

```
def def_storage_energy_power_ratio_rule(m, stf, sit, sto, com):
return (m.cap_sto_c[stf, sit, sto, com] == m.cap_sto_p[stf, sit, sto, com] *
m.storage_dict['ep-ratio'][(stf, sit, sto, com)])
```