예제 #1
0
    def maximize_points(self, players=None):
        model = pyomo.ConcreteModel()
        model.starting_roster = constants.starting_roster
        model.positions = [
            position for position in model.starting_roster.keys()
        ]

        model.players = self.players if players is None else players

        # Decision variable: who is being used?
        model.used = pyomo.Var(model.players, within=pyomo.Binary)
        model.used_by_pos = pyomo.Var(model.players,
                                      model.positions,
                                      within=pyomo.Binary)

        # Decision variable: who is playing what position?
        model.games_played = pyomo.Var(model.players,
                                       model.positions,
                                       within=pyomo.NonNegativeIntegers)

        # Limit number of players used
        model.cap_players_used = pyomo.Constraint(rule=self.cap_players_used)

        # Limit starting roster
        model.limit_roster_rule = pyomo.Constraint(model.positions,
                                                   rule=self.limit_roster)

        # Limit positions players can play
        model.limit_positions_rule = pyomo.Constraint(
            model.players, model.positions, rule=self.limit_positions)

        # Limit to 1 position per player
        model.limit_playtime_rule = pyomo.Constraint(model.players,
                                                     rule=self.limit_playtime)
        model.limit_playtime_bypos_rule1 = \
            pyomo.Constraint(model.players, model.positions, rule=self.limit_playtime_bypos1)
        model.limit_playtime_bypos_rule2 = \
            pyomo.Constraint(model.players, model.positions, rule=self.limit_playtime_bypos2)

        # Only true RP play RP - due to starts limit
        model.only_true_rp_rule1 = pyomo.Constraint(model.players,
                                                    rule=self.only_true_rp1)
        model.only_true_rp_rule2 = pyomo.Constraint(model.players,
                                                    rule=self.only_true_rp2)

        # Constrain which players can be modeled as 'replaceable' to fill out remaining playing time at position
        model.limit_replaceability = pyomo.Constraint(
            model.players, model.positions, rule=self.limit_replaceability)

        # Objective function
        model.objective = pyomo.Objective(rule=self.objective,
                                          sense=pyomo.maximize)

        return model
예제 #2
0
model.m = pyomo.Param(within=pyomo.NonNegativeIntegers)
model.n = pyomo.Param(within=pyomo.NonNegativeIntegers)

# although not required, it is convenient to define index sets
model.I = pyomo.RangeSet(1, model.m)
model.J = pyomo.RangeSet(1, model.n)

# now we define the coefficients (which are themselves defined over index sets!)
model.a = pyomo.Param(model.I, model.J)
model.b = pyomo.Param(model.I)
model.c = pyomo.Param(model.J)

# the next line declares a variable indexed by the set J
model.x = pyomo.Var(model.J, domain=pyomo.NonNegativeReals)

def objective(model):
    """Abstract representation of our model objective.""" 
    obj = pyomo.summation(model.c, model.x)
    return obj

# add the objective function to the model object as an attribute (OBJ can be arbitrary!)
model.OBJ = pyomo.Objective(rule=objective)

def constraints(model, i):
    """Abstract representation of model constraints."""
    # return the expression for the constraint for i
    return sum(model.a[i,j] * model.x[j] for j in model.J) >= model.b[i]

# the next line creates one constraint for each member of the set model.I (CONS can be arbitrary!)
model.CONS = pyomo.Constraint(model.I, rule=constraints)
예제 #3
0
    """Agent faces a sequence of flow budget constraints"""
    # extract variables
    k = model.capital
    c = model.consumption
    i = model.investment

    # extract parameters
    r = model.r
    w = model.w
    l_bar = model.l_bar

    return c[t] + i[t] == w[t] * l_bar + r * k[t]


model.budget_constraints = pyomo.Constraint(
    model.periods,
    rule=flow_budget_constraints,
    doc='Agent faces a sequence of flow budget constraints.')


def capital_evolution_rule(model, t):
    """Agent's capital stock evolves depending on current capital stock and investment rate."""
    # extract variables
    k = model.capital
    i = model.investment

    # extract parameters
    delta = model.delta

    return k[t + 1] == (1 - delta) * k[t] + i[t]

예제 #4
0
    def create_optimal_model(self, team_players, available_players,
                             prob_avail_after):

        model = pyomo.ConcreteModel()

        # Set bounds of problem
        model.weeks = constants.week_weights.keys()
        model.positions = constants.roster.keys()
        model.roster_size = sum(constants.roster.values())

        mcfadden = PlayerClass.Player('D. McFadden Dal - RB')
        points = {
            1: 4.74,
            2: 11.89,
            3: 12.09,
            4: 11.99,
            5: 12.2,
            6: 0,
            7: 11.61,
            8: 13.25,
            9: 3.43,
            10: 3.21,
            11: 3.44,
            12: 3.52,
            13: 3.44,
            14: 3.27,
            15: 3.24,
            16: 3.33
        }
        mcfadden.add_points(points)

        # Determine current and available players
        model.team_players = team_players + [mcfadden]
        model.avail_players = available_players
        model.players = model.team_players + model.avail_players

        model.prob_avail_after = {
            key: prob_avail_after[key]
            for key in prob_avail_after.keys()
        }
        for player in model.team_players:
            model.prob_avail_after[player] = 1.0

        ########### Decision Variables ###########
        model.starting = pyomo.Var(model.players,
                                   model.positions,
                                   model.weeks,
                                   within=pyomo.Binary)
        model.starts = pyomo.Var(model.players,
                                 within=pyomo.NonNegativeIntegers)
        model.used = pyomo.Var(model.players, within=pyomo.Binary)

        ########### Constraints ###########
        model.position_eligibility = pyomo.Constraint(
            model.players,
            model.positions,
            model.weeks,
            rule=self.position_eligibility)
        model.weekly_roster_size = pyomo.Constraint(
            model.positions, model.weeks, rule=self.weekly_roster_size)
        model.only_one_position = pyomo.Constraint(model.players,
                                                   model.weeks,
                                                   rule=self.only_one_position)
        model.set_starts = pyomo.Constraint(model.players,
                                            rule=self.set_starts)
        model.set_used = pyomo.Constraint(model.players, rule=self.set_used)
        model.set_used2 = pyomo.Constraint(model.players, rule=self.set_used2)
        model.cap_used = pyomo.Constraint(model.players, rule=self.cap_used)

        ########### Objective function ###########
        model.objective = pyomo.Objective(rule=self.objective,
                                          sense=pyomo.maximize)

        return model
def flow_budget_constraints(model, t):
    """Agent faces a sequence of flow budget constraints"""
    # extract variables
    c = model.consumption
    l = model.labor_supply
    A = model.assets

    # extract parameters
    r = model.r
    w = model.w

    return c[t] + A[t + 1] == w[t] * l[t] + (1 + r) * A[t]


model.budget_constraints = pyomo.Constraint(
    model.periods,
    rule=flow_budget_constraints,
    doc='Agent faces a sequence of flow budget constraints.')


def borrowing_constraint(model, t):
    """Agent's assets cannot fall below some minimum amount."""
    return model.assets[t] >= model.minimum_assets


model.borrowing_constraint = pyomo.Constraint(
    model.periods,
    rule=borrowing_constraint,
    doc='There is a lower bound on agent assets.')


def endowment(model):
예제 #6
0
 def add_constraint(self, name, expression, time=None):
     cname = self._t_id(name, time) if time is not None else name
     self._model.add_component(cname,
                               pyomo.Constraint(name=name, rule=expression))
예제 #7
0
 def add_constraint_set(self, name, index, expression):
     cname = self._id(name)
     self._parent_problem().add_component_to_problem(
         pyomo.Constraint(index, name=cname, rule=expression))
예제 #8
0
 def add_constraint(self, name, time, expression):
     '''Create a new constraint and add it to the object's constraints and the model's constraints.'''
     cname = self._t_id(name, time)
     self._parent_problem().add_component_to_problem(
         pyomo.Constraint(name=cname, rule=expression))
예제 #9
0
    k = model.capital
    c = model.consumption
    b = model.debt

    # extract parameters
    r = model.r
    w = model.w
    q = model.q
    l_bar = model.l_bar

    return c[t] + q[t] * k[t + 1] + (1 + r) * b[t] == w[t] * l_bar + (
        r + q[t]) * k[t] + b[t + 1]


model.budget_constraints = pyomo.Constraint(
    model.periods,
    rule=flow_budget_constraints,
    doc='Agent faces a sequence of flow budget constraints.')


def borrowing_constraint(model, t):
    """Agent's borrowing capacity depends on collateral."""
    # extract variables
    k = model.capital
    b = model.debt

    # extract parameters
    theta = model.theta
    r = model.r
    q = model.q

    return (1 + r) * b[t] <= theta * q[t + 1] * k[t]
예제 #10
0
def create_model(data, timesteps):
    """ Create a VICUS model object from input data.
    
    Creates and returns a Pyomo ConcreteModel object, given a model
    input file (supported formats: Excel spreadsheet [planned: SQLite DB])
    
    Args:
        data: input dict with fields for Commodities, Processes, 
            Storage and timeseries for Demand and SupIm
        timesteps: numpy array of timestep labels, matching the ones 
            used in the Demand and SupIm timeseries
            
    Returns:
        A coopr.pyomo ConcreteModel object, ready to be instantiated and
        solved.
                  
    """
    m = pyomo.ConcreteModel()
    m.name = 'VICUS'
    m.created = datetime.now().strftime('%Y%m%dT%H%M%S', )

    # Preparations
    # ============
    # Data import. Syntax to access a value within equation definitions looks
    # like this:
    #
    #     m.process.loc[sit, pro, coin, cout][attribute]
    #
    get_inputs = itemgetter("commodity", "process", "storage", "demand",
                            "supim")
    (m.commodity, m.process, m.storage, m.demand, m.supim) = get_inputs(data)

    # Sets
    # ====
    # Syntax: m.{name} = Set({domain}, initialize={values})
    # where name: set name
    #       domain: set domain for tuple sets, a cartesian set product
    #       values: set values, a list or array of element tuples
    m.t = pyomo.Set(ordered=True, initialize=timesteps)
    m.tm = pyomo.Set(within=m.t, initialize=timesteps[1:])
    m.co = pyomo.Set(initialize=m.commodity.index.levels[0])
    m.coin = pyomo.Set(within=m.co, initialize=m.process.index.levels[1])
    m.cout = pyomo.Set(within=m.co, initialize=m.process.index.levels[2])
    m.co_type = pyomo.Set(initialize=m.commodity.index.levels[1])
    m.pro = pyomo.Set(initialize=m.process.index.levels[0])
    m.sto = pyomo.Set(initialize=m.storage.index.levels[0])
    m.cost_type = pyomo.Set(initialize=['Inv', 'Fix', 'Var', 'Fuel'])

    # sets of existing tuples:
    # co_tuples = [('Coal', 'Stock'), ('Wind', 'SupIm'), ('ElecAC', 'Demand')...]
    # pro_tuples = [('pp', 'Coal', 'ElecAC'), ('wt', 'Wind', 'ElecAC')...]
    # sto_tuples = [('bat', 'ElecDC'), ('pst', 'ElecAC')...]
    m.co_tuples = pyomo.Set(within=m.co * m.co_type,
                            initialize=m.commodity.index)
    m.pro_tuples = pyomo.Set(within=m.pro * m.coin * m.cout,
                             initialize=m.process.index)
    m.sto_tuples = pyomo.Set(within=m.sto * m.co, initialize=m.storage.index)

    # subsets of commodities by type
    # for shorter equations that apply to only one commodity type
    m.co_supim = pyomo.Set(within=m.co,
                           initialize=(c[0] for c in m.co_tuples
                                       if c[1] == 'SupIm'))
    m.co_stock = pyomo.Set(within=m.co,
                           initialize=(c[0] for c in m.co_tuples
                                       if c[1] == 'Stock'))
    m.co_demand = pyomo.Set(within=m.co,
                            initialize=(c[0] for c in m.co_tuples
                                        if c[1] == 'Demand'))

    # Parameters
    # ==========
    # for model entities (commodity, process, storage) no Pyomo params
    # are needed, just use the DataFrames m.commodity, m.process and
    # m.storage directly.
    # Syntax: m.{name} = Param({domain}, initialize={values})
    # where name: param name
    #       domain: one or multiple model sets; empty for scalar parameters
    #       values: dict of values, addressed by elements of domain sets
    m.weight = pyomo.Param(initialize=float(8760) / len(m.t))

    # Variables
    # =========
    # listed alphabetically
    # Syntax: m.{name} = Var({domain}, within={range})
    # where name: variable name
    #       domain: variable domain, consisting of one or multiple sets
    #       range: variable values, like Binary, Integer, NonNegativeReals
    m.cap_pro = pyomo.Var(m.pro_tuples,
                          within=pyomo.NonNegativeReals,
                          doc='Total process capacity (kW)')
    m.cap_pro_new = pyomo.Var(m.pro_tuples,
                              within=pyomo.NonNegativeReals,
                              doc='New process capacity (kW)')
    m.cap_sto_c = pyomo.Var(m.sto_tuples,
                            within=pyomo.NonNegativeReals,
                            doc='Total storage size (kWh)')
    m.cap_sto_c_new = pyomo.Var(m.sto_tuples,
                                within=pyomo.NonNegativeReals,
                                doc='New storage capacity (kWh)')
    m.cap_sto_p = pyomo.Var(m.sto_tuples,
                            within=pyomo.NonNegativeReals,
                            doc='Total storage power (kW)')
    m.cap_sto_p_new = pyomo.Var(m.sto_tuples,
                                within=pyomo.NonNegativeReals,
                                doc='New storage power (kW)')
    m.co2_pro_out = pyomo.Var(
        m.tm,
        m.pro_tuples,
        within=pyomo.NonNegativeReals,
        doc='CO2 emissions from processes (kg) per timestep')
    m.costs = pyomo.Var(m.cost_type,
                        within=pyomo.NonNegativeReals,
                        doc='Costs by type (EUR/a)')
    m.e_co_stock = pyomo.Var(
        m.tm,
        m.co_stock,
        within=pyomo.NonNegativeReals,
        doc='Source power flow from stock commodities (kW) per timestep')
    m.e_pro_in = pyomo.Var(m.tm,
                           m.pro_tuples,
                           within=pyomo.NonNegativeReals,
                           doc='Power flow into process (kW) per timestep')
    m.e_pro_out = pyomo.Var(m.tm,
                            m.pro_tuples,
                            within=pyomo.NonNegativeReals,
                            doc='Power flow out of process (kW) per timestep')
    m.e_sto_in = pyomo.Var(m.tm,
                           m.sto_tuples,
                           within=pyomo.NonNegativeReals,
                           doc='Power flow into storage (kW) per timestep')
    m.e_sto_out = pyomo.Var(m.tm,
                            m.sto_tuples,
                            within=pyomo.NonNegativeReals,
                            doc='Power flow out of storage (kW) per timestep')
    m.e_sto_con = pyomo.Var(m.t,
                            m.sto_tuples,
                            within=pyomo.NonNegativeReals,
                            doc='Energy content of storage (kWh) in timestep')

    # Equation definition
    # ===================
    # listed by topic. All equations except the Objective function are
    # of type Constraint, although there are two semantics for those,
    # indicated by the name prefix (def, res).
    #  - def: definition, usually equations, defining variable values
    #  - res: restriction, usually inequalities, limiting variable values
    # topics
    #  - commodity
    #  - process
    #  - storage
    #  - emissions
    #  - costs

    # commodity
    def res_demand_rule(m, tm, co, co_type):
        if co not in m.co_demand:
            return pyomo.Constraint.Skip
        else:
            provided_energy = -commodity_balance(m, tm, co)
            return provided_energy >= \
                   m.demand.loc[tm][co] * \
                   m.commodity.loc[co, co_type]['peak']

    def def_e_co_stock_rule(m, tm, co, co_type):
        if co not in m.co_stock:
            return pyomo.Constraint.Skip
        else:
            return m.e_co_stock[tm, co] == commodity_balance(m, tm, co)

    def res_stock_hour_rule(m, tm, co, co_type):
        if co not in m.co_stock:
            return pyomo.Constraint.Skip
        else:
            return m.e_co_stock[tm, co] <= \
                   m.commodity.loc[co, co_type]['maxperhour']

    def res_stock_total_rule(m, co, co_type):
        if co not in m.co_stock:
            return pyomo.Constraint.Skip
        else:
            # calculate total consumption of commodity co
            total_consumption = 0
            for tm in m.tm:
                total_consumption += m.e_co_stock[tm, co] * m.weight
            return total_consumption <= m.commodity.loc[co, co_type]['max']

    # process
    def def_process_capacity_rule(m, tm, pro, coin, cout):
        return m.cap_pro[pro,coin,cout] == \
               m.cap_pro_new[pro,coin,cout] + \
               m.process.loc[pro,coin,cout]['inst-cap']

    def def_process_output_rule(m, tm, pro, coin, cout):
        return m.e_pro_out[tm, pro, coin, cout] == \
               m.e_pro_in[tm, pro, coin, cout] * \
               m.process.loc[pro, coin, cout]['eff']

    def def_intermittent_supply_rule(m, tm, pro, coin, cout):
        if coin in m.co_supim:
            return m.e_pro_in[tm, pro, coin, cout] == \
                   m.cap_pro[pro, coin, cout] * m.supim.loc[tm][coin]
        else:
            return pyomo.Constraint.Skip

    def def_co2_emissions_rule(m, tm, pro, coin, cout):
        return m.co2_pro_out[tm, pro, coin, cout] == \
               m.e_pro_in[tm, pro, coin, cout] * \
               m.process.loc[pro, coin, cout]['co2'] * \
               m.weight

    def res_process_output_by_capacity_rule(m, tm, pro, coin, cout):
        return m.e_pro_out[tm, pro, coin, cout] <= m.cap_pro[pro, coin, cout]

    def res_process_capacity_rule(m, pro, coin, cout):
        return (m.process.loc[pro, coin, cout]['cap-lo'],
                m.cap_pro[pro, coin, cout], m.process.loc[pro, coin,
                                                          cout]['cap-up'])

    # storage
    def def_storage_state_rule(m, t, sto, co):
        return m.e_sto_con[t, sto, co] == \
               m.e_sto_con[t-1, sto, co] + \
               m.e_sto_in[t, sto, co] * m.storage.loc[sto, co]['eff-in'] - \
               m.e_sto_out[t, sto, co] / m.storage.loc[sto, co]['eff-out']

    def def_storage_power_rule(m, sto, co):
        return m.cap_sto_p[sto, co] == \
               m.cap_sto_p_new[sto, co] + \
               m.storage.loc[sto, co]['inst-cap-p']

    def def_storage_capacity_rule(m, sto, co):
        return m.cap_sto_c[sto, co] == \
               m.cap_sto_c_new[sto, co] + \
               m.storage.loc[sto, co]['inst-cap-p']

    def res_storage_input_by_power_rule(m, t, sto, co):
        return m.e_sto_in[t, sto, co] <= m.cap_sto_p[sto, co]

    def res_storage_output_by_power_rule(m, t, sto, co):
        return m.e_sto_out[t, sto, co] <= m.cap_sto_p[sto, co]

    def res_storage_state_by_capacity_rule(m, t, sto, co):
        return m.e_sto_con[t, sto, co] <= m.cap_sto_c[sto, co]

    def res_storage_power_rule(m, sto, co):
        return (m.storage.loc[sto, co]['cap-lo-p'], m.cap_sto_p[sto, co],
                m.storage.loc[sto, co]['cap-up-p'])

    def res_storage_capacity_rule(m, sto, co):
        return (m.storage.loc[sto, co]['cap-lo-c'], m.cap_sto_c[sto, co],
                m.storage.loc[sto, co]['cap-up-c'])

    def res_initial_and_final_storage_state_rule(m, t, sto, co):
        if t == m.t[1]:  # first timestep (Pyomo uses 1-based indexing)
            return m.e_sto_con[t, sto, co] == \
                   m.cap_sto_c[sto, co] * \
                   m.storage.loc[sto, co]['init']
        elif t == m.t[-1]:  # last timestep
            return m.e_sto_con[t, sto, co] >= \
                   m.cap_sto_c[sto, co] * \
                   m.storage.loc[sto, co]['init']
        else:
            return pyomo.Constraint.Skip

    # emissions
    def res_co2_emission_rule(m):
        return pyomo.summation(m.co2_pro_out) <= \
               m.commodity.loc['CO2','Env']['max']

    # costs
    def def_costs_rule(m, cost_type):
        """ Calculate total costs by cost type.
        
        Sums up process activity and capacity expansions
        and sums them in the cost types that are specified in the set
        m.cost_type. To change or add cost types, add/change entries 
        there and modify the if/elif cases in this function accordingly.
        
        Cost types are
          - Investment costs for process power, storage power and 
            storage capacity, annualized.
          - Fixed costs for process & storage power, storage capacity.
          - Variable costs for process and storage activity.
          - Fuel costs for purchased stock commodities.
        """
        if cost_type == 'Inv':
            return m.costs['Inv'] == \
                sum(m.cap_pro_new[p] *
                    m.process.loc[p]['inv-cost'] *
                    m.process.loc[p]['annuity_factor']
                    for p in m.pro_tuples) + \
                sum(m.cap_sto_p_new[s] *
                    m.storage.loc[s]['inv-cost-p'] *
                    m.storage.loc[s]['annuity_factor'] +
                    m.cap_sto_c_new[s] *
                    m.storage.loc[s]['inv-cost-c'] *
                    m.storage.loc[s]['annuity_factor']
                    for s in m.sto_tuples)

        elif cost_type == 'Fix':
            return m.costs['Fix'] == \
                sum(m.cap_pro[p] * m.process.loc[p]['fix-cost']
                    for p in m.pro_tuples) + \
                sum(m.cap_sto_p[s] * m.storage.loc[s]['fix-cost-p'] +
                    m.cap_sto_c[s] * m.storage.loc[s]['fix-cost-c']
                    for s in m.sto_tuples)

        elif cost_type == 'Var':
            return m.costs['Var'] == \
                sum(m.e_pro_out[(tm,) + p] *
                    m.process.loc[p]['var-cost'] *
                    m.weight
                    for tm in m.tm for p in m.pro_tuples) + \
                sum(m.e_sto_con[(tm,) + s] *
                    m.storage.loc[s]['var-cost-c'] * m.weight +
                    (m.e_sto_in[(tm,) + s] + m.e_sto_out[(tm,) + s]) *
                    m.storage.loc[s]['var-cost-p'] * m.weight
                    for tm in m.tm for s in m.sto_tuples)

        elif cost_type == 'Fuel':
            return m.costs['Fuel'] == \
                sum(m.e_co_stock[(tm,c[0])] *
                    m.commodity.loc[c]['price'] *
                    m.weight
                    for tm in m.tm for c in m.co_tuples
                    if c[0] in m.co_stock)

        else:
            raise NotImplementedError("Unknown cost type!")

    def obj_rule(m):
        """ Return sum of total costs over all cost types.
        
        Simply calculates the sum of m.costs over all m.cost_types.
        """
        return pyomo.summation(m.costs)

    # Equation declaration
    # ====================
    # declarations connect rule functions to the model, specifying
    # the model sets for which the constraints are enforced.

    # commodity
    m.res_demand = pyomo.Constraint(m.tm,
                                    m.co_tuples,
                                    doc='storage + process balance >= demand')
    m.def_e_co_stock = pyomo.Constraint(
        m.tm,
        m.co_tuples,
        doc='commodity source term = hourly commodity consumption')
    m.res_stock_hour = pyomo.Constraint(
        m.tm,
        m.co_tuples,
        doc='hourly commodity source term <= commodity.maxperhour')
    m.res_stock_total = pyomo.Constraint(
        m.co_tuples, doc='total commodity source term <= commodity.max')

    # process
    m.def_process_capacity = pyomo.Constraint(
        m.tm,
        m.pro_tuples,
        doc='total process capacity = inst-cap + new capacity')
    m.def_process_output = pyomo.Constraint(
        m.tm, m.pro_tuples, doc='process output = process input * efficiency')
    m.def_intermittent_supply = pyomo.Constraint(
        m.tm,
        m.pro_tuples,
        doc='process output = process capacity * supim timeseries')
    m.def_co2_emissions = pyomo.Constraint(
        m.tm,
        m.pro_tuples,
        doc='process co2 output = process input * process.co2 * weight')
    m.res_process_output_by_capacity = pyomo.Constraint(
        m.tm, m.pro_tuples, doc='process output <= process capacity')
    m.res_process_capacity = pyomo.Constraint(
        m.pro_tuples,
        doc='process.cap-lo <= process capacity <= process.cap-up')

    # storage
    m.def_storage_state = pyomo.Constraint(
        m.tm, m.sto_tuples, doc='storage[t] = storage[t-1] + input - output')
    m.def_storage_power = pyomo.Constraint(
        m.sto_tuples, doc='storage power = inst-cap + new power')
    m.def_storage_capacity = pyomo.Constraint(
        m.sto_tuples, doc='storage capacity = inst-cap + new capacity')
    m.res_storage_input_by_power = pyomo.Constraint(
        m.tm, m.sto_tuples, doc='storage input <= storage power')
    m.res_storage_output_by_power = pyomo.Constraint(
        m.tm, m.sto_tuples, doc='storage output <= storage power')
    m.res_storage_state_by_capacity = pyomo.Constraint(
        m.t, m.sto_tuples, doc='storage content <= storage capacity')
    m.res_storage_power = pyomo.Constraint(
        m.sto_tuples, doc='storage.cap-lo <= storage power <= storage.cap-up')
    m.res_storage_capacity = pyomo.Constraint(
        m.sto_tuples,
        doc='storage.cap-lo <= storage capacity <= storage.cap-up')
    m.res_initial_and_final_storage_state = pyomo.Constraint(
        m.t,
        m.sto_tuples,
        doc='storage content initial == and final >= storage.init * capacity')

    # emissions
    m.res_co2_emission = pyomo.Constraint(
        doc='total co2 emissions <= commodity.co2.max')

    # costs
    m.def_costs = pyomo.Constraint(m.cost_type,
                                   doc='main cost function by cost type')
    m.obj = pyomo.Objective(sense=pyomo.minimize,
                            doc='cost = sum of all cost types')

    return m