Commodity Constraints

Commodity Balance: The function commodity balance calculates the in- and outflows into all processes, storages and transmission of a commodity \(c\) in a site \(v\) in support timeframe \(y\) at a timestep \(t\). The value of the function \(\mathrm{CB}\) being greater than zero \(\mathrm{CB} > 0\) means that the presence of the commodity \(c\) in the site \(v\) in support timeframe \(y\) at the timestep \(t\) is getting by the interaction with the technologies given above. Correspondingly, the value of the function being less than zero means that the presence of the commodity in the site at the timestep is getting more than before by the technologies given above. The mathematical explanation of this rule for general problems is explained in Energy Storage.

In script modelhelper.py the value of the commodity balance function \(\mathrm{CB}(y,v,c,t)\) is calculated by the following code fragment:

def commodity_balance(m, tm, stf, sit, com):
    """Calculate commodity balance at given timestep.
    For a given commodity co and timestep tm, calculate the balance of
    consumed (to process/storage/transmission, counts positive) and provided
    (from process/storage/transmission, counts negative) commodity flow. Used
    as helper function in create_model for constraints on demand and stock
    commodities.
    Args:
        m: the model object
        tm: the timestep
        site: the site
        com: the commodity
    Returns
        balance: net value of consumed (positive) or provided (negative) power
    """
    balance = (sum(m.e_pro_in[(tm, stframe, site, process, com)]
                   # usage as input for process increases balance
                   for stframe, site, process in m.pro_tuples
                   if site == sit and stframe == stf and
                   (stframe, process, com) in m.r_in_dict) -
               sum(m.e_pro_out[(tm, stframe, site, process, com)]
                   # output from processes decreases balance
                   for stframe, site, process in m.pro_tuples
                   if site == sit and stframe == stf and
                   (stframe, process, com) in m.r_out_dict))
    if m.mode['tra']:
        balance += transmission_balance(m, tm, stf, sit, com)
    if m.mode['sto']:
        balance += storage_balance(m, tm, stf, sit, com)

    return balance

where the two functions introducing the partly balances for transmissions and storages, respectively, are given by:

def transmission_balance(m, tm, stf, sit, com):
    """called in commodity balance
    For a given commodity co and timestep tm, calculate the balance of
    import and export """

    return (sum(m.e_tra_in[(tm, stframe, site_in, site_out,
                            transmission, com)]
                # exports increase balance
                for stframe, site_in, site_out, transmission, commodity
                in m.tra_tuples
                if (site_in == sit and stframe == stf and
                    commodity == com)) -
            sum(m.e_tra_out[(tm, stframe, site_in, site_out,
                             transmission, com)]
                # imports decrease balance
                for stframe, site_in, site_out, transmission, commodity
                in m.tra_tuples
                if (site_out == sit and stframe == stf and
                    commodity == com)))
def storage_balance(m, tm, stf, sit, com):
    """called in commodity balance
    For a given commodity co and timestep tm, calculate the balance of
    storage input and output """

    return sum(m.e_sto_in[(tm, stframe, site, storage, com)] -
               m.e_sto_out[(tm, stframe, site, storage, com)]
               # usage as input for storage increases consumption
               # output from storage decreases consumption
               for stframe, site, storage, commodity in m.sto_tuples
               if site == sit and stframe == stf and commodity == com)

Vertex Rule: The vertex rule is the main constraint that has to be satisfied for every commodity. It represents a version of “Kirchhoff’s current law” or local energy conservation. This constraint is defined differently for each commodity type. The inequality requires, that any imbalance (CB>0, CB<0) of a commodity \(c\) in a site \(v\) and support timeframe \(y\) at a timestep \(t\) to be balanced by a corresponding source term or demand. The rule is not defined for environmental or SupIm commodities. The mathematical explanation of this rule is given in Minimal Optimization Model.

In script model.py the constraint vertex rule is defined and calculated by the following code fragments:

m.res_vertex = pyomo.Constraint(
    m.tm, m.com_tuples,
    rule=res_vertex_rule,
    doc='storage + transmission + process + source + buy - sell == demand')
def res_vertex_rule(m, tm, stf, sit, com, com_type):
    # environmental or supim commodities don't have this constraint (yet)
    if com in m.com_env:
        return pyomo.Constraint.Skip
    if com in m.com_supim:
        return pyomo.Constraint.Skip

    # helper function commodity_balance calculates balance from input to
    # and output from processes, storage and transmission.
    # if power_surplus > 0: production/storage/imports create net positive
    #                       amount of commodity com
    # if power_surplus < 0: production/storage/exports consume a net
    #                       amount of the commodity com
    power_surplus = - commodity_balance(m, tm, stf, sit, com)

    # if com is a stock commodity, the commodity source term e_co_stock
    # can supply a possibly negative power_surplus
    if com in m.com_stock:
        power_surplus += m.e_co_stock[tm, stf, sit, com, com_type]

    # if Buy and sell prices are enabled
    if m.mode['bsp']:
        power_surplus += bsp_surplus(m, tm, stf, sit, com, com_type)

    # if com is a demand commodity, the power_surplus is reduced by the
    # demand value; no scaling by m.dt or m.weight is needed here, as this
    # constraint is about power (MW), not energy (MWh)
    if com in m.com_demand:
        try:
            power_surplus -= m.demand_dict[(sit, com)][(stf, tm)]
        except KeyError:
            pass

    if m.mode['dsm']:
        power_surplus += dsm_surplus(m, tm, stf, sit, com)

    return power_surplus == 0

where the two functions introducing the effects of Buy/Sell or DSM events, respectively, are given by:

def bsp_surplus(m, tm, stf, sit, com, com_type):

    power_surplus = 0

    # if com is a sell commodity, the commodity source term e_co_sell
    # can supply a possibly positive power_surplus
    if com in m.com_sell:
        power_surplus -= m.e_co_sell[tm, stf, sit, com, com_type]

    # if com is a buy commodity, the commodity source term e_co_buy
    # can supply a possibly negative power_surplus
    if com in m.com_buy:
        power_surplus += m.e_co_buy[tm, stf, sit, com, com_type]

    return power_surplus
def dsm_surplus(m, tm, stf, sit, com):
    """ called in vertex rule
        calculate dsm surplus"""
    if (stf, sit, com) in m.dsm_site_tuples:
        return (- m.dsm_up[tm, stf, sit, com] +
                sum(m.dsm_down[t, tm, stf, sit, com]
                    for t in dsm_time_tuples(
                    tm, m.timesteps[1:],
                    max(int(1 / m.dt *
                        m.dsm_dict['delay'][(stf, sit, com)]), 1))))
    else:
        return 0

Stock Per Step Rule: The constraint stock per step rule applies only for commodities of type “Stock” (\(c \in C_\text{st}\)). This constraint limits the amount of stock commodity \(c \in C_\text{st}\), that can be used by the energy system in the site \(v\) in support timeframe \(y\) at the timestep \(t\). This amount is limited by the product of the parameter maximum stock supply limit per hour \(\overline{l}_{yvc}\) and the timestep length \(\Delta t\). The mathematical explanation of this rule is given in Minimal Optimization Model.

In script model.py the constraint stock per step rule is defined and calculated by the following code fragment:

m.res_stock_step = pyomo.Constraint(
    m.tm, m.com_tuples,
    rule=res_stock_step_rule,
    doc='stock commodity input per step <= commodity.maxperstep')
def res_stock_step_rule(m, tm, stf, sit, com, com_type):
    if com not in m.com_stock:
        return pyomo.Constraint.Skip
    else:
        return (m.e_co_stock[tm, stf, sit, com, com_type] <=
                m.dt * m.commodity_dict['maxperhour']
                [(stf, sit, com, com_type)])

