def _create(self, group=None): """ Creates the linear constraint for the class:`.nodes.ExtractionTurbine`. Parameters ---------- group : list List of :class:`ExtractionTurbine` objects e.g. group = [extr1, extr2, ...]. """ if group is None: return None m = self.parent_block() for n in group: n.power_heat_index = [ n.conversion_factors[m.es.groups[n._power_output().label]][t] / n.conversion_factors[m.es.groups[n._heat_output().label]][t] for t in m.TIMESTEPS ] def _fuel_consumption_rule(block): """ """ for t in m.TIMESTEPS: for n in group: lhs = m.flow[n._input(), n, t] rhs = ((m.flow[n, n._power_output(), t] + m.flow[n, n._heat_output(), t] * n.power_loss_index[t]) / n.efficiency_condensing) block.fuel_consumption.add((n, t), (lhs == rhs)) self.fuel_consumption = Constraint(group, noruleinit=True) self.fuel_consuption_build = BuildAction(rule=_fuel_consumption_rule) def _power_to_heat_rule(block): """ """ for t in m.TIMESTEPS: for n in group: lhs = m.flow[n, n._power_output(), t] rhs = (m.flow[n, n._heat_output(), t] * n.power_heat_index[t]) block.power_heat.add((n, t), (lhs >= rhs)) self.power_heat = Constraint(group, noruleinit=True) self.power_heat_build = BuildAction(rule=_power_to_heat_rule)
def _create(self, group=None): """Creates the balance constraints for the class:`Bus` block. Parameters ---------- group : list List of oemof bus (b) object for which the bus balance is created e.g. group = [b1, b2, b3, .....] """ if group is None: return None m = self.parent_block() ins = {} outs = {} for n in group: ins[n] = [i for i in n.inputs] outs[n] = [o for o in n.outputs] def _busbalance_rule(block): for t in m.TIMESTEPS: for g in group: lhs = sum(m.flow[i, g, t] for i in ins[g]) rhs = sum(m.flow[g, o, t] for o in outs[g]) expr = (lhs == rhs) # no inflows no outflows yield: 0 == 0 which is True if expr is not True: block.balance.add((g, t), expr) self.balance = Constraint(group, m.TIMESTEPS, noruleinit=True) self.balance_build = BuildAction(rule=_busbalance_rule)
def _create(self, group=None): """ Creates constraints for backpressure turbine. Parameters ---------- group : list List of :class:`BackpressureTurbine` objects e.g. group = [bp1, bp2, ...]. """ if group is None: return None for n in group: n.calculate_coefficients() m = self.parent_block() def _total_efficiency_rule(block): """Rule definition for electrical efficiency relation of backpressure turbine. """ for t in m.TIMESTEPS: for n in group: lhs = (m.flow[n._input(), n, t] * sum(c[0] for c in n.conversion_factors.values())) rhs = sum(m.flow[n, o, t] for o in n.outputs) block.electrical_eff.add((n, t), (lhs == rhs)) self.electrical_eff = Constraint(group, noruleinit=True) self.electrical_efficiency_build = BuildAction( rule=_total_efficiency_rule) def _electrical_efficiency_rule(block): """ """ for t in m.TIMESTEPS: for n in group: lhs = m.flow[n._input(), n, t] rhs = (m.BinaryFlow.status[n, n._power_output(), t] * n.coeff[0] + n.coeff[1] * m.flow[n, n._power_output(), t]) block.electrical_efficiency.add((n, t), lhs == rhs) self.electrical_efficiency = Constraint(group, noruleinit=True) self.electrical_efficiency_build = BuildAction( rule=_electrical_efficiency_rule)
def _create(self, group=None): """ Creates constraints for backpressure turbine. Parameters ---------- group : list List of :class:`BackpressureTurbine` objects e.g. group = [bp1, bp2, ...]. """ if group is None: return None m = self.parent_block() def _electrical_efficiency_rule(block): """Rule definition for electrical efficiency relation of backpressure turbine. """ for t in m.TIMESTEPS: for n in group: lhs = (m.flow[n._input(), n, t] * n.conversion_factors[n._power_output()][t]) rhs = m.flow[n, n._power_output(), t] block.electrical_eff.add((n, t), (lhs == rhs)) self.electrical_eff = Constraint(group, noruleinit=True) self.electrical_efficiency_build = BuildAction( rule=_electrical_efficiency_rule) def _power_to_heat_rule(block): """Rule definition of power to heat relation of backpressure turbine. """ for t in m.TIMESTEPS: for n in group: lhs = (m.flow[n, n._power_output(), t] / n.conversion_factors[n._power_output()][t]) rhs = (m.flow[n, n._heat_output(), t] / n.conversion_factors[n._heat_output()][t]) block.power_heat.add((n, t), (lhs == rhs)) self.power_heat = Constraint(group, noruleinit=True) self.power_heat_build = BuildAction(rule=_power_to_heat_rule)
def _create(self, group=None): """ Creates the linear constraint for the class:`Transformer` block. Parameters ---------- group : list List of oemof.solph.Transformers objects for which the linear relation of inputs and outputs is created e.g. group = [trsf1, trsf2, trsf3, ...]. Note that the relation is created for all existing relations of all inputs and all outputs of the transformer. The components inside the list need to hold an attribute `conversion_factors` of type dict containing the conversion factors for all inputs to outputs. """ if group is None: return None m = self.parent_block() in_flows = {n: [i for i in n.inputs.keys()] for n in group} out_flows = {n: [o for o in n.outputs.keys()] for n in group} self.relation = Constraint( [(n, i, o, t) for t in m.TIMESTEPS for n in group for o in out_flows[n] for i in in_flows[n]], noruleinit=True) def _input_output_relation(block): for t in m.TIMESTEPS: for n in group: for o in out_flows[n]: for i in in_flows[n]: try: lhs = (m.flow[i, n, t] / n.conversion_factors[i][t]) rhs = (m.flow[n, o, t] / n.conversion_factors[o][t]) except ValueError: raise ValueError( "Error in constraint creation", "source: {0}, target: {1}".format( n.label, o.label)) block.relation.add((n, i, o, t), (lhs == rhs)) self.relation_build = BuildAction(rule=_input_output_relation)
def _create(self, group=None): r""" Creates sets, variables and constraints for all standard flows. Parameters ---------- group : list List containing tuples containing flow (f) objects and the associated source (s) and target (t) of flow e.g. groups=[(s1, t1, f1), (s2, t2, f2),..] """ if group is None: return None m = self.parent_block() # ########################## SETS ################################# # set for all flows with an global limit on the flow over time self.SUMMED_MAX_FLOWS = Set( initialize=[(g[0], g[1]) for g in group if g[2].summed_max is not None and g[2].nominal_value is not None]) self.SUMMED_MIN_FLOWS = Set( initialize=[(g[0], g[1]) for g in group if g[2].summed_min is not None and g[2].nominal_value is not None]) self.NEGATIVE_GRADIENT_FLOWS = Set( initialize=[(g[0], g[1]) for g in group if g[2].negative_gradient['ub'][0] is not None]) self.POSITIVE_GRADIENT_FLOWS = Set( initialize=[(g[0], g[1]) for g in group if g[2].positive_gradient['ub'][0] is not None]) self.INTEGER_FLOWS = Set(initialize=[(g[0], g[1]) for g in group if g[2].integer]) # ######################### Variables ################################ self.positive_gradient = Var(self.POSITIVE_GRADIENT_FLOWS, m.TIMESTEPS) self.negative_gradient = Var(self.NEGATIVE_GRADIENT_FLOWS, m.TIMESTEPS) self.integer_flow = Var(self.INTEGER_FLOWS, m.TIMESTEPS, within=NonNegativeIntegers) # set upper bound of gradient variable for i, o, f in group: if m.flows[i, o].positive_gradient['ub'][0] is not None: for t in m.TIMESTEPS: self.positive_gradient[i, o, t].setub( f.positive_gradient['ub'][t] * f.nominal_value) if m.flows[i, o].negative_gradient['ub'][0] is not None: for t in m.TIMESTEPS: self.negative_gradient[i, o, t].setub( f.negative_gradient['ub'][t] * f.nominal_value) # ######################### CONSTRAINTS ############################### def _flow_summed_max_rule(model): """Rule definition for build action of max. sum flow constraint. """ for inp, out in self.SUMMED_MAX_FLOWS: lhs = sum(m.flow[inp, out, ts] * m.timeincrement[ts] for ts in m.TIMESTEPS) rhs = (m.flows[inp, out].summed_max * m.flows[inp, out].nominal_value) self.summed_max.add((inp, out), lhs <= rhs) self.summed_max = Constraint(self.SUMMED_MAX_FLOWS, noruleinit=True) self.summed_max_build = BuildAction(rule=_flow_summed_max_rule) def _flow_summed_min_rule(model): """Rule definition for build action of min. sum flow constraint. """ for inp, out in self.SUMMED_MIN_FLOWS: lhs = sum(m.flow[inp, out, ts] * m.timeincrement[ts] for ts in m.TIMESTEPS) rhs = (m.flows[inp, out].summed_min * m.flows[inp, out].nominal_value) self.summed_min.add((inp, out), lhs >= rhs) self.summed_min = Constraint(self.SUMMED_MIN_FLOWS, noruleinit=True) self.summed_min_build = BuildAction(rule=_flow_summed_min_rule) def _positive_gradient_flow_rule(model): """Rule definition for positive gradient constraint. """ for inp, out in self.POSITIVE_GRADIENT_FLOWS: for ts in m.TIMESTEPS: if ts > 0: lhs = m.flow[inp, out, ts] - m.flow[inp, out, ts - 1] rhs = self.positive_gradient[inp, out, ts] self.positive_gradient_constr.add((inp, out, ts), lhs <= rhs) else: pass # return(Constraint.Skip) self.positive_gradient_constr = Constraint( self.POSITIVE_GRADIENT_FLOWS, m.TIMESTEPS, noruleinit=True) self.positive_gradient_build = BuildAction( rule=_positive_gradient_flow_rule) def _negative_gradient_flow_rule(model): """Rule definition for negative gradient constraint. """ for inp, out in self.NEGATIVE_GRADIENT_FLOWS: for ts in m.TIMESTEPS: if ts > 0: lhs = m.flow[inp, out, ts - 1] - m.flow[inp, out, ts] rhs = self.negative_gradient[inp, out, ts] self.negative_gradient_constr.add((inp, out, ts), lhs <= rhs) else: pass # return(Constraint.Skip) self.negative_gradient_constr = Constraint( self.NEGATIVE_GRADIENT_FLOWS, m.TIMESTEPS, noruleinit=True) self.negative_gradient_build = BuildAction( rule=_negative_gradient_flow_rule) def _integer_flow_rule(block, ii, oi, ti): """Force flow variable to NonNegativeInteger values. """ return self.integer_flow[ii, oi, ti] == m.flow[ii, oi, ti] self.integer_flow_constr = Constraint(self.INTEGER_FLOWS, m.TIMESTEPS, rule=_integer_flow_rule)
def _create(self, group=None): """ Creates the linear constraint for the class:`LinearTransformer` block. Parameters ---------- group : list List of oemof.solph.LinearTransformers (trsf) objects for which the linear relation of inputs and outputs is created e.g. group = [trsf1, trsf2, trsf3, ...]. Note that the relation is created for all existing relations of the inputs and all outputs of the transformer. The components inside the list need to hold a attribute `conversion_factors` of type dict containing the conversion factors from inputs to outputs. """ if group is None: return None m = self.parent_block() for n in group: n.inflow = list(n.inputs)[0] n.label_main_flow = str( [k for k, v in n.conversion_factor_single_flow.items()][0]) n.main_output = [ o for o in n.outputs if n.label_main_flow == o.label ][0] n.tapped_output = [ o for o in n.outputs if n.label_main_flow != o.label ][0] n.conversion_factor_single_flow_sq = ( n.conversion_factor_single_flow[m.es.groups[ n.main_output.label]]) n.flow_relation_index = [ n.conversion_factors[m.es.groups[n.main_output.label]][t] / n.conversion_factors[m.es.groups[n.tapped_output.label]][t] for t in m.TIMESTEPS ] n.main_flow_loss_index = [ (n.conversion_factor_single_flow_sq[t] - n.conversion_factors[m.es.groups[n.main_output.label]][t]) / n.conversion_factors[m.es.groups[n.tapped_output.label]][t] for t in m.TIMESTEPS ] def _input_output_relation_rule(block): """Connection between input, main output and tapped output. """ for t in m.TIMESTEPS: for g in group: lhs = m.flow[g.inflow, g, t] rhs = ((m.flow[g, g.main_output, t] + m.flow[g, g.tapped_output, t] * g.main_flow_loss_index[t]) / g.conversion_factor_single_flow_sq[t]) block.input_output_relation.add((n, t), (lhs == rhs)) self.input_output_relation = Constraint(group, noruleinit=True) self.input_output_relation_build = BuildAction( rule=_input_output_relation_rule) def _out_flow_relation_rule(block): """Relation between main and tapped output in full chp mode. """ for t in m.TIMESTEPS: for g in group: lhs = m.flow[g, g.main_output, t] rhs = (m.flow[g, g.tapped_output, t] * g.flow_relation_index[t]) block.out_flow_relation.add((g, t), (lhs >= rhs)) self.out_flow_relation = Constraint(group, noruleinit=True) self.out_flow_relation_build = BuildAction( rule=_out_flow_relation_rule)