예제 #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
# add number of linear constraints as attribute 
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
def lifetime_utility(model):
    """Abstract representation of our model objective."""
    # extract variables
    c = model.consumption

    # extract parameters
    beta = model.beta
    T = model.periods

    # compute utility
    U = sum(beta**t * flow_utility(model, c[t]) for t in T)

    return U


model.lifetime_utility = pyomo.Objective(rule=lifetime_utility,
                                         sense=pyomo.maximize)

##### Define the model constraints #####


def flow_budget_constraints(model, t):
    """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
예제 #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
예제 #5
0
def HASM(shpfile,
         field,
         cellsize,
         IniRasFile=None,
         reTol=1e-5,
         options='HASM6',
         solver='cplex',
         out_raster=None):
    #get the initial values for a surface#
    if (not options == 'HASM6') and (IniRasFile is None):
        print 'initial values is needed for ' + options
        return 0
    import util
    F0, Zs, RCix, extent, r, c = util.input(shpfile,
                                            field,
                                            cellsize,
                                            IniRasFile=IniRasFile,
                                            bndFile=bndFile)
    print solver, ',', options, ",Beigin " + options + " modelling:" + str(
        time.ctime())
    t1 = time.time()
    #set up HASM model and declare necessary variables
    md = pym.ConcreteModel('HASMmodel')
    k = 0  #declare a model for HASM application
    md.F = pym.Var(range(r), range(c))  #declare a two dimension surface

    #grid where there is a sample, is set with the sample's value directly
    #md.constraints = pym.ConstraintList()
    for i in range(len(Zs)):  #Zs[pts*3], rcIx[pts*2]
        md.F[RCix[i, 0], RCix[i, 1]].value = Zs[i]
        md.F[RCix[i, 0], RCix[i, 1]].fixed = True  #left
        #md.constraints.add(md.F[RCix[i,0],RCix[i,1]] - Zs[i]==0)
    #fix the four boundary side
    if not (options == 'HASM6'):  #boundary values is not fixed in HASM6
        #fix the four boundary side
        for i in range(r):
            md.F[i, 0].value = F0[i, 0]
            md.F[i, 0].fixed = True  #left
            md.F[i, c - 1].value = F0[i, c - 1]
            md.F[i, c - 1].fixed = True  #right
        for j in range(c):
            md.F[0, j].value = F0[0, j]
            md.F[0, j].fixed = True  #bottom
            md.F[r - 1, j].value = F0[r - 1, j]
            md.F[r - 1, j].fixed = True  #up
    rere0 = 1e38
    print solver, ',', r, '*', c, ', reTol=', reTol
    while (1):  #iterate until HASM meet the precision
        t11 = time.time()
        if k > 0: md.del_component('smooth')
        md.smooth = pym.Objective(expr=H456_rule(md, F0, cellsize, options),
                                  sense=pym.minimize)
        #md.smooth.pprint()
        # Create a solver plugin, other solvers can also be tested here
        optimizer = opt.SolverFactory(solver)
        instance = md.create()
        results = optimizer.solve(instance)
        instance.load(results)
        F1 = model2matrix(md, r, c)
        rere = ((F1 - F0)**2).sum() / (F0**2).sum()
        k += 1  #relative residuals
        print k, ',relative Residual||x(n+1)-x(n)||2/||x(n)||2=,', rere, ', ', np.round(
            time.time() - t11), ' seconds'
        if rere > rere0:
            print 'Divergence happened, previous results returned.'
            print '#' * 50
            F1 = F0
            break
        else:
            rere0 = rere

        if rere <= reTol: break
        else: F0 = F1

    return F1, extent
예제 #6
0
 def add_objective(self, expression, sense=pyomo.minimize):
     '''add an objective to the problem'''
     self._model.objective = pyomo.Objective(name='objective',
                                             rule=expression,
                                             sense=sense)
예제 #7
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