Total Stock Rule: The constraint total stock rule applies only for commodities of type “Stock” (\(c \in C_\text{st}\)). This constraint limits the amount of stock commodity \(c \in C_\text{st}\), that can be used annually by the energy system in the site \(v\) and support timeframe \(y\). This amount is limited by the parameter maximum annual stock supply limit per vertex \(\overline{L}_{yvc}\). The annual usage of stock commodity is calculated by the sum of the products of the parameter weight \(w\) and the variable stock commodity source term \(\rho_{yvct}\), summed over all timesteps \(t \in T_m\). The mathematical explanation of this rule is given in Minimal Optimization Model.

In script model.py the constraint total stock rule is defined and calculated by the following code fragment:

m.res_stock_total = pyomo.Constraint(
    m.com_tuples,
    rule=res_stock_total_rule,
    doc='total stock commodity input <= commodity.max')
def res_stock_total_rule(m, stf, sit, com, com_type):
    if com not in m.com_stock:
        return pyomo.Constraint.Skip
    else:
        # calculate total consumption of commodity com
        total_consumption = 0
        for tm in m.tm:
            total_consumption += (
                m.e_co_stock[tm, stf, sit, com, com_type])
        total_consumption *= m.weight
        return (total_consumption <=
                m.commodity_dict['max'][(stf, sit, com, com_type)])

Sell Per Step Rule: The constraint sell per step rule applies only for commodities of type “Sell” ( \(c \in C_\text{sell}\)). This constraint limits the amount of sell commodity \(c \in C_\text{sell}\), that can be sold by the energy system in the site \(v\) in support timeframe \(y\) at the timestep \(t\). The limit is defined by the parameter maximum sell supply limit per hour \(\overline{g}_{yvc}\). To satisfy this constraint, the value of the variable sell commodity source term \(\varrho_{yvct}\) must be less than or equal to the value of the parameter maximum sell supply limit per hour \(\overline{g}_{yvc}\) multiplied with the length of the time steps \(\Delta t\). The mathematical explanation of this rule is given in Trading with an External Market.

In script BuySellPrice.py the constraint sell per step rule is defined and calculated by the following code fragment:

m.res_sell_step = pyomo.Constraint(
   m.tm, m.com_tuples,
   rule=res_sell_step_rule,
   doc='sell commodity output per step <= commodity.maxperstep')
def res_sell_step_rule(m, tm, stf, sit, com, com_type):
    if com not in m.com_sell:
        return pyomo.Constraint.Skip
    else:
        return (m.e_co_sell[tm, stf, sit, com, com_type] <=
                m.dt * m.commodity_dict['maxperhour']
                [(stf, sit, com, com_type)])

Total Sell Rule: The constraint total sell rule applies only for commodities of type “Sell” ( \(c \in C_\text{sell}\)). This constraint limits the amount of sell commodity \(c \in C_\text{sell}\), that can be sold annually by the energy system in the site \(v\) and support timeframe \(y\). The limit is defined by the parameter maximum annual sell supply limit per vertex \(\overline{G}_{yvc}\). The annual usage of sell commodity is calculated by the sum of the products of the parameter weight \(w\) and the variable sell commodity source term \(\varrho_{yvct}\), summed over all timesteps \(t \in T_m\). The mathematical explanation of this rule is given in Trading with an External Market.

In script BuySellPrice.py the constraint total sell rule is defined and calculated by the following code fragment:

m.res_sell_total = pyomo.Constraint(
    m.com_tuples,
    rule=res_sell_total_rule,
    doc='total sell commodity output <= commodity.max')
def res_sell_total_rule(m, stf, sit, com, com_type):
    if com not in m.com_sell:
        return pyomo.Constraint.Skip
    else:
        # calculate total sale of commodity com
        total_consumption = 0
        for tm in m.tm:
            total_consumption += (
                m.e_co_sell[tm, stf, sit, com, com_type])
        total_consumption *= m.weight
        return (total_consumption <=
                m.commodity_dict['max'][(stf, sit, com, com_type)])

Buy Per Step Rule: The constraint buy per step rule applies only for commodities of type “Buy” ( \(c \in C_\text{buy}\)). This constraint limits the amount of buy commodity \(c \in C_\text{buy}\), that can be bought by the energy system in the site \(v\) in support timeframe \(y\) at the timestep \(t\). The limit is defined by the parameter maximum buy supply limit per time step \(\overline{b}_{yvc}\). To satisfy this constraint, the value of the variable buy commodity source term \(\psi_{yvct}\) must be less than or equal to the value of the parameter maximum buy supply limit per time step \(\overline{b}_{yvc}\), multiplied by the length of the time steps \(\Delta t\). The mathematical explanation of this rule is given in Trading with an External Market.

In script BuySellPrice.py the constraint buy per step rule is defined and calculated by the following code fragment:

m.res_buy_step = pyomo.Constraint(
    m.tm, m.com_tuples,
    rule=res_buy_step_rule,
    doc='buy commodity output per step <= commodity.maxperstep')
def res_buy_step_rule(m, tm, stf, sit, com, com_type):
    if com not in m.com_buy:
        return pyomo.Constraint.Skip
    else:
        return (m.e_co_buy[tm, stf, sit, com, com_type] <=
                m.dt * m.commodity_dict['maxperhour']
                [(stf, sit, com, com_type)])

Total Buy Rule: The constraint total buy rule applies only for commodities of type “Buy” ( \(c \in C_\text{buy}\)). This constraint limits the amount of buy commodity \(c \in C_\text{buy}\), that can be bought annually by the energy system in the site \(v\) in support timeframe \(y\). The limit is defined by the parameter maximum annual buy supply limit per vertex \(\overline{B}_{yvc}\). To satisfy this constraint, the annual usage of buy commodity must be less than or equal to the value of the parameter buy supply limit per vertex \(\overline{B}_{yvc}\). The annual usage of buy commodity is calculated by the sum of the products of the parameter weight \(w\) and the variable buy commodity source term \(\psi_{yvct}\), summed over all modeled timesteps \(t \in T_m\). The mathematical explanation of this rule is given in Trading with an External Market.

In script BuySellPrice.py the constraint total buy rule is defined and calculated by the following code fragment:

m.res_buy_total = pyomo.Constraint(
   m.com_tuples,
   rule=res_buy_total_rule,
   doc='total buy commodity output <= commodity.max')
def res_buy_total_rule(m, stf, sit, com, com_type):
    if com not in m.com_buy:
        return pyomo.Constraint.Skip
    else:
        # calculate total sale of commodity com
        total_consumption = 0
        for tm in m.tm:
            total_consumption += (
                m.e_co_buy[tm, stf, sit, com, com_type])
        total_consumption *= m.weight
        return (total_consumption <=
                m.commodity_dict['max'][(stf, sit, com, com_type)])

Environmental Output Per Step Rule: The constraint environmental output per step rule applies only for commodities of type “Env” (\(c \in C_\text{env}\)). This constraint limits the amount of environmental commodity \(c \in C_\text{env}\), that can be released to environment by the energy system in the site \(v\) in support timeframe \(y\) at the timestep \(t\). The limit is defined by the parameter maximum environmental output per time step \(\overline{m}_{yvc}\). To satisfy this constraint, the negative value of the commodity balance for the given environmental commodity \(c \in C_\text{env}\) must be less than or equal to the value of the parameter maximum environmental output per time step \(\overline{m}_{yvc}\), multiplied by the length of the time steps \(\Delta t\). The mathematical explanation of this rule is given in Minimal Optimization Model.

In script model.py the constraint environmental output per step rule is defined and calculated by the following code fragment:

m.res_env_step = pyomo.Constraint(
    m.tm, m.com_tuples,
    rule=res_env_step_rule,
    doc='environmental output per step <= commodity.maxperstep')
