Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #######################################################################################
- # Combined Method
- class SinkDSMCombinedBlock(SimpleBlock):
- r"""Block for the linear relation of a DSM component and an electrical bus
- Note: This component is under development. Use it with care.
- **The following constraints are created for method=delay:**
- .. math::
- &
- (1) \quad; flow_{t} = demand_{t} + DSM_{t}^{up} - \sum_{tt=t-L}^{t+L} DSM_{t,tt}^{do} \quad \forall t \\
- &
- (2) \quad; DSM_{t}^{up} = \sum_{tt=t-L}^{t+L} DSM_{t,tt}^{do} \quad \forall t \\
- &
- (3) \quad; DSM_{t}^{up} \leq C_{t}^{up} \quad \forall t \\
- &
- (4) \quad; /sum_{t=tt-L}^{tt+L} DSM_{t,tt}^{do} \leq C_{t}^{do] \quad \forall tt \\
- &
- (5) \quad; DSM_{tt}^{up} + \sum_{t=tt-L}^{tt+L} DSM_{t,tt}^{do} \leq max \{ C_{t}^{up},C_{t}^{do} \} \quad \forall tt \\
- &
- **Table: Symbols and attribute names of variables and parameters**
- .. csv-table:: Variables (V) and Parameters (P)
- :header: "symbol", "attribute", "type", "explanation"
- :widths: 1, 1, 1, 1
- ":math:`DSM_{t}^{up}` ", ":py:obj:`DSMdo[g,t,tt]` ", "V", "DSM up shift (additional load)"
- ":math:`DSM_{t,tt}^{do}` ", ":py:obj:`DSMup[g,t]`", "V", "DSM down shift (less load)"
- ":math:`flow_{t}` ", ":py:obj:`flow[g,t]`", "V", "production at electrical bus"
- ":math:`L` ", ":py:obj:`delay_time`", "P", "delay time for load shift"
- ":math:`demand_{t} ` ", ":py:obj:`demand[t]`", "P", "electrical demand"
- ":math:`C_{t}^{do} ` ", ":py:obj:`c_do[tt]`", "P", "DSM down shift capacity"
- ":math:`C_{t}^{up} ` ", ":py:obj:`c_up[tt]`", "P", "DSM up shift capacity"
- """
- CONSTRAINT_GROUP = True
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- def _create(self, group=None):
- if group is None:
- return None
- m = self.parent_block()
- # for all DSM components get inflow from bus_elec
- for n in group:
- n.inflow = list(n.inputs)[0]
- """ TODO: incomplete interval
- if (m.TIMESTEPS._bounds[1] % self.shift_interval) > 0:
- raise ValueError('Only complete intervals can be optimized. Change number of timesteps')
- else:
- """
- # ************* SETS *********************************
- # Set of DSM Components
- self.DSM = Set(initialize=[g for g in group])
- # ************* VARIABLES *****************************
- # Variable load shift down (MWh)
- self.DSMdo = Var(self.DSM, m.TIMESTEPS, m.TIMESTEPS, initialize=0, within=NonNegativeReals)
- # Variable load shift up(MWh)
- self.DSMup = Var(self.DSM, m.TIMESTEPS, initialize=0, within=NonNegativeReals)
- # ************* CONSTRAINTS *****************************
- # Demand Production Relation
- def _input_output_relation_rule(block):
- """
- Relation between input data and pyomo variables. The actual demand after DSM.
- Generator Production == Demand +- DSM
- """
- for t in m.TIMESTEPS:
- for g in group:
- shft_intvl = g.shift_interval
- intvl_start = (t // shft_intvl) * shft_intvl
- intvl_end = (t // shft_intvl + 1) * shft_intvl
- # ##### full interval
- if (t // shft_intvl) < (m.TIMESTEPS._bounds[1] // shft_intvl):
- # first time steps a day: 0, 1, ... delay-time
- if (t % shft_intvl) < g.delay_time:
- # Generator loads from bus
- lhs = m.flow[g.inflow, g, t]
- # Demand +- DSM
- rhs = g.demand[t] + self.DSMup[g, t] - sum(
- self.DSMdo[g, tt, t] for tt in range(intvl_start, t + g.delay_time + 1))
- # add constraint
- block.input_output_relation.add((g, t), (lhs == rhs))
- # main use case
- elif (intvl_start + g.delay_time) <= t < (intvl_end - g.delay_time):
- # Generator loads from bus
- lhs = m.flow[g.inflow, g, t]
- # Demand +- DSM
- rhs = g.demand[t] + self.DSMup[g, t] - sum(
- self.DSMdo[g, tt, t] for tt in range(t - g.delay_time, t + g.delay_time + 1))
- # add constraint
- block.input_output_relation.add((g, t), (lhs == rhs))
- # last time steps: end - delay time
- else:
- # Generator loads from bus
- lhs = m.flow[g.inflow, g, t]
- # Demand +- DSM
- rhs = g.demand[t] + self.DSMup[g, t] - sum(
- self.DSMdo[g, tt, t] for tt in range(t - g.delay_time, intvl_end))
- block.input_output_relation.add((g, t), (lhs == rhs))
- # ##### incomplete interval
- else:
- # first time steps: 0 + delay time
- if (t % shft_intvl) < g.delay_time:
- # Generator loads from bus
- lhs = m.flow[g.inflow, g, t]
- # Demand +- DSM
- rhs = g.demand[t] + self.DSMup[g, t] - sum(
- self.DSMdo[g, tt, t] for tt in range(intvl_start, t + g.delay_time + 1))
- # add constraint
- block.input_output_relation.add((g, t), (lhs == rhs))
- # main use case
- elif (intvl_start + g.delay_time) <= t <= (m.TIMESTEPS._bounds[1] - g.delay_time): ## evtl +1
- # Generator loads from bus
- lhs = m.flow[g.inflow, g, t]
- # Demand +- DSM
- rhs = g.demand[t] + self.DSMup[g, t] - sum(
- self.DSMdo[g, tt, t] for tt in range(t - g.delay_time, t + g.delay_time + 1))
- # add constraint
- block.input_output_relation.add((g, t), (lhs == rhs))
- # last time steps: end - delay time
- else:
- # Generator loads from bus
- lhs = m.flow[g.inflow, g, t]
- # Demand +- DSM
- rhs = g.demand[t] + self.DSMup[g, t] - sum(
- self.DSMdo[g, tt, t] for tt in range(t - g.delay_time, m.TIMESTEPS._bounds[1] + 1))
- # add constraint
- block.input_output_relation.add((g, t), (lhs == rhs))
- self.input_output_relation = Constraint(group, m.TIMESTEPS, noruleinit=True)
- self.input_output_relation_build = BuildAction(rule=_input_output_relation_rule)
- # Equation 7
- def dsmupdo_constraint_rule(block):
- '''
- Equation 7 by Zerrahn, Schill:
- Every upward load shift has to be compensated by downward load shifts in a defined time frame.
- Slightly modified equations for the first and last time steps due to variable initialization.
- '''
- for t in m.TIMESTEPS:
- for g in group:
- shft_intvl = g.shift_interval
- intvl_start = (t // shft_intvl) * shft_intvl
- intvl_end = (t // shft_intvl + 1) * shft_intvl
- # ##### full interval
- if (t // shft_intvl) < (m.TIMESTEPS._bounds[1] // shft_intvl):
- # first time steps: interval start + delay time
- if (t % shft_intvl) < g.delay_time:
- # DSM up
- lhs = self.DSMup[g, t]
- # DSM down
- rhs = sum(self.DSMdo[g, t, tt] for tt in range(
- intvl_start, (t + g.delay_time + 1)))
- # add constraint
- block.dsmupdo_constraint.add((g, t), (lhs == rhs))
- # main use case
- elif (intvl_start + g.delay_time) <= t < (intvl_end - g.delay_time):
- # DSM up
- lhs = self.DSMup[g, t]
- # DSM down
- rhs = sum(self.DSMdo[g, t, tt] for tt in range(t - g.delay_time, t + g.delay_time + 1))
- # add constraint
- block.dsmupdo_constraint.add((g, t), (lhs == rhs))
- # last time steps: interval end - delay time
- else:
- # DSM up
- lhs = self.DSMup[g, t]
- # DSM down
- rhs = sum(self.DSMdo[g, t, tt] for tt in range(t - g.delay_time, intvl_end))
- # add constraint
- block.dsmupdo_constraint.add((g, t), (lhs == rhs))
- # ##### incomplete interval
- else:
- # first time steps of incomplete interval: interval start + delay time
- if (t % shft_intvl) < g.delay_time:
- # DSM up
- lhs = self.DSMup[g, t]
- # DSM down
- rhs = sum(self.DSMdo[g, t, tt] for tt in range(intvl_start, t + g.delay_time + 1))
- # add constraint
- block.dsmupdo_constraint.add((g, t), (lhs == rhs))
- # main use case
- elif (intvl_start + g.delay_time) <= t <= (m.TIMESTEPS._bounds[1] - g.delay_time):
- # DSM up
- lhs = self.DSMup[g, t]
- # DSM down
- rhs = sum(self.DSMdo[g, t, tt] for tt in range(t - g.delay_time, t + g.delay_time + 1))
- # add constraint
- block.dsmupdo_constraint.add((g, t), (lhs == rhs))
- # last time steps: end - delay time
- else:
- # DSM up
- lhs = self.DSMup[g, t]
- # DSM down
- rhs = sum(
- self.DSMdo[g, t, tt] for tt in range(t - g.delay_time, m.TIMESTEPS._bounds[1] + 1))
- # add constraint
- block.dsmupdo_constraint.add((g, t), (lhs == rhs))
- self.dsmupdo_constraint = Constraint(group, m.TIMESTEPS, noruleinit=True)
- self.dsmupdo_constraint_build = BuildAction(rule=dsmupdo_constraint_rule)
- # Equation 8
- def dsmup_constraint_rule(block):
- '''
- Equation 8 by Zerrahn, Schill:
- Realised upward load shift at time t has to be smaller than upward DSM capacity at time t.
- '''
- for t in m.TIMESTEPS:
- for g in group:
- # DSM up
- lhs = self.DSMup[g, t]
- # Capacity DSMup
- rhs = g.c_up[t]
- # add constraint
- block.dsmup_constraint.add((g, t), (lhs <= rhs))
- self.dsmup_constraint = Constraint(group, m.TIMESTEPS, noruleinit=True)
- self.dsmup_constraint_build = BuildAction(rule=dsmup_constraint_rule)
- # Equation 9
- def dsmdo_constraint_rule(block):
- '''
- Equation 9 by Zerrahn, Schill:
- Realised downward load shift at time t has to be smaller than downward DSM capacity at time t.
- '''
- for tt in m.TIMESTEPS:
- for g in group:
- shft_intvl = g.shift_interval
- intvl_start = (tt // shft_intvl) * shft_intvl
- intvl_end = (tt // shft_intvl + 1) * shft_intvl
- # ##### full interval
- if (tt // shft_intvl) < (m.TIMESTEPS._bounds[1] // shft_intvl):
- # first times steps: 0 + delay time
- if (tt % shft_intvl) < g.delay_time:
- # DSM down
- lhs = sum(self.DSMdo[g, t, tt] for t in range(intvl_start, tt + g.delay_time + 1))
- # Capacity DSM down
- rhs = g.c_do[tt]
- # add constraint
- block.dsmdo_constraint.add((g, tt), (lhs <= rhs))
- # main use case
- elif (intvl_start + g.delay_time) <= tt < (intvl_end - g.delay_time):
- # DSM down
- lhs = sum(self.DSMdo[g, t, tt] for t in range(tt - g.delay_time, tt + g.delay_time + 1))
- # Capacity DSM down
- rhs = g.c_do[tt]
- # add constraint
- block.dsmdo_constraint.add((g, tt), (lhs <= rhs))
- # last time steps: end - delay time
- else:
- # DSM down
- lhs = sum(self.DSMdo[g, t, tt] for t in range(tt - g.delay_time, intvl_end))
- # Capacity DSM down
- rhs = g.c_do[tt]
- # add constraint
- block.dsmdo_constraint.add((g, tt), (lhs <= rhs))
- # ##### incomplete interval
- else:
- # first time steps: 0 + delay time
- if (tt % shft_intvl) < g.delay_time:
- # DSM down
- lhs = sum(self.DSMdo[g, t, tt] for t in range(intvl_start, tt + g.delay_time + 1))
- # Capacity DSM down
- rhs = g.c_do[tt]
- # add constraint
- block.dsmdo_constraint.add((g, tt), (lhs <= rhs))
- # main use case
- elif intvl_start + g.delay_time <= tt <= (m.TIMESTEPS._bounds[1] - g.delay_time):
- # DSM down
- lhs = sum(self.DSMdo[g, t, tt] for t in range(tt - g.delay_time, tt + g.delay_time + 1))
- # Capacity DSM down
- rhs = g.c_do[tt]
- # add constraint
- block.dsmdo_constraint.add((g, tt), (lhs <= rhs))
- # last time steps: end - delay time
- else:
- # DSM down
- lhs = sum(self.DSMdo[g, t, tt] for t in range(tt - g.delay_time, m.TIMESTEPS._bounds[1] +1))
- # Capacity DSM down
- rhs = g.c_do[tt]
- # add constraint
- block.dsmdo_constraint.add((g, tt), (lhs <= rhs))
- self.dsmdo_constraint = Constraint(group, m.TIMESTEPS, noruleinit=True)
- self.dsmdo_constraint_build = BuildAction(rule=dsmdo_constraint_rule)
- # Equation 10
- def C2_constraint_rule(block):
- '''
- Equation 10 by Zerrahn, Schill:
- The realised DSM up or down at time T has to be smaller than the maximum downward or upward capacity
- at time T. Therefore in total each DSM unit can only be shifted up OR down.
- '''
- for tt in m.TIMESTEPS:
- for g in group:
- shft_intvl = g.shift_interval
- intvl_start = (tt // shft_intvl) * shft_intvl
- intvl_end = (tt // shft_intvl + 1) * shft_intvl
- # ##### full interval
- if (tt // shft_intvl) < (m.TIMESTEPS._bounds[1] // shft_intvl):
- # first times steps: 0 + delay time
- if (tt % shft_intvl) < g.delay_time:
- # DSM up/down
- lhs = self.DSMup[g, tt] + sum(self.DSMdo[g, t, tt] for t in range(intvl_start, tt + g.delay_time + 1))
- # max capacity at tt
- rhs = max(g.c_up[tt], g.c_do[tt])
- # add constraint
- block.C2_constraint.add((g, tt), (lhs <= rhs))
- elif (intvl_start + g.delay_time) <= tt < (intvl_end - g.delay_time):
- # DSM up/down
- lhs = self.DSMup[g, tt] + sum(
- self.DSMdo[g, t, tt] for t in range(tt - g.delay_time, tt + g.delay_time + 1))
- # max capacity at tt
- rhs = max(g.c_up[tt], g.c_do[tt])
- # add constraint
- block.C2_constraint.add((g, tt), (lhs <= rhs))
- else:
- # DSM up/down
- lhs = self.DSMup[g, tt] + sum(
- self.DSMdo[g, t, tt] for t in range(tt - g.delay_time, intvl_end))
- # max capacity at tt
- rhs = max(g.c_up[tt], g.c_do[tt])
- # add constraint
- block.C2_constraint.add((g, tt), (lhs <= rhs))
- # ##### incomplete interval
- else:
- # first times steps: 0 + delay time
- if (tt % shft_intvl) < g.delay_time:
- # DSM up/down
- lhs = self.DSMup[g, tt] + sum(self.DSMdo[g, t, tt] for t in range(intvl_start, tt + g.delay_time + 1))
- # max capacity at tt
- rhs = max(g.c_up[tt], g.c_do[tt])
- # add constraint
- block.C2_constraint.add((g, tt), (lhs <= rhs))
- elif (intvl_start + g.delay_time) <= tt <= (m.TIMESTEPS._bounds[1] - g.delay_time):
- # DSM up/down
- lhs = self.DSMup[g, tt] + sum(
- self.DSMdo[g, t, tt] for t in range(tt - g.delay_time, tt + g.delay_time + 1))
- # max capacity at tt
- rhs = max(g.c_up[tt], g.c_do[tt])
- # add constraint
- block.C2_constraint.add((g, tt), (lhs <= rhs))
- else:
- # DSM up/down
- lhs = self.DSMup[g, tt] + sum(
- self.DSMdo[g, t, tt] for t in range(tt - g.delay_time, m.TIMESTEPS._bounds[1] + 1))
- # max capacity at tt
- rhs = max(g.c_up[tt], g.c_do[tt])
- # add constraint
- block.C2_constraint.add((g, tt), (lhs <= rhs))
- self.C2_constraint = Constraint(group, m.TIMESTEPS, noruleinit=True)
- self.C2_constraint_build = BuildAction(rule=C2_constraint_rule)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement