2d_constraints.gms 129 KB
 Erkka Rinne committed Aug 04, 2017 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ``````\$ontext This file is part of Backbone. Backbone is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Backbone is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Backbone. If not, see . \$offtext `````` 18 `````` `````` Topi Rasku committed Oct 11, 2017 19 ``````* ============================================================================= `````` Niina Helistö committed Jul 06, 2018 20 ``````* --- Constraint Equation Definitions ----------------------------------------- `````` Topi Rasku committed Oct 11, 2017 21 22 23 24 ``````* ============================================================================= * --- Energy Balance ---------------------------------------------------------- `````` Topi Rasku committed Apr 04, 2019 25 26 27 ``````q_balance(gn(grid, node), msft(m, s, f, t)) // Energy/power balance dynamics solved using implicit Euler discretization \${ not p_gn(grid, node, 'boundAll') } .. `````` Topi Rasku committed Oct 11, 2017 28 29 30 31 `````` // The left side of the equation is the change in the state (will be zero if the node doesn't have a state) + p_gn(grid, node, 'energyStoredPerUnitOfState')\${gn_state(grid, node)} // Unit conversion between v_state of a particular node and energy variables (defaults to 1, but can have node based values if e.g. v_state is in Kelvins and each node has a different heat storage capacity) * [ `````` Erkka Rinne committed Nov 02, 2018 32 33 `````` + v_state(grid, node, s, f+df_central(f,t), t) // The difference between current - v_state(grid, node, s+ds_state(grid,node,s,t), f+df(f,t+dt(t)), t+dt(t)) // ... and previous state of the node `````` Topi Rasku committed Oct 11, 2017 34 35 36 37 38 39 40 41 `````` ] =E= // The right side of the equation contains all the changes converted to energy terms + p_stepLength(m, f, t) // Multiply with the length of the timestep to convert power into energy * ( // Self discharge out of the model boundaries `````` Topi Rasku committed Jun 05, 2018 42 `````` - p_gn(grid, node, 'selfDischargeLoss')\${ gn_state(grid, node) } `````` Erkka Rinne committed Nov 02, 2018 43 `````` * v_state(grid, node, s, f+df_central(f,t), t) // The current state of the node `````` Topi Rasku committed Oct 11, 2017 44 45 `````` // Energy diffusion from this node to neighbouring nodes `````` Topi Rasku committed Apr 03, 2019 46 `````` - sum(gnn_state(grid, node, to_node), `````` Topi Rasku committed Oct 11, 2017 47 `````` + p_gnn(grid, node, to_node, 'diffCoeff') `````` Erkka Rinne committed Nov 02, 2018 48 `````` * v_state(grid, node, s, f+df_central(f,t), t) `````` Topi Rasku committed Oct 11, 2017 49 50 51 `````` ) // END sum(to_node) // Energy diffusion from neighbouring nodes to this node `````` Topi Rasku committed Apr 03, 2019 52 `````` + sum(gnn_state(grid, from_node, node), `````` Topi Rasku committed Oct 11, 2017 53 `````` + p_gnn(grid, from_node, node, 'diffCoeff') `````` Erkka Rinne committed Nov 02, 2018 54 `````` * v_state(grid, from_node, s, f+df_central(f,t), t) // Incoming diffusion based on the state of the neighbouring node `````` Topi Rasku committed Oct 11, 2017 55 56 57 `````` ) // END sum(from_node) // Controlled energy transfer, applies when the current node is on the left side of the connection `````` Topi Rasku committed Apr 03, 2019 58 `````` - sum(gn2n_directional(grid, node, node_), `````` Topi Rasku committed Oct 11, 2017 59 `````` + (1 - p_gnn(grid, node, node_, 'transferLoss')) // Reduce transfer losses `````` Erkka Rinne committed Nov 02, 2018 60 `````` * v_transfer(grid, node, node_, s, f, t) `````` Topi Rasku committed Oct 11, 2017 61 `````` + p_gnn(grid, node, node_, 'transferLoss') // Add transfer losses back if transfer is from this node to another node `````` Erkka Rinne committed Nov 02, 2018 62 `````` * v_transferRightward(grid, node, node_, s, f, t) `````` Topi Rasku committed Oct 11, 2017 63 64 65 `````` ) // END sum(node_) // Controlled energy transfer, applies when the current node is on the right side of the connection `````` Topi Rasku committed Apr 03, 2019 66 `````` + sum(gn2n_directional(grid, node_, node), `````` Erkka Rinne committed Nov 02, 2018 67 `````` + v_transfer(grid, node_, node, s, f, t) `````` Topi Rasku committed Oct 11, 2017 68 `````` - p_gnn(grid, node_, node, 'transferLoss') // Reduce transfer losses if transfer is from another node to this node `````` Erkka Rinne committed Nov 02, 2018 69 `````` * v_transferRightward(grid, node_, node, s, f, t) `````` Topi Rasku committed Oct 11, 2017 70 71 72 73 `````` ) // END sum(node_) // Interactions between the node and its units + sum(gnuft(grid, node, unit, f, t), `````` Erkka Rinne committed Nov 02, 2018 74 `````` + v_gen(grid, node, unit, s, f, t) // Unit energy generation and consumption `````` Juha Kiviluoma committed Dec 05, 2016 75 `````` ) `````` Topi Rasku committed Oct 11, 2017 76 77 `````` // Spilling energy out of the endogenous grids in the model `````` Erkka Rinne committed Nov 02, 2018 78 `````` - v_spill(grid, node, s, f, t)\${node_spill(node)} `````` Topi Rasku committed Oct 11, 2017 79 80 `````` // Power inflow and outflow timeseries to/from the node `````` Erkka Rinne committed Nov 02, 2018 81 `````` + ts_influx_(grid, node, f, t, s) // Incoming (positive) and outgoing (negative) absolute value time series `````` Topi Rasku committed Oct 11, 2017 82 83 `````` // Dummy generation variables, for feasibility purposes `````` Erkka Rinne committed Nov 02, 2018 84 85 `````` + vq_gen('increase', grid, node, s, f, t) // Note! When stateSlack is permitted, have to take caution with the penalties so that it will be used first - vq_gen('decrease', grid, node, s, f, t) // Note! When stateSlack is permitted, have to take caution with the penalties so that it will be used first `````` Topi Rasku committed Oct 11, 2017 86 `````` ) // END * p_stepLength `````` 87 ``````; `````` Topi Rasku committed Oct 11, 2017 88 89 `````` * --- Reserve Demand ---------------------------------------------------------- `````` Topi Rasku committed Oct 05, 2018 90 91 ``````// NOTE! Currently, there are multiple identical instances of the reserve balance equation being generated for each forecast branch even when the reserves are committed and identical between the forecasts. // NOTE! This could be solved by formulating a new "ft_reserves" set to cover only the relevant forecast-time steps, but it would possibly make the reserves even more confusing. `````` Topi Rasku committed Oct 11, 2017 92 `````` `````` Erkka Rinne committed Nov 02, 2018 93 ``````q_resDemand(restypeDirectionNode(restype, up_down, node), sft(s, f, t)) `````` Topi Rasku committed Oct 05, 2018 94 95 `````` \${ ord(t) < tSolveFirst + p_nReserves(node, restype, 'reserve_length') and not [ restypeReleasedForRealization(restype) `````` Erkka Rinne committed Nov 15, 2018 96 `````` and sft_realized(s, f, t)] `````` Topi Rasku committed Oct 05, 2018 97 `````` } .. `````` Topi Rasku committed Apr 04, 2019 98 `````` `````` Topi Rasku committed Oct 11, 2017 99 100 `````` // Reserve provision by capable units on this node + sum(nuft(node, unit, f, t)\${nuRescapable(restype, up_down, node, unit)}, `````` Erkka Rinne committed Nov 02, 2018 101 `````` + v_reserve(restype, up_down, node, unit, s, f+df_reserves(node, restype, f, t), t) `````` Topi Rasku committed Jan 15, 2019 102 103 104 105 `````` * [ // Account for reliability of reserves + 1\${sft_realized(s, f+df_reserves(node, restype, f, t), t)} // reserveReliability limits the reliability of reserves locked ahead of time. + p_nuReserves(node, unit, restype, 'reserveReliability')\${not sft_realized(s, f+df_reserves(node, restype, f, t), t)} ] // END * v_reserve `````` Topi Rasku committed Oct 11, 2017 106 107 `````` ) // END sum(nuft) `````` 108 `````` // Reserve provision from other reserve categories when they can be shared `````` Topi Rasku committed Dec 05, 2018 109 `````` + sum((nuft(node, unit, f, t), restype_)\${p_nuRes2Res(node, unit, restype_, up_down, restype)}, `````` Erkka Rinne committed Dec 12, 2018 110 `````` + v_reserve(restype_, up_down, node, unit, s, f+df_reserves(node, restype_, f, t), t) `````` Topi Rasku committed Dec 05, 2018 111 `````` * p_nuRes2Res(node, unit, restype_, up_down, restype) `````` Topi Rasku committed Jan 15, 2019 112 113 114 115 116 `````` * [ // Account for reliability of reserves + 1\${sft_realized(s, f+df_reserves(node, restype, f, t), t)} // reserveReliability limits the reliability of reserves locked ahead of time. + p_nuReserves(node, unit, restype, 'reserveReliability')\${not sft_realized(s, f+df_reserves(node, restype, f, t), t)} * p_nuReserves(node, unit, restype_, 'reserveReliability') ] // END * v_reserve `````` 117 118 `````` ) // END sum(nuft) `````` Topi Rasku committed Oct 11, 2017 119 `````` // Reserve provision to this node via transfer links `````` 120 `````` + sum(gn2n_directional(grid, node_, node)\${restypeDirectionNodeNode(restype, up_down, node_, node)}, `````` Topi Rasku committed Oct 11, 2017 121 `````` + (1 - p_gnn(grid, node_, node, 'transferLoss') ) `````` Erkka Rinne committed Nov 02, 2018 122 `````` * v_resTransferRightward(restype, up_down, node_, node, s, f+df_reserves(node_, restype, f, t), t) // Reserves from another node - reduces the need for reserves in the node `````` Topi Rasku committed Oct 11, 2017 123 `````` ) // END sum(gn2n_directional) `````` 124 `````` + sum(gn2n_directional(grid, node, node_)\${restypeDirectionNodeNode(restype, up_down, node_, node)}, `````` Topi Rasku committed Oct 11, 2017 125 `````` + (1 - p_gnn(grid, node, node_, 'transferLoss') ) `````` Erkka Rinne committed Nov 02, 2018 126 `````` * v_resTransferLeftward(restype, up_down, node, node_, s, f+df_reserves(node_, restype, f, t), t) // Reserves from another node - reduces the need for reserves in the node `````` Topi Rasku committed Oct 11, 2017 127 128 129 130 131 132 133 134 `````` ) // END sum(gn2n_directional) =G= // Demand for reserves + ts_reserveDemand_(restype, up_down, node, f, t)\${p_nReserves(node, restype, 'use_time_series')} + p_nReserves(node, restype, up_down)\${not p_nReserves(node, restype, 'use_time_series')} `````` Niina Helistö committed Nov 02, 2018 135 136 `````` // Reserve demand increase because of units + sum(nuft(node, unit, f, t)\${p_nuReserves(node, unit, restype, 'reserve_increase_ratio')}, // Could be better to have 'reserve_increase_ratio' separately for up and down directions `````` Erkka Rinne committed Nov 11, 2018 137 `````` + sum(gnu(grid, node, unit), v_gen(grid, node, unit, s, f, t)) // Reserve sets and variables are currently lacking the grid dimension... `````` Niina Helistö committed Nov 02, 2018 138 139 140 `````` * p_nuReserves(node, unit, restype, 'reserve_increase_ratio') ) // END sum(nuft) `````` Topi Rasku committed Oct 11, 2017 141 `````` // Reserve provisions to another nodes via transfer links `````` 142 `````` + sum(gn2n_directional(grid, node, node_)\${restypeDirectionNodeNode(restype, up_down, node, node_)}, // If trasferring reserves to another node, increase your own reserves by same amount `````` Erkka Rinne committed Nov 02, 2018 143 `````` + v_resTransferRightward(restype, up_down, node, node_, s, f+df_reserves(node, restype, f, t), t) `````` Topi Rasku committed Oct 11, 2017 144 `````` ) // END sum(gn2n_directional) `````` 145 `````` + sum(gn2n_directional(grid, node_, node)\${restypeDirectionNodeNode(restype, up_down, node, node_)}, // If trasferring reserves to another node, increase your own reserves by same amount `````` Erkka Rinne committed Nov 02, 2018 146 `````` + v_resTransferLeftward(restype, up_down, node_, node, s, f+df_reserves(node, restype, f, t), t) `````` Topi Rasku committed Oct 11, 2017 147 148 149 `````` ) // END sum(gn2n_directional) // Reserve demand feasibility dummy variables `````` Erkka Rinne committed Nov 02, 2018 150 151 `````` - vq_resDemand(restype, up_down, node, s, f+df_reserves(node, restype, f, t), t) - vq_resMissing(restype, up_down, node, s, f+df_reserves(node, restype, f, t), t)\${ft_reservesFixed(node, restype, f+df_reserves(node, restype, f, t), t)} `````` 152 ``````; `````` Topi Rasku committed Oct 11, 2017 153 `````` `````` ran li committed Nov 25, 2018 154 155 156 157 ``````* --- N-1 Reserve Demand ---------------------------------------------------------- // NOTE! Currently, there are multiple identical instances of the reserve balance equation being generated for each forecast branch even when the reserves are committed and identical between the forecasts. // NOTE! This could be solved by formulating a new "ft_reserves" set to cover only the relevant forecast-time steps, but it would possibly make the reserves even more confusing. `````` Erkka Rinne committed Jan 17, 2019 158 ``````q_resDemandLargestInfeedUnit(grid, restypeDirectionNode(restype, 'up', node), unit_fail(unit_), sft(s, f, t)) `````` ran li committed Nov 25, 2018 159 `````` \${ ord(t) < tSolveFirst + p_nReserves(node, restype, 'reserve_length') `````` Juha Kiviluoma committed Feb 01, 2019 160 `````` and gn(grid, node) `````` ran li committed Nov 25, 2018 161 162 163 `````` and not [ restypeReleasedForRealization(restype) and ft_realized(f, t) ] `````` 164 `````` and p_nuReserves(node, unit_, restype, 'portion_of_infeed_to_reserve') `````` ran li committed Nov 25, 2018 165 `````` } .. `````` Topi Rasku committed Apr 04, 2019 166 `````` `````` ran li committed Nov 25, 2018 167 168 `````` // Reserve provision by capable units on this node excluding the failing one + sum(nuft(node, unit, f, t)\${nuRescapable(restype, 'up', node, unit) and (ord(unit_) ne ord(unit))}, `````` Erkka Rinne committed Dec 12, 2018 169 `````` + v_reserve(restype, 'up', node, unit, s, f+df_reserves(node, restype, f, t), t) `````` Topi Rasku committed Jan 15, 2019 170 171 172 173 `````` * [ // Account for reliability of reserves + 1\${sft_realized(s, f+df_reserves(node, restype, f, t), t)} // reserveReliability limits the reliability of reserves locked ahead of time. + p_nuReserves(node, unit, restype, 'reserveReliability')\${not sft_realized(s, f+df_reserves(node, restype, f, t), t)} ] // END * v_reserve `````` ran li committed Nov 25, 2018 174 175 176 `````` ) // END sum(nuft) // Reserve provision from other reserve categories when they can be shared `````` Topi Rasku committed Dec 05, 2018 177 `````` + sum((nuft(node, unit, f, t), restype_)\${p_nuRes2Res(node, unit, restype_, 'up', restype)}, `````` Erkka Rinne committed Dec 12, 2018 178 `````` + v_reserve(restype_, 'up', node, unit, s, f+df_reserves(node, restype_, f, t), t) `````` Topi Rasku committed Dec 05, 2018 179 `````` * p_nuRes2Res(node, unit, restype_, 'up', restype) `````` Topi Rasku committed Jan 15, 2019 180 181 182 183 184 `````` * [ // Account for reliability of reserves + 1\${sft_realized(s, f+df_reserves(node, restype, f, t), t)} // reserveReliability limits the reliability of reserves locked ahead of time. + p_nuReserves(node, unit, restype, 'reserveReliability')\${not sft_realized(s, f+df_reserves(node, restype, f, t), t)} * p_nuReserves(node, unit, restype_, 'reserveReliability') ] // END * v_reserve `````` ran li committed Nov 25, 2018 185 186 187 188 189 `````` ) // END sum(nuft) // Reserve provision to this node via transfer links + sum(gn2n_directional(grid, node_, node)\${restypeDirectionNodeNode(restype, 'up', node_, node)}, + (1 - p_gnn(grid, node_, node, 'transferLoss') ) `````` Erkka Rinne committed Dec 12, 2018 190 `````` * v_resTransferRightward(restype, 'up', node_, node, s, f+df_reserves(node_, restype, f, t), t) // Reserves from another node - reduces the need for reserves in the node `````` ran li committed Nov 25, 2018 191 192 193 `````` ) // END sum(gn2n_directional) + sum(gn2n_directional(grid, node, node_)\${restypeDirectionNodeNode(restype, 'up', node_, node)}, + (1 - p_gnn(grid, node, node_, 'transferLoss') ) `````` Erkka Rinne committed Dec 12, 2018 194 `````` * v_resTransferLeftward(restype, 'up', node, node_, s, f+df_reserves(node_, restype, f, t), t) // Reserves from another node - reduces the need for reserves in the node `````` ran li committed Nov 25, 2018 195 196 197 198 199 `````` ) // END sum(gn2n_directional) =G= // Demand for reserves of the failing one `````` Erkka Rinne committed Jan 17, 2019 200 `````` v_gen(grid,node,unit_,s,f,t) * p_nuReserves(node, unit_, restype, 'portion_of_infeed_to_reserve') `````` ran li committed Nov 25, 2018 201 202 `````` // Reserve provisions to another nodes via transfer links `````` Niina Helistö committed Feb 12, 2019 203 `````` + sum(gn2n_directional(grid, node, node_)\${restypeDirectionNodeNode(restype, 'up', node, node_)}, // If trasferring reserves to another node, increase your own reserves by same amount `````` Erkka Rinne committed Dec 12, 2018 204 `````` + v_resTransferRightward(restype, 'up', node, node_, s, f+df_reserves(node, restype, f, t), t) `````` ran li committed Nov 25, 2018 205 `````` ) // END sum(gn2n_directional) `````` Niina Helistö committed Feb 12, 2019 206 `````` + sum(gn2n_directional(grid, node_, node)\${restypeDirectionNodeNode(restype, 'up', node, node_)}, // If trasferring reserves to another node, increase your own reserves by same amount `````` Erkka Rinne committed Dec 12, 2018 207 `````` + v_resTransferLeftward(restype, 'up', node_, node, s, f+df_reserves(node, restype, f, t), t) `````` ran li committed Nov 25, 2018 208 209 210 `````` ) // END sum(gn2n_directional) // Reserve demand feasibility dummy variables `````` Erkka Rinne committed Dec 12, 2018 211 212 `````` - vq_resDemand(restype, 'up', node, s, f+df_reserves(node, restype, f, t), t) - vq_resMissing(restype, 'up', node, s, f+df_reserves(node, restype, f, t), t)\${ft_reservesFixed(node, restype, f+df_reserves(node, restype, f, t), t)} `````` ran li committed Nov 25, 2018 213 ``````; `````` Topi Rasku committed Oct 11, 2017 214 215 ``````* --- Maximum Downward Capacity ----------------------------------------------- `````` Topi Rasku committed Apr 04, 2019 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 ``````q_maxDownward(gnu(grid, node, unit), msft(m, s, f, t)) \${ gnuft(grid, node, unit, f, t) and { [ ord(t) < tSolveFirst + smax(restype, p_nReserves(node, restype, 'reserve_length')) // Unit is either providing and sum(restype, nuRescapable(restype, 'down', node, unit)) // downward reserves ] // NOTE!!! Could be better to form a gnuft_reserves subset? or [ // the unit has an online variable uft_online(unit, f, t) and [ (unit_minLoad(unit) and p_gnu(grid, node, unit, 'unitSizeGen')) // generators with a min. load or p_gnu(grid, node, unit, 'maxCons') // or consuming units with an online variable ] ] // END or or [ // consuming units with investment possibility gnu_input(grid, node, unit) and [unit_investLP(unit) or unit_investMIP(unit)] ] }} .. `````` Topi Rasku committed Oct 11, 2017 236 `````` // Energy generation/consumption `````` Erkka Rinne committed Nov 02, 2018 237 `````` + v_gen(grid, node, unit, s, f, t) `````` Topi Rasku committed Oct 11, 2017 238 239 `````` // Considering output constraints (e.g. cV line) `````` 240 241 `````` + sum(gngnu_constrainedOutputRatio(grid, node, grid_output, node_, unit), + p_gnu(grid_output, node_, unit, 'cV') `````` Erkka Rinne committed Nov 02, 2018 242 `````` * v_gen(grid_output, node_, unit, s, f, t) `````` Topi Rasku committed Oct 11, 2017 243 244 245 `````` ) // END sum(gngnu_constrainedOutputRatio) // Downward reserve participation `````` 246 `````` - sum(nuRescapable(restype, 'down', node, unit)\${ord(t) < tSolveFirst + p_nReserves(node, restype, 'reserve_length')}, `````` Erkka Rinne committed Nov 02, 2018 247 `````` + v_reserve(restype, 'down', node, unit, s, f+df_reserves(node, restype, f, t), t) // (v_reserve can be used only if the unit is capable of providing a particular reserve) `````` Topi Rasku committed Oct 11, 2017 248 249 250 251 252 253 `````` ) // END sum(nuRescapable) =G= // Must be greater than minimum load or maximum consumption (units with min-load and both generation and consumption are not allowed) // Generation units, greater than minload + p_gnu(grid, node, unit, 'unitSizeGen') `````` Topi Rasku committed Nov 09, 2017 254 `````` * sum(suft(effGroup, unit, f, t), // Uses the minimum 'lb' for the current efficiency approximation `````` Topi Rasku committed Oct 11, 2017 255 256 257 258 `````` + p_effGroupUnit(effGroup, unit, 'lb')\${not ts_effGroupUnit(effGroup, unit, 'lb', f, t)} + ts_effGroupUnit(effGroup, unit, 'lb', f, t) ) // END sum(effGroup) * [ // Online variables should only be generated for units with restrictions `````` Erkka Rinne committed Nov 02, 2018 259 260 `````` + v_online_LP(unit, s, f+df_central(f,t), t)\${uft_onlineLP(unit, f+df_central(f,t), t)} // LP online variant + v_online_MIP(unit, s, f+df_central(f,t), t)\${uft_onlineMIP(unit, f+df_central(f,t), t)} // MIP online variant `````` Topi Rasku committed Oct 11, 2017 261 262 `````` ] // END v_online `````` Topi Rasku committed Jan 24, 2019 263 264 265 266 `````` // Units in run-up phase neet to keep up with the run-up rate + p_gnu(grid, node, unit, 'unitSizeGen') * sum(unitStarttype(unit, starttype)\${uft_startupTrajectory(unit, f, t)}, sum(runUpCounter(unit, counter)\${t_active(t+dt_trajectory(counter))}, // Sum over the run-up intervals `````` Topi Rasku committed Apr 04, 2019 267 268 `````` + [ + v_startup_LP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) `````` Topi Rasku committed Apr 04, 2019 269 `````` \${ uft_onlineLP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } `````` Topi Rasku committed Apr 04, 2019 270 `````` + v_startup_MIP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) `````` Topi Rasku committed Apr 04, 2019 271 `````` \${ uft_onlineMIP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } `````` Topi Rasku committed Apr 04, 2019 272 `````` ] `````` Topi Rasku committed Jan 25, 2019 273 `````` * p_uCounter_runUpMin(unit, counter) `````` Topi Rasku committed Jan 24, 2019 274 275 276 277 278 279 `````` ) // END sum(runUpCounter) ) // END sum(unitStarttype) // Units in shutdown phase need to keep up with the shutdown rate + p_gnu(grid, node, unit, 'unitSizeGen') * sum(shutdownCounter(unit, counter)\${t_active(t+dt_trajectory(counter)) and uft_shutdownTrajectory(unit, f, t)}, // Sum over the shutdown intervals `````` Topi Rasku committed Apr 04, 2019 280 281 282 283 284 285 `````` + [ + v_shutdown_LP(unit, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) \${ uft_onlineLP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } + v_shutdown_MIP(unit, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) \${ uft_onlineMIP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } ] `````` Topi Rasku committed Jan 25, 2019 286 `````` * p_uCounter_shutdownMin(unit, counter) `````` Topi Rasku committed Jan 24, 2019 287 `````` ) // END sum(shutdownCounter) `````` Juha Kiviluoma committed Apr 06, 2018 288 `````` `````` Topi Rasku committed Oct 11, 2017 289 290 291 292 293 `````` // Consuming units, greater than maxCons // Available capacity restrictions - p_unit(unit, 'availability') * [ // Capacity factors for flow units `````` Topi Rasku committed Jun 05, 2018 294 `````` + sum(flowUnit(flow, unit), `````` Erkka Rinne committed Nov 02, 2018 295 `````` + ts_cf_(flow, node, f, t, s) `````` Topi Rasku committed Oct 11, 2017 296 297 298 299 300 301 302 303 `````` ) // END sum(flow) + 1\${not unit_flow(unit)} ] // END * p_unit(availability) * [ // Online capacity restriction + p_gnu(grid, node, unit, 'maxCons')\${not uft_online(unit, f, t)} // Use initial maximum if no online variables + p_gnu(grid, node, unit, 'unitSizeCons') * [ `````` 304 `````` // Capacity online `````` Erkka Rinne committed Nov 02, 2018 305 306 `````` + v_online_LP(unit, s, f+df_central(f,t), t)\${uft_onlineLP(unit, f, t)} + v_online_MIP(unit, s, f+df_central(f,t), t)\${uft_onlineMIP(unit, f, t)} `````` 307 308 309 310 311 312 313 314 `````` // Investments to additional non-online capacity + sum(t_invest(t_)\${ ord(t_)<=ord(t) and not uft_online(unit, f, t) }, + v_invest_LP(unit, t_)\${unit_investLP(unit)} // NOTE! v_invest_LP also for consuming units is positive + v_invest_MIP(unit, t_)\${unit_investMIP(unit)} // NOTE! v_invest_MIP also for consuming units is positive ) // END sum(t_invest) `````` Topi Rasku committed Oct 11, 2017 315 316 `````` ] // END * p_gnu(unitSizeCons) ] // END * p_unit(availability) `````` Topi Rasku committed Mar 29, 2017 317 ``````; `````` Topi Rasku committed Oct 11, 2017 318 319 320 `````` * --- Maximum Upwards Capacity ------------------------------------------------ `````` Topi Rasku committed Apr 04, 2019 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 ``````q_maxUpward(gnu(grid, node, unit), msft(m, s, f, t)) \${ gnuft(grid, node, unit, f, t) and { [ ord(t) < tSolveFirst + smax(restype, p_nReserves(node, restype, 'reserve_length')) // Unit is either providing and sum(restype, nuRescapable(restype, 'up', node, unit)) // upward reserves ] or [ uft_online(unit, f, t) // or the unit has an online variable and [ [unit_minLoad(unit) and p_gnu(grid, node, unit, 'unitSizeCons')] // consuming units with min_load or [p_gnu(grid, node, unit, 'maxGen')] // generators with an online variable ] ] or [ gnu_output(grid, node, unit) // generators with investment possibility and (unit_investLP(unit) or unit_investMIP(unit)) ] }}.. `````` Topi Rasku committed Oct 11, 2017 340 `````` // Energy generation/consumption `````` Erkka Rinne committed Nov 02, 2018 341 `````` + v_gen(grid, node, unit, s, f, t) `````` Topi Rasku committed Oct 11, 2017 342 343 344 345 `````` // Considering output constraints (e.g. cV line) + sum(gngnu_constrainedOutputRatio(grid, node, grid_output, node_, unit), + p_gnu(grid_output, node_, unit, 'cV') `````` Erkka Rinne committed Nov 02, 2018 346 `````` * v_gen(grid_output, node_, unit, s, f, t) `````` Topi Rasku committed Oct 11, 2017 347 348 349 `````` ) // END sum(gngnu_constrainedOutputRatio) // Upwards reserve participation `````` 350 `````` + sum(nuRescapable(restype, 'up', node, unit)\${ord(t) < tSolveFirst + p_nReserves(node, restype, 'reserve_length')}, `````` Erkka Rinne committed Nov 02, 2018 351 `````` + v_reserve(restype, 'up', node, unit, s, f+df_reserves(node, restype, f, t), t) `````` Topi Rasku committed Oct 11, 2017 352 353 354 355 356 `````` ) // END sum(nuRescapable) =L= // must be less than available/online capacity // Consuming units `````` Niina Helistö committed Mar 01, 2019 357 `````` - p_gnu(grid, node, unit, 'unitSizeCons') `````` Topi Rasku committed Nov 09, 2017 358 `````` * sum(suft(effGroup, unit, f, t), // Uses the minimum 'lb' for the current efficiency approximation `````` Topi Rasku committed Oct 11, 2017 359 360 361 362 `````` + p_effGroupUnit(effGroup, unit, 'lb')\${not ts_effGroupUnit(effGroup, unit, 'lb', f, t)} + ts_effGroupUnit(effGroup, unit, 'lb', f, t) ) // END sum(effGroup) * [ `````` Erkka Rinne committed Nov 02, 2018 363 364 `````` + v_online_LP(unit, s, f+df_central(f,t), t)\${uft_onlineLP(unit, f, t)} // Consuming units are restricted by their min. load (consuming is negative) + v_online_MIP(unit, s, f+df_central(f,t), t)\${uft_onlineMIP(unit, f, t)} // Consuming units are restricted by their min. load (consuming is negative) `````` Topi Rasku committed Oct 11, 2017 365 366 367 368 369 370 371 `````` ] // END * p_gnu(unitSizeCons) // Generation units // Available capacity restrictions + p_unit(unit, 'availability') // Generation units are restricted by their (available) capacity * [ // Capacity factor for flow units `````` Topi Rasku committed Jun 05, 2018 372 `````` + sum(flowUnit(flow, unit), `````` Erkka Rinne committed Nov 02, 2018 373 `````` + ts_cf_(flow, node, f, t, s) `````` Topi Rasku committed Oct 11, 2017 374 375 376 377 378 379 380 381 `````` ) // END sum(flow) + 1\${not unit_flow(unit)} ] // END * p_unit(availability) * [ // Online capacity restriction + p_gnu(grid, node, unit, 'maxGen')\${not uft_online(unit, f, t)} // Use initial maxGen if no online variables + p_gnu(grid, node, unit, 'unitSizeGen') * [ `````` 382 `````` // Capacity online `````` Erkka Rinne committed Nov 02, 2018 383 384 `````` + v_online_LP(unit, s, f+df_central(f,t), t)\${uft_onlineLP(unit, f ,t)} + v_online_MIP(unit, s, f+df_central(f,t), t)\${uft_onlineMIP(unit, f, t)} `````` 385 386 387 388 389 390 391 392 `````` // Investments to non-online capacity + sum(t_invest(t_)\${ ord(t_)<=ord(t) and not uft_online(unit, f ,t) }, + v_invest_LP(unit, t_)\${unit_investLP(unit)} + v_invest_MIP(unit, t_)\${unit_investMIP(unit)} ) // END sum(t_invest) `````` Topi Rasku committed Oct 11, 2017 393 394 `````` ] // END * p_gnu(unitSizeGen) ] // END * p_unit(availability) `````` Juha Kiviluoma committed Apr 06, 2018 395 `````` `````` Topi Rasku committed Jan 24, 2019 396 397 398 399 `````` // Units in run-up phase neet to keep up with the run-up rate + p_gnu(grid, node, unit, 'unitSizeGen') * sum(unitStarttype(unit, starttype)\${uft_startupTrajectory(unit, f, t)}, sum(runUpCounter(unit, counter)\${t_active(t+dt_trajectory(counter))}, // Sum over the run-up intervals `````` Topi Rasku committed Apr 04, 2019 400 401 `````` + [ + v_startup_LP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) `````` Topi Rasku committed Apr 04, 2019 402 `````` \${ uft_onlineLP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } `````` Topi Rasku committed Apr 04, 2019 403 `````` + v_startup_MIP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) `````` Topi Rasku committed Apr 04, 2019 404 `````` \${ uft_onlineMIP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } `````` Topi Rasku committed Apr 04, 2019 405 `````` ] `````` Topi Rasku committed Jan 25, 2019 406 `````` * p_uCounter_runUpMax(unit, counter) `````` Topi Rasku committed Jan 24, 2019 407 408 409 410 411 412 `````` ) // END sum(runUpCounter) ) // END sum(unitStarttype) // Units in shutdown phase need to keep up with the shutdown rate + p_gnu(grid, node, unit, 'unitSizeGen') * sum(shutdownCounter(unit, counter)\${t_active(t+dt_trajectory(counter)) and uft_shutdownTrajectory(unit, f, t)}, // Sum over the shutdown intervals `````` Topi Rasku committed Apr 04, 2019 413 414 415 416 417 418 `````` + [ + v_shutdown_LP(unit, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) \${ uft_onlineLP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } + v_shutdown_MIP(unit, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) \${ uft_onlineMIP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } ] `````` Topi Rasku committed Jan 25, 2019 419 `````` * p_uCounter_shutdownMax(unit, counter) `````` Topi Rasku committed Jan 24, 2019 420 `````` ) // END sum(shutdownCounter) `````` 421 ``````; `````` Topi Rasku committed Oct 11, 2017 422 `````` `````` Niina Helistö committed Nov 01, 2018 423 424 ``````* --- Reserve Provision of Units with Investments ----------------------------- `````` Topi Rasku committed Apr 04, 2019 425 426 427 428 429 430 431 ``````q_reserveProvision(nuRescapable(restypeDirectionNode(restype, up_down, node), unit), sft(s, f, t)) \${ ord(t) <= tSolveFirst + p_nReserves(node, restype, 'reserve_length') and nuft(node, unit, f, t) and (unit_investLP(unit) or unit_investMIP(unit)) and not ft_reservesFixed(node, restype, f+df_reserves(node, restype, f, t), t) } .. `````` Erkka Rinne committed Nov 02, 2018 432 `````` + v_reserve(restype, up_down, node, unit, s, f+df_reserves(node, restype, f, t), t) `````` Niina Helistö committed Nov 01, 2018 433 434 435 436 437 438 439 440 441 442 443 444 445 `````` =L= + p_nuReserves(node, unit, restype, up_down) * [ + sum(grid, p_gnu(grid, node, unit, 'maxGen') + p_gnu(grid, node, unit, 'maxCons') ) // Reserve sets and variables are currently lacking the grid dimension... + sum(t_invest(t_)\${ ord(t_)<=ord(t) }, + v_invest_LP(unit, t_)\${unit_investLP(unit)} * sum(grid, p_gnu(grid, node, unit, 'unitSizeTot')) // Reserve sets and variables are currently lacking the grid dimension... + v_invest_MIP(unit, t_)\${unit_investMIP(unit)} * sum(grid, p_gnu(grid, node, unit, 'unitSizeTot')) // Reserve sets and variables are currently lacking the grid dimension... ) // END sum(t_) ] `````` Niina Helistö committed Nov 02, 2018 446 447 448 449 `````` * p_unit(unit, 'availability') // Taking into account availability... * [ // ... and capacity factor for flow units + sum(flowUnit(flow, unit), `````` Erkka Rinne committed Nov 02, 2018 450 `````` + ts_cf_(flow, node, f, t, s) `````` Niina Helistö committed Nov 02, 2018 451 452 `````` ) // END sum(flow) + 1\${not unit_flow(unit)} `````` Niina Helistö committed Nov 01, 2018 453 454 455 `````` ] // How to consider reserveReliability in the case of investments when we typically only have "realized" time steps? ; `````` Topi Rasku committed Oct 11, 2017 456 457 ``````* --- Unit Startup and Shutdown ----------------------------------------------- `````` Topi Rasku committed Apr 04, 2019 458 459 460 461 ``````q_startshut(ms(m, s), uft_online(unit, f, t)) \${ msft(m, s, f, t) }.. `````` Niina Helistö committed Aug 09, 2018 462 `````` // Units currently online `````` Erkka Rinne committed Nov 02, 2018 463 464 `````` + v_online_LP (unit, s, f+df_central(f,t), t)\${uft_onlineLP (unit, f, t)} + v_online_MIP(unit, s, f+df_central(f,t), t)\${uft_onlineMIP(unit, f, t)} `````` Topi Rasku committed Oct 11, 2017 465 466 `````` // Units previously online `````` Niina Helistö committed Aug 09, 2018 467 `````` // The same units `````` Erkka Rinne committed Nov 02, 2018 468 `````` - v_online_LP (unit, s+ds(s,t), f+df(f,t+dt(t)), t+dt(t))\${ uft_onlineLP_withPrevious(unit, f+df(f,t+dt(t)), t+dt(t)) `````` Niina Helistö committed Aug 09, 2018 469 `````` and not uft_aggregator_first(unit, f, t) } // This reaches to tFirstSolve when dt = -1 `````` Erkka Rinne committed Nov 02, 2018 470 `````` - v_online_MIP(unit, s+ds(s,t), f+df(f,t+dt(t)), t+dt(t))\${ uft_onlineMIP_withPrevious(unit, f+df(f,t+dt(t)), t+dt(t)) `````` Niina Helistö committed Aug 09, 2018 471 472 473 474 `````` and not uft_aggregator_first(unit, f, t) } // Aggregated units just before they are turned into aggregator units - sum(unit_\${unitAggregator_unit(unit, unit_)}, `````` Erkka Rinne committed Nov 02, 2018 475 476 `````` + v_online_LP (unit_, s, f+df(f,t+dt(t)), t+dt(t))\${uft_onlineLP_withPrevious(unit_, f+df(f,t+dt(t)), t+dt(t))} + v_online_MIP(unit_, s, f+df(f,t+dt(t)), t+dt(t))\${uft_onlineMIP_withPrevious(unit_, f+df(f,t+dt(t)), t+dt(t))} `````` Niina Helistö committed Aug 15, 2018 477 `````` )\${uft_aggregator_first(unit, f, t)} // END sum(unit_) `````` Topi Rasku committed Nov 02, 2017 478 `````` `````` Juha Kiviluoma committed Apr 06, 2018 479 480 `````` =E= `````` Topi Rasku committed Oct 11, 2017 481 `````` // Unit startup and shutdown `````` Juha Kiviluoma committed Jul 31, 2018 482 `````` `````` Niina Helistö committed Aug 09, 2018 483 `````` // Add startup of units dt_toStartup before the current t (no start-ups for aggregator units before they become active) `````` Topi Rasku committed Nov 07, 2017 484 `````` + sum(unitStarttype(unit, starttype), `````` Topi Rasku committed Apr 04, 2019 485 `````` + v_startup_LP(unit, starttype, s, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t)) `````` Topi Rasku committed Apr 04, 2019 486 `````` \${ uft_onlineLP_withPrevious(unit, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t)) } `````` Topi Rasku committed Apr 04, 2019 487 `````` + v_startup_MIP(unit, starttype, s, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t)) `````` Topi Rasku committed Apr 04, 2019 488 `````` \${ uft_onlineMIP_withPrevious(unit, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t)) } `````` Niina Helistö committed Aug 09, 2018 489 `````` )\${not [unit_aggregator(unit) and ord(t) + dt_toStartup(unit, t) <= tSolveFirst + p_unit(unit, 'lastStepNotAggregated')]} // END sum(starttype) `````` Juha Kiviluoma committed Jul 31, 2018 490 `````` `````` Niina Helistö committed Aug 09, 2018 491 492 493 494 `````` // NOTE! According to 3d_setVariableLimits, // cannot start a unit if the time when the unit would become online is outside // the horizon when the unit has an online variable // --> no need to add start-ups of aggregated units to aggregator units `````` Juha Kiviluoma committed Jul 31, 2018 495 `````` `````` Niina Helistö committed Aug 09, 2018 496 `````` // Shutdown of units at time t `````` Topi Rasku committed Apr 04, 2019 497 498 499 500 `````` - v_shutdown_LP(unit, s, f, t) \${ uft_onlineLP(unit, f, t) } - v_shutdown_MIP(unit, s, f, t) \${ uft_onlineMIP(unit, f, t) } `````` 501 ``````; `````` Topi Rasku committed Oct 11, 2017 502 `````` `````` 503 ``````*--- Startup Type ------------------------------------------------------------- `````` Topi Rasku committed Nov 06, 2017 504 ``````// !!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! `````` Topi Rasku committed Nov 06, 2017 505 506 507 ``````// This formulation doesn't work as intended when unitCount > 1, as one recent // shutdown allows for multiple hot/warm startups on subsequent time steps. // Pending changes. `````` 508 `````` `````` Topi Rasku committed Apr 04, 2019 509 510 511 512 ``````q_startuptype(ms(m, s), starttypeConstrained(starttype), uft_online(unit, f, t)) \${ msft(m, s, f, t) and unitStarttype(unit, starttype) } .. `````` 513 514 `````` // Startup type `````` Topi Rasku committed Apr 04, 2019 515 516 `````` + v_startup_LP(unit, starttype, s, f, t)\${ uft_onlineLP(unit, f, t) } + v_startup_MIP(unit, starttype, s, f, t)\${ uft_onlineMIP(unit, f, t) } `````` 517 518 519 520 `````` =L= // Subunit shutdowns within special startup timeframe `````` Topi Rasku committed Apr 04, 2019 521 522 523 524 525 526 527 `````` + sum(unitCounter(unit, counter)\${ dt_starttypeUnitCounter(starttype, unit, counter) and t_active(t+(dt_starttypeUnitCounter(starttype, unit, counter)+1)) }, + v_shutdown_LP(unit, s, f+df(f,t+(dt_starttypeUnitCounter(starttype, unit, counter)+1)), t+(dt_starttypeUnitCounter(starttype, unit, counter)+1)) \${ uft_onlineLP_withPrevious(unit, f+df(f,t+(dt_starttypeUnitCounter(starttype, unit, counter)+1)), t+(dt_starttypeUnitCounter(starttype, unit, counter)+1)) } + v_shutdown_MIP(unit, s, f+df(f,t+(dt_starttypeUnitCounter(starttype, unit, counter)+1)), t+(dt_starttypeUnitCounter(starttype, unit, counter)+1)) \${ uft_onlineMIP_withPrevious(unit, f+df(f,t+(dt_starttypeUnitCounter(starttype, unit, counter)+1)), t+(dt_starttypeUnitCounter(starttype, unit, counter)+1)) } `````` Niina Helistö committed Aug 15, 2018 528 529 530 `````` ) // END sum(counter) // NOTE: for aggregator units, shutdowns for aggregated units are not considered `````` 531 ``````; `````` 532 `````` `````` Juha Kiviluoma committed Apr 03, 2018 533 `````` `````` 534 535 ``````*--- Online Limits with Startup Type Constraints and Investments -------------- `````` Topi Rasku committed Apr 04, 2019 536 537 538 539 540 541 542 543 544 ``````q_onlineLimit(ms(m, s), uft_online(unit, f, t)) \${ msft(m, s, f, t) and { p_unit(unit, 'minShutdownHours') or p_u_runUpTimeIntervals(unit) or unit_investLP(unit) or unit_investMIP(unit) }} .. `````` 545 `````` // Online variables `````` Erkka Rinne committed Nov 02, 2018 546 547 `````` + v_online_LP(unit, s, f+df_central(f,t), t)\${uft_onlineLP(unit, f, t)} + v_online_MIP(unit, s, f+df_central(f,t), t)\${uft_onlineMIP(unit, f ,t)} `````` 548 549 550 551 552 553 `````` =L= // Number of existing units + p_unit(unit, 'unitCount') `````` Niina Helistö committed May 25, 2018 554 `````` // Number of units unable to become online due to restrictions `````` Topi Rasku committed Apr 04, 2019 555 556 557 558 559 560 561 `````` - sum(unitCounter(unit, counter)\${ dt_downtimeUnitCounter(unit, counter) and t_active(t+(dt_downtimeUnitCounter(unit, counter) + 1)) }, + v_shutdown_LP(unit, s, f+df(f,t+(dt_downtimeUnitCounter(unit, counter) + 1)), t+(dt_downtimeUnitCounter(unit, counter) + 1)) \${ uft_onlineLP_withPrevious(unit, f+df(f,t+(dt_downtimeUnitCounter(unit, counter) + 1)), t+(dt_downtimeUnitCounter(unit, counter) + 1)) } + v_shutdown_MIP(unit, s, f+df(f,t+(dt_downtimeUnitCounter(unit, counter) + 1)), t+(dt_downtimeUnitCounter(unit, counter) + 1)) \${ uft_onlineMIP_withPrevious(unit, f+df(f,t+(dt_downtimeUnitCounter(unit, counter) + 1)), t+(dt_downtimeUnitCounter(unit, counter) + 1)) } `````` Niina Helistö committed Aug 15, 2018 562 563 564 `````` ) // END sum(counter) // Number of units unable to become online due to restrictions (aggregated units in the past horizon or if they have an online variable) `````` Topi Rasku committed Jan 24, 2019 565 `````` - sum(unitAggregator_unit(unit, unit_), `````` Topi Rasku committed Apr 04, 2019 566 567 568 569 570 571 572 `````` + sum(unitCounter(unit, counter)\${ dt_downtimeUnitCounter(unit, counter) and t_active(t+(dt_downtimeUnitCounter(unit, counter) + 1)) }, + v_shutdown_LP(unit_, s, f+df(f,t+(dt_downtimeUnitCounter(unit, counter) + 1)), t+(dt_downtimeUnitCounter(unit, counter) + 1)) \${ uft_onlineLP_withPrevious(unit_, f+df(f,t+(dt_downtimeUnitCounter(unit, counter) + 1)), t+(dt_downtimeUnitCounter(unit, counter) + 1)) } + v_shutdown_MIP(unit_, s, f+df(f,t+(dt_downtimeUnitCounter(unit, counter) + 1)), t+(dt_downtimeUnitCounter(unit, counter) + 1)) \${ uft_onlineMIP_withPrevious(unit_, f+df(f,t+(dt_downtimeUnitCounter(unit, counter) + 1)), t+(dt_downtimeUnitCounter(unit, counter) + 1)) } `````` Niina Helistö committed Aug 15, 2018 573 574 `````` ) // END sum(counter) )\${unit_aggregator(unit)} // END sum(unit_) `````` 575 576 577 `````` // Investments into units + sum(t_invest(t_)\${ord(t_)<=ord(t)}, `````` Niina Helistö committed Mar 26, 2018 578 579 `````` + v_invest_LP(unit, t_)\${unit_investLP(unit)} + v_invest_MIP(unit, t_)\${unit_investMIP(unit)} `````` 580 581 582 `````` ) // END sum(t_invest) ; `````` Juha Kiviluoma committed Apr 10, 2018 583 584 585 586 ``````*--- Both q_offlineAfterShutdown and q_onlineOnStartup work when there is only one unit. * These equations prohibit single units turning on and off at the same time step. * Unfortunately there seems to be no way to prohibit this when unit count is > 1. * (it shouldn't be worthwhile anyway if there is a startup cost, but it can fall within the solution gap). `````` Topi Rasku committed Apr 04, 2019 587 588 589 590 ``````q_onlineOnStartUp(s_active(s), uft_online(unit, f, t)) \${ sft(s, f, t) and sum(starttype, unitStarttype(unit, starttype)) }.. `````` Juha Kiviluoma committed Apr 06, 2018 591 592 `````` // Units currently online `````` Erkka Rinne committed Nov 02, 2018 593 594 `````` + v_online_LP(unit, s, f+df_central(f,t), t)\${uft_onlineLP(unit, f, t)} + v_online_MIP(unit, s, f+df_central(f,t), t)\${uft_onlineMIP(unit, f, t)} `````` Juha Kiviluoma committed Apr 06, 2018 595 596 597 598 `````` =G= + sum(unitStarttype(unit, starttype), `````` Topi Rasku committed Apr 04, 2019 599 `````` + v_startup_LP(unit, starttype, s, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t)) //dt_toStartup displaces the time step to the one where the unit would be started up in order to reach online at t `````` Topi Rasku committed Apr 04, 2019 600 `````` \${ uft_onlineLP_withPrevious(unit, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t)) } `````` Topi Rasku committed Apr 04, 2019 601 `````` + v_startup_MIP(unit, starttype, s, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t)) //dt_toStartup displaces the time step to the one where the unit would be started up in order to reach online at t `````` Topi Rasku committed Apr 04, 2019 602 `````` \${ uft_onlineMIP_withPrevious(unit, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t)) } `````` Juha Kiviluoma committed Apr 06, 2018 603 604 605 `````` ) // END sum(starttype) ; `````` Topi Rasku committed Apr 04, 2019 606 607 608 609 ``````q_offlineAfterShutdown(s_active(s), uft_online(unit, f, t)) \${ sft(s, f, t) and sum(starttype, unitStarttype(unit, starttype)) }.. `````` Juha Kiviluoma committed Apr 06, 2018 610 `````` `````` Juha Kiviluoma committed Apr 10, 2018 611 612 613 614 615 `````` // Number of existing units + p_unit(unit, 'unitCount') // Investments into units + sum(t_invest(t_)\${ord(t_)<=ord(t)}, `````` Niina Helistö committed Apr 10, 2018 616 617 `````` + v_invest_LP(unit, t_)\${unit_investLP(unit)} + v_invest_MIP(unit, t_)\${unit_investMIP(unit)} `````` Juha Kiviluoma committed Apr 10, 2018 618 619 `````` ) // END sum(t_invest) `````` Juha Kiviluoma committed Apr 06, 2018 620 `````` // Units currently online `````` Erkka Rinne committed Nov 02, 2018 621 622 `````` - v_online_LP(unit, s, f+df_central(f,t), t)\${uft_onlineLP(unit, f, t)} - v_online_MIP(unit, s, f+df_central(f,t), t)\${uft_onlineMIP(unit, f, t)} `````` Juha Kiviluoma committed Apr 06, 2018 623 624 625 `````` =G= `````` Topi Rasku committed Apr 04, 2019 626 627 628 629 `````` + v_shutdown_LP(unit, s, f, t) \${ uft_onlineLP(unit, f, t) } + v_shutdown_MIP(unit, s, f, t) \${ uft_onlineMIP(unit, f, t) } `````` Juha Kiviluoma committed Apr 06, 2018 630 631 ``````; `````` 632 633 ``````*--- Minimum Unit Uptime ------------------------------------------------------ `````` Topi Rasku committed Apr 04, 2019 634 635 636 637 ``````q_onlineMinUptime(ms(m, s), uft_online(unit, f, t)) \${ msft(m, s, f, t) and p_unit(unit, 'minOperationHours') } .. `````` 638 639 `````` // Units currently online `````` Erkka Rinne committed Nov 02, 2018 640 641 `````` + v_online_LP(unit, s, f+df_central(f,t), t)\${uft_onlineLP(unit, f, t)} + v_online_MIP(unit, s, f+df_central(f,t), t)\${uft_onlineMIP(unit, f, t)} `````` 642 643 644 645 `````` =G= // Units that have minimum operation time requirements active `````` Topi Rasku committed Apr 04, 2019 646 647 648 `````` + sum(unitCounter(unit, counter)\${ dt_uptimeUnitCounter(unit, counter) and t_active(t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)) // Don't sum over counters that don't point to an active time step }, `````` Topi Rasku committed Nov 07, 2017 649 `````` + sum(unitStarttype(unit, starttype), `````` Topi Rasku committed Apr 04, 2019 650 `````` + v_startup_LP(unit, starttype, s, f+df(f,t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)), t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)) `````` Topi Rasku committed Apr 04, 2019 651 `````` \${ uft_onlineLP_withPrevious(unit, f+df(f,t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)), t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)) } `````` Topi Rasku committed Apr 04, 2019 652 `````` + v_startup_MIP(unit, starttype, s, f+df(f,t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)), t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)) `````` Topi Rasku committed Apr 04, 2019 653 `````` \${ uft_onlineMIP_withPrevious(unit, f+df(f,t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)), t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)) } `````` 654 `````` ) // END sum(starttype) `````` Niina Helistö committed Aug 15, 2018 655 656 657 `````` ) // END sum(counter) // Units that have minimum operation time requirements active (aggregated units in the past horizon or if they have an online variable) `````` Topi Rasku committed Oct 19, 2018 658 `````` + sum(unitAggregator_unit(unit, unit_), `````` Topi Rasku committed Apr 04, 2019 659 660 661 `````` + sum(unitCounter(unit, counter)\${ dt_uptimeUnitCounter(unit, counter) and t_active(t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)) // Don't sum over counters that don't point to an active time step }, `````` Niina Helistö committed Aug 15, 2018 662 `````` + sum(unitStarttype(unit, starttype), `````` Topi Rasku committed Apr 04, 2019 663 `````` + v_startup_LP(unit, starttype, s, f+df(f,t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)), t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)) `````` Topi Rasku committed Apr 04, 2019 664 `````` \${ uft_onlineLP_withPrevious(unit, f+df(f,t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)), t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)) } `````` Topi Rasku committed Apr 04, 2019 665 `````` + v_startup_MIP(unit, starttype, s, f+df(f,t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)), t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)) `````` Topi Rasku committed Apr 04, 2019 666 `````` \${ uft_onlineMIP_withPrevious(unit, f+df(f,t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)), t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)) } `````` Niina Helistö committed Aug 15, 2018 667 668 669 `````` ) // END sum(starttype) ) // END sum(counter) )\${unit_aggregator(unit)} // END sum(unit_) `````` 670 671 ``````; `````` Niina Helistö committed Jan 28, 2019 672 673 ``````* --- Cyclic Boundary Conditions for Online State ----------------------------- `````` Topi Rasku committed Apr 04, 2019 674 675 676 677 678 ``````q_onlineCyclic(uss_bound(unit, s_, s), m) \${ ms(m, s_) and ms(m, s) and tSolveFirst = mSettings(m, 't_start') }.. `````` Niina Helistö committed Jan 28, 2019 679 680 681 682 `````` // Initial value of the state of the unit at the start of the sample + sum(mst_start(m, s, t), + sum(sft(s, f, t), `````` Topi Rasku committed Apr 12, 2019 683 684 685 686 `````` + v_online_LP(unit, s, f+df(f,t+dt(t)), t+dt(t)) \${uft_onlineLP_withPrevious(unit, f+df(f,t+dt(t)), t+dt(t))} + v_online_MIP(unit, s, f+df(f,t+dt(t)), t+dt(t)) \${uft_onlineMIP_withPrevious(unit, f+df(f,t+dt(t)), t+dt(t))} `````` Niina Helistö committed Jan 28, 2019 687 688 689 690 691 692 693 694 695 696 697 698 699 700 `````` ) // END sum(ft) ) // END sum(mst_start) =E= // State of the unit at the end of the sample + sum(mst_end(m, s_, t_), + sum(sft(s_, f_, t_), + v_online_LP(unit, s_, f_, t_)\${uft_onlineLP(unit, f_, t_)} + v_online_MIP(unit, s_, f_, t_)\${uft_onlineMIP(unit, f_, t_)} ) // END sum(ft) ) // END sum(mst_end) ; `````` Topi Rasku committed Oct 11, 2017 701 ``````* --- Ramp Constraints -------------------------------------------------------- `````` 702 `````` `````` Topi Rasku committed Apr 04, 2019 703 704 705 706 ``````q_genRamp(ms(m, s), gnuft_ramp(grid, node, unit, f, t)) \${ ord(t) > msStart(m, s) + 1 and msft(m, s, f, t) } .. `````` Topi Rasku committed Oct 11, 2017 707 `````` `````` Topi Rasku committed Jan 25, 2019 708 709 `````` + v_genRamp(grid, node, unit, s, f, t) * p_stepLength(m, f, t) `````` Niina Helistö committed Jul 12, 2018 710 `````` `````` Topi Rasku committed Apr 03, 2017 711 `````` =E= `````` Niina Helistö committed Jul 12, 2018 712 `````` `````` Niina Helistö committed Aug 09, 2018 713 `````` // Change in generation over the interval: v_gen(t) - v_gen(t-1) `````` Erkka Rinne committed Nov 02, 2018 714 `````` + v_gen(grid, node, unit, s, f, t) `````` 715 `````` `````` Niina Helistö committed Aug 09, 2018 716 `````` // Unit generation at t-1 (except aggregator units right before the aggregation threshold, see next term) `````` Erkka Rinne committed Nov 02, 2018 717 `````` - v_gen(grid, node, unit, s+ds(s,t), f+df(f,t+dt(t)), t+dt(t))\${not uft_aggregator_first(unit, f, t)} `````` Niina Helistö committed Aug 09, 2018 718 719 `````` // Unit generation at t-1, aggregator units right before the aggregation threshold + sum(unit_\${unitAggregator_unit(unit, unit_)}, `````` Erkka Rinne committed Nov 02, 2018 720 `````` - v_gen(grid, node, unit_, s+ds(s,t), f+df(f,t+dt(t)), t+dt(t)) `````` Niina Helistö committed Aug 09, 2018 721 `````` )\${uft_aggregator_first(unit, f, t)} `````` Topi Rasku committed Apr 03, 2017 722 ``````; `````` Topi Rasku committed Oct 11, 2017 723 `````` `````` 724 ``````* --- Ramp Up Limits ---------------------------------------------------------- `````` 725 `````` `````` Topi Rasku committed Apr 04, 2019 726 727 728 729 730 731 732 733 734 735 736 737 ``````q_rampUpLimit(ms(m, s), gnuft_ramp(grid, node, unit, f, t)) \${ ord(t) > msStart(m, s) + 1 and msft(m, s, f, t) and p_gnu(grid, node, unit, 'maxRampUp') and [ sum(restype, nuRescapable(restype, 'up', node, unit)) or uft_online(unit, f, t) or unit_investLP(unit) or unit_investMIP(unit) ] } .. // Ramp speed of the unit? `````` Erkka Rinne committed Nov 02, 2018 738 `````` + v_genRamp(grid, node, unit, s, f, t) `````` 739 `````` + sum(nuRescapable(restype, 'up', node, unit)\${ord(t) < tSolveFirst + p_nReserves(node, restype, 'reserve_length')}, `````` Erkka Rinne committed Nov 02, 2018 740 `````` + v_reserve(restype, 'up', node, unit, s, f+df_reserves(node, restype, f, t), t) // (v_reserve can be used only if the unit is capable of providing a particular reserve) `````` Niina Helistö committed Jul 12, 2018 741 742 743 744 745 `````` ) // END sum(nuRescapable) / p_stepLength(m, f, t) =L= `````` Juha Kiviluoma committed May 17, 2018 746 `````` // Ramping capability of units without an online variable `````` Niina Helistö committed Jul 12, 2018 747 748 749 750 751 752 753 754 755 756 757 758 `````` + ( + ( p_gnu(grid, node, unit, 'maxGen') + p_gnu(grid, node, unit, 'maxCons') )\${not uft_online(unit, f, t)} + sum(t_invest(t_)\${ ord(t_)<=ord(t) }, + v_invest_LP(unit, t_)\${not uft_onlineLP(unit, f, t) and unit_investLP(unit)} * p_gnu(grid, node, unit, 'unitSizeTot') + v_invest_MIP(unit, t_)\${not uft_onlineMIP(unit, f, t) and unit_investMIP(unit)} * p_gnu(grid, node, unit, 'unitSizeTot') ) ) * p_gnu(grid, node, unit, 'maxRampUp') * 60 // Unit conversion from [p.u./min] to [p.u./h] `````` Juha Kiviluoma committed May 17, 2018 759 `````` // Ramping capability of units with an online variable `````` Niina Helistö committed Jul 12, 2018 760 `````` + ( `````` Topi Rasku committed Apr 12, 2019 761 762 763 764 `````` + v_online_LP(unit, s, f+df_central(f,t), t) \${uft_onlineLP(unit, f, t)} + v_online_MIP(unit, s, f+df_central(f,t), t) \${uft_onlineMIP(unit, f, t)} `````` Niina Helistö committed Jul 12, 2018 765 766 767 768 769 `````` ) * p_gnu(grid, node, unit, 'unitSizeTot') * p_gnu(grid, node, unit, 'maxRampUp') * 60 // Unit conversion from [p.u./min] to [p.u./h] `````` Niina Helistö committed Mar 08, 2019 770 771 772 773 774 775 776 777 778 779 780 781 782 `````` // Generation units not be able to ramp from zero to min. load within one time interval according to their maxRampUp + sum(unitStarttype(unit, starttype)\${ uft_online(unit, f, t) and gnu_output(grid, node, unit) and not uft_startupTrajectory(unit, f, t) and ( + sum(suft(effGroup, unit, f, t), // Uses the minimum 'lb' for the current efficiency approximation + p_effGroupUnit(effGroup, unit, 'lb')\${not ts_effGroupUnit(effGroup, unit, 'lb', f, t)} + ts_effGroupUnit(effGroup, unit, 'lb', f, t) ) // END sum(effGroup) / p_stepLength(m, f, t) - p_gnu(grid, node, unit, 'maxRampUp') * 60 > 0 ) }, `````` Topi Rasku committed Apr 04, 2019 783 784 785 786 `````` + v_startup_LP(unit, starttype, s, f, t) \${ uft_onlineLP(unit, f, t) } + v_startup_MIP(unit, starttype, s, f, t) \${ uft_onlineMIP(unit, f, t) } `````` Niina Helistö committed Mar 08, 2019 787 788 789 790 791 792 793 794 795 796 797 798 `````` ) // END sum(starttype) * p_gnu(grid, node, unit, 'unitSizeTot') * ( + sum(suft(effGroup, unit, f, t), // Uses the minimum 'lb' for the current efficiency approximation + p_effGroupUnit(effGroup, unit, 'lb')\${not ts_effGroupUnit(effGroup, unit, 'lb', f, t)} + ts_effGroupUnit(effGroup, unit, 'lb', f, t) ) // END sum(effGroup) / p_stepLength(m, f, t) - p_gnu(grid, node, unit, 'maxRampUp') * 60 // Unit conversion from [p.u./min] to [p.u./h] ) // END * v_startup `````` Topi Rasku committed Jan 24, 2019 799 800 801 802 `````` // Units in the run-up phase need to keep up with the run-up rate + p_gnu(grid, node, unit, 'unitSizeTot') * sum(unitStarttype(unit, starttype)\${uft_startupTrajectory(unit, f, t)}, sum(runUpCounter(unit, counter)\${t_active(t+dt_trajectory(counter))}, // Sum over the run-up intervals `````` Topi Rasku committed Apr 04, 2019 803 804 `````` + [ + v_startup_LP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) `````` Topi Rasku committed Apr 04, 2019 805 `````` \${ uft_onlineLP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } `````` Topi Rasku committed Apr 04, 2019 806 `````` + v_startup_MIP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) `````` Topi Rasku committed Apr 04, 2019 807 `````` \${ uft_onlineMIP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } `````` Topi Rasku committed Apr 04, 2019 808 `````` ] `````` Topi Rasku committed Jan 24, 2019 809 810 811 812 813 814 815 816 `````` * [ + p_unit(unit, 'rampSpeedToMinLoad') + ( p_gnu(grid, node, unit, 'maxRampUp') - p_unit(unit, 'rampSpeedToMinLoad') )\${ not runUpCounter(unit, counter+1) } // Ramp speed adjusted for the last run-up interval * ( p_u_runUpTimeIntervalsCeil(unit) - p_u_runUpTimeIntervals(unit) ) ] * 60 // Unit conversion from [p.u./min] into [p.u./h] ) // END sum(runUpCounter) ) // END sum(unitStarttype) `````` Niina Helistö committed Jul 12, 2018 817 `````` `````` Niina Helistö committed Mar 08, 2019 818 `````` // Shutdown of consumption units according to maxRampUp `````` Topi Rasku committed Apr 04, 2019 819 820 821 822 823 824 `````` + [ + v_shutdown_LP(unit, s, f, t) \${uft_onlineLP(unit, f, t) and gnu_input(grid, node, unit)} + v_shutdown_MIP(unit, s, f, t) \${uft_onlineMIP(unit, f, t) and gnu_input(grid, node, unit)} ] `````` Niina Helistö committed Jul 12, 2018 825 `````` * p_gnu(grid, node, unit, 'unitSizeTot') `````` Niina Helistö committed Mar 08, 2019 826 827 828 `````` * p_gnu(grid, node, unit, 'maxRampUp') * 60 // Unit conversion from [p.u./min] to [p.u./h] // Consumption units not be able to ramp from min. load to zero within one time interval according to their maxRampUp `````` Topi Rasku committed Apr 04, 2019 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 `````` + [ + v_shutdown_LP(unit, s, f, t) \${ uft_onlineLP(unit, f, t) } + v_shutdown_MIP(unit, s, f, t) \${ uft_onlineMIP(unit, f, t) } ] \${ gnu_input(grid, node, unit) and ( + sum(suft(effGroup, unit, f, t), // Uses the minimum 'lb' for the current efficiency approximation + p_effGroupUnit(effGroup, unit, 'lb')\${not ts_effGroupUnit(effGroup, unit, 'lb', f, t)} + ts_effGroupUnit(effGroup, unit, 'lb', f, t) ) // END sum(effGroup) / p_stepLength(m, f, t) - p_gnu(grid, node, unit, 'maxRampUp') * 60 > 0 ) } `````` Niina Helistö committed Mar 08, 2019 845 846 847 848 849 850 851 852 853 `````` * p_gnu(grid, node, unit, 'unitSizeTot') * ( + sum(suft(effGroup, unit, f, t), // Uses the minimum 'lb' for the current efficiency approximation + p_effGroupUnit(effGroup, unit, 'lb')\${not ts_effGroupUnit(effGroup, unit, 'lb', f, t)} + ts_effGroupUnit(effGroup, unit, 'lb', f, t) ) // END sum(effGroup) / p_stepLength(m, f, t) - p_gnu(grid, node, unit, 'maxRampUp') * 60 // Unit conversion from [p.u./min] to [p.u./h] `````` Niina Helistö committed Mar 11, 2019 854 `````` ) // END * v_shutdown `````` Topi Rasku committed Mar 21, 2017 855 ``````; `````` Juha Kiviluoma committed Apr 06, 2018 856 `````` `````` 857 ``````* --- Ramp Down Limits -------------------------------------------------------- `````` 858 `````` `````` Topi Rasku committed Apr 04, 2019 859 860 861 862 863 864 865 866 867 868 869 870 ``````q_rampDownLimit(ms(m, s), gnuft_ramp(grid, node, unit, f, t)) \${ ord(t) > msStart(m, s) + 1 and msft(m, s, f, t) and p_gnu(grid, node, unit, 'maxRampDown') and [ sum(restype, nuRescapable(restype, 'down', node, unit)) or uft_online(unit, f, t) or unit_investLP(unit) or unit_investMIP(unit) ] } .. // Ramp speed of the unit? `````` Erkka Rinne committed Nov 02, 2018 871 `````` + v_genRamp(grid, node, unit, s, f, t) `````` 872 `````` - sum(nuRescapable(restype, 'down', node, unit)\${ord(t) < tSolveFirst + p_nReserves(node, restype, 'reserve_length')}, `````` Erkka Rinne committed Nov 02, 2018 873 `````` + v_reserve(restype, 'down', node, unit, s, f+df_reserves(node, restype, f, t), t) // (v_reserve can be used only if the unit is capable of providing a particular reserve) `````` Niina Helistö committed Jul 12, 2018 874 875 876 877 878 `````` ) // END sum(nuRescapable) / p_stepLength(m, f, t) =G= `````` 879 `````` // Ramping capability of units without online variable `````` Niina Helistö committed Jul 12, 2018 880 `````` - ( `````` Topi Rasku committed Apr 12, 2019 881 882 `````` + ( p_gnu(grid, node, unit, 'maxGen') + p_gnu(grid, node, unit, 'maxCons') ) \${not uft_online(unit, f, t)} `````` Niina Helistö committed Jul 12, 2018 883 `````` + sum(t_invest(t_)\${ ord(t_)<=ord(t) }, `````` Topi Rasku committed Apr 12, 2019 884 885 `````` + v_invest_LP(unit, t_) \${not uft_onlineLP(unit, f, t) and unit_investLP(unit)} `````` Niina Helistö committed Jul 12, 2018 886 `````` * p_gnu(grid, node, unit, 'unitSizeTot') `````` Topi Rasku committed Apr 12, 2019 887 888 `````` + v_invest_MIP(unit, t_) \${not uft_onlineMIP(unit, f, t) and unit_investMIP(unit)} `````` Niina Helistö committed Jul 12, 2018 889 890 891 892 893 894 `````` * p_gnu(grid, node, unit, 'unitSizeTot') ) ) * p_gnu(grid, node, unit, 'maxRampDown') * 60 // Unit conversion from [p.u./min] to [p.u./h] `````` Juha Kiviluoma committed May 17, 2018 895 `````` // Ramping capability of units that are online `````` Niina Helistö committed Jul 12, 2018 896 `````` - ( `````` Topi Rasku committed Apr 12, 2019 897 898 899 900 `````` + v_online_LP(unit, s, f+df_central(f,t), t) \${uft_onlineLP(unit, f, t)} + v_online_MIP(unit, s, f+df_central(f,t), t) \${uft_onlineMIP(unit, f, t)} `````` Niina Helistö committed Jul 12, 2018 901 902 903 904 905 `````` ) * p_gnu(grid, node, unit, 'unitSizeTot') * p_gnu(grid, node, unit, 'maxRampDown') * 60 // Unit conversion from [p.u./min] to [p.u./h] `````` Niina Helistö committed Mar 08, 2019 906 `````` // Shutdown of generation units according to maxRampDown `````` Topi Rasku committed Apr 04, 2019 907 908 909 910 911 912 913 914 915 `````` - [ + v_shutdown_LP(unit, s, f, t) \${ uft_onlineLP(unit, f, t) } + v_shutdown_MIP(unit, s, f, t) \${ uft_onlineMIP(unit, f, t) } ] \${ gnu_output(grid, node, unit) and not uft_shutdownTrajectory(unit, f, t) } `````` Niina Helistö committed Jul 12, 2018 916 `````` * p_gnu(grid, node, unit, 'unitSizeTot') `````` Niina Helistö committed Mar 08, 2019 917 918 919 `````` * p_gnu(grid, node, unit, 'maxRampDown') * 60 // Unit conversion from [p.u./min] to [p.u./h] // Generation units not be able to ramp from min. load to zero within one time interval according to their maxRampDown `````` Topi Rasku committed Apr 04, 2019 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 `````` - [ + v_shutdown_LP(unit, s, f, t) \${ uft_onlineLP(unit, f, t) } + v_shutdown_MIP(unit, s, f, t) \${ uft_onlineMIP(unit, f, t) } ] \${ gnu_output(grid, node, unit) and not uft_shutdownTrajectory(unit, f, t) and ( + sum(suft(effGroup, unit, f, t), // Uses the minimum 'lb' for the current efficiency approximation + p_effGroupUnit(effGroup, unit, 'lb')\${not ts_effGroupUnit(effGroup, unit, 'lb', f, t)} + ts_effGroupUnit(effGroup, unit, 'lb', f, t) ) // END sum(effGroup) / p_stepLength(m, f, t) - p_gnu(grid, node, unit, 'maxRampDown') * 60 > 0 ) } `````` Niina Helistö committed Mar 08, 2019 937 938 939 940 941 942 943 944 945 946 `````` * p_gnu(grid, node, unit, 'unitSizeTot') * ( + sum(suft(effGroup, unit, f, t), // Uses the minimum 'lb' for the current efficiency approximation + p_effGroupUnit(effGroup, unit, 'lb')\${not ts_effGroupUnit(effGroup, unit, 'lb', f, t)} + ts_effGroupUnit(effGroup, unit, 'lb', f, t) ) // END sum(effGroup) / p_stepLength(m, f, t) - p_gnu(grid, node, unit, 'maxRampDown') * 60 // Unit conversion from [p.u./min] to [p.u./h] ) // END * v_shutdown `````` Niina Helistö committed Jul 11, 2018 947 `````` `````` Topi Rasku committed Jan 24, 2019 948 949 `````` // Units in shutdown phase need to keep up with the shutdown ramp rate - p_gnu(grid, node, unit, 'unitSizeGen') `````` Topi Rasku committed Jan 25, 2019 950 951 `````` * [ + sum(shutdownCounter(unit, counter)\${t_active(t+dt_trajectory(counter)) and uft_shutdownTrajectory(unit, f, t)}, // Sum over the shutdown intervals `````` Topi Rasku committed Apr 04, 2019 952 953 954 955 956 957 `````` + [ + v_shutdown_LP(unit, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) \${ uft_onlineLP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } + v_shutdown_MIP(unit, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) \${ uft_onlineMIP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } ] `````` Topi Rasku committed Jan 25, 2019 958 `````` * [ `````` Niina Helistö committed Mar 13, 2019 959 960 961 `````` + p_gnu(grid, node, unit, 'maxRampDown')\${ not shutdownCounter(unit, counter-1) } // Normal maxRampDown limit applies to the time interval when v_shutdown happens, i.e. over the change from online to offline (symmetrical to v_startup) + p_unit(unit, 'rampSpeedFromMinLoad')\${ shutdownCounter(unit, counter-1) } // Normal trajectory ramping + ( p_gnu(grid, node, unit, 'maxRampDown') - p_unit(unit, 'rampSpeedFromMinLoad') )\${ shutdownCounter(unit, counter-1) and not shutdownCounter(unit, counter-2) } // Ramp speed adjusted for the first shutdown interval `````` Topi Rasku committed Jan 25, 2019 962 963 964 `````` * ( p_u_shutdownTimeIntervalsCeil(unit) - p_u_shutdownTimeIntervals(unit) ) ] ) // END sum(shutdownCounter) `````` Topi Rasku committed Jan 24, 2019 965 `````` // Units need to be able to shut down after shut down trajectory `````` Topi Rasku committed Apr 04, 2019 966 967 968 969 970 971 972 `````` + [ + v_shutdown_LP(unit, s, f+df(f, t+dt_toShutdown(unit, t)), t+dt_toShutdown(unit, t)) \${ uft_onlineLP_withPrevious(unit, f+df(f, t+dt_toShutdown(unit, t)), t+dt_toShutdown(unit, t)) } + v_shutdown_MIP(unit, s, f+df(f, t+dt_toShutdown(unit, t)), t+dt_toShutdown(unit, t)) \${ uft_onlineMIP_withPrevious(unit, f+df(f, t+dt_toShutdown(unit, t)), t+dt_toShutdown(unit, t)) } ] \${uft_shutdownTrajectory(unit, f, t)} `````` Niina Helistö committed Mar 13, 2019 973 974 975 976 977 `````` * [ + p_unit(unit, 'rampSpeedFromMinload') + ( p_gnu(grid, node, unit, 'maxRampDown') - p_unit(unit, 'rampSpeedFromMinLoad') )\${ sum(shutdownCounter(unit, counter), 1) = 1 } // Ramp speed adjusted if the unit has only one shutdown interval * ( p_u_shutdownTimeIntervalsCeil(unit) - p_u_shutdownTimeIntervals(unit) ) ] `````` Topi Rasku committed Jan 25, 2019 978 979 `````` ] * 60 // Unit conversion from [p.u./min] to [p.u./h] `````` Niina Helistö committed Mar 08, 2019 980 981 982 983 984 985 986 987 988 989 990 991 992 `````` // Consumption units not be able to ramp from zero to min. load within one time interval according to their maxRampDown - sum(unitStarttype(unit, starttype)\${ uft_online(unit, f, t) and gnu_input(grid, node, unit) and ( + sum(suft(effGroup, unit, f, t), // Uses the minimum 'lb' for the current efficiency approximation + p_effGroupUnit(effGroup, unit, 'lb')\${not ts_effGroupUnit(effGroup, unit, 'lb', f, t)} + ts_effGroupUnit(effGroup, unit, 'lb', f, t) ) // END sum(effGroup) / p_stepLength(m, f, t) - p_gnu(grid, node, unit, 'maxRampDown') * 60 > 0 ) }, `````` Topi Rasku committed Apr 04, 2019 993 994 995 996 `````` + v_startup_LP(unit, starttype, s, f, t) \${ uft_onlineLP(unit, f, t) } + v_startup_MIP(unit, starttype, s, f, t) \${ uft_onlineMIP(unit, f, t) } `````` Niina Helistö committed Mar 08, 2019 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 `````` ) // END sum(starttype) * p_gnu(grid, node, unit, 'unitSizeTot') * ( + sum(suft(effGroup, unit, f, t), // Uses the minimum 'lb' for the current efficiency approximation + p_effGroupUnit(effGroup, unit, 'lb')\${not ts_effGroupUnit(effGroup, unit, 'lb', f, t)} + ts_effGroupUnit(effGroup, unit, 'lb', f, t) ) // END sum(effGroup) / p_stepLength(m, f, t) - p_gnu(grid, node, unit, 'maxRampDown') * 60 // Unit conversion from [p.u./min] to [p.u./h] ) // END * v_startup `````` Juha Kiviluoma committed Jun 15, 2018 1008 1009 ``````; `````` 1010 1011 ``````* --- Ramps separated into upward and downward ramps -------------------------- `````` Topi Rasku committed Apr 04, 2019 1012 1013 1014 1015 1016 ``````q_rampUpDown(ms(m, s), gnuft_ramp(grid, node, unit, f, t)) \${ ord(t) > msStart(m, s) + 1 and msft(m, s, f, t) and sum(slack, gnuft_rampCost(grid, node, unit, slack, f, t)) } .. `````` 1017 `````` `````` Topi Rasku committed Apr 04, 2019 1018 `````` // Ramp speed of the unit? `````` Erkka Rinne committed Nov 02, 2018 1019 `````` + v_genRamp(grid, node, unit, s, f, t) `````` 1020 `````` `````` Niina Helistö committed Jul 12, 2018 1021 `````` =E= `````` 1022 `````` `````` Niina Helistö committed Jul 12, 2018 1023 1024 `````` // Upward and downward ramp categories + sum(slack\${ gnuft_rampCost(grid, node, unit, slack, f, t) }, `````` Erkka Rinne committed Nov 02, 2018 1025 1026 `````` + v_genRampUpDown(grid, node, unit, slack, s, f, t)\$upwardSlack(slack) - v_genRampUpDown(grid, node, unit, slack, s, f, t)\$downwardSlack(slack) `````` Niina Helistö committed Jul 12, 2018 1027 `````` ) // END sum(slack) `````` Niina Helistö committed Mar 11, 2019 1028 1029 1030 1031 1032 1033 `````` // Start-up of generation units to min. load (not counted in the ramping costs) + sum(unitStarttype(unit, starttype)\${ uft_online(unit, f, t) and gnu_output(grid, node, unit) and not uft_startupTrajectory(unit, f, t) }, `````` Niina Helistö committed Apr 11, 2019 1034 1035 1036 1037 `````` + v_startup_LP(unit, starttype, s, f, t) \${ uft_onlineLP(unit, f, t) } + v_startup_MIP(unit, starttype, s, f, t) \${ uft_onlineMIP(unit, f, t) } `````` Niina Helistö committed Mar 11, 2019 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 `````` ) // END sum(starttype) * p_gnu(grid, node, unit, 'unitSizeTot') * ( + sum(suft(effGroup, unit, f, t), // Uses the minimum 'lb' for the current efficiency approximation + p_effGroupUnit(effGroup, unit, 'lb')\${not ts_effGroupUnit(effGroup, unit, 'lb', f, t)} + ts_effGroupUnit(effGroup, unit, 'lb', f, t) ) // END sum(effGroup) / p_stepLength(m, f, t) ) // END * v_startup // Generation units in the run-up phase need to keep up with the run-up rate (not counted in the ramping costs) + p_gnu(grid, node, unit, 'unitSizeGen') * sum(unitStarttype(unit, starttype)\${uft_startupTrajectory(unit, f, t)}, sum(runUpCounter(unit, counter)\${t_active(t+dt_trajectory(counter))}, // Sum over the run-up intervals `````` Niina Helistö committed Apr 11, 2019 1052 1053 1054 1055 1056 1057 `````` + [ + v_startup_LP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) \${ uft_onlineLP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))} + v_startup_MIP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) \${ uft_onlineMIP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))} ] `````` Niina Helistö committed Mar 11, 2019 1058 `````` * [ `````` Niina Helistö committed Mar 13, 2019 1059 1060 1061 1062 1063 1064 `````` + p_uCounter_runUpMin(unit, counter)\${ not runUpCounter(unit, counter-1) } // Ramp speed adjusted for the first run-up interval / p_stepLength(m, f, t) // Ramp is the change of v_gen divided by interval length + p_unit(unit, 'rampSpeedToMinLoad')\${ runUpCounter(unit, counter-1) and runUpCounter(unit, counter+1) } // Normal trajectory ramping in the middle of the trajectory * 60 // Unit conversion from [p.u./min] into [p.u./h] + p_u_minRampSpeedInLastRunUpInterval(unit)\${ runUpCounter(unit, counter-1) and not runUpCounter(unit, counter+1) } // Ramp speed adjusted for the last run-up interval * 60 // Unit conversion from [p.u./min] into [p.u./h] `````` Niina Helistö committed Mar 11, 2019 1065 1066 1067 1068 1069 `````` ] ) // END sum(runUpCounter) ) // END sum(unitStarttype) // Shutdown of consumption units from min. load (not counted in the ramping costs) `````` Niina Helistö committed Apr 11, 2019 1070 1071 1072 1073 1074 1075 `````` + [ + v_shutdown_LP(unit, s, f, t) \${ uft_onlineLP(unit, f, t) and gnu_input(grid, node, unit)} + v_shutdown_MIP(unit, s, f, t) \${ uft_onlineMIP(unit, f, t) and gnu_input(grid, node, unit)} ] `````` Niina Helistö committed Mar 11, 2019 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 `````` * p_gnu(grid, node, unit, 'unitSizeTot') * ( + sum(suft(effGroup, unit, f, t), // Uses the minimum 'lb' for the current efficiency approximation + p_effGroupUnit(effGroup, unit, 'lb')\${not ts_effGroupUnit(effGroup, unit, 'lb', f, t)} + ts_effGroupUnit(effGroup, unit, 'lb', f, t) ) // END sum(effGroup) / p_stepLength(m, f, t) ) // END * v_shutdown // Shutdown of generation units from min. load (not counted in the ramping costs) `````` Niina Helistö committed Apr 11, 2019 1086 1087 1088 1089 1090 1091 `````` - [ + v_shutdown_LP(unit, s, f, t) \${ uft_onlineLP(unit, f, t) and gnu_output(grid, node, unit) and not uft_shutdownTrajectory(unit, f, t)} + v_shutdown_MIP(unit, s, f, t) \${ uft_onlineMIP(unit, f, t) and gnu_output(grid, node, unit) and not uft_shutdownTrajectory(unit, f, t)} ] `````` Niina Helistö committed Mar 11, 2019 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 `````` * p_gnu(grid, node, unit, 'unitSizeTot') * ( + sum(suft(effGroup, unit, f, t), // Uses the minimum 'lb' for the current efficiency approximation + p_effGroupUnit(effGroup, unit, 'lb')\${not ts_effGroupUnit(effGroup, unit, 'lb', f, t)} + ts_effGroupUnit(effGroup, unit, 'lb', f, t) ) // END sum(effGroup) / p_stepLength(m, f, t) ) // END * v_shutdown // Generation units in shutdown phase need to keep up with the shutdown ramp rate (not counted in the ramping costs) - p_gnu(grid, node, unit, 'unitSizeGen') * [ + sum(shutdownCounter(unit, counter)\${t_active(t+dt_trajectory(counter)) and uft_shutdownTrajectory(unit, f, t)}, // Sum over the shutdown intervals `````` Niina Helistö committed Apr 11, 2019 1105 1106 `````` + [ + v_shutdown_LP(unit, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) `````` Topi Rasku committed Apr 12, 2019 1107 `````` \${ uft_onlineLP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))} `````` Niina Helistö committed Apr 11, 2019 1108 `````` + v_shutdown_MIP(unit, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) `````` Topi Rasku committed Apr 12, 2019 1109 `````` \${ uft_onlineMIP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))} `````` Niina Helistö committed Apr 11, 2019 1110 `````` ] `````` Niina Helistö committed Mar 11, 2019 1111 `````` * [ `````` Niina Helistö committed Mar 13, 2019 1112 1113 1114 1115 1116 `````` // Note that ramping happening during shutdown trajectory when ord(counter) = 1 is considered 'normal ramping' and causes ramping costs + p_u_minRampSpeedInFirstShutdownInterval(unit)\${ not shutdownCounter(unit, counter-2) and shutdownCounter(unit, counter-1) } // Ramp speed adjusted for the first shutdown interval * 60 // Unit conversion from [p.u./min] into [p.u./h] + p_unit(unit, 'rampSpeedFromMinLoad')\${ shutdownCounter(unit, counter-2) } // Normal trajectory ramping in the middle of the trajectory * 60 // Unit conversion from [p.u./min] into [p.u./h] `````` Niina Helistö committed Mar 11, 2019 1117 1118 1119 `````` ] ) // END sum(shutdownCounter) // Units need to be able to shut down after shut down trajectory `````` Niina Helistö committed Apr 11, 2019 1120 1121 `````` + [ + v_shutdown_LP(unit, s, f+df(f, t+dt_toShutdown(unit, t)), t+dt_toShutdown(unit, t)) `````` Topi Rasku committed Apr 12, 2019 1122 `````` \${ uft_onlineLP_withPrevious(unit, f+df(f, t+dt_toShutdown(unit, t)), t+dt_toShutdown(unit, t))} `````` Niina Helistö committed Apr 11, 2019 1123 `````` + v_shutdown_MIP(unit, s, f+df(f, t+dt_toShutdown(unit, t)), t+dt_toShutdown(unit, t)) `````` Topi Rasku committed Apr 12, 2019 1124 `````` \${ uft_onlineMIP_withPrevious(unit, f+df(f, t+dt_toShutdown(unit, t)), t+dt_toShutdown(unit, t))} `````` Niina Helistö committed Apr 11, 2019 1125 `````` ] `````` Niina Helistö committed Mar 13, 2019 1126 1127 `````` * sum(shutdownCounter(unit, counter)\${not shutdownCounter(unit, counter+1)}, p_uCounter_shutdownMin(unit, counter)) // Minimum generation level at the last shutdown interval / p_stepLength(m, f, t) // Ramp is the change of v_gen divided by interval length `````` Niina Helistö committed Mar 11, 2019 1128 1129 1130 1131 1132 1133 `````` ] // Start-up of consumption units to min. load (not counted in the ramping costs) - sum(unitStarttype(unit, starttype)\${ uft_online(unit, f, t) and gnu_input(grid, node, unit) }, `````` Niina Helistö committed Apr 11, 2019 1134 1135 1136 1137 `````` + v_startup_LP(unit, starttype, s, f, t) \${ uft_onlineLP(unit, f, t) } + v_startup_MIP(unit, starttype, s, f, t) \${ uft_onlineMIP(unit, f, t) } `````` Niina Helistö committed Mar 11, 2019 1138 1139 1140 1141 1142 1143 1144 1145 1146 `````` ) // END sum(starttype) * p_gnu(grid, node, unit, 'unitSizeTot') * ( + sum(suft(effGroup, unit, f, t), // Uses the minimum 'lb' for the current efficiency approximation + p_effGroupUnit(effGroup, unit, 'lb')\${not ts_effGroupUnit(effGroup, unit, 'lb', f, t)} + ts_effGroupUnit(effGroup, unit, 'lb', f, t) ) // END sum(effGroup) / p_stepLength(m, f, t) ) // END * v_startup `````` Juha Kiviluoma committed Apr 03, 2018 1147 1148 ``````; `````` Niina Helistö committed Jul 24, 2018 1149 ``````* --- Upward and downward ramps constrained by slack boundaries --------------- `````` 1150 `````` `````` Topi Rasku committed Apr 04, 2019 1151 1152 1153 1154 ``````q_rampSlack(ms(m, s), gnuft_rampCost(grid, node, unit, slack, f, t)) \${ ord(t) > msStart(m, s) + 1 and msft(m, s, f, t) } .. `````` 1155 `````` `````` Topi Rasku committed Apr 04, 2019 1156 `````` // Directional ramp speed of the unit? `````` Erkka Rinne committed Nov 02, 2018 1157 `````` + v_genRampUpDown(grid, node, unit, slack, s, f, t) `````` 1158 `````` `````` Niina Helistö committed Jul 12, 2018 1159 `````` =L= `````` 1160 1161 `````` // Ramping capability of units without an online variable `````` Niina Helistö committed Jul 12, 2018 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 `````` + ( + ( p_gnu(grid, node, unit, 'maxGen') + p_gnu(grid, node, unit, 'maxCons') )\${not uft_online(unit, f, t)} + sum(t_invest(t_)\${ ord(t_)<=ord(t) }, + v_invest_LP(unit, t_)\${not uft_onlineLP(unit, f, t) and unit_investLP(unit)} * p_gnu(grid, node, unit, 'unitSizeTot') + v_invest_MIP(unit, t_)\${not uft_onlineMIP(unit, f, t) and unit_investMIP(unit)} * p_gnu(grid, node, unit, 'unitSizeTot') ) ) * p_gnuBoundaryProperties(grid, node, unit, slack, 'rampLimit') * 60 // Unit conversion from [p.u./min] to [p.u./h] `````` 1173 1174 `````` // Ramping capability of units with an online variable ``````