def res_env_step_rule(m, tm, stf, sit, com, com_type):
    if com not in m.com_env:
        return pyomo.Constraint.Skip
    else:
        environmental_output = - commodity_balance(m, tm, stf, sit, com)
        return (environmental_output <=
                m.dt * m.commodity_dict['maxperhour']
                [(stf, sit, com, com_type)])

Total Environmental Output Rule: The constraint total environmental output rule applies only for commodities of type “Env” ( \(c \in C_\text{env}\)). This constraint limits the amount of environmental commodity \(c \in C_\text{env}\), that can be released to environment annually by the energy system in the site \(v\) in support timeframe \(y\). The limit is defined by the parameter maximum annual environmental output limit per vertex \(\overline{M}_{yvc}\). To satisfy this constraint, the annual release of environmental commodity must be less than or equal to the value of the parameter maximum annual environmental output \(\overline{M}_{yvc}\). The annual release of environmental commodity is calculated by the sum of the products of the parameter weight \(w\) and the negative value of commodity balance function, summed over all modeled time steps \(t \in T_m\). The mathematical explanation of this rule is given in Minimal Optimization Model.

In script model.py the constraint total environmental output rule is defined and calculated by the following code fragment:

m.res_env_total = pyomo.Constraint(
    m.com_tuples,
    rule=res_env_total_rule,
    doc='total environmental commodity output <= commodity.max')
def res_env_total_rule(m, stf, sit, com, com_type):
    if com not in m.com_env:
        return pyomo.Constraint.Skip
    else:
        # calculate total creation of environmental commodity com
        env_output_sum = 0
        for tm in m.tm:
            env_output_sum += (- commodity_balance(m, tm, stf, sit, com))
        env_output_sum *= m.weight
        return (env_output_sum <=
                m.commodity_dict['max'][(stf, sit, com, com_type)])

Demand Side Management Constraints

The DSM equations are taken from the Paper of Zerrahn and Schill “On the representation of demand-side management in power system models”, DOI: 10.1016/j.energy.2015.03.037.

DSM Variables Rule: The DSM variables rule defines the relation between the up- and downshifted DSM commodities. An upshift \(\delta_{yvct}^\text{up}\) in site \(v\) and support timeframe \(y\) of demand commodity \(c\) in time step \(t\) can be compensated during a certain time step interval \([t-y_{yvc}/{\Delta t}, t+y_{yvc}/{\Delta t}]\) by multiple downshifts \(\delta_{t,tt,yvc}^\text{down}\). Here, \(y_{yvc}\) represents the allowable delay time of downshifts in hours, which is scaled into time steps by dividing by the timestep length \({\Delta t}\). Depending on the DSM efficiency \(e_{yvc}\), an upshift in a DSM commodity may correspond to multiple downshifts which sum to less than the original upshift. The mathematical explanation of this rule is given in Demand Side Management.

In script dsm.py the constraint DSM variables rule is defined by the following code fragment:

m.def_dsm_variables = pyomo.Constraint(
    m.tm, m.dsm_site_tuples,
    rule=def_dsm_variables_rule,
    doc='DSMup * efficiency factor n == DSMdo (summed)')
def def_dsm_variables_rule(m, tm, stf, sit, com):
    dsm_down_sum = 0
    for tt in dsm_time_tuples(tm,
                              m.timesteps[1:],
                              max(int(1 / m.dt *
                                  m.dsm_dict['delay'][(stf, sit, com)]), 1)):
        dsm_down_sum += m.dsm_down[tm, tt, stf, sit, com]
    return dsm_down_sum == (m.dsm_up[tm, stf, sit, com] *
                            m.dsm_dict['eff'][(stf, sit, com)])

DSM Upward Rule: The DSM upshift \(\delta_{yvct}^\text{up}\) in site \(v\) and support timeframe \(y\) of demand commodity \(c\) in time step \(t\) is limited by the DSM maximal upshift per hour \(\overline{K}_{yvc}^\text{up}\), multiplied by the length of the time steps \(\Delta t\). The mathematical explanation of this rule is given in Demand Side Management.

