Source code for prepshot._model.investment

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

"""This module is used to determine investment-related constraints. 
The model computes the retirement of each technology and transmission line
with these considerations:

* The historical capacity of the technology and transmission line is
  based on its capacity ratio.
* Each planning and scheduling period is based on the existing capacity.

The existing capacity for each year, in each zone, for each technology,
is as follows:

.. math::
    
    {\\rm{cap}}_{y,z,e}^{\\rm{existingtech}}=
    \\sum_{{\\rm{age}}=1}^{{{T}}_e
    -(y-y_{\\rm{start}})}{{\\rm{CAP}}}_{{\\rm{age}},z,e}^{\\rm{inittech}}
    +\\sum_{y_{\\rm{pre}}={\\max}(y_{\\rm{start}}, y-{{T}}_e)}^{y}
    {{\\rm{cap}}_{y_{\\rm{pre}},z,e}^{\\rm{invtech}}}\\quad\\forall y,z,e

The existing capacity of the transmission lines for each year,
from :math:`z_{\\rm{from}}` zone to :math:`z_{\\rm{to}}`-th zone, is as
follows:

.. math::

    {\\rm{cap}}_{y,z_{\\rm{from}},z_{\\rm{to}}}^{\\rm{existingline}}=
    \\sum_{{\\rm{age}}=1}^{{T}_{\\rm{line}}
    -(y-y_{\\rm{start}})}{{\\rm{CAP}}}_{{\\rm{age}},z_{\\rm{from}},
    z_{\\rm{to}}}^{\\rm{initline}}
    +\\sum_{y_{\\rm{pre}}={\\max}(y_{\\rm{start}}, y-{{T}}_{\\rm{line}})}^{y}
    {{\\rm{cap}}_{y_{\\rm{pre}},
    z_{\\rm{from}},z_{\\rm{to}}}^{\\rm{invline}}}\\quad\\forall
    y,z_{\\rm{from}}\\neq z_{\\rm{to}}
"""

from typing import Union

import numpy as np
import pyoptinterface as poi

[docs]class AddInvestmentConstraints: """Add constraints for investment in the model. """
[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.remaining_technology = poi.make_tupledict( model.year, model.zone, model.tech, rule=self.tech_lifetime_rule ) model.cap_existing = poi.make_tupledict( model.year, model.zone, model.tech, rule=self.remaining_capacity_rule ) model.tech_up_bound_cons = poi.make_tupledict( model.year, model.zone, model.tech, rule=self.tech_up_bound_rule ) model.new_tech_up_bound_cons = poi.make_tupledict( model.year, model.zone, model.tech, rule=self.new_tech_up_bound_rule ) model.new_tech_low_bound_cons = poi.make_tupledict( model.year, model.zone, model.tech, rule=self.new_tech_low_bound_rule )
[docs] def tech_up_bound_rule( self, y : int, z : str, te : str ) -> poi.ConstraintIndex: """Allowed capacity of commercial operation technology is less than or equal to the predefined upper bound. Parameters ---------- y : int Year. z : str Zone. te : str Technology. Returns ------- poi.ConstraintIndex The constraint of the model. """ model = self.model tub = model.params['technology_upper_bound'][te, z] if tub != np.Inf: lhs = model.cap_existing[y, z, te] - tub return model.add_linear_constraint(lhs, poi.Leq, 0) return None
[docs] def new_tech_up_bound_rule( self, y : int, z : str, te : str ) -> poi.ConstraintIndex: """New investment technology upper bound in specific year and zone. Parameters ---------- y : int Year. z : str Zone. te : str Technology. Returns ------- poi.ConstraintIndex The constraint of the model. """ model = self.model ntub = model.params['new_technology_upper_bound'][te, z] if ntub != np.Inf: lhs = model.cap_newtech[y, z, te] - ntub return model.add_linear_constraint(lhs, poi.Leq, 0) return None
[docs] def new_tech_low_bound_rule( self, y : int, z : str, te : str ) -> poi.ConstraintIndex: """New investment technology lower bound. Parameters ---------- y : int Year. z : str Zone. te : str Technology. Returns ------- poi.ConstraintIndex The constraint of the model. """ model = self.model ntlb = model.params['new_technology_lower_bound'][te, z] lhs = model.cap_newtech[y, z, te] - ntlb return model.add_linear_constraint(lhs, poi.Geq, 0)
[docs] def tech_lifetime_rule( self, y : int, z : str, te : str ) -> poi.ConstraintIndex: """Caculation of remaining technology capacity based on lifetime constraints. Parameters ---------- y : int Year. z : str Zone. te : str Technology. Returns ------- poi.ExprBuilder The expression of the model. """ model = self.model lifetime = model.params['lifetime'][te, y] service_time = y - model.params['year'][0] hcap = model.params['historical_capacity'] remaining_time = int(lifetime - service_time) if remaining_time <= 0: return 0 return poi.quicksum(hcap[z, te, a] for a in range(0, remaining_time))
[docs] def remaining_capacity_rule( self, y : int, z : str, te : str ) -> poi.ExprBuilder: """Remaining capacity of initial technology due to lifetime restrictions. Where in modeled year y, the available technology consists of the following. 1. The remaining in-service installed capacity from the initial technology. 2. The remaining in-service installed capacity from newly built technology in the previous modelled years. Parameters ---------- y : int Planned year. z : str Zone. te : str technology. Returns ------- poi.ExprBuilder The expression of the model. """ model = self.model year = model.params['year'] lt = model.params['lifetime'] cap_existing = poi.ExprBuilder() new_tech = poi.quicksum( model.cap_newtech[yy, z, te] for yy in year[:year.index(y) + 1] if y - yy < lt[te, y] ) cap_existing += new_tech cap_existing += model.remaining_technology[y, z, te] return cap_existing