2d_constraints.gms 175 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 `````` `````` 93 94 ``````q_resDemand(restypeDirectionGroup(restype, up_down, group), sft(s, f, t)) \${ ord(t) < tSolveFirst + p_groupReserves(group, restype, 'reserve_length') `````` Topi Rasku committed Oct 05, 2018 95 `````` 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 `````` `````` 99 `````` // Reserve provision by capable units on this group `````` Niina Helistö committed Oct 01, 2019 100 `````` + sum(gnuft(grid, node, unit, f, t)\${ gnGroup(grid, node, group) `````` Niina Helistö committed Oct 03, 2019 101 `````` and gnuRescapable(restype, up_down, grid, node, unit) `````` Niina Helistö committed Oct 01, 2019 102 `````` }, `````` Niina Helistö committed Oct 03, 2019 103 `````` + v_reserve(restype, up_down, grid, node, unit, s, f+df_reserves(grid, node, restype, f, t), t) `````` Topi Rasku committed Jan 15, 2019 104 `````` * [ // Account for reliability of reserves `````` Niina Helistö committed Oct 03, 2019 105 106 `````` + 1\${sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} // reserveReliability limits the reliability of reserves locked ahead of time. + p_gnuReserves(grid, node, unit, restype, 'reserveReliability')\${not sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} `````` Topi Rasku committed Jan 15, 2019 107 `````` ] // END * v_reserve `````` 108 `````` ) // END sum(gnuft) `````` Topi Rasku committed Oct 11, 2017 109 `````` `````` 110 `````` // Reserve provision from other reserve categories when they can be shared `````` Niina Helistö committed Oct 01, 2019 111 `````` + sum((gnuft(grid, node, unit, f, t), restype_)\${ gnGroup(grid, node, group) `````` Niina Helistö committed Oct 03, 2019 112 `````` and p_gnuRes2Res(grid, node, unit, restype_, up_down, restype) `````` Niina Helistö committed Oct 01, 2019 113 `````` }, `````` Niina Helistö committed Oct 03, 2019 114 115 `````` + v_reserve(restype_, up_down, grid, node, unit, s, f+df_reserves(grid, node, restype_, f, t), t) * p_gnuRes2Res(grid, node, unit, restype_, up_down, restype) `````` Topi Rasku committed Jan 15, 2019 116 `````` * [ // Account for reliability of reserves `````` Niina Helistö committed Oct 03, 2019 117 118 119 `````` + 1\${sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} // reserveReliability limits the reliability of reserves locked ahead of time. + p_gnuReserves(grid, node, unit, restype, 'reserveReliability')\${not sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} * p_gnuReserves(grid, node, unit, restype_, 'reserveReliability') `````` Topi Rasku committed Jan 15, 2019 120 `````` ] // END * v_reserve `````` 121 `````` ) // END sum(gnuft) `````` 122 `````` `````` 123 `````` // Reserve provision to this group via transfer links `````` Niina Helistö committed Oct 01, 2019 124 125 `````` + sum(gn2n_directional(grid, node_, node)\${ gnGroup(grid, node, group) and not gnGroup(grid, node_, group) `````` Niina Helistö committed Oct 03, 2019 126 `````` and restypeDirectionGridNodeNode(restype, up_down, grid, node_, node) `````` Niina Helistö committed Oct 01, 2019 127 `````` }, `````` Topi Rasku committed Oct 11, 2017 128 `````` + (1 - p_gnn(grid, node_, node, 'transferLoss') ) `````` Niina Helistö committed Oct 03, 2019 129 `````` * v_resTransferRightward(restype, up_down, grid, node_, node, s, f+df_reserves(grid, node_, restype, f, t), t) // Reserves from another node - reduces the need for reserves in the node `````` Topi Rasku committed Oct 11, 2017 130 `````` ) // END sum(gn2n_directional) `````` Niina Helistö committed Oct 01, 2019 131 132 `````` + sum(gn2n_directional(grid, node, node_)\${ gnGroup(grid, node, group) and not gnGroup(grid, node_, group) `````` Niina Helistö committed Oct 03, 2019 133 `````` and restypeDirectionGridNodeNode(restype, up_down, grid, node_, node) `````` Niina Helistö committed Oct 01, 2019 134 `````` }, `````` Topi Rasku committed Oct 11, 2017 135 `````` + (1 - p_gnn(grid, node, node_, 'transferLoss') ) `````` Niina Helistö committed Oct 03, 2019 136 `````` * v_resTransferLeftward(restype, up_down, grid, node, node_, s, f+df_reserves(grid, node_, restype, f, t), t) // Reserves from another node - reduces the need for reserves in the node `````` Topi Rasku committed Oct 11, 2017 137 138 139 140 141 `````` ) // END sum(gn2n_directional) =G= // Demand for reserves `````` 142 143 `````` + ts_reserveDemand(restype, up_down, group, f, t)\${p_groupReserves(group, restype, 'use_time_series')} + p_groupReserves(group, restype, up_down)\${not p_groupReserves(group, restype, 'use_time_series')} `````` Topi Rasku committed Oct 11, 2017 144 `````` `````` Niina Helistö committed Nov 02, 2018 145 `````` // Reserve demand increase because of units `````` Niina Helistö committed Oct 01, 2019 146 `````` + sum(gnuft(grid, node, unit, f, t)\${ gnGroup(grid, node, group) `````` Niina Helistö committed Oct 03, 2019 147 `````` and p_gnuReserves(grid, node, unit, restype, 'reserve_increase_ratio') // Could be better to have 'reserve_increase_ratio' separately for up and down directions `````` Niina Helistö committed Oct 01, 2019 148 `````` }, `````` Niina Helistö committed Oct 03, 2019 149 150 `````` + v_gen(grid, node, unit, s, f, t) * p_gnuReserves(grid, node, unit, restype, 'reserve_increase_ratio') `````` Niina Helistö committed Nov 02, 2018 151 152 `````` ) // END sum(nuft) `````` 153 `````` // Reserve provisions to other groups via transfer links `````` Niina Helistö committed Oct 01, 2019 154 155 `````` + sum(gn2n_directional(grid, node, node_)\${ gnGroup(grid, node, group) and not gnGroup(grid, node_, group) `````` Niina Helistö committed Oct 03, 2019 156 `````` and restypeDirectionGridNodeNode(restype, up_down, grid, node, node_) `````` Niina Helistö committed Oct 01, 2019 157 `````` }, // If trasferring reserves to another node, increase your own reserves by same amount `````` Niina Helistö committed Oct 03, 2019 158 `````` + v_resTransferRightward(restype, up_down, grid, node, node_, s, f+df_reserves(grid, node, restype, f, t), t) `````` Topi Rasku committed Oct 11, 2017 159 `````` ) // END sum(gn2n_directional) `````` Niina Helistö committed Oct 01, 2019 160 161 `````` + sum(gn2n_directional(grid, node_, node)\${ gnGroup(grid, node, group) and not gnGroup(grid, node_, group) `````` Niina Helistö committed Oct 03, 2019 162 `````` and restypeDirectionGridNodeNode(restype, up_down, grid, node, node_) `````` Niina Helistö committed Oct 01, 2019 163 `````` }, // If trasferring reserves to another node, increase your own reserves by same amount `````` Niina Helistö committed Oct 03, 2019 164 `````` + v_resTransferLeftward(restype, up_down, grid, node_, node, s, f+df_reserves(grid, node, restype, f, t), t) `````` Topi Rasku committed Oct 11, 2017 165 166 167 `````` ) // END sum(gn2n_directional) // Reserve demand feasibility dummy variables `````` 168 169 `````` - vq_resDemand(restype, up_down, group, s, f+df_reservesGroup(group, restype, f, t), t) - vq_resMissing(restype, up_down, group, s, f+df_reservesGroup(group, restype, f, t), t)\${ft_reservesFixed(group, restype, f+df_reservesGroup(group, restype, f, t), t)} `````` 170 ``````; `````` Topi Rasku committed Oct 11, 2017 171 `````` `````` ran li committed Nov 25, 2018 172 173 174 175 ``````* --- 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. `````` Niina Helistö committed Oct 01, 2019 176 177 ``````q_resDemandLargestInfeedUnit(restypeDirectionGroup(restype, 'up', group), unit_fail(unit_), sft(s, f, t)) \${ ord(t) < tSolveFirst + p_groupReserves(group, restype, 'reserve_length') `````` ran li committed Nov 25, 2018 178 179 180 `````` and not [ restypeReleasedForRealization(restype) and ft_realized(f, t) ] `````` Niina Helistö committed Oct 03, 2019 181 `````` and sum(gnGroup(grid, node, group), p_gnuReserves(grid, node, unit_, restype, 'portion_of_infeed_to_reserve')) `````` Niina Helistö committed Oct 01, 2019 182 183 `````` and uft(unit_, f, t) // only active units and sum(gnGroup(grid, node, group), gnu_output(grid, node, unit_)) // only units with output capacity 'inside the group' `````` ran li committed Nov 25, 2018 184 `````` } .. `````` Topi Rasku committed Apr 04, 2019 185 `````` `````` Niina Helistö committed Oct 01, 2019 186 187 `````` // Reserve provision by capable units on this group excluding the failing one + sum(gnuft(grid, node, unit, f, t)\${ gnGroup(grid, node, group) `````` Niina Helistö committed Oct 03, 2019 188 `````` and gnuRescapable(restype, 'up', grid, node, unit) `````` Niina Helistö committed Oct 01, 2019 189 190 `````` and (ord(unit_) ne ord(unit)) }, `````` Niina Helistö committed Oct 03, 2019 191 `````` + v_reserve(restype, 'up', grid, node, unit, s, f+df_reserves(grid, node, restype, f, t), t) `````` Topi Rasku committed Jan 15, 2019 192 `````` * [ // Account for reliability of reserves `````` Niina Helistö committed Oct 03, 2019 193 194 `````` + 1\${sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} // reserveReliability limits the reliability of reserves locked ahead of time. + p_gnuReserves(grid, node, unit, restype, 'reserveReliability')\${not sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} `````` Topi Rasku committed Jan 15, 2019 195 `````` ] // END * v_reserve `````` ran li committed Nov 25, 2018 196 197 198 `````` ) // END sum(nuft) // Reserve provision from other reserve categories when they can be shared `````` Niina Helistö committed Oct 01, 2019 199 `````` + sum((gnuft(grid, node, unit, f, t), restype_)\${ gnGroup(grid, node, group) `````` Niina Helistö committed Oct 03, 2019 200 `````` and p_gnuRes2Res(grid, node, unit, restype_, 'up', restype) `````` Niina Helistö committed Oct 01, 2019 201 202 `````` and (ord(unit_) ne ord(unit)) }, `````` Niina Helistö committed Oct 03, 2019 203 204 `````` + v_reserve(restype_, 'up', grid, node, unit, s, f+df_reserves(grid, node, restype_, f, t), t) * p_gnuRes2Res(grid, node, unit, restype_, 'up', restype) `````` Topi Rasku committed Jan 15, 2019 205 `````` * [ // Account for reliability of reserves `````` Niina Helistö committed Oct 03, 2019 206 207 208 `````` + 1\${sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} // reserveReliability limits the reliability of reserves locked ahead of time. + p_gnuReserves(grid, node, unit, restype, 'reserveReliability')\${not sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} * p_gnuReserves(grid, node, unit, restype_, 'reserveReliability') `````` Topi Rasku committed Jan 15, 2019 209 `````` ] // END * v_reserve `````` ran li committed Nov 25, 2018 210 211 `````` ) // END sum(nuft) `````` Niina Helistö committed Oct 01, 2019 212 213 214 `````` // Reserve provision to this group via transfer links + sum(gn2n_directional(grid, node_, node)\${ gnGroup(grid, node, group) and not gnGroup(grid, node_, group) `````` Niina Helistö committed Oct 03, 2019 215 `````` and restypeDirectionGridNodeNode(restype, 'up', grid, node_, node) `````` Niina Helistö committed Oct 01, 2019 216 `````` }, `````` ran li committed Nov 25, 2018 217 `````` + (1 - p_gnn(grid, node_, node, 'transferLoss') ) `````` Niina Helistö committed Oct 03, 2019 218 `````` * v_resTransferRightward(restype, 'up', grid, node_, node, s, f+df_reserves(grid, node_, restype, f, t), t) // Reserves from another node - reduces the need for reserves in the node `````` ran li committed Nov 25, 2018 219 `````` ) // END sum(gn2n_directional) `````` Niina Helistö committed Oct 01, 2019 220 221 `````` + sum(gn2n_directional(grid, node, node_)\${ gnGroup(grid, node, group) and not gnGroup(grid, node_, group) `````` Niina Helistö committed Oct 03, 2019 222 `````` and restypeDirectionGridNodeNode(restype, 'up', grid, node_, node) `````` Niina Helistö committed Oct 01, 2019 223 `````` }, `````` ran li committed Nov 25, 2018 224 `````` + (1 - p_gnn(grid, node, node_, 'transferLoss') ) `````` Niina Helistö committed Oct 03, 2019 225 `````` * v_resTransferLeftward(restype, 'up', grid, node, node_, s, f+df_reserves(grid, node_, restype, f, t), t) // Reserves from another node - reduces the need for reserves in the node `````` ran li committed Nov 25, 2018 226 227 228 229 `````` ) // END sum(gn2n_directional) =G= `````` Juha Kiviluoma committed Aug 28, 2019 230 `````` // Demand for reserves due to a large unit that could fail `````` Niina Helistö committed Oct 01, 2019 231 232 `````` + sum(gnGroup(grid, node, group), + v_gen(grid, node, unit_, s, f, t) `````` Niina Helistö committed Oct 03, 2019 233 `````` * p_gnuReserves(grid, node, unit_, restype, 'portion_of_infeed_to_reserve') `````` Niina Helistö committed Oct 01, 2019 234 `````` ) // END sum(gnGroup) `````` ran li committed Nov 25, 2018 235 `````` `````` Niina Helistö committed Oct 01, 2019 236 237 238 `````` // Reserve provisions to other groups via transfer links + sum(gn2n_directional(grid, node, node_)\${ gnGroup(grid, node, group) and not gnGroup(grid, node_, group) `````` Niina Helistö committed Oct 03, 2019 239 `````` and restypeDirectionGridNodeNode(restype, 'up', grid, node, node_) `````` Niina Helistö committed Oct 01, 2019 240 `````` }, // If trasferring reserves to another node, increase your own reserves by same amount `````` Niina Helistö committed Oct 03, 2019 241 `````` + v_resTransferRightward(restype, 'up', grid, node, node_, s, f+df_reserves(grid, node, restype, f, t), t) `````` ran li committed Nov 25, 2018 242 `````` ) // END sum(gn2n_directional) `````` Niina Helistö committed Oct 01, 2019 243 244 `````` + sum(gn2n_directional(grid, node_, node)\${ gnGroup(grid, node, group) and not gnGroup(grid, node_, group) `````` Niina Helistö committed Oct 03, 2019 245 `````` and restypeDirectionGridNodeNode(restype, 'up', grid, node, node_) `````` Niina Helistö committed Oct 01, 2019 246 `````` }, // If trasferring reserves to another node, increase your own reserves by same amount `````` Niina Helistö committed Oct 03, 2019 247 `````` + v_resTransferLeftward(restype, 'up', grid, node_, node, s, f+df_reserves(grid, node, restype, f, t), t) `````` ran li committed Nov 25, 2018 248 249 250 `````` ) // END sum(gn2n_directional) // Reserve demand feasibility dummy variables `````` Niina Helistö committed Oct 01, 2019 251 252 `````` - vq_resDemand(restype, 'up', group, s, f+df_reservesGroup(group, restype, f, t), t) - vq_resMissing(restype, 'up', group, s, f+df_reservesGroup(group, restype, f, t), t)\${ft_reservesFixed(group, restype, f+df_reservesGroup(group, restype, f, t), t)} `````` ran li committed Nov 25, 2018 253 ``````; `````` ran li committed Aug 27, 2019 254 `````` `````` Niina Helistö committed Oct 01, 2019 255 256 ``````* --- ROCOF Limit -- Units ---------------------------------------------------- `````` Niina Helistö committed Sep 24, 2019 257 258 259 ``````q_rateOfChangeOfFrequencyUnit(group, unit_fail(unit_), sft(s, f, t)) \${ p_groupPolicy(group, 'defaultFrequency') and p_groupPolicy(group, 'ROCOF') `````` Niina Helistö committed Oct 01, 2019 260 261 `````` and uft(unit_, f, t) // only active units and sum(gnGroup(grid, node, group), gnu_output(grid, node, unit_)) // only units with output capacity 'inside the group' `````` ran li committed Sep 05, 2019 262 263 `````` } .. `````` Niina Helistö committed Sep 24, 2019 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 `````` // Kinetic/rotational energy in the system + p_groupPolicy(group, 'ROCOF')*2 * [ + sum(gnu_output(grid, node, unit)\${ ord(unit) ne ord(unit_) and gnGroup(grid, node, group) and gnuft(grid, node, unit, f, t) }, + p_gnu(grid, node, unit, 'inertia') * p_gnu(grid ,node, unit, 'unitSizeMVA') * [ + 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)} + v_gen(grid, node, unit, s, f, t)\${not uft_online(unit, f, t)} / p_gnu(grid, node, unit, 'unitSizeGen') ] // * p_gnu ) // END sum(gnu_output) ] // END * p_groupPolicy `````` ran li committed Sep 05, 2019 283 284 285 `````` =G= `````` Niina Helistö committed Sep 24, 2019 286 287 288 289 290 291 `````` // Demand for kinetic/rotational energy due to a large unit that could fail + p_groupPolicy(group, 'defaultFrequency') * sum(gnu_output(grid, node, unit_)\${ gnGroup(grid, node, group) }, + v_gen(grid, node, unit_ , s, f, t) ) // END sum(gnu_output) `````` ran li committed Sep 05, 2019 292 ``````; `````` Niina Helistö committed Sep 24, 2019 293 `````` `````` Niina Helistö committed Oct 01, 2019 294 295 296 ``````* --- ROCOF Limit -- Transfer Links ------------------------------------------- q_rateOfChangeOfFrequencyTransfer(group, gn2n(grid, node_, node_fail), sft(s, f, t)) `````` Niina Helistö committed Sep 24, 2019 297 298 299 300 301 302 303 `````` \${ p_groupPolicy(group, 'defaultFrequency') and p_groupPolicy(group, 'ROCOF') and gnGroup(grid, node_, group) // only interconnectors where one end is 'inside the group' and not gnGroup(grid, node_fail, group) // and the other end is 'outside the group' and [ p_gnn(grid, node_, node_fail, 'portion_of_transfer_to_reserve') or p_gnn(grid, node_fail, node_, 'portion_of_transfer_to_reserve') ] `````` ran li committed Sep 05, 2019 304 305 `````` } .. `````` Niina Helistö committed Sep 24, 2019 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 `````` // Kinetic/rotational energy in the system + p_groupPolicy(group, 'ROCOF')*2 * [ + sum(gnu_output(grid, node, unit)\${ gnGroup(grid, node, group) and gnuft(grid, node, unit, f, t) }, + p_gnu(grid, node, unit, 'inertia') * p_gnu(grid ,node, unit, 'unitSizeMVA') * [ + 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)} + v_gen(grid, node, unit, s, f, t)\${not uft_online(unit, f, t)} / p_gnu(grid, node, unit, 'unitSizeGen') ] // * p_gnu ) // END sum(gnu_output) ] // END * p_groupPolicy `````` ran li committed Sep 05, 2019 324 325 326 `````` =G= `````` Niina Helistö committed Sep 24, 2019 327 328 329 330 331 `````` // Demand for kinetic/rotational energy due to a large interconnector that could fail + p_groupPolicy(group, 'defaultFrequency') * [ // Loss of import due to potential interconnector failures + p_gnn(grid, node_fail, node_, 'portion_of_transfer_to_reserve') `````` Niina Helistö committed Oct 01, 2019 332 `````` * v_transferRightward(grid, node_fail, node_, s, f, t)\${gn2n_directional(grid, node_fail, node_)} `````` Niina Helistö committed Sep 24, 2019 333 334 `````` * (1 - p_gnn(grid, node_fail, node_, 'transferLoss') ) + p_gnn(grid, node_, node_fail, 'portion_of_transfer_to_reserve') `````` Niina Helistö committed Oct 01, 2019 335 `````` * v_transferLeftward(grid, node_, node_fail, s, f, t)\${gn2n_directional(grid, node_, node_fail)} `````` Niina Helistö committed Sep 24, 2019 336 337 338 `````` * (1 - p_gnn(grid, node_, node_fail, 'transferLoss') ) // Loss of export due to potential interconnector failures + p_gnn(grid, node_fail, node_, 'portion_of_transfer_to_reserve') `````` Niina Helistö committed Oct 01, 2019 339 `````` * v_transferLeftward(grid, node_fail, node_, s, f, t)\${gn2n_directional(grid, node_fail, node_)} `````` Niina Helistö committed Sep 24, 2019 340 `````` + p_gnn(grid, node_, node_fail, 'portion_of_transfer_to_reserve') `````` Niina Helistö committed Oct 01, 2019 341 `````` * v_transferRightward(grid, node_, node_fail, s, f, t)\${gn2n_directional(grid, node_, node_fail)} `````` Niina Helistö committed Sep 24, 2019 342 `````` ] // END * p_groupPolicy `````` ran li committed Sep 05, 2019 343 ``````; `````` Niina Helistö committed Sep 24, 2019 344 `````` `````` Niina Helistö committed Oct 01, 2019 345 ``````* --- N-1 Upward reserve demand due to a possibility that an interconnector that is transferring power to the node group fails ------------------------------------------------- `````` ran li committed Aug 27, 2019 346 347 348 ``````// 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. `````` Niina Helistö committed Oct 01, 2019 349 350 ``````q_resDemandLargestInfeedTransferUp(restypeDirectionGroup(restype, 'up', group), gn2n(grid, node_, node_fail), sft(s, f, t)) \${ ord(t) < tSolveFirst + p_groupReserves(group, restype, 'reserve_length') `````` ran li committed Aug 27, 2019 351 352 `````` and not [ restypeReleasedForRealization(restype) and sft_realized(s, f, t)] `````` Niina Helistö committed Oct 01, 2019 353 354 355 `````` and gn2n_directional(grid, node_, node_fail) and [ (gnGroup(grid, node_, group) and not gnGroup(grid, node_fail, group)) // only interconnectors where one end is 'inside the group' or (gnGroup(grid, node_fail, group) and not gnGroup(grid, node_, group)) // and the other end is 'outside the group' `````` Niina Helistö committed Sep 24, 2019 356 `````` ] `````` Niina Helistö committed Oct 01, 2019 357 358 359 360 `````` and [ p_gnn(grid, node_, node_fail, 'portion_of_transfer_to_reserve') or p_gnn(grid, node_fail, node_, 'portion_of_transfer_to_reserve') ] and p_groupReserves3D(group, restype, 'up', 'LossOfTrans') `````` ran li committed Aug 27, 2019 361 362 `````` } .. `````` Niina Helistö committed Oct 01, 2019 363 364 `````` // Reserve provision by capable units on this group + sum(gnuft(grid, node, unit, f, t)\${ gnGroup(grid, node, group) `````` Niina Helistö committed Oct 03, 2019 365 `````` and gnuRescapable(restype, 'up', grid, node, unit) `````` Niina Helistö committed Oct 01, 2019 366 `````` }, `````` Niina Helistö committed Oct 03, 2019 367 `````` + v_reserve(restype, 'up', grid, node, unit, s, f+df_reserves(grid, node, restype, f, t), t) `````` ran li committed Aug 27, 2019 368 `````` * [ // Account for reliability of reserves `````` Niina Helistö committed Oct 03, 2019 369 370 `````` + 1\${sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} // reserveReliability limits the reliability of reserves locked ahead of time. + p_gnuReserves(grid, node, unit, restype, 'reserveReliability')\${not sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} `````` ran li committed Aug 27, 2019 371 `````` ] // END * v_reserve `````` Niina Helistö committed Oct 01, 2019 372 `````` ) // END sum(gnuft) `````` ran li committed Aug 27, 2019 373 374 `````` // Reserve provision from other reserve categories when they can be shared `````` Niina Helistö committed Oct 01, 2019 375 `````` + sum((gnuft(grid, node, unit, f, t), restype_)\${ gnGroup(grid, node, group) `````` Niina Helistö committed Oct 03, 2019 376 `````` and p_gnuRes2Res(grid, node, unit, restype_, 'up', restype) `````` Niina Helistö committed Oct 01, 2019 377 `````` }, `````` Niina Helistö committed Oct 03, 2019 378 379 `````` + v_reserve(restype_, 'up', grid, node, unit, s, f+df_reserves(grid, node, restype_, f, t), t) * p_gnuRes2Res(grid, node, unit, restype_, 'up', restype) `````` ran li committed Aug 27, 2019 380 `````` * [ // Account for reliability of reserves `````` Niina Helistö committed Oct 03, 2019 381 382 383 `````` + 1\${sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} // reserveReliability limits the reliability of reserves locked ahead of time. + p_gnuReserves(grid, node, unit, restype, 'reserveReliability')\${not sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} * p_gnuReserves(grid, node, unit, restype_, 'reserveReliability') `````` ran li committed Aug 27, 2019 384 `````` ] // END * v_reserve `````` Niina Helistö committed Oct 01, 2019 385 `````` ) // END sum(gnuft) `````` ran li committed Aug 27, 2019 386 `````` `````` Niina Helistö committed Oct 01, 2019 387 388 389 390 `````` // Reserve provision to this group via transfer links + sum(gn2n_directional(grid, from_node, to_node)\${ gnGroup(grid, to_node, group) and not gnGroup(grid, from_node, group) and not (from_node(node_) and to_node(node_fail)) // excluding the failing link `````` Niina Helistö committed Oct 03, 2019 391 `````` and restypeDirectionGridNodeNode(restype, 'up', grid, from_node, to_node) `````` Niina Helistö committed Oct 01, 2019 392 393 `````` }, + (1 - p_gnn(grid, from_node, to_node, 'transferLoss') ) `````` Niina Helistö committed Oct 03, 2019 394 `````` * v_resTransferRightward(restype, 'up', grid, from_node, to_node, s, f+df_reserves(grid, from_node, restype, f, t), t) `````` ran li committed Aug 27, 2019 395 `````` ) // END sum(gn2n_directional) `````` Niina Helistö committed Oct 01, 2019 396 397 398 `````` + sum(gn2n_directional(grid, to_node, from_node)\${ gnGroup(grid, to_node, group) and not gnGroup(grid, from_node, group) and not (to_node(node_) and from_node(node_fail)) // excluding the failing link `````` Niina Helistö committed Oct 03, 2019 399 `````` and restypeDirectionGridNodeNode(restype, 'up', grid, from_node, to_node) `````` Niina Helistö committed Oct 01, 2019 400 401 `````` }, + (1 - p_gnn(grid, to_node, from_node, 'transferLoss') ) `````` Niina Helistö committed Oct 03, 2019 402 `````` * v_resTransferLeftward(restype, 'up', grid, to_node, from_node, s, f+df_reserves(grid, from_node, restype, f, t), t) `````` ran li committed Aug 27, 2019 403 404 405 406 `````` ) // END sum(gn2n_directional) =G= `````` Niina Helistö committed Oct 01, 2019 407 408 409 410 411 `````` // Demand for upward reserve due to potential interconnector failures (sudden loss of import) + p_gnn(grid, node_, node_fail, 'portion_of_transfer_to_reserve')\${gnGroup(grid, node_fail, group)} * v_transferRightward(grid, node_, node_fail, s, f, t) // multiply with efficiency? + p_gnn(grid, node_fail, node_, 'portion_of_transfer_to_reserve')\${gnGroup(grid, node_, group)} * v_transferLeftward(grid, node_, node_fail, s, f, t) // multiply with efficiency? `````` ran li committed Sep 04, 2019 412 `````` `````` Niina Helistö committed Oct 01, 2019 413 414 415 416 `````` // Reserve provisions to other groups via transfer links + sum(gn2n_directional(grid, from_node, to_node)\${ gnGroup(grid, from_node, group) and not gnGroup(grid, to_node, group) and not (from_node(node_) and to_node(node_fail)) // excluding the failing link `````` Niina Helistö committed Oct 03, 2019 417 `````` and restypeDirectionGridNodeNode(restype, 'up', grid, from_node, to_node) `````` Niina Helistö committed Oct 01, 2019 418 `````` }, `````` ran li committed Sep 04, 2019 419 `````` // Reserve transfers to other nodes increase the reserve need of the present node `````` Niina Helistö committed Oct 03, 2019 420 `````` + v_resTransferRightward(restype, 'up', grid, from_node, to_node, s, f+df_reserves(grid, from_node, restype, f, t), t) `````` ran li committed Sep 04, 2019 421 `````` ) // END sum(gn2n_directional) `````` Niina Helistö committed Oct 01, 2019 422 423 424 `````` + sum(gn2n_directional(grid, to_node, from_node)\${ gnGroup(grid, from_node, group) and not gnGroup(grid, to_node, group) and not (to_node(node_) and from_node(node_fail)) // excluding the failing link `````` Niina Helistö committed Oct 03, 2019 425 `````` and restypeDirectionGridNodeNode(restype, 'up', grid, from_node, to_node) `````` Niina Helistö committed Oct 01, 2019 426 `````` }, `````` ran li committed Sep 04, 2019 427 `````` // Reserve transfers to other nodes increase the reserve need of the present node `````` Niina Helistö committed Oct 03, 2019 428 `````` + v_resTransferLeftward(restype, 'up', grid, to_node, from_node, s, f+df_reserves(grid, from_node, restype, f, t), t) `````` ran li committed Sep 04, 2019 429 430 431 `````` ) // END sum(gn2n_directional) // Reserve demand feasibility dummy variables `````` Niina Helistö committed Oct 01, 2019 432 433 `````` - vq_resDemand(restype, 'up', group, s, f+df_reservesGroup(group, restype, f, t), t) - vq_resMissing(restype, 'up', group, s, f+df_reservesGroup(group, restype, f, t), t)\${ft_reservesFixed(group, restype, f+df_reservesGroup(group, restype, f, t), t)} `````` ran li committed Sep 04, 2019 434 435 ``````; `````` Niina Helistö committed Oct 01, 2019 436 ``````* --- N-1 Downward reserve demand due to a possibility that an interconnector that is transferring power from the node group fails ------------------------------------------------- `````` ran li committed Sep 04, 2019 437 438 439 ``````// 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. `````` Niina Helistö committed Oct 01, 2019 440 441 ``````q_resDemandLargestInfeedTransferDown(restypeDirectionGroup(restype, 'down', group), gn2n(grid, node_, node_fail), sft(s, f, t)) \${ ord(t) < tSolveFirst + p_groupReserves(group, restype, 'reserve_length') `````` ran li committed Sep 04, 2019 442 443 `````` and not [ restypeReleasedForRealization(restype) and sft_realized(s, f, t)] `````` Niina Helistö committed Oct 01, 2019 444 445 446 `````` and gn2n_directional(grid, node_, node_fail) and [ (gnGroup(grid, node_, group) and not gnGroup(grid, node_fail, group)) // only interconnectors where one end is 'inside the group' or (gnGroup(grid, node_fail, group) and not gnGroup(grid, node_, group)) // and the other end is 'outside the group' `````` Niina Helistö committed Sep 24, 2019 447 `````` ] `````` Niina Helistö committed Oct 01, 2019 448 449 450 451 `````` and [ p_gnn(grid, node_, node_fail, 'portion_of_transfer_to_reserve') or p_gnn(grid, node_fail, node_, 'portion_of_transfer_to_reserve') ] and p_groupReserves3D(group, restype, 'down', 'LossOfTrans') `````` ran li committed Sep 04, 2019 452 453 `````` } .. `````` Niina Helistö committed Oct 01, 2019 454 455 `````` // Reserve provision by capable units on this group + sum(gnuft(grid, node, unit, f, t)\${ gnGroup(grid, node, group) `````` Niina Helistö committed Oct 03, 2019 456 `````` and gnuRescapable(restype, 'down', grid, node, unit) `````` Niina Helistö committed Oct 01, 2019 457 `````` }, `````` Niina Helistö committed Oct 03, 2019 458 `````` + v_reserve(restype, 'down', grid, node, unit, s, f+df_reserves(grid, node, restype, f, t), t) `````` ran li committed Sep 04, 2019 459 `````` * [ // Account for reliability of reserves `````` Niina Helistö committed Oct 03, 2019 460 461 `````` + 1\${sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} // reserveReliability limits the reliability of reserves locked ahead of time. + p_gnuReserves(grid, node, unit, restype, 'reserveReliability')\${not sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} `````` ran li committed Sep 04, 2019 462 `````` ] // END * v_reserve `````` Niina Helistö committed Oct 01, 2019 463 `````` ) // END sum(gnuft) `````` ran li committed Sep 04, 2019 464 465 `````` // Reserve provision from other reserve categories when they can be shared `````` Niina Helistö committed Oct 01, 2019 466 `````` + sum((gnuft(grid, node, unit, f, t), restype_)\${ gnGroup(grid, node, group) `````` Niina Helistö committed Oct 03, 2019 467 `````` and p_gnuRes2Res(grid, node, unit, restype_, 'down', restype) `````` Niina Helistö committed Oct 01, 2019 468 `````` }, `````` Niina Helistö committed Oct 03, 2019 469 470 `````` + v_reserve(restype_, 'down', grid, node, unit, s, f+df_reserves(grid, node, restype_, f, t), t) * p_gnuRes2Res(grid, node, unit, restype_, 'down', restype) `````` ran li committed Sep 04, 2019 471 `````` * [ // Account for reliability of reserves `````` Niina Helistö committed Oct 03, 2019 472 473 474 `````` + 1\${sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} // reserveReliability limits the reliability of reserves locked ahead of time. + p_gnuReserves(grid, node, unit, restype, 'reserveReliability')\${not sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} * p_gnuReserves(grid, node, unit, restype_, 'reserveReliability') `````` ran li committed Sep 04, 2019 475 `````` ] // END * v_reserve `````` Niina Helistö committed Oct 01, 2019 476 `````` ) // END sum(gnuft) `````` ran li committed Sep 04, 2019 477 `````` `````` Niina Helistö committed Oct 01, 2019 478 479 480 481 `````` // Reserve provision to this group via transfer links + sum(gn2n_directional(grid, from_node, to_node)\${ gnGroup(grid, to_node, group) and not gnGroup(grid, from_node, group) and not (from_node(node_) and to_node(node_fail)) // excluding the failing link `````` Niina Helistö committed Oct 03, 2019 482 `````` and restypeDirectionGridNodeNode(restype, 'down', grid, from_node, to_node) `````` Niina Helistö committed Oct 01, 2019 483 484 `````` }, + (1 - p_gnn(grid, from_node, to_node, 'transferLoss') ) `````` Niina Helistö committed Oct 03, 2019 485 `````` * v_resTransferRightward(restype, 'down', grid, from_node, to_node, s, f+df_reserves(grid, from_node, restype, f, t), t) `````` ran li committed Sep 04, 2019 486 `````` ) // END sum(gn2n_directional) `````` Niina Helistö committed Oct 01, 2019 487 488 489 `````` + sum(gn2n_directional(grid, to_node, from_node)\${ gnGroup(grid, to_node, group) and not gnGroup(grid, from_node, group) and not (to_node(node_) and from_node(node_fail)) // excluding the failing link `````` Niina Helistö committed Oct 03, 2019 490 `````` and restypeDirectionGridNodeNode(restype, 'down', grid, from_node, to_node) `````` Niina Helistö committed Oct 01, 2019 491 492 `````` }, + (1 - p_gnn(grid, to_node, from_node, 'transferLoss') ) `````` Niina Helistö committed Oct 03, 2019 493 `````` * v_resTransferLeftward(restype, 'down', grid, to_node, from_node, s, f+df_reserves(grid, from_node, restype, f, t), t) `````` ran li committed Sep 04, 2019 494 495 496 497 `````` ) // END sum(gn2n_directional) =G= `````` Niina Helistö committed Oct 01, 2019 498 499 500 501 502 `````` // Demand for downward reserve due to potential interconnector failures (sudden loss of export) + p_gnn(grid, node_, node_fail, 'portion_of_transfer_to_reserve')\${gnGroup(grid, node_, group)} * v_transferRightward(grid, node_, node_fail, s, f, t) + p_gnn(grid, node_fail, node_, 'portion_of_transfer_to_reserve')\${gnGroup(grid, node_fail, group)} * v_transferLeftward(grid, node_, node_fail, s, f, t) `````` ran li committed Sep 02, 2019 503 `````` `````` Niina Helistö committed Oct 01, 2019 504 505 506 507 `````` // Reserve provisions to other groups via transfer links + sum(gn2n_directional(grid, from_node, to_node)\${ gnGroup(grid, from_node, group) and not gnGroup(grid, to_node, group) and not (from_node(node_) and to_node(node_fail)) // excluding the failing link `````` Niina Helistö committed Oct 03, 2019 508 `````` and restypeDirectionGridNodeNode(restype, 'down', grid, from_node, to_node) `````` Niina Helistö committed Oct 01, 2019 509 `````` }, `````` ran li committed Sep 02, 2019 510 `````` // Reserve transfers to other nodes increase the reserve need of the present node `````` Niina Helistö committed Oct 03, 2019 511 `````` + v_resTransferRightward(restype, 'down', grid, from_node, to_node, s, f+df_reserves(grid, from_node, restype, f, t), t) `````` ran li committed Sep 02, 2019 512 `````` ) // END sum(gn2n_directional) `````` Niina Helistö committed Oct 01, 2019 513 514 515 `````` + sum(gn2n_directional(grid, to_node, from_node)\${ gnGroup(grid, from_node, group) and not gnGroup(grid, to_node, group) and not (to_node(node_) and from_node(node_fail)) // excluding the failing link `````` Niina Helistö committed Oct 03, 2019 516 `````` and restypeDirectionGridNodeNode(restype, 'down', grid, from_node, to_node) `````` Niina Helistö committed Oct 01, 2019 517 `````` }, `````` ran li committed Sep 02, 2019 518 `````` // Reserve transfers to other nodes increase the reserve need of the present node `````` Niina Helistö committed Oct 03, 2019 519 `````` + v_resTransferLeftward(restype, 'down', grid, to_node, from_node, s, f+df_reserves(grid, from_node, restype, f, t), t) `````` ran li committed Sep 02, 2019 520 521 522 `````` ) // END sum(gn2n_directional) // Reserve demand feasibility dummy variables `````` Niina Helistö committed Oct 01, 2019 523 524 `````` - vq_resDemand(restype, 'down', group, s, f+df_reservesGroup(group, restype, f, t), t) - vq_resMissing(restype, 'down', group, s, f+df_reservesGroup(group, restype, f, t), t)\${ft_reservesFixed(group, restype, f+df_reservesGroup(group, restype, f, t), t)} `````` ran li committed Sep 02, 2019 525 ``````; `````` 526 `````` `````` Niina Helistö committed Oct 01, 2019 527 ``````* --- N-1 reserve demand due to a possibility that an interconnector that is transferring power to/from the node group fails ------------------------------------------------- `````` ran li committed Sep 04, 2019 528 529 530 ``````// 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. `````` Niina Helistö committed Oct 01, 2019 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 ``````q_resDemandLargestInfeedTransfer(restypeDirectionGroup(restype, up_down, group), gn2n(grid, node_left, node_right), sft(s, f, t)) \${ ord(t) < tSolveFirst + p_groupReserves(group, restype, 'reserve_length') and not [ restypeReleasedForRealization(restype) and sft_realized(s, f, t)] and gn2n_directional(grid, node_left, node_right) and [ (gnGroup(grid, node_left, group) and not gnGroup(grid, node_right, group)) // only interconnectors where one end is 'inside the group' or (gnGroup(grid, node_right, group) and not gnGroup(grid, node_left, group)) // and the other end is 'outside the group' ] and [ p_gnn(grid, node_left, node_right, 'portion_of_transfer_to_reserve') or p_gnn(grid, node_right, node_left, 'portion_of_transfer_to_reserve') ] and p_groupReserves3D(group, restype, up_down, 'LossOfTrans') } .. // Reserve provision by capable units on this group + sum(gnuft(grid, node, unit, f, t)\${ gnGroup(grid, node, group) `````` Niina Helistö committed Oct 03, 2019 547 `````` and gnuRescapable(restype, up_down, grid, node, unit) `````` Niina Helistö committed Oct 01, 2019 548 `````` }, `````` Niina Helistö committed Oct 03, 2019 549 `````` + v_reserve(restype, up_down, grid, node, unit, s, f+df_reserves(grid, node, restype, f, t), t) `````` Niina Helistö committed Oct 01, 2019 550 `````` * [ // Account for reliability of reserves `````` Niina Helistö committed Oct 03, 2019 551 552 `````` + 1\${sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} // reserveReliability limits the reliability of reserves locked ahead of time. + p_gnuReserves(grid, node, unit, restype, 'reserveReliability')\${not sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} `````` Niina Helistö committed Oct 01, 2019 553 554 555 556 557 `````` ] // END * v_reserve ) // END sum(gnuft) // Reserve provision from other reserve categories when they can be shared + sum((gnuft(grid, node, unit, f, t), restype_)\${ gnGroup(grid, node, group) `````` Niina Helistö committed Oct 03, 2019 558 `````` and p_gnuRes2Res(grid, node, unit, restype_, up_down, restype) `````` Niina Helistö committed Oct 01, 2019 559 `````` }, `````` Niina Helistö committed Oct 03, 2019 560 561 `````` + v_reserve(restype_, up_down, grid, node, unit, s, f+df_reserves(grid, node, restype_, f, t), t) * p_gnuRes2Res(grid, node, unit, restype_, up_down, restype) `````` Niina Helistö committed Oct 01, 2019 562 `````` * [ // Account for reliability of reserves `````` Niina Helistö committed Oct 03, 2019 563 564 565 `````` + 1\${sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} // reserveReliability limits the reliability of reserves locked ahead of time. + p_gnuReserves(grid, node, unit, restype, 'reserveReliability')\${not sft_realized(s, f+df_reserves(grid, node, restype, f, t), t)} * p_gnuReserves(grid, node, unit, restype_, 'reserveReliability') `````` Niina Helistö committed Oct 01, 2019 566 567 568 569 570 571 572 `````` ] // END * v_reserve ) // END sum(gnuft) // Reserve provision to this group via transfer links + sum(gn2n_directional(grid, node_, node)\${ gnGroup(grid, node, group) and not gnGroup(grid, node_, group) and not (sameas(node_, node_left) and sameas(node, node_right)) // excluding the failing link `````` Niina Helistö committed Oct 03, 2019 573 `````` and restypeDirectionGridNodeNode(restype, up_down, grid, node_, node) `````` Niina Helistö committed Oct 01, 2019 574 575 `````` }, + (1 - p_gnn(grid, node_, node, 'transferLoss') ) `````` Niina Helistö committed Oct 03, 2019 576 `````` * v_resTransferRightward(restype, up_down, grid, node_, node, s, f+df_reserves(grid, node_, restype, f, t), t) `````` Niina Helistö committed Oct 01, 2019 577 578 579 580 `````` ) // END sum(gn2n_directional) + sum(gn2n_directional(grid, node, node_)\${ gnGroup(grid, node, group) and not gnGroup(grid, node_, group) and not (sameas(node, node_left) and sameas(node_, node_right)) // excluding the failing link `````` Niina Helistö committed Oct 03, 2019 581 `````` and restypeDirectionGridNodeNode(restype, up_down, grid, node_, node) `````` Niina Helistö committed Oct 01, 2019 582 583 `````` }, + (1 - p_gnn(grid, node, node_, 'transferLoss') ) `````` Niina Helistö committed Oct 03, 2019 584 `````` * v_resTransferLeftward(restype, up_down, grid, node, node_, s, f+df_reserves(grid, node_, restype, f, t), t) `````` Niina Helistö committed Oct 01, 2019 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 `````` ) // END sum(gn2n_directional) =G= // Demand for upward reserve due to potential interconnector failures (sudden loss of import) + [ + p_gnn(grid, node_left, node_right, 'portion_of_transfer_to_reserve')\${gnGroup(grid, node_right, group)} * v_transferRightward(grid, node_left, node_right, s, f, t) // multiply with efficiency? + p_gnn(grid, node_right, node_left, 'portion_of_transfer_to_reserve')\${gnGroup(grid, node_left, group)} * v_transferLeftward(grid, node_left, node_right, s, f, t) // multiply with efficiency? ]\${sameas(up_down, 'up')} // Demand for downward reserve due to potential interconnector failures (sudden loss of export) + [ + p_gnn(grid, node_left, node_right, 'portion_of_transfer_to_reserve')\${gnGroup(grid, node_left, group)} * v_transferRightward(grid, node_left, node_right, s, f, t) + p_gnn(grid, node_right, node_left, 'portion_of_transfer_to_reserve')\${gnGroup(grid, node_right, group)} * v_transferLeftward(grid, node_left, node_right, s, f, t) ]\${sameas(up_down, 'down')} // Reserve provisions to other groups via transfer links + sum(gn2n_directional(grid, node, node_)\${ gnGroup(grid, node, group) and not gnGroup(grid, node_, group) and not (sameas(node, node_left) and sameas(node_, node_right)) // excluding the failing link `````` Niina Helistö committed Oct 03, 2019 608 `````` and restypeDirectionGridNodeNode(restype, up_down, grid, node, node_) `````` Niina Helistö committed Oct 01, 2019 609 610 `````` }, // Reserve transfers to other nodes increase the reserve need of the present node `````` Niina Helistö committed Oct 03, 2019 611 `````` + v_resTransferRightward(restype, up_down, grid, node, node_, s, f+df_reserves(grid, node, restype, f, t), t) `````` Niina Helistö committed Oct 01, 2019 612 613 614 615 `````` ) // END sum(gn2n_directional) + sum(gn2n_directional(grid, node_, node)\${ gnGroup(grid, node, group) and not gnGroup(grid, node_, group) and not (sameas(node_, node_left) and sameas(node, node_right)) // excluding the failing link `````` Niina Helistö committed Oct 03, 2019 616 `````` and restypeDirectionGridNodeNode(restype, up_down, grid, node, node_) `````` Niina Helistö committed Oct 01, 2019 617 618 `````` }, // Reserve transfers to other nodes increase the reserve need of the present node `````` Niina Helistö committed Oct 03, 2019 619 `````` + v_resTransferLeftward(restype, up_down, grid, node_, node, s, f+df_reserves(grid, node, restype, f, t), t) `````` Niina Helistö committed Oct 01, 2019 620 621 622 623 624 625 `````` ) // END sum(gn2n_directional) // Reserve demand feasibility dummy variables - vq_resDemand(restype, up_down, group, s, f+df_reservesGroup(group, restype, f, t), t) - vq_resMissing(restype, up_down, group, s, f+df_reservesGroup(group, restype, f, t), t)\${ft_reservesFixed(group, restype, f+df_reservesGroup(group, restype, f, t), t)} ; `````` ran li committed Sep 04, 2019 626 `````` `````` Topi Rasku committed Oct 11, 2017 627 628 ``````* --- Maximum Downward Capacity ----------------------------------------------- `````` Topi Rasku committed Aug 09, 2019 629 ``````q_maxDownward(gnu(grid, node, unit), msft(m, s, f, t)) `````` Topi Rasku committed Apr 04, 2019 630 631 `````` \${ gnuft(grid, node, unit, f, t) and { `````` Niina Helistö committed Oct 03, 2019 632 633 `````` [ ord(t) < tSolveFirst + smax(restype, p_gnReserves(grid, node, restype, 'reserve_length')) // Unit is either providing and sum(restype, gnuRescapable(restype, 'down', grid, node, unit)) // downward reserves `````` Topi Rasku committed Apr 04, 2019 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 `````` ] // 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 649 `````` // Energy generation/consumption `````` Erkka Rinne committed Nov 02, 2018 650 `````` + v_gen(grid, node, unit, s, f, t) `````` Topi Rasku committed Oct 11, 2017 651 652 `````` // Considering output constraints (e.g. cV line) `````` 653 654 `````` + sum(gngnu_constrainedOutputRatio(grid, node, grid_output, node_, unit), + p_gnu(grid_output, node_, unit, 'cV') `````` Erkka Rinne committed Nov 02, 2018 655 `````` * v_gen(grid_output, node_, unit, s, f, t) `````` Topi Rasku committed Oct 11, 2017 656 657 658 `````` ) // END sum(gngnu_constrainedOutputRatio) // Downward reserve participation `````` Niina Helistö committed Oct 07, 2019 659 660 661 `````` - sum(gnuRescapable(restype, 'down', grid, node, unit)\${ ord(t) < tSolveFirst + p_gnReserves(grid, node, restype, 'reserve_length') and not gnuOfflineRescapable(restype, grid, node, unit) }, `````` Niina Helistö committed Oct 03, 2019 662 `````` + v_reserve(restype, 'down', grid, node, unit, s, f+df_reserves(grid, 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 663 664 665 666 667 668 `````` ) // 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 669 `````` * sum(suft(effGroup, unit, f, t), // Uses the minimum 'lb' for the current efficiency approximation `````` Topi Rasku committed Oct 11, 2017 670 671 672 673 `````` + 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 674 675 `````` + 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 676 677 `````` ] // END v_online `````` Topi Rasku committed Jan 24, 2019 678 679 680 681 `````` // 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 682 683 `````` + [ + v_startup_LP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) `````` Topi Rasku committed Apr 04, 2019 684 `````` \${ uft_onlineLP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } `````` Topi Rasku committed Apr 04, 2019 685 `````` + v_startup_MIP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) `````` Topi Rasku committed Apr 04, 2019 686 `````` \${ uft_onlineMIP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } `````` Topi Rasku committed Apr 04, 2019 687 `````` ] `````` Topi Rasku committed Jan 25, 2019 688 `````` * p_uCounter_runUpMin(unit, counter) `````` Topi Rasku committed Jan 24, 2019 689 690 691 692 693 694 `````` ) // 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 695 696 697 698 699 700 `````` + [ + 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 701 `````` * p_uCounter_shutdownMin(unit, counter) `````` Topi Rasku committed Jan 24, 2019 702 `````` ) // END sum(shutdownCounter) `````` Juha Kiviluoma committed Apr 06, 2018 703 `````` `````` Topi Rasku committed Oct 11, 2017 704 705 706 707 708 `````` // Consuming units, greater than maxCons // Available capacity restrictions - p_unit(unit, 'availability') * [ // Capacity factors for flow units `````` Topi Rasku committed Jun 05, 2018 709 `````` + sum(flowUnit(flow, unit), `````` Erkka Rinne committed Nov 02, 2018 710 `````` + ts_cf_(flow, node, f, t, s) `````` Topi Rasku committed Oct 11, 2017 711 712 713 714 715 716 `````` ) // 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 `````` 717 718 719 720 `````` // !!! TEMPORARY SOLUTION !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + [ + p_gnu(grid, node, unit, 'unitSizeCons') + p_gnu(grid, node, unit, 'maxCons')\${not p_gnu(grid, node, unit, 'unitSizeCons') > 0} `````` Topi Rasku committed Aug 09, 2019 721 `````` / ( p_unit(unit, 'unitCount') + 1\${not p_unit(unit, 'unitCount') > 0} ) `````` 722 723 `````` ] // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! `````` Topi Rasku committed Oct 11, 2017 724 `````` * [ `````` 725 `````` // Capacity online `````` Erkka Rinne committed Nov 02, 2018 726 727 `````` + 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)} `````` 728 729 730 731 732 733 734 735 `````` // 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 736 737 `````` ] // END * p_gnu(unitSizeCons) ] // END * p_unit(availability) `````` Topi Rasku committed Mar 29, 2017 738 ``````; `````` Topi Rasku committed Oct 11, 2017 739 `````` `````` 740 741 ``````* --- Maximum Downward Capacity for Production/Consumption, Online Reserves and Offline Reserves --- `````` Niina Helistö committed Oct 07, 2019 742 ``````q_maxDownwardOfflineReserve(gnu(grid, node, unit), msft(m, s, f, t)) `````` 743 744 `````` \${ gnuft(grid, node, unit, f, t) and { `````` Niina Helistö committed Oct 07, 2019 745 746 `````` [ ord(t) < tSolveFirst + smax(restype, p_gnReserves(grid, node, restype, 'reserve_length')) // Unit is providing and sum(restype, gnuRescapable(restype, 'down', grid, node, unit)) // downward reserves `````` 747 748 749 `````` ] } `````` Niina Helistö committed Oct 07, 2019 750 `````` and { sum(restype, gnuOfflineRescapable(restype, grid, node, unit))} // and it can provide some reserve products although being offline `````` 751 752 753 754 755 756 757 758 759 760 761 762 763 `````` }.. // Energy generation/consumption + v_gen(grid, node, unit, s, f, t) // Considering output constraints (e.g. cV line) + sum(gngnu_constrainedOutputRatio(grid, node, grid_output, node_, unit), + p_gnu(grid_output, node_, unit, 'cV') * v_gen(grid_output, node_, unit, s, f, t) ) // END sum(gngnu_constrainedOutputRatio) // Downward reserve participation `````` Niina Helistö committed Oct 07, 2019 764 765 `````` - sum(gnuRescapable(restype, 'down', grid, node, unit)\${ord(t) < tSolveFirst + p_gnReserves(grid, node, restype, 'reserve_length')}, + v_reserve(restype, 'down', grid, node, unit, s, f+df_reserves(grid, node, restype, f, t), t) `````` 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 `````` ) // END sum(nuRescapable) =G= // Must be greater than maximum consumption // Consuming units // Available capacity restrictions - p_unit(unit, 'availability') // Consumption units are also restricted by their (available) capacity * [ // Capacity factors for flow units + sum(flowUnit(flow, unit), + ts_cf_(flow, node, f, t, s) ) // END sum(flow) + 1\${not unit_flow(unit)} ] // END * p_unit(availability) * [ // Existing capacity + p_gnu(grid, node, unit, 'maxCons') // Investments to new capacity + [ + p_gnu(grid, node, unit, 'unitSizeCons') ] * [ + sum(t_invest(t_)\${ ord(t_)<=ord(t) }, + v_invest_LP(unit, t_)\${unit_investLP(unit)} + v_invest_MIP(unit, t_)\${unit_investMIP(unit)} ) // END sum(t_invest) ] // END * p_gnu(unitSizeCons) ] // END * p_unit(availability) ; `````` Niina Helistö committed Sep 06, 2019 798 ``````* --- Maximum Upwards Capacity for Production/Consumption and Online Reserves --- `````` Topi Rasku committed Oct 11, 2017 799 `````` `````` Topi Rasku committed Aug 09, 2019 800 ``````q_maxUpward(gnu(grid, node, unit), msft(m, s, f, t)) `````` Topi Rasku committed Apr 04, 2019 801 802 `````` \${ gnuft(grid, node, unit, f, t) and { `````` Niina Helistö committed Oct 03, 2019 803 804 `````` [ ord(t) < tSolveFirst + smax(restype, p_gnReserves(grid, node, restype, 'reserve_length')) // Unit is either providing and sum(restype, gnuRescapable(restype, 'up', grid, node, unit)) // upward reserves `````` Topi Rasku committed Apr 04, 2019 805 806 807 808 809 810 811 812 813 814 815 816 `````` ] 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)) ] `````` Ciara O'Dwyer committed Sep 02, 2019 817 818 819 `````` } }.. `````` Topi Rasku committed Apr 04, 2019 820 `````` `````` Topi Rasku committed Oct 11, 2017 821 `````` // Energy generation/consumption `````` Erkka Rinne committed Nov 02, 2018 822 `````` + v_gen(grid, node, unit, s, f, t) `````` Topi Rasku committed Oct 11, 2017 823 824 825 826 `````` // 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 827 `````` * v_gen(grid_output, node_, unit, s, f, t) `````` Topi Rasku committed Oct 11, 2017 828 829 830 `````` ) // END sum(gngnu_constrainedOutputRatio) // Upwards reserve participation `````` Niina Helistö committed Oct 07, 2019 831 832 833 `````` + sum(gnuRescapable(restype, 'up', grid, node, unit)\${ ord(t) < tSolveFirst + p_gnReserves(grid, node, restype, 'reserve_length') and not gnuOfflineRescapable(restype, grid, node, unit) }, `````` Niina Helistö committed Oct 03, 2019 834 `````` + v_reserve(restype, 'up', grid, node, unit, s, f+df_reserves(grid, node, restype, f, t), t) `````` Topi Rasku committed Oct 11, 2017 835 836 837 838 839 `````` ) // END sum(nuRescapable) =L= // must be less than available/online capacity // Consuming units `````` Niina Helistö committed Mar 01, 2019 840 `````` - p_gnu(grid, node, unit, 'unitSizeCons') `````` Topi Rasku committed Nov 09, 2017 841 `````` * sum(suft(effGroup, unit, f, t), // Uses the minimum 'lb' for the current efficiency approximation `````` Topi Rasku committed Oct 11, 2017 842 843 844 845 `````` + 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 846 847 `````` + 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 848 849 850 851 852 853 854 `````` ] // 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 855 `````` + sum(flowUnit(flow, unit), `````` Erkka Rinne committed Nov 02, 2018 856 `````` + ts_cf_(flow, node, f, t, s) `````` Topi Rasku committed Oct 11, 2017 857 858 859 860 861 862 863 864 `````` ) // 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') * [ `````` 865 `````` // Capacity online `````` Erkka Rinne committed Nov 02, 2018 866 867 `````` + 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)} `````` 868 869 870 871 872 873 874 875 `````` // 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 876 877 `````` ] // END * p_gnu(unitSizeGen) ] // END * p_unit(availability) `````` Juha Kiviluoma committed Apr 06, 2018 878 `````` `````` Topi Rasku committed Jan 24, 2019 879 880 881 882 `````` // 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 883 884 `````` + [ + v_startup_LP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) `````` Topi Rasku committed Apr 04, 2019 885 `````` \${ uft_onlineLP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } `````` Topi Rasku committed Apr 04, 2019 886 `````` + v_startup_MIP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) `````` Topi Rasku committed Apr 04, 2019 887 `````` \${ uft_onlineMIP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } `````` Topi Rasku committed Apr 04, 2019 888 `````` ] `````` Topi Rasku committed Jan 25, 2019 889 `````` * p_uCounter_runUpMax(unit, counter) `````` Topi Rasku committed Jan 24, 2019 890 891 892 893 894 895 `````` ) // 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 896 897 898 899 900 901 `````` + [ + 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 902 `````` * p_uCounter_shutdownMax(unit, counter) `````` Topi Rasku committed Jan 24, 2019 903 `````` ) // END sum(shutdownCounter) `````` 904 ``````; `````` Topi Rasku committed Oct 11, 2017 905 `````` `````` Niina Helistö committed Sep 06, 2019 906 ``````* --- Maximum Upwards Capacity for Production/Consumption, Online Reserves and Offline Reserves --- `````` Ciara O'Dwyer committed Sep 02, 2019 907 `````` `````` Niina Helistö committed Oct 07, 2019 908 ``````q_maxUpwardOfflineReserve(gnu(grid, node, unit), msft(m, s, f, t)) `````` Ciara O'Dwyer committed Sep 02, 2019 909 910 `````` \${ gnuft(grid, node, unit, f, t) and { `````` Niina Helistö committed Oct 07, 2019 911 912 `````` [ ord(t) < tSolveFirst + smax(restype, p_gnReserves(grid, node, restype, 'reserve_length')) // Unit is providing and sum(restype, gnuRescapable(restype, 'up', grid, node, unit)) // upward reserves `````` Ciara O'Dwyer committed Sep 02, 2019 913 914 915 `````` ] } `````` Niina Helistö committed Oct 07, 2019 916 `````` and { sum(restype, gnuOfflineRescapable(restype, grid, node, unit))} // and it can provide some reserve products although being offline `````` Ciara O'Dwyer committed Sep 02, 2019 917 918 919 920 921 922 923 924 925 926 927 928 929 `````` }.. // Energy generation/consumption + v_gen(grid, node, unit, s, f, t) // Considering output constraints (e.g. cV line) + sum(gngnu_constrainedOutputRatio(grid, node, grid_output, node_, unit), + p_gnu(grid_output, node_, unit, 'cV') * v_gen(grid_output, node_, unit, s, f, t) ) // END sum(gngnu_constrainedOutputRatio) // Upwards reserve participation `````` Niina Helistö committed Oct 07, 2019 930 931 `````` + sum(gnuRescapable(restype, 'up', grid, node, unit)\${ord(t) < tSolveFirst + p_gnReserves(grid, node, restype, 'reserve_length')}, + v_reserve(restype, 'up', grid, node, unit, s, f+df_reserves(grid, node, restype, f, t), t) `````` Ciara O'Dwyer committed Sep 02, 2019 932 933 `````` ) // END sum(nuRescapable) `````` Niina Helistö committed Sep 06, 2019 934 `````` =L= // must be less than available capacity `````` Ciara O'Dwyer committed Sep 02, 2019 935 936 937 938 939 940 941 942 943 944 945 946 `````` // Generation units // Available capacity restrictions + p_unit(unit, 'availability') // Generation units are restricted by their (available) capacity * [ // Capacity factor for flow units + sum(flowUnit(flow, unit), + ts_cf_(flow, node, f, t, s) ) // END sum(flow) + 1\${not unit_flow(unit)} ] // END * p_unit(availability) * [ `````` Niina Helistö committed Sep 06, 2019 947 `````` // Capacity restriction `````` Ciara O'Dwyer committed Sep 02, 2019 948 949 `````` + p_gnu(grid, node, unit, 'unitSizeGen') * [ `````` Niina Helistö committed Sep 06, 2019 950 951 `````` // Existing capacity + p_unit(unit, 'unitCount') `````` Ciara O'Dwyer committed Sep 02, 2019 952 `````` `````` Niina Helistö committed Sep 06, 2019 953 `````` // Investments to new capacity `````` Ciara O'Dwyer committed Sep 03, 2019 954 `````` + sum(t_invest(t_)\${ ord(t_)<=ord(t) `````` Niina Helistö committed Sep 06, 2019 955 `````` }, `````` Ciara O'Dwyer committed Sep 03, 2019 956 957 958 `````` + v_invest_LP(unit, t_)\${unit_investLP(unit)} + v_invest_MIP(unit, t_)\${unit_investMIP(unit)} ) // END sum(t_invest) `````` Ciara O'Dwyer committed Sep 02, 2019 959 960 961 962 `````` ] // END * p_gnu(unitSizeGen) ] // END * p_unit(availability) ; `````` Niina Helistö committed Nov 01, 2018 963 964 ``````* --- Reserve Provision of Units with Investments ----------------------------- `````` Niina Helistö committed Oct 03, 2019 965 966 967 ``````q_reserveProvision(gnuRescapable(restypeDirectionGridNode(restype, up_down, grid, node), unit), sft(s, f, t)) \${ ord(t) <= tSolveFirst + p_gnReserves(grid, node, restype, 'reserve_length') and gnuft(grid, node, unit, f, t) `````` Topi Rasku committed Apr 04, 2019 968 `````` and (unit_investLP(unit) or unit_investMIP(unit)) `````` 969 970 `````` and not sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node, group), ft_reservesFixed(group, restype, f+df_reservesGroup(group, restype, f, t), t)) `````` Topi Rasku committed Apr 04, 2019 971 972 `````` } .. `````` Niina Helistö committed Oct 03, 2019 973 `````` + v_reserve(restype, up_down, grid, node, unit, s, f+df_reserves(grid, node, restype, f, t), t) `````` Niina Helistö committed Nov 01, 2018 974 975 976 `````` =L= `````` Niina Helistö committed Oct 03, 2019 977 `````` + p_gnuReserves(grid, node, unit, restype, up_down) `````` Niina Helistö committed Nov 01, 2018 978 `````` * [ `````` Niina Helistö committed Oct 03, 2019 979 `````` + [ p_gnu(grid, node, unit, 'maxGen') + p_gnu(grid, node, unit, 'maxCons') ] `````` Niina Helistö committed Nov 01, 2018 980 981 `````` + sum(t_invest(t_)\${ ord(t_)<=ord(t) }, + v_invest_LP(unit, t_)\${unit_investLP(unit)} `````` Niina Helistö committed Oct 03, 2019 982 `````` * p_gnu(grid, node, unit, 'unitSizeTot') `````` Niina Helistö committed Nov 01, 2018 983 `````` + v_invest_MIP(unit, t_)\${unit_investMIP(unit)} `````` Niina Helistö committed Oct 03, 2019 984 `````` * p_gnu(grid, node, unit, 'unitSizeTot') `````` Niina Helistö committed Nov 01, 2018 985 986 `````` ) // END sum(t_) ] `````` Niina Helistö committed Nov 02, 2018 987 988 989 990 `````` * p_unit(unit, 'availability') // Taking into account availability... * [ // ... and capacity factor for flow units + sum(flowUnit(flow, unit), `````` Erkka Rinne committed Nov 02, 2018 991 `````` + ts_cf_(flow, node, f, t, s) `````` Niina Helistö committed Nov 02, 2018 992 993 `````` ) // END sum(flow) + 1\${not unit_flow(unit)} `````` Niina Helistö committed Nov 01, 2018 994 995 996 `````` ] // How to consider reserveReliability in the case of investments when we typically only have "realized" time steps? ; `````` Niina Helistö committed Sep 06, 2019 997 ``````* --- Online Reserve Provision of Units with Online Variables ----------------- `````` Ciara O'Dwyer committed Sep 02, 2019 998 `````` `````` Niina Helistö committed Oct 07, 2019 999 1000 ``````q_reserveProvisionOnline(gnuRescapable(restypeDirectionGridNode(restype, up_down, grid, node), unit), sft(s, f, t)) \${ ord(t) <= tSolveFirst + p_gnReserves(grid, node, restype, 'reserve_length') ``````