In script dsm.py the constraint DSM upward rule is defined by the following code fragment:

m.res_dsm_upward = pyomo.Constraint(
    m.tm, m.dsm_site_tuples,
    rule=res_dsm_upward_rule,
    doc='DSMup <= Cup (threshold capacity of DSMup)')
def res_dsm_upward_rule(m, tm, stf, sit, com):
    return m.dsm_up[tm, stf, sit, com] <= (m.dt *
                                           m.dsm_dict['cap-max-up']
                                           [(stf, sit, com)])

DSM Downward Rule: The total DSM downshift \(\delta_{t,tt,yvc}^\text{down}\) in site \(v\) and support timeframe \(y\) of demand commodity \(c\) in time step \(t\) is limited by the DSM maximal downshift per hour \(\overline{K}_{yvc}^\text{down}\), multiplied by the length of the time steps \(\Delta t\). The mathematical explanation of this rule is given in Demand Side Management.

In script dsm.py the constraint DSM downward rule is defined by the following code fragment:

m.res_dsm_downward = pyomo.Constraint(
    m.tm, m.dsm_site_tuples,
    rule=res_dsm_downward_rule,
    doc='DSMdo (summed) <= Cdo (threshold capacity of DSMdo)')
def res_dsm_downward_rule(m, tm, stf, sit, com):
    dsm_down_sum = 0
    for t in dsm_time_tuples(tm,
                             m.timesteps[1:],
                             max(int(1 / m.dt *
                                 m.dsm_dict['delay'][(stf, sit, com)]), 1)):
        dsm_down_sum += m.dsm_down[t, tm, stf, sit, com]
    return dsm_down_sum <= (m.dt * m.dsm_dict['cap-max-do'][(stf, sit, com)])

DSM Maximum Rule: The DSM maximum rule limits the shift of one DSM unit in site \(v\) in support timeframe \(y\) of demand commodity \(c\) in time step \(t\). The mathematical explanation of this rule is given in Demand Side Management.

In script dsm.py the constraint DSM maximum rule is defined by the following code fragment:

m.res_dsm_maximum = pyomo.Constraint(
    m.tm, m.dsm_site_tuples,
    rule=res_dsm_maximum_rule,
    doc='DSMup + DSMdo (summed) <= max(Cup,Cdo)')
def res_dsm_maximum_rule(m, tm, stf, sit, com):
    dsm_down_sum = 0
    for t in dsm_time_tuples(tm,
                             m.timesteps[1:],
                             max(int(1 / m.dt *
                                 m.dsm_dict['delay'][(stf, sit, com)]), 1)):
        dsm_down_sum += m.dsm_down[t, tm, stf, sit, com]

    max_dsm_limit = m.dt * max(m.dsm_dict['cap-max-up'][(stf, sit, com)],
                               m.dsm_dict['cap-max-do'][(stf, sit, com)])
    return m.dsm_up[tm, stf, sit, com] + dsm_down_sum <= max_dsm_limit

DSM Recovery Rule: The DSM recovery rule limits the upshift in site \(v\) and support timeframe \(y\) of demand commodity \(c\) during a set recovery period \(o_{yvc}\). Since the recovery period \(o_{yvc}\) is input as hours, it is scaled into time steps by dividing it by the length of the time steps \(\Delta t\). The mathematical explanation of this rule is given in Demand Side Management.

In script dsm.py the constraint DSM recovery rule is defined by the following code fragment:

m.res_dsm_recovery = pyomo.Constraint(
    m.tm, m.dsm_site_tuples,
    rule=res_dsm_recovery_rule,
    doc='DSMup(t, t + recovery time R) <= Cup * delay time L')
