Source code for prepshot._model.storage

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""This module contains energy storage related functions. Symmetrical energy 
storage system is considered in this module. It means that the energy storage
system has the same power capacity for charging and discharging.

Similar to the power discharging process, the charging power of storage
technology :math:`e` (:math:`{\\rm{power}}_{h,m,y,z,e}^{{c}}`) is also limited
by the existing installed capacity and technical minimum charging power
(:math:`{\\underline{{\\rm{POWER}}}}_{h,m,y,z,e}^{{c}}`) as follows:

.. math::

    {\\underline{{\\rm{POWER}}}}_{h,m,y,z,e}^{{c}}\\times
    {\\rm{cap}}_{y,z,e}^{\\rm{existingtech}}\\le{\\rm{power}}_{h,m,y,z,e}^{{c}}
    \\le {\\rm{cap}}_{y,z,e}^{\\rm{existingtech}}\\quad\\forall h,m,y,z,e
    \\in {\\mathcal{STOR}}

The charging generation (:math:`{\\rm{charge}}_{h,m,y,z,e}`) and
:math:`{\\rm{power}}_{h,m,y,z,e}^{c}` need to meet the following formula:

.. math::
    
    {\\rm{charge}}_{h,m,y,z,e}={\\rm{power}}_{h,m,y,z,e}^{\\rm{c}}\\times
    \\Delta h{\\times\\eta}_{y,e}^{{\\rm{in}}}
    \\quad\\forall h,m,y,z,e\\in {\\mathcal{STOR}}

Changes in stored electricity
(:math:`{\\rm{storage}}_{h,m,y,z,e}^{\\rm{energy}}`) in two successive periods
should be balanced by the charging (:math:`{\\rm{charge}}_{h,m,y,z,e}`) and
discharging (:math:`{\\rm{gen}}_{h,m,y,z,e}`) processes:

.. math::
    
    {\\rm{storage}}_{h,m,y,z,e}^{\\rm{energy}}-
    {\\rm{storage}}_{h-1,m,y,z,e}^{\\rm{energy}}
    ={\\rm{charge}}_{h,m,y,z,e}-{\\rm{gen}}_{h,m,y,z,e}

In addition, the initial (when :math:`h=h_{\rm{start}}`) stored electricity
(:math:`{\\rm{storage}}_{h=h_{\\rm{start}},m,y,z,e}^{\\rm{energy}}`) of
storage technology :math:`e` in each month of each year can be calculated
based on the proportion of the maximum storage capacity, as follows:

.. math::

    {\\rm{storage}}_{h=h_{\\rm{start}},m,y,z,e}^{\\rm{energy}}
    ={{\\rm{STORAGE}}}_{m,y,z,e}^{\\rm{energy}}\\times{{\\rm{EP}}}_e\\times
    {\\rm{cap}}_{y,z,e}^{\\rm{existingtech}}\\quad\\forall m,y,z,e\\in
    {\\mathcal{STOR}}

The instantaneous storage energy level
(:math:`{\\rm{storage}}_{h,m,y,z,e}^{\\rm{energy}}`) of storage technology
:math:`e` should not exceed the maximum energy storage capacity, as follows:

.. math::

    {\\rm{storage}}_{h,m,y,z,e}^{\\rm{energy}}\\le{{\\rm{EP}}}_e\\times
    {\\rm{cap}}_{y,z,e}^{\\rm{existingtech}}
    \\quad\\forall h,m,y,z,e\\in {\\mathcal{STOR}}
"""

from typing import Union

import pyoptinterface as poi

[docs]class AddStorageConstraints: """Energy storage class. """
[docs] def __init__(self, model : object) -> None: """Initialize the class and add constraints. Parameters ---------- model : object Model object depending on the solver. """ self.model = model model.energy_storage_balance_cons = poi.make_tupledict( model.hour, model.month, model.year, model.zone, model.storage_tech, rule=self.energy_storage_balance_rule ) model.init_energy_storage_cons = poi.make_tupledict( model.month, model.year, model.zone, model.storage_tech, rule=self.init_energy_storage_rule ) model.end_energy_storage_cons = poi.make_tupledict( model.month, model.year, model.zone, model.storage_tech, rule=self.end_energy_storage_rule ) model.energy_storage_up_bound_cons = poi.make_tupledict( model.hour, model.month, model.year, model.zone, model.storage_tech, rule=self.energy_storage_up_bound_rule ) model.energy_storage_gen_cons = poi.make_tupledict( model.hour, model.month, model.year, model.zone, model.storage_tech, rule=self.energy_storage_gen_rule )
[docs] def energy_storage_balance_rule( self, h : int, m : int, y : int, z : str, te : str ) -> poi.ConstraintIndex: """Energy storage balance. Parameters ---------- h : int Hour. m : int Month. y : int Year. z : str Zone. te : str Technology. Returns ------- poi.ConstraintIndex The constraint of the model. """ model = self.model de = model.params['discharge_efficiency'][te, y] ce = model.params['charge_efficiency'][te, y] return model.add_linear_constraint( model.storage[h, m, y, z, te] - ( model.storage[h-1, m, y, z, te] - model.gen[h, m, y, z, te] / de + model.charge[h, m, y, z, te] * ce ), poi.Eq, 0 )
[docs] def init_energy_storage_rule( self, m : int, y : int, z : str, te : str ) -> poi.ConstraintIndex: """Initial energy storage. Parameters ---------- m : int Month. y : int Year. z : str Zone. te : str Technology. Returns ------- poi.ConstraintIndex The constraint of the model. """ model = self.model esl = model.params['initial_energy_storage_level'][te, z] epr = model.params['energy_to_power_ratio'][te] dt = model.params['dt'] lhs = ( model.storage[0, m, y, z, te] - esl * model.cap_existing[y, z, te] * epr * dt ) return model.add_linear_constraint(lhs, poi.Eq, 0)
[docs] def end_energy_storage_rule( self, m : int, y : int, z : str, te : str ) -> poi.ConstraintIndex: """End energy storage. Parameters ---------- m : int Month. y : int Year. z : str Zone. te : str Technology. Returns ------- poi.ConstraintIndex The constraint of the model. """ model = self.model h_init = model.params['hour'][-1] lhs = ( model.storage[h_init, m, y, z, te] - model.storage[0, m, y, z, te] ) return model.add_linear_constraint(lhs, poi.Eq, 0)
[docs] def energy_storage_up_bound_rule( self, h : int, m : int, y : int, z : str, te : str ) -> poi.ConstraintIndex: """Energy storage upper bound. Parameters ---------- h : int Hour. m : int Month. y : int Year. z : str Zone. te : str Technology. Returns ------- poi.ConstraintIndex The constraint of the model. """ model = self.model epr = model.params['energy_to_power_ratio'][te] dt = model.params['dt'] lhs = ( model.storage[h, m, y, z, te] - model.cap_existing[y, z, te] * epr * dt ) return model.add_linear_constraint(lhs, poi.Leq, 0)
[docs] def energy_storage_gen_rule( self, h : int, m : int, y : int, z : str, te : str ) -> poi.ConstraintIndex: """Energy storage generation. Parameters ---------- h : int Hour. m : int Month. y : int Year. z : str Zone. te : str Technology. Returns ------- poi.ConstraintIndex The constraint of the model. """ model = self.model de = model.params['discharge_efficiency'][te, y] lhs = model.gen[h, m, y, z, te] / de \ - model.storage[h-1, m, y, z, te] return model.add_linear_constraint(lhs, poi.Leq, 0)