# 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:

1. The initial and final storage states are specified by a value of the parameter $$I_{yvs}$$ between 0 and 1.
2. $$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:

$\forall v\in V, s\in S\colon\ \epsilon_{vst_1}^\text{con} \leq \epsilon_{vst_N}^\text{con}$

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)])