def res_dsm_recovery_rule(m, tm, stf, sit, com):
    dsm_up_sum = 0
    for t in dsm_recovery(tm,
                          m.timesteps[1:],
                          max(int(1 / m.dt *
                              m.dsm_dict['recov'][(stf, sit, com)]), 1)):
        dsm_up_sum += m.dsm_up[t, stf, sit, com]
    return dsm_up_sum <= (m.dsm_dict['cap-max-up'][(stf, sit, com)] *
                          m.dsm_dict['delay'][(stf, sit, com)])

Global Environmental Constraint

Global CO2 Limit Rule: The constraint global CO2 limit rule applies to the whole energy system in one support timeframe \(y\), that is to say it applies to every site and timestep. This constraint restricts the total amount of CO2 emission to environment. The constraint states that the sum of released CO2 across all sites \(v\in V\) and timesteps \(t \in T_m\) must be less than or equal to the parameter maximum global annual CO2 emission limit \(\overline{L}_{CO_{2},y}\), where the amount of released CO2 in a single site \(v\) at a single timestep \(t\) is calculated by the product of commodity balance of environmental commodities \(\mathrm{CB}(y,v,CO_{2},t)\) and the parameter weight \(w\). This constraint is skipped if the value of the parameter \(\overline{L}_{CO_{2},y}\) is set to inf. The mathematical explanation of this rule is given in Multinode Optimization Model .

In script model.py the constraint annual global CO2 limit rule is defined and calculated by the following code fragment:

def res_global_co2_limit_rule(m, stf):
    if math.isinf(m.global_prop_dict['value'][stf, 'CO2 limit']):
        return pyomo.Constraint.Skip
    elif m.global_prop_dict['value'][stf, 'CO2 limit'] >= 0:
        co2_output_sum = 0
        for tm in m.tm:
            for sit in m.sit:
                # minus because negative commodity_balance represents creation
                # of that commodity.
                co2_output_sum += (- commodity_balance(m, tm,
                                                       stf, sit, 'CO2'))

        # scaling to annual output (cf. definition of m.weight)
        co2_output_sum *= m.weight
        return (co2_output_sum <= m.global_prop_dict['value']
                                                    [stf, 'CO2 limit'])
    else:
        return pyomo.Constraint.Skip

Global CO2 Budget Rule: The constraint global CO2 budget rule applies to the whole energy system over the entire modeling horizon, that is to say it applies to every support timeframe, site and timestep. This constraint restricts the total amount of CO2 emission to environment. The constraint states that the sum of released CO2 across all support timeframe \(y\in Y\), sites \(v\in V\) and timesteps \(t \in T_m\) must be less than or equal to the parameter maximum global CO2 emission budget \(\overline{\overline{L}}_{CO_{2}}\), where the amount of released CO2 in a single support timeframe \(y\) in a single site \(v\) and at a single timestep \(t\) is calculated by the product of the commodity balance of environmental commodities \(\mathrm{CB}(y,v,CO_{2},t)\) and the parameter weight \(w\). This constraint is skipped if the value of the parameter \(\overline{\overline{L}}_{CO_{2}}\) is set to inf. The mathematical explanation of this rule is given in Intertemporal Optimization Model.

In script model.py the constraint global CO2 budget is defined and calculated by the following code fragment:

def res_global_co2_budget_rule(m):
    if math.isinf(m.global_prop_dict['value'][min(m.stf_list), 'CO2 budget']):
        return pyomo.Constraint.Skip
    elif (m.global_prop_dict['value'][min(m.stf_list), 'CO2 budget']) >= 0:
        co2_output_sum = 0
        for stf in m.stf:
            for tm in m.tm:
                for sit in m.sit:
                    # minus because negative commodity_balance represents
                    # creation of that commodity.
                    co2_output_sum += (- commodity_balance
                                       (m, tm, stf, sit, 'CO2') *
                                       m.weight *
                                       stf_dist(stf, m))

        return (co2_output_sum <=
                m.global_prop_dict['value'][min(m.stf), 'CO2 budget'])
    else:
        return pyomo.Constraint.Skip