Advertisement
Guest User

Untitled

a guest
Oct 13th, 2019
139
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 19.31 KB | None | 0 0
  1. #######################################################################################
  2. # Combined Method
  3.  
  4.  
  5. class SinkDSMCombinedBlock(SimpleBlock):
  6. r"""Block for the linear relation of a DSM component and an electrical bus
  7.  
  8. Note: This component is under development. Use it with care.
  9.  
  10. **The following constraints are created for method=delay:**
  11.  
  12. .. math::
  13. &
  14. (1) \quad; flow_{t} = demand_{t} + DSM_{t}^{up} - \sum_{tt=t-L}^{t+L} DSM_{t,tt}^{do} \quad \forall t \\
  15. &
  16. (2) \quad; DSM_{t}^{up} = \sum_{tt=t-L}^{t+L} DSM_{t,tt}^{do} \quad \forall t \\
  17. &
  18. (3) \quad; DSM_{t}^{up} \leq C_{t}^{up} \quad \forall t \\
  19. &
  20. (4) \quad; /sum_{t=tt-L}^{tt+L} DSM_{t,tt}^{do} \leq C_{t}^{do] \quad \forall tt \\
  21. &
  22. (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 \\
  23. &
  24.  
  25. **Table: Symbols and attribute names of variables and parameters**
  26.  
  27. .. csv-table:: Variables (V) and Parameters (P)
  28. :header: "symbol", "attribute", "type", "explanation"
  29. :widths: 1, 1, 1, 1
  30.  
  31. ":math:`DSM_{t}^{up}` ", ":py:obj:`DSMdo[g,t,tt]` ", "V", "DSM up shift (additional load)"
  32. ":math:`DSM_{t,tt}^{do}` ", ":py:obj:`DSMup[g,t]`", "V", "DSM down shift (less load)"
  33. ":math:`flow_{t}` ", ":py:obj:`flow[g,t]`", "V", "production at electrical bus"
  34. ":math:`L` ", ":py:obj:`delay_time`", "P", "delay time for load shift"
  35. ":math:`demand_{t} ` ", ":py:obj:`demand[t]`", "P", "electrical demand"
  36. ":math:`C_{t}^{do} ` ", ":py:obj:`c_do[tt]`", "P", "DSM down shift capacity"
  37. ":math:`C_{t}^{up} ` ", ":py:obj:`c_up[tt]`", "P", "DSM up shift capacity"
  38.  
  39. """
  40. CONSTRAINT_GROUP = True
  41.  
  42. def __init__(self, *args, **kwargs):
  43. super().__init__(*args, **kwargs)
  44.  
  45. def _create(self, group=None):
  46. if group is None:
  47. return None
  48.  
  49. m = self.parent_block()
  50.  
  51. # for all DSM components get inflow from bus_elec
  52. for n in group:
  53. n.inflow = list(n.inputs)[0]
  54.  
  55. """ TODO: incomplete interval
  56.  
  57. if (m.TIMESTEPS._bounds[1] % self.shift_interval) > 0:
  58. raise ValueError('Only complete intervals can be optimized. Change number of timesteps')
  59. else:
  60. """
  61.  
  62.  
  63. # ************* SETS *********************************
  64.  
  65. # Set of DSM Components
  66. self.DSM = Set(initialize=[g for g in group])
  67.  
  68. # ************* VARIABLES *****************************
  69.  
  70. # Variable load shift down (MWh)
  71. self.DSMdo = Var(self.DSM, m.TIMESTEPS, m.TIMESTEPS, initialize=0, within=NonNegativeReals)
  72.  
  73. # Variable load shift up(MWh)
  74. self.DSMup = Var(self.DSM, m.TIMESTEPS, initialize=0, within=NonNegativeReals)
  75.  
  76. # ************* CONSTRAINTS *****************************
  77.  
  78. # Demand Production Relation
  79. def _input_output_relation_rule(block):
  80. """
  81. Relation between input data and pyomo variables. The actual demand after DSM.
  82. Generator Production == Demand +- DSM
  83. """
  84. for t in m.TIMESTEPS:
  85. for g in group:
  86.  
  87. shft_intvl = g.shift_interval
  88. intvl_start = (t // shft_intvl) * shft_intvl
  89. intvl_end = (t // shft_intvl + 1) * shft_intvl
  90.  
  91. # ##### full interval
  92.  
  93. if (t // shft_intvl) < (m.TIMESTEPS._bounds[1] // shft_intvl):
  94.  
  95. # first time steps a day: 0, 1, ... delay-time
  96. if (t % shft_intvl) < g.delay_time:
  97.  
  98. # Generator loads from bus
  99. lhs = m.flow[g.inflow, g, t]
  100. # Demand +- DSM
  101. rhs = g.demand[t] + self.DSMup[g, t] - sum(
  102. self.DSMdo[g, tt, t] for tt in range(intvl_start, t + g.delay_time + 1))
  103. # add constraint
  104. block.input_output_relation.add((g, t), (lhs == rhs))
  105.  
  106. # main use case
  107. elif (intvl_start + g.delay_time) <= t < (intvl_end - g.delay_time):
  108.  
  109. # Generator loads from bus
  110. lhs = m.flow[g.inflow, g, t]
  111. # Demand +- DSM
  112. rhs = g.demand[t] + self.DSMup[g, t] - sum(
  113. self.DSMdo[g, tt, t] for tt in range(t - g.delay_time, t + g.delay_time + 1))
  114. # add constraint
  115. block.input_output_relation.add((g, t), (lhs == rhs))
  116.  
  117. # last time steps: end - delay time
  118. else:
  119. # Generator loads from bus
  120. lhs = m.flow[g.inflow, g, t]
  121. # Demand +- DSM
  122. rhs = g.demand[t] + self.DSMup[g, t] - sum(
  123. self.DSMdo[g, tt, t] for tt in range(t - g.delay_time, intvl_end))
  124. block.input_output_relation.add((g, t), (lhs == rhs))
  125.  
  126. # ##### incomplete interval
  127. else:
  128. # first time steps: 0 + delay time
  129. if (t % shft_intvl) < g.delay_time:
  130.  
  131. # Generator loads from bus
  132. lhs = m.flow[g.inflow, g, t]
  133. # Demand +- DSM
  134. rhs = g.demand[t] + self.DSMup[g, t] - sum(
  135. self.DSMdo[g, tt, t] for tt in range(intvl_start, t + g.delay_time + 1))
  136. # add constraint
  137. block.input_output_relation.add((g, t), (lhs == rhs))
  138.  
  139. # main use case
  140. elif (intvl_start + g.delay_time) <= t <= (m.TIMESTEPS._bounds[1] - g.delay_time): ## evtl +1
  141.  
  142. # Generator loads from bus
  143. lhs = m.flow[g.inflow, g, t]
  144. # Demand +- DSM
  145. rhs = g.demand[t] + self.DSMup[g, t] - sum(
  146. self.DSMdo[g, tt, t] for tt in range(t - g.delay_time, t + g.delay_time + 1))
  147. # add constraint
  148. block.input_output_relation.add((g, t), (lhs == rhs))
  149.  
  150. # last time steps: end - delay time
  151. else:
  152. # Generator loads from bus
  153. lhs = m.flow[g.inflow, g, t]
  154. # Demand +- DSM
  155. rhs = g.demand[t] + self.DSMup[g, t] - sum(
  156. self.DSMdo[g, tt, t] for tt in range(t - g.delay_time, m.TIMESTEPS._bounds[1] + 1))
  157. # add constraint
  158. block.input_output_relation.add((g, t), (lhs == rhs))
  159.  
  160. self.input_output_relation = Constraint(group, m.TIMESTEPS, noruleinit=True)
  161. self.input_output_relation_build = BuildAction(rule=_input_output_relation_rule)
  162.  
  163. # Equation 7
  164. def dsmupdo_constraint_rule(block):
  165. '''
  166. Equation 7 by Zerrahn, Schill:
  167. Every upward load shift has to be compensated by downward load shifts in a defined time frame.
  168. Slightly modified equations for the first and last time steps due to variable initialization.
  169. '''
  170.  
  171. for t in m.TIMESTEPS:
  172. for g in group:
  173.  
  174. shft_intvl = g.shift_interval
  175. intvl_start = (t // shft_intvl) * shft_intvl
  176. intvl_end = (t // shft_intvl + 1) * shft_intvl
  177.  
  178. # ##### full interval
  179.  
  180. if (t // shft_intvl) < (m.TIMESTEPS._bounds[1] // shft_intvl):
  181.  
  182. # first time steps: interval start + delay time
  183. if (t % shft_intvl) < g.delay_time:
  184.  
  185. # DSM up
  186. lhs = self.DSMup[g, t]
  187. # DSM down
  188. rhs = sum(self.DSMdo[g, t, tt] for tt in range(
  189. intvl_start, (t + g.delay_time + 1)))
  190. # add constraint
  191. block.dsmupdo_constraint.add((g, t), (lhs == rhs))
  192.  
  193. # main use case
  194. elif (intvl_start + g.delay_time) <= t < (intvl_end - g.delay_time):
  195.  
  196. # DSM up
  197. lhs = self.DSMup[g, t]
  198. # DSM down
  199. rhs = sum(self.DSMdo[g, t, tt] for tt in range(t - g.delay_time, t + g.delay_time + 1))
  200. # add constraint
  201. block.dsmupdo_constraint.add((g, t), (lhs == rhs))
  202.  
  203. # last time steps: interval end - delay time
  204. else:
  205.  
  206. # DSM up
  207. lhs = self.DSMup[g, t]
  208. # DSM down
  209. rhs = sum(self.DSMdo[g, t, tt] for tt in range(t - g.delay_time, intvl_end))
  210. # add constraint
  211. block.dsmupdo_constraint.add((g, t), (lhs == rhs))
  212.  
  213. # ##### incomplete interval
  214. else:
  215. # first time steps of incomplete interval: interval start + delay time
  216. if (t % shft_intvl) < g.delay_time:
  217.  
  218. # DSM up
  219. lhs = self.DSMup[g, t]
  220. # DSM down
  221. rhs = sum(self.DSMdo[g, t, tt] for tt in range(intvl_start, t + g.delay_time + 1))
  222. # add constraint
  223. block.dsmupdo_constraint.add((g, t), (lhs == rhs))
  224.  
  225. # main use case
  226. elif (intvl_start + g.delay_time) <= t <= (m.TIMESTEPS._bounds[1] - g.delay_time):
  227.  
  228. # DSM up
  229. lhs = self.DSMup[g, t]
  230. # DSM down
  231. rhs = sum(self.DSMdo[g, t, tt] for tt in range(t - g.delay_time, t + g.delay_time + 1))
  232. # add constraint
  233. block.dsmupdo_constraint.add((g, t), (lhs == rhs))
  234.  
  235. # last time steps: end - delay time
  236. else:
  237.  
  238. # DSM up
  239. lhs = self.DSMup[g, t]
  240. # DSM down
  241. rhs = sum(
  242. self.DSMdo[g, t, tt] for tt in range(t - g.delay_time, m.TIMESTEPS._bounds[1] + 1))
  243. # add constraint
  244. block.dsmupdo_constraint.add((g, t), (lhs == rhs))
  245.  
  246. self.dsmupdo_constraint = Constraint(group, m.TIMESTEPS, noruleinit=True)
  247. self.dsmupdo_constraint_build = BuildAction(rule=dsmupdo_constraint_rule)
  248.  
  249. # Equation 8
  250. def dsmup_constraint_rule(block):
  251. '''
  252. Equation 8 by Zerrahn, Schill:
  253. Realised upward load shift at time t has to be smaller than upward DSM capacity at time t.
  254. '''
  255.  
  256. for t in m.TIMESTEPS:
  257. for g in group:
  258. # DSM up
  259. lhs = self.DSMup[g, t]
  260. # Capacity DSMup
  261. rhs = g.c_up[t]
  262. # add constraint
  263. block.dsmup_constraint.add((g, t), (lhs <= rhs))
  264.  
  265. self.dsmup_constraint = Constraint(group, m.TIMESTEPS, noruleinit=True)
  266. self.dsmup_constraint_build = BuildAction(rule=dsmup_constraint_rule)
  267.  
  268. # Equation 9
  269. def dsmdo_constraint_rule(block):
  270. '''
  271. Equation 9 by Zerrahn, Schill:
  272. Realised downward load shift at time t has to be smaller than downward DSM capacity at time t.
  273. '''
  274.  
  275. for tt in m.TIMESTEPS:
  276. for g in group:
  277.  
  278. shft_intvl = g.shift_interval
  279. intvl_start = (tt // shft_intvl) * shft_intvl
  280. intvl_end = (tt // shft_intvl + 1) * shft_intvl
  281.  
  282. # ##### full interval
  283.  
  284. if (tt // shft_intvl) < (m.TIMESTEPS._bounds[1] // shft_intvl):
  285.  
  286. # first times steps: 0 + delay time
  287. if (tt % shft_intvl) < g.delay_time:
  288.  
  289. # DSM down
  290. lhs = sum(self.DSMdo[g, t, tt] for t in range(intvl_start, tt + g.delay_time + 1))
  291. # Capacity DSM down
  292. rhs = g.c_do[tt]
  293. # add constraint
  294. block.dsmdo_constraint.add((g, tt), (lhs <= rhs))
  295.  
  296. # main use case
  297. elif (intvl_start + g.delay_time) <= tt < (intvl_end - g.delay_time):
  298.  
  299. # DSM down
  300. lhs = sum(self.DSMdo[g, t, tt] for t in range(tt - g.delay_time, tt + g.delay_time + 1))
  301. # Capacity DSM down
  302. rhs = g.c_do[tt]
  303. # add constraint
  304. block.dsmdo_constraint.add((g, tt), (lhs <= rhs))
  305.  
  306. # last time steps: end - delay time
  307. else:
  308.  
  309. # DSM down
  310. lhs = sum(self.DSMdo[g, t, tt] for t in range(tt - g.delay_time, intvl_end))
  311. # Capacity DSM down
  312. rhs = g.c_do[tt]
  313. # add constraint
  314. block.dsmdo_constraint.add((g, tt), (lhs <= rhs))
  315.  
  316. # ##### incomplete interval
  317. else:
  318. # first time steps: 0 + delay time
  319. if (tt % shft_intvl) < g.delay_time:
  320.  
  321. # DSM down
  322. lhs = sum(self.DSMdo[g, t, tt] for t in range(intvl_start, tt + g.delay_time + 1))
  323. # Capacity DSM down
  324. rhs = g.c_do[tt]
  325. # add constraint
  326. block.dsmdo_constraint.add((g, tt), (lhs <= rhs))
  327.  
  328. # main use case
  329. elif intvl_start + g.delay_time <= tt <= (m.TIMESTEPS._bounds[1] - g.delay_time):
  330.  
  331. # DSM down
  332. lhs = sum(self.DSMdo[g, t, tt] for t in range(tt - g.delay_time, tt + g.delay_time + 1))
  333. # Capacity DSM down
  334. rhs = g.c_do[tt]
  335. # add constraint
  336. block.dsmdo_constraint.add((g, tt), (lhs <= rhs))
  337.  
  338. # last time steps: end - delay time
  339. else:
  340.  
  341. # DSM down
  342. lhs = sum(self.DSMdo[g, t, tt] for t in range(tt - g.delay_time, m.TIMESTEPS._bounds[1] +1))
  343. # Capacity DSM down
  344. rhs = g.c_do[tt]
  345. # add constraint
  346. block.dsmdo_constraint.add((g, tt), (lhs <= rhs))
  347.  
  348.  
  349.  
  350.  
  351. self.dsmdo_constraint = Constraint(group, m.TIMESTEPS, noruleinit=True)
  352. self.dsmdo_constraint_build = BuildAction(rule=dsmdo_constraint_rule)
  353.  
  354. # Equation 10
  355. def C2_constraint_rule(block):
  356. '''
  357. Equation 10 by Zerrahn, Schill:
  358. The realised DSM up or down at time T has to be smaller than the maximum downward or upward capacity
  359. at time T. Therefore in total each DSM unit can only be shifted up OR down.
  360. '''
  361.  
  362. for tt in m.TIMESTEPS:
  363. for g in group:
  364.  
  365. shft_intvl = g.shift_interval
  366. intvl_start = (tt // shft_intvl) * shft_intvl
  367. intvl_end = (tt // shft_intvl + 1) * shft_intvl
  368.  
  369.  
  370. # ##### full interval
  371.  
  372. if (tt // shft_intvl) < (m.TIMESTEPS._bounds[1] // shft_intvl):
  373.  
  374. # first times steps: 0 + delay time
  375. if (tt % shft_intvl) < g.delay_time:
  376.  
  377. # DSM up/down
  378. lhs = self.DSMup[g, tt] + sum(self.DSMdo[g, t, tt] for t in range(intvl_start, tt + g.delay_time + 1))
  379. # max capacity at tt
  380. rhs = max(g.c_up[tt], g.c_do[tt])
  381. # add constraint
  382. block.C2_constraint.add((g, tt), (lhs <= rhs))
  383.  
  384. elif (intvl_start + g.delay_time) <= tt < (intvl_end - g.delay_time):
  385.  
  386. # DSM up/down
  387. lhs = self.DSMup[g, tt] + sum(
  388. self.DSMdo[g, t, tt] for t in range(tt - g.delay_time, tt + g.delay_time + 1))
  389. # max capacity at tt
  390. rhs = max(g.c_up[tt], g.c_do[tt])
  391. # add constraint
  392. block.C2_constraint.add((g, tt), (lhs <= rhs))
  393.  
  394. else:
  395.  
  396. # DSM up/down
  397. lhs = self.DSMup[g, tt] + sum(
  398. self.DSMdo[g, t, tt] for t in range(tt - g.delay_time, intvl_end))
  399. # max capacity at tt
  400. rhs = max(g.c_up[tt], g.c_do[tt])
  401. # add constraint
  402. block.C2_constraint.add((g, tt), (lhs <= rhs))
  403.  
  404. # ##### incomplete interval
  405. else:
  406.  
  407. # first times steps: 0 + delay time
  408. if (tt % shft_intvl) < g.delay_time:
  409.  
  410. # DSM up/down
  411. lhs = self.DSMup[g, tt] + sum(self.DSMdo[g, t, tt] for t in range(intvl_start, tt + g.delay_time + 1))
  412. # max capacity at tt
  413. rhs = max(g.c_up[tt], g.c_do[tt])
  414. # add constraint
  415. block.C2_constraint.add((g, tt), (lhs <= rhs))
  416.  
  417. elif (intvl_start + g.delay_time) <= tt <= (m.TIMESTEPS._bounds[1] - g.delay_time):
  418.  
  419. # DSM up/down
  420. lhs = self.DSMup[g, tt] + sum(
  421. self.DSMdo[g, t, tt] for t in range(tt - g.delay_time, tt + g.delay_time + 1))
  422. # max capacity at tt
  423. rhs = max(g.c_up[tt], g.c_do[tt])
  424. # add constraint
  425. block.C2_constraint.add((g, tt), (lhs <= rhs))
  426.  
  427. else:
  428.  
  429. # DSM up/down
  430. lhs = self.DSMup[g, tt] + sum(
  431. self.DSMdo[g, t, tt] for t in range(tt - g.delay_time, m.TIMESTEPS._bounds[1] + 1))
  432. # max capacity at tt
  433. rhs = max(g.c_up[tt], g.c_do[tt])
  434. # add constraint
  435. block.C2_constraint.add((g, tt), (lhs <= rhs))
  436.  
  437. self.C2_constraint = Constraint(group, m.TIMESTEPS, noruleinit=True)
  438. self.C2_constraint_build = BuildAction(rule=C2_constraint_rule)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement