2d_constraints.gms 176 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 ``````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') `````` 27 `````` and p_gn(grid, node, 'nodeBalance') `````` Topi Rasku committed Apr 04, 2019 28 `````` } .. `````` Topi Rasku committed Oct 11, 2017 29 30 31 32 `````` // 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 33 34 `````` + 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 35 36 37 38 39 40 41 42 `````` ] =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 43 `````` - p_gn(grid, node, 'selfDischargeLoss')\${ gn_state(grid, node) } `````` Erkka Rinne committed Nov 02, 2018 44 `````` * v_state(grid, node, s, f+df_central(f,t), t) // The current state of the node `````` Topi Rasku committed Oct 11, 2017 45 46 `````` // Energy diffusion from this node to neighbouring nodes `````` Topi Rasku committed Apr 03, 2019 47 `````` - sum(gnn_state(grid, node, to_node), `````` Topi Rasku committed Oct 11, 2017 48 `````` + p_gnn(grid, node, to_node, 'diffCoeff') `````` Erkka Rinne committed Nov 02, 2018 49 `````` * v_state(grid, node, s, f+df_central(f,t), t) `````` Topi Rasku committed Oct 11, 2017 50 51 52 `````` ) // END sum(to_node) // Energy diffusion from neighbouring nodes to this node `````` Topi Rasku committed Apr 03, 2019 53 `````` + sum(gnn_state(grid, from_node, node), `````` Topi Rasku committed Oct 11, 2017 54 `````` + p_gnn(grid, from_node, node, 'diffCoeff') `````` Erkka Rinne committed Nov 02, 2018 55 `````` * 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 56 57 58 `````` ) // 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 59 `````` - sum(gn2n_directional(grid, node, node_), `````` Niina Helistö committed Jun 04, 2021 60 61 62 63 64 65 `````` + v_transfer(grid, node, node_, s, f, t) + [ + p_gnn(grid, node_, node, 'transferLoss')\${not gn2n_timeseries(grid, node_, node, 'transferLoss')} + ts_gnn_(grid, node_, node, 'transferLoss', f, t)\${gn2n_timeseries(grid, node_, node, 'transferLoss')} ] // Reduce transfer losses if transfer is from another node to this node * v_transferLeftward(grid, node, node_, s, f, t) `````` Topi Rasku committed Oct 11, 2017 66 67 68 `````` ) // 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 69 `````` + sum(gn2n_directional(grid, node_, node), `````` Erkka Rinne committed Nov 02, 2018 70 `````` + v_transfer(grid, node_, node, s, f, t) `````` Niina Helistö committed Jun 04, 2021 71 72 73 74 `````` - [ + p_gnn(grid, node_, node, 'transferLoss')\${not gn2n_timeseries(grid, node_, node, 'transferLoss')} + ts_gnn_(grid, node_, node, 'transferLoss', f, t)\${gn2n_timeseries(grid, node_, node, 'transferLoss')} ] // Reduce transfer losses if transfer is from another node to this node `````` Erkka Rinne committed Nov 02, 2018 75 `````` * v_transferRightward(grid, node_, node, s, f, t) `````` Topi Rasku committed Oct 11, 2017 76 77 78 79 `````` ) // END sum(node_) // Interactions between the node and its units + sum(gnuft(grid, node, unit, f, t), `````` Erkka Rinne committed Nov 02, 2018 80 `````` + v_gen(grid, node, unit, s, f, t) // Unit energy generation and consumption `````` Juha Kiviluoma committed Dec 05, 2016 81 `````` ) `````` Topi Rasku committed Oct 11, 2017 82 83 `````` // Spilling energy out of the endogenous grids in the model `````` Erkka Rinne committed Nov 02, 2018 84 `````` - v_spill(grid, node, s, f, t)\${node_spill(node)} `````` Topi Rasku committed Oct 11, 2017 85 86 `````` // Power inflow and outflow timeseries to/from the node `````` Erkka Rinne committed Oct 24, 2019 87 `````` + ts_influx_(grid, node, s, f, t) // Incoming (positive) and outgoing (negative) absolute value time series `````` Topi Rasku committed Oct 11, 2017 88 89 `````` // Dummy generation variables, for feasibility purposes `````` Erkka Rinne committed Nov 02, 2018 90 91 `````` + 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 92 `````` ) // END * p_stepLength `````` 93 ``````; `````` Topi Rasku committed Oct 11, 2017 94 95 `````` * --- Reserve Demand ---------------------------------------------------------- `````` Topi Rasku committed Oct 05, 2018 96 97 ``````// 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 98 `````` `````` 99 100 ``````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 101 `````` and not [ restypeReleasedForRealization(restype) `````` Erkka Rinne committed Nov 15, 2018 102 `````` and sft_realized(s, f, t)] `````` Niina Helistö committed Nov 21, 2019 103 `````` and not restype_inertia(restype) `````` Topi Rasku committed Oct 05, 2018 104 `````` } .. `````` Topi Rasku committed Apr 04, 2019 105 `````` `````` 106 `````` // Reserve provision by capable units on this group `````` Niina Helistö committed Oct 01, 2019 107 `````` + sum(gnuft(grid, node, unit, f, t)\${ gnGroup(grid, node, group) `````` Niina Helistö committed Oct 03, 2019 108 `````` and gnuRescapable(restype, up_down, grid, node, unit) `````` Niina Helistö committed Oct 01, 2019 109 `````` }, `````` Niina Helistö committed Oct 03, 2019 110 `````` + v_reserve(restype, up_down, grid, node, unit, s, f+df_reserves(grid, node, restype, f, t), t) `````` Topi Rasku committed Jan 15, 2019 111 `````` * [ // Account for reliability of reserves `````` Niina Helistö committed Oct 03, 2019 112 113 `````` + 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 114 `````` ] // END * v_reserve `````` 115 `````` ) // END sum(gnuft) `````` Topi Rasku committed Oct 11, 2017 116 `````` `````` 117 `````` // Reserve provision from other reserve categories when they can be shared `````` Niina Helistö committed Oct 01, 2019 118 `````` + sum((gnuft(grid, node, unit, f, t), restype_)\${ gnGroup(grid, node, group) `````` Niina Helistö committed Oct 03, 2019 119 `````` and p_gnuRes2Res(grid, node, unit, restype_, up_down, restype) `````` Niina Helistö committed Oct 01, 2019 120 `````` }, `````` Niina Helistö committed Oct 03, 2019 121 122 `````` + 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 123 `````` * [ // Account for reliability of reserves `````` Niina Helistö committed Oct 03, 2019 124 125 126 `````` + 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 127 `````` ] // END * v_reserve `````` 128 `````` ) // END sum(gnuft) `````` 129 `````` `````` 130 `````` // Reserve provision to this group via transfer links `````` 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 `````` }, `````` Niina Helistö committed Jun 04, 2021 135 136 137 138 `````` + [1 - p_gnn(grid, node_, node, 'transferLoss')\${not gn2n_timeseries(grid, node_, node, 'transferLoss')} - ts_gnn_(grid, node_, node, 'transferLoss', f, t)\${gn2n_timeseries(grid, node_, node, 'transferLoss')} ] `````` Niina Helistö committed Oct 03, 2019 139 `````` * 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 140 `````` ) // END sum(gn2n_directional) `````` Niina Helistö committed Oct 01, 2019 141 142 `````` + sum(gn2n_directional(grid, node, node_)\${ gnGroup(grid, node, group) and not gnGroup(grid, node_, group) `````` Niina Helistö committed Oct 03, 2019 143 `````` and restypeDirectionGridNodeNode(restype, up_down, grid, node_, node) `````` Niina Helistö committed Oct 01, 2019 144 `````` }, `````` Niina Helistö committed Jun 04, 2021 145 146 147 148 `````` + [1 - p_gnn(grid, node_, node, 'transferLoss')\${not gn2n_timeseries(grid, node_, node, 'transferLoss')} - ts_gnn_(grid, node_, node, 'transferLoss', f, t)\${gn2n_timeseries(grid, node_, node, 'transferLoss')} ] `````` Niina Helistö committed Oct 03, 2019 149 `````` * 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 150 151 152 153 154 `````` ) // END sum(gn2n_directional) =G= // Demand for reserves `````` Tomi J. Lindroos committed Mar 03, 2020 155 156 `````` + ts_reserveDemand(restype, up_down, group, f, t)\${p_groupReserves(group, restype, 'useTimeSeries')} + p_groupReserves(group, restype, up_down)\${not p_groupReserves(group, restype, 'useTimeSeries')} `````` Topi Rasku committed Oct 11, 2017 157 `````` `````` Niina Helistö committed Nov 02, 2018 158 `````` // Reserve demand increase because of units `````` Niina Helistö committed Oct 01, 2019 159 `````` + sum(gnuft(grid, node, unit, f, t)\${ gnGroup(grid, node, group) `````` Niina Helistö committed Oct 03, 2019 160 `````` 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 161 `````` }, `````` Niina Helistö committed Oct 03, 2019 162 163 `````` + v_gen(grid, node, unit, s, f, t) * p_gnuReserves(grid, node, unit, restype, 'reserve_increase_ratio') `````` Niina Helistö committed Nov 02, 2018 164 165 `````` ) // END sum(nuft) `````` 166 `````` // Reserve provisions to other groups via transfer links `````` Niina Helistö committed Oct 01, 2019 167 168 `````` + sum(gn2n_directional(grid, node, node_)\${ gnGroup(grid, node, group) and not gnGroup(grid, node_, group) `````` Niina Helistö committed Oct 03, 2019 169 `````` and restypeDirectionGridNodeNode(restype, up_down, grid, node, node_) `````` Niina Helistö committed Oct 01, 2019 170 `````` }, // If trasferring reserves to another node, increase your own reserves by same amount `````` Niina Helistö committed Oct 03, 2019 171 `````` + v_resTransferRightward(restype, up_down, grid, node, node_, s, f+df_reserves(grid, node, restype, f, t), t) `````` Topi Rasku committed Oct 11, 2017 172 `````` ) // END sum(gn2n_directional) `````` Niina Helistö committed Oct 01, 2019 173 174 `````` + sum(gn2n_directional(grid, node_, node)\${ gnGroup(grid, node, group) and not gnGroup(grid, node_, group) `````` Niina Helistö committed Oct 03, 2019 175 `````` and restypeDirectionGridNodeNode(restype, up_down, grid, node, node_) `````` Niina Helistö committed Oct 01, 2019 176 `````` }, // If trasferring reserves to another node, increase your own reserves by same amount `````` Niina Helistö committed Oct 03, 2019 177 `````` + v_resTransferLeftward(restype, up_down, grid, node_, node, s, f+df_reserves(grid, node, restype, f, t), t) `````` Topi Rasku committed Oct 11, 2017 178 179 180 `````` ) // END sum(gn2n_directional) // Reserve demand feasibility dummy variables `````` 181 182 `````` - 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)} `````` 183 ``````; `````` Topi Rasku committed Oct 11, 2017 184 `````` `````` ran li committed Nov 25, 2018 185 186 187 188 ``````* --- 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 189 190 ``````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 191 192 193 `````` and not [ restypeReleasedForRealization(restype) and ft_realized(f, t) ] `````` Niina Helistö committed Oct 03, 2019 194 `````` and sum(gnGroup(grid, node, group), p_gnuReserves(grid, node, unit_, restype, 'portion_of_infeed_to_reserve')) `````` Niina Helistö committed Oct 01, 2019 195 196 `````` 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 197 `````` } .. `````` Topi Rasku committed Apr 04, 2019 198 `````` `````` Niina Helistö committed Oct 01, 2019 199 200 `````` // 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 201 `````` and gnuRescapable(restype, 'up', grid, node, unit) `````` Niina Helistö committed Oct 01, 2019 202 203 `````` and (ord(unit_) ne ord(unit)) }, `````` Niina Helistö committed Oct 03, 2019 204 `````` + v_reserve(restype, 'up', grid, node, unit, s, f+df_reserves(grid, node, restype, f, t), t) `````` Topi Rasku committed Jan 15, 2019 205 `````` * [ // Account for reliability of reserves `````` Niina Helistö committed Oct 03, 2019 206 207 `````` + 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 208 `````` ] // END * v_reserve `````` ran li committed Nov 25, 2018 209 210 211 `````` ) // END sum(nuft) // Reserve provision from other reserve categories when they can be shared `````` Niina Helistö committed Oct 01, 2019 212 `````` + sum((gnuft(grid, node, unit, f, t), restype_)\${ gnGroup(grid, node, group) `````` Niina Helistö committed Oct 03, 2019 213 `````` and p_gnuRes2Res(grid, node, unit, restype_, 'up', restype) `````` Niina Helistö committed Oct 01, 2019 214 215 `````` and (ord(unit_) ne ord(unit)) }, `````` Niina Helistö committed Oct 03, 2019 216 217 `````` + 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 218 `````` * [ // Account for reliability of reserves `````` Niina Helistö committed Oct 03, 2019 219 220 221 `````` + 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 222 `````` ] // END * v_reserve `````` ran li committed Nov 25, 2018 223 224 `````` ) // END sum(nuft) `````` Niina Helistö committed Oct 01, 2019 225 226 227 `````` // 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 228 `````` and restypeDirectionGridNodeNode(restype, 'up', grid, node_, node) `````` Niina Helistö committed Oct 01, 2019 229 `````` }, `````` Niina Helistö committed Jun 04, 2021 230 231 232 233 `````` + [1 - p_gnn(grid, node_, node, 'transferLoss')\${not gn2n_timeseries(grid, node_, node, 'transferLoss')} - ts_gnn_(grid, node_, node, 'transferLoss', f, t)\${gn2n_timeseries(grid, node_, node, 'transferLoss')} ] `````` Niina Helistö committed Oct 03, 2019 234 `````` * 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 235 `````` ) // END sum(gn2n_directional) `````` Niina Helistö committed Oct 01, 2019 236 237 `````` + sum(gn2n_directional(grid, node, node_)\${ gnGroup(grid, node, group) and not gnGroup(grid, node_, group) `````` Niina Helistö committed Oct 03, 2019 238 `````` and restypeDirectionGridNodeNode(restype, 'up', grid, node_, node) `````` Niina Helistö committed Oct 01, 2019 239 `````` }, `````` Niina Helistö committed Jun 04, 2021 240 241 242 243 `````` + [1 - p_gnn(grid, node_, node, 'transferLoss')\${not gn2n_timeseries(grid, node_, node, 'transferLoss')} - ts_gnn_(grid, node_, node, 'transferLoss', f, t)\${gn2n_timeseries(grid, node_, node, 'transferLoss')} ] `````` Niina Helistö committed Oct 03, 2019 244 `````` * 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 245 246 247 248 `````` ) // END sum(gn2n_directional) =G= `````` Juha Kiviluoma committed Aug 28, 2019 249 `````` // Demand for reserves due to a large unit that could fail `````` Niina Helistö committed Oct 01, 2019 250 251 `````` + sum(gnGroup(grid, node, group), + v_gen(grid, node, unit_, s, f, t) `````` Niina Helistö committed Oct 03, 2019 252 `````` * p_gnuReserves(grid, node, unit_, restype, 'portion_of_infeed_to_reserve') `````` Niina Helistö committed Oct 01, 2019 253 `````` ) // END sum(gnGroup) `````` ran li committed Nov 25, 2018 254 `````` `````` Niina Helistö committed Oct 01, 2019 255 256 257 `````` // 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 258 `````` and restypeDirectionGridNodeNode(restype, 'up', grid, node, node_) `````` Niina Helistö committed Oct 01, 2019 259 `````` }, // If trasferring reserves to another node, increase your own reserves by same amount `````` Niina Helistö committed Oct 03, 2019 260 `````` + v_resTransferRightward(restype, 'up', grid, node, node_, s, f+df_reserves(grid, node, restype, f, t), t) `````` ran li committed Nov 25, 2018 261 `````` ) // END sum(gn2n_directional) `````` Niina Helistö committed Oct 01, 2019 262 263 `````` + sum(gn2n_directional(grid, node_, node)\${ gnGroup(grid, node, group) and not gnGroup(grid, node_, group) `````` Niina Helistö committed Oct 03, 2019 264 `````` and restypeDirectionGridNodeNode(restype, 'up', grid, node, node_) `````` Niina Helistö committed Oct 01, 2019 265 `````` }, // If trasferring reserves to another node, increase your own reserves by same amount `````` Niina Helistö committed Oct 03, 2019 266 `````` + v_resTransferLeftward(restype, 'up', grid, node_, node, s, f+df_reserves(grid, node, restype, f, t), t) `````` ran li committed Nov 25, 2018 267 268 269 `````` ) // END sum(gn2n_directional) // Reserve demand feasibility dummy variables `````` Niina Helistö committed Oct 01, 2019 270 271 `````` - 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 272 ``````; `````` ran li committed Aug 27, 2019 273 `````` `````` Niina Helistö committed Oct 01, 2019 274 275 ``````* --- ROCOF Limit -- Units ---------------------------------------------------- `````` Niina Helistö committed Sep 24, 2019 276 277 278 ``````q_rateOfChangeOfFrequencyUnit(group, unit_fail(unit_), sft(s, f, t)) \${ p_groupPolicy(group, 'defaultFrequency') and p_groupPolicy(group, 'ROCOF') `````` 279 `````` and p_groupPolicy(group, 'dynamicInertia') `````` Niina Helistö committed Oct 01, 2019 280 281 `````` 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 282 283 `````` } .. `````` Niina Helistö committed Sep 24, 2019 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 `````` // 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)} `````` 299 `````` / p_gnu(grid, node, unit, 'unitSize') `````` Niina Helistö committed Sep 24, 2019 300 301 302 `````` ] // * p_gnu ) // END sum(gnu_output) ] // END * p_groupPolicy `````` ran li committed Sep 05, 2019 303 304 305 `````` =G= `````` Niina Helistö committed Sep 24, 2019 306 307 308 309 310 311 `````` // 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 312 ``````; `````` Niina Helistö committed Sep 24, 2019 313 `````` `````` Niina Helistö committed Oct 01, 2019 314 315 316 ``````* --- ROCOF Limit -- Transfer Links ------------------------------------------- q_rateOfChangeOfFrequencyTransfer(group, gn2n(grid, node_, node_fail), sft(s, f, t)) `````` Niina Helistö committed Sep 24, 2019 317 318 `````` \${ p_groupPolicy(group, 'defaultFrequency') and p_groupPolicy(group, 'ROCOF') `````` 319 `````` and p_groupPolicy(group, 'dynamicInertia') `````` Niina Helistö committed Sep 24, 2019 320 321 322 323 324 `````` 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 325 326 `````` } .. `````` Niina Helistö committed Sep 24, 2019 327 328 329 330 331 332 333 334 335 336 337 338 339 340 `````` // 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)} `````` 341 `````` / p_gnu(grid, node, unit, 'unitSize') `````` Niina Helistö committed Sep 24, 2019 342 343 344 `````` ] // * p_gnu ) // END sum(gnu_output) ] // END * p_groupPolicy `````` ran li committed Sep 05, 2019 345 346 347 `````` =G= `````` Niina Helistö committed Sep 24, 2019 348 349 350 351 352 `````` // 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 353 `````` * v_transferRightward(grid, node_fail, node_, s, f, t)\${gn2n_directional(grid, node_fail, node_)} `````` Niina Helistö committed Jun 04, 2021 354 355 356 357 `````` * [1 - p_gnn(grid, node_fail, node_, 'transferLoss')\${not gn2n_timeseries(grid, node_fail, node_, 'transferLoss')} - ts_gnn_(grid, node_fail, node_, 'transferLoss', f, t)\${gn2n_timeseries(grid, node_fail, node_, 'transferLoss')} ] `````` Niina Helistö committed Sep 24, 2019 358 `````` + p_gnn(grid, node_, node_fail, 'portion_of_transfer_to_reserve') `````` Niina Helistö committed Oct 01, 2019 359 `````` * v_transferLeftward(grid, node_, node_fail, s, f, t)\${gn2n_directional(grid, node_, node_fail)} `````` Niina Helistö committed Jun 04, 2021 360 361 362 363 `````` * [1 - p_gnn(grid, node_fail, node_, 'transferLoss')\${not gn2n_timeseries(grid, node_fail, node_, 'transferLoss')} - ts_gnn_(grid, node_fail, node_, 'transferLoss', f, t)\${gn2n_timeseries(grid, node_fail, node_, 'transferLoss')} ] `````` Niina Helistö committed Sep 24, 2019 364 365 `````` // 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 366 `````` * v_transferLeftward(grid, node_fail, node_, s, f, t)\${gn2n_directional(grid, node_fail, node_)} `````` Niina Helistö committed Sep 24, 2019 367 `````` + p_gnn(grid, node_, node_fail, 'portion_of_transfer_to_reserve') `````` Niina Helistö committed Oct 01, 2019 368 `````` * v_transferRightward(grid, node_, node_fail, s, f, t)\${gn2n_directional(grid, node_, node_fail)} `````` Niina Helistö committed Sep 24, 2019 369 `````` ] // END * p_groupPolicy `````` ran li committed Sep 05, 2019 370 ``````; `````` Niina Helistö committed Sep 24, 2019 371 `````` `````` Niina Helistö committed Oct 01, 2019 372 ``````* --- 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 373 374 375 ``````// 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 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 ``````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 392 `````` and gnuRescapable(restype, up_down, grid, node, unit) `````` Niina Helistö committed Oct 01, 2019 393 `````` }, `````` Niina Helistö committed Oct 03, 2019 394 `````` + v_reserve(restype, up_down, grid, node, unit, s, f+df_reserves(grid, node, restype, f, t), t) `````` Niina Helistö committed Oct 01, 2019 395 `````` * [ // Account for reliability of reserves `````` Niina Helistö committed Oct 03, 2019 396 397 `````` + 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 398 399 400 401 402 `````` ] // 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 403 `````` and p_gnuRes2Res(grid, node, unit, restype_, up_down, restype) `````` Niina Helistö committed Oct 01, 2019 404 `````` }, `````` Niina Helistö committed Oct 03, 2019 405 406 `````` + 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 407 `````` * [ // Account for reliability of reserves `````` Niina Helistö committed Oct 03, 2019 408 409 410 `````` + 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 411 412 413 414 415 416 417 `````` ] // 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 418 `````` and restypeDirectionGridNodeNode(restype, up_down, grid, node_, node) `````` Niina Helistö committed Oct 01, 2019 419 `````` }, `````` Niina Helistö committed Jun 04, 2021 420 421 422 423 `````` + [1 - p_gnn(grid, node_, node, 'transferLoss')\${not gn2n_timeseries(grid, node_, node, 'transferLoss')} - ts_gnn_(grid, node_, node, 'transferLoss', f, t)\${gn2n_timeseries(grid, node_, node, 'transferLoss')} ] `````` Niina Helistö committed Oct 03, 2019 424 `````` * v_resTransferRightward(restype, up_down, grid, node_, node, s, f+df_reserves(grid, node_, restype, f, t), t) `````` Niina Helistö committed Oct 01, 2019 425 426 427 428 `````` ) // 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 429 `````` and restypeDirectionGridNodeNode(restype, up_down, grid, node_, node) `````` Niina Helistö committed Oct 01, 2019 430 `````` }, `````` Niina Helistö committed Jun 04, 2021 431 432 433 434 `````` + [1 - p_gnn(grid, node_, node, 'transferLoss')\${not gn2n_timeseries(grid, node_, node, 'transferLoss')} - ts_gnn_(grid, node_, node, 'transferLoss', f, t)\${gn2n_timeseries(grid, node_, node, 'transferLoss')} ] `````` Niina Helistö committed Oct 03, 2019 435 `````` * v_resTransferLeftward(restype, up_down, grid, node, node_, s, f+df_reserves(grid, node_, restype, f, t), t) `````` Niina Helistö committed Oct 01, 2019 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 `````` ) // 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 459 `````` and restypeDirectionGridNodeNode(restype, up_down, grid, node, node_) `````` Niina Helistö committed Oct 01, 2019 460 461 `````` }, // Reserve transfers to other nodes increase the reserve need of the present node `````` Niina Helistö committed Oct 03, 2019 462 `````` + v_resTransferRightward(restype, up_down, grid, node, node_, s, f+df_reserves(grid, node, restype, f, t), t) `````` Niina Helistö committed Oct 01, 2019 463 464 465 466 `````` ) // 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 467 `````` and restypeDirectionGridNodeNode(restype, up_down, grid, node, node_) `````` Niina Helistö committed Oct 01, 2019 468 469 `````` }, // Reserve transfers to other nodes increase the reserve need of the present node `````` Niina Helistö committed Oct 03, 2019 470 `````` + v_resTransferLeftward(restype, up_down, grid, node_, node, s, f+df_reserves(grid, node, restype, f, t), t) `````` Niina Helistö committed Oct 01, 2019 471 472 473 474 475 476 `````` ) // 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 477 `````` `````` Topi Rasku committed Oct 11, 2017 478 479 ``````* --- Maximum Downward Capacity ----------------------------------------------- `````` Topi Rasku committed Aug 09, 2019 480 ``````q_maxDownward(gnu(grid, node, unit), msft(m, s, f, t)) `````` Topi Rasku committed Apr 04, 2019 481 `````` \${ gnuft(grid, node, unit, f, t) `````` Niina Helistö committed Feb 20, 2020 482 `````` and (p_gnu(grid, node, unit, 'capacity') or p_gnu(grid, node, unit, 'unitSize')) `````` Topi Rasku committed Apr 04, 2019 483 `````` and { `````` Niina Helistö committed Oct 03, 2019 484 485 `````` [ 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 486 487 488 489 490 `````` ] // NOTE!!! Could be better to form a gnuft_reserves subset? or [ // the unit has an online variable uft_online(unit, f, t) and [ `````` 491 492 `````` (unit_minLoad(unit) and gnu_output(grid, node, unit)) // generating units with a min. load or gnu_input(grid, node, unit) // or consuming units with an online variable `````` Topi Rasku committed Apr 04, 2019 493 494 495 496 497 498 499 500 `````` ] ] // 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 501 `````` // Energy generation/consumption `````` Erkka Rinne committed Nov 02, 2018 502 `````` + v_gen(grid, node, unit, s, f, t) `````` Topi Rasku committed Oct 11, 2017 503 504 `````` // Downward reserve participation `````` Niina Helistö committed Oct 07, 2019 505 506 507 `````` - 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 508 `````` + 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 509 510 511 512 513 `````` ) // 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 `````` 514 `````` + p_gnu(grid, node, unit, 'unitSize')\$gnu_output(grid, node, unit) `````` Topi Rasku committed Nov 09, 2017 515 `````` * sum(suft(effGroup, unit, f, t), // Uses the minimum 'lb' for the current efficiency approximation `````` Topi Rasku committed Oct 11, 2017 516 517 518 519 `````` + 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 520 521 `````` + 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 522 523 `````` ] // END v_online `````` Topi Rasku committed Jan 24, 2019 524 `````` // Units in run-up phase neet to keep up with the run-up rate `````` Niina Helistö committed Mar 02, 2020 525 `````` + p_gnu(grid, node, unit, 'unitSize')\$gnu_output(grid, node, unit) `````` Topi Rasku committed Jan 24, 2019 526 527 `````` * 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 528 529 `````` + [ + v_startup_LP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) `````` Topi Rasku committed Apr 04, 2019 530 `````` \${ uft_onlineLP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } `````` Topi Rasku committed Apr 04, 2019 531 `````` + v_startup_MIP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) `````` Topi Rasku committed Apr 04, 2019 532 `````` \${ uft_onlineMIP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } `````` Topi Rasku committed Apr 04, 2019 533 `````` ] `````` Topi Rasku committed Jan 25, 2019 534 `````` * p_uCounter_runUpMin(unit, counter) `````` Topi Rasku committed Jan 24, 2019 535 536 537 538 `````` ) // END sum(runUpCounter) ) // END sum(unitStarttype) // Units in shutdown phase need to keep up with the shutdown rate `````` 539 `````` + p_gnu(grid, node, unit, 'unitSize')\$gnu_output(grid, node, unit) `````` Topi Rasku committed Jan 24, 2019 540 `````` * 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 541 542 543 544 545 546 `````` + [ + 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 547 `````` * p_uCounter_shutdownMin(unit, counter) `````` Topi Rasku committed Jan 24, 2019 548 `````` ) // END sum(shutdownCounter) `````` Juha Kiviluoma committed Apr 06, 2018 549 `````` `````` Topi Rasku committed Oct 11, 2017 550 551 `````` // Consuming units, greater than maxCons // Available capacity restrictions `````` 552 `````` - p_unit(unit, 'availability')\$gnu_input(grid, node, unit) `````` Topi Rasku committed Oct 11, 2017 553 554 `````` * [ // Capacity factors for flow units `````` Topi Rasku committed Jun 05, 2018 555 `````` + sum(flowUnit(flow, unit), `````` Erkka Rinne committed Oct 24, 2019 556 `````` + ts_cf_(flow, node, s, f, t) `````` Topi Rasku committed Oct 11, 2017 557 558 559 560 561 `````` ) // END sum(flow) + 1\${not unit_flow(unit)} ] // END * p_unit(availability) * [ // Online capacity restriction `````` 562 `````` + p_gnu(grid, node, unit, 'capacity')\${not uft_online(unit, f, t)} // Use initial maximum if no online variables `````` 563 564 `````` // !!! TEMPORARY SOLUTION !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + [ `````` 565 566 `````` + p_gnu(grid, node, unit, 'unitSize') + p_gnu(grid, node, unit, 'capacity')\${not p_gnu(grid, node, unit, 'unitSize') > 0} `````` Topi Rasku committed Aug 09, 2019 567 `````` / ( p_unit(unit, 'unitCount') + 1\${not p_unit(unit, 'unitCount') > 0} ) `````` 568 569 `````` ] // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! `````` Topi Rasku committed Oct 11, 2017 570 `````` * [ `````` 571 `````` // Capacity online `````` Erkka Rinne committed Nov 02, 2018 572 573 `````` + 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)} `````` 574 575 `````` // Investments to additional non-online capacity `````` Niina Helistö committed Jun 23, 2020 576 577 `````` + v_invest_LP(unit)\${unit_investLP(unit) and not uft_online(unit, f, t)} // NOTE! v_invest_LP also for consuming units is positive + v_invest_MIP(unit)\${unit_investMIP(unit) and not uft_online(unit, f, t)} // NOTE! v_invest_MIP also for consuming units is positive `````` 578 `````` ] // END * p_gnu(unitSize) `````` Topi Rasku committed Oct 11, 2017 579 `````` ] // END * p_unit(availability) `````` Topi Rasku committed Mar 29, 2017 580 ``````; `````` Topi Rasku committed Oct 11, 2017 581 `````` `````` 582 583 ``````* --- Maximum Downward Capacity for Production/Consumption, Online Reserves and Offline Reserves --- `````` Niina Helistö committed Oct 07, 2019 584 ``````q_maxDownwardOfflineReserve(gnu(grid, node, unit), msft(m, s, f, t)) `````` 585 `````` \${ gnuft(grid, node, unit, f, t) `````` Niina Helistö committed Feb 20, 2020 586 `````` and (p_gnu(grid, node, unit, 'capacity') or p_gnu(grid, node, unit, 'unitSize')) `````` 587 `````` and { `````` Niina Helistö committed Oct 07, 2019 588 589 `````` [ 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 `````` 590 591 592 `````` ] } `````` Niina Helistö committed Oct 07, 2019 593 `````` and { sum(restype, gnuOfflineRescapable(restype, grid, node, unit))} // and it can provide some reserve products although being offline `````` 594 595 596 597 598 599 600 `````` }.. // Energy generation/consumption + v_gen(grid, node, unit, s, f, t) // Downward reserve participation `````` Niina Helistö committed Oct 07, 2019 601 602 `````` - 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) `````` 603 604 605 606 607 608 `````` ) // END sum(nuRescapable) =G= // Must be greater than maximum consumption // Consuming units // Available capacity restrictions `````` 609 `````` - p_unit(unit, 'availability')\$gnu_input(grid, node, unit) // Consumption units are also restricted by their (available) capacity `````` 610 611 612 `````` * [ // Capacity factors for flow units + sum(flowUnit(flow, unit), `````` Erkka Rinne committed Oct 24, 2019 613 `````` + ts_cf_(flow, node, s, f, t) `````` 614 615 616 617 618 `````` ) // END sum(flow) + 1\${not unit_flow(unit)} ] // END * p_unit(availability) * [ // Existing capacity `````` 619 `````` + p_gnu(grid, node, unit, 'capacity') `````` 620 621 `````` // Investments to new capacity + [ `````` 622 `````` + p_gnu(grid, node, unit, 'unitSize') `````` 623 624 `````` ] * [ `````` Niina Helistö committed Jun 23, 2020 625 626 `````` + v_invest_LP(unit)\${unit_investLP(unit)} + v_invest_MIP(unit)\${unit_investMIP(unit)} `````` 627 `````` ] // END * p_gnu(unitSize) `````` 628 629 630 631 `````` ] // END * p_unit(availability) ; `````` Niina Helistö committed Sep 06, 2019 632 ``````* --- Maximum Upwards Capacity for Production/Consumption and Online Reserves --- `````` Topi Rasku committed Oct 11, 2017 633 `````` `````` Topi Rasku committed Aug 09, 2019 634 ``````q_maxUpward(gnu(grid, node, unit), msft(m, s, f, t)) `````` Topi Rasku committed Apr 04, 2019 635 `````` \${ gnuft(grid, node, unit, f, t) `````` Niina Helistö committed Feb 20, 2020 636 `````` and (p_gnu(grid, node, unit, 'capacity') or p_gnu(grid, node, unit, 'unitSize')) `````` Topi Rasku committed Apr 04, 2019 637 `````` and { `````` Niina Helistö committed Oct 03, 2019 638 639 `````` [ 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 640 641 642 643 `````` ] or [ uft_online(unit, f, t) // or the unit has an online variable and [ `````` 644 645 `````` [unit_minLoad(unit) and gnu_input(grid, node, unit)] // consuming units with min_load or gnu_output(grid, node, unit) // generators with an online variable `````` Topi Rasku committed Apr 04, 2019 646 647 648 649 650 651 `````` ] ] 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 652 653 654 `````` } }.. `````` Topi Rasku committed Apr 04, 2019 655 `````` `````` Topi Rasku committed Oct 11, 2017 656 `````` // Energy generation/consumption `````` Erkka Rinne committed Nov 02, 2018 657 `````` + v_gen(grid, node, unit, s, f, t) `````` Topi Rasku committed Oct 11, 2017 658 659 `````` // Upwards reserve participation `````` Niina Helistö committed Oct 07, 2019 660 661 662 `````` + 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 663 `````` + v_reserve(restype, 'up', grid, node, unit, s, f+df_reserves(grid, node, restype, f, t), t) `````` Topi Rasku committed Oct 11, 2017 664 665 666 667 668 `````` ) // END sum(nuRescapable) =L= // must be less than available/online capacity // Consuming units `````` 669 `````` - p_gnu(grid, node, unit, 'unitSize')\$gnu_input(grid, node, unit) `````` Topi Rasku committed Nov 09, 2017 670 `````` * sum(suft(effGroup, unit, f, t), // Uses the minimum 'lb' for the current efficiency approximation `````` Topi Rasku committed Oct 11, 2017 671 672 673 674 `````` + 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 675 676 `````` + 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) `````` 677 `````` ] // END * p_gnu(unitSize) `````` Topi Rasku committed Oct 11, 2017 678 679 680 `````` // Generation units // Available capacity restrictions `````` 681 `````` + p_unit(unit, 'availability')\$gnu_output(grid, node, unit) // Generation units are restricted by their (available) capacity `````` Topi Rasku committed Oct 11, 2017 682 683 `````` * [ // Capacity factor for flow units `````` Topi Rasku committed Jun 05, 2018 684 `````` + sum(flowUnit(flow, unit), `````` Erkka Rinne committed Oct 24, 2019 685 `````` + ts_cf_(flow, node, s, f, t) `````` Topi Rasku committed Oct 11, 2017 686 687 688 689 690 `````` ) // END sum(flow) + 1\${not unit_flow(unit)} ] // END * p_unit(availability) * [ // Online capacity restriction `````` 691 692 `````` + p_gnu(grid, node, unit, 'capacity')\${not uft_online(unit, f, t)} // Use initial capacity if no online variables + p_gnu(grid, node, unit, 'unitSize') `````` Topi Rasku committed Oct 11, 2017 693 `````` * [ `````` 694 `````` // Capacity online `````` Erkka Rinne committed Nov 02, 2018 695 696 `````` + 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)} `````` 697 698 `````` // Investments to non-online capacity `````` Niina Helistö committed Jun 23, 2020 699 700 `````` + v_invest_LP(unit)\${unit_investLP(unit) and not uft_online(unit, f ,t)} + v_invest_MIP(unit)\${unit_investMIP(unit) and not uft_online(unit, f ,t)} `````` 701 `````` ] // END * p_gnu(unitSize) `````` Topi Rasku committed Oct 11, 2017 702 `````` ] // END * p_unit(availability) `````` Juha Kiviluoma committed Apr 06, 2018 703 `````` `````` Topi Rasku committed Jan 24, 2019 704 `````` // Units in run-up phase neet to keep up with the run-up rate `````` 705 `````` + p_gnu(grid, node, unit, 'unitSize')\$gnu_output(grid, node, unit) `````` Topi Rasku committed Jan 24, 2019 706 707 `````` * 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 708 709 `````` + [ + v_startup_LP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) `````` Topi Rasku committed Apr 04, 2019 710 `````` \${ uft_onlineLP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } `````` Topi Rasku committed Apr 04, 2019 711 `````` + v_startup_MIP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) `````` Topi Rasku committed Apr 04, 2019 712 `````` \${ uft_onlineMIP_withPrevious(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) } `````` Topi Rasku committed Apr 04, 2019 713 `````` ] `````` Topi Rasku committed Jan 25, 2019 714 `````` * p_uCounter_runUpMax(unit, counter) `````` Topi Rasku committed Jan 24, 2019 715 716 717 718 `````` ) // END sum(runUpCounter) ) // END sum(unitStarttype) // Units in shutdown phase need to keep up with the shutdown rate `````` 719 `````` + p_gnu(grid, node, unit, 'unitSize')\$gnu_output(grid, node, unit) `````` Topi Rasku committed Jan 24, 2019 720 `````` * 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 721 722 723 724 725 726 `````` + [ + 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 727 `````` * p_uCounter_shutdownMax(unit, counter) `````` Topi Rasku committed Jan 24, 2019 728 `````` ) // END sum(shutdownCounter) `````` 729 ``````; `````` Topi Rasku committed Oct 11, 2017 730 `````` `````` Niina Helistö committed Sep 06, 2019 731 ``````* --- Maximum Upwards Capacity for Production/Consumption, Online Reserves and Offline Reserves --- `````` Ciara O'Dwyer committed Sep 02, 2019 732 `````` `````` Niina Helistö committed Oct 07, 2019 733 ``````q_maxUpwardOfflineReserve(gnu(grid, node, unit), msft(m, s, f, t)) `````` Ciara O'Dwyer committed Sep 02, 2019 734 `````` \${ gnuft(grid, node, unit, f, t) `````` Niina Helistö committed Feb 20, 2020 735 `````` and (p_gnu(grid, node, unit, 'capacity') or p_gnu(grid, node, unit, 'unitSize')) `````` Ciara O'Dwyer committed Sep 02, 2019 736 `````` and { `````` Niina Helistö committed Oct 07, 2019 737 738 `````` [ 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 739 740 741 `````` ] } `````` Niina Helistö committed Oct 07, 2019 742 `````` 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 743 744 745 746 747 748 749 `````` }.. // Energy generation/consumption + v_gen(grid, node, unit, s, f, t) // Upwards reserve participation `````` Niina Helistö committed Oct 07, 2019 750 751 `````` + 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 752 753 `````` ) // END sum(nuRescapable) `````` Niina Helistö committed Sep 06, 2019 754 `````` =L= // must be less than available capacity `````` Ciara O'Dwyer committed Sep 02, 2019 755 756 757 `````` // Generation units // Available capacity restrictions `````` 758 `````` + p_unit(unit, 'availability')\$gnu_output(grid, node, unit) // Generation units are restricted by their (available) capacity `````` Ciara O'Dwyer committed Sep 02, 2019 759 760 761 `````` * [ // Capacity factor for flow units + sum(flowUnit(flow, unit), `````` Erkka Rinne committed Oct 24, 2019 762 `````` + ts_cf_(flow, node, s, f, t) `````` Ciara O'Dwyer committed Sep 02, 2019 763 764 765 766 `````` ) // END sum(flow) + 1\${not unit_flow(unit)} ] // END * p_unit(availability) * [ `````` Niina Helistö committed Sep 06, 2019 767 `````` // Capacity restriction `````` 768 `````` + p_gnu(grid, node, unit, 'unitSize') `````` Ciara O'Dwyer committed Sep 02, 2019 769 `````` * [ `````` Niina Helistö committed Sep 06, 2019 770 771 `````` // Existing capacity + p_unit(unit, 'unitCount') `````` Ciara O'Dwyer committed Sep 02, 2019 772 `````` `````` Niina Helistö committed Sep 06, 2019 773 `````` // Investments to new capacity `````` Niina Helistö committed Jun 23, 2020 774 775 `````` + v_invest_LP(unit)\${unit_investLP(unit)} + v_invest_MIP(unit)\${unit_investMIP(unit)} `````` 776 `````` ] // END * p_gnu(unitSize) `````` Ciara O'Dwyer committed Sep 02, 2019 777 778 779 `````` ] // END * p_unit(availability) ; `````` Niina Helistö committed Nov 01, 2018 780 781 ``````* --- Reserve Provision of Units with Investments ----------------------------- `````` Niina Helistö committed Oct 03, 2019 782 783 784 ``````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 785 `````` and (unit_investLP(unit) or unit_investMIP(unit)) `````` 786 787 `````` 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 788 789 `````` } .. `````` Niina Helistö committed Oct 03, 2019 790 `````` + v_reserve(restype, up_down, grid, node, unit, s, f+df_reserves(grid, node, restype, f, t), t) `````` Niina Helistö committed Nov 01, 2018 791 792 793 `````` =L= `````` Niina Helistö committed Oct 03, 2019 794 `````` + p_gnuReserves(grid, node, unit, restype, up_down) `````` Niina Helistö committed Nov 01, 2018 795 `````` * [ `````` 796 `````` + p_gnu(grid, node, unit, 'capacity') `````` Niina Helistö committed Jun 23, 2020 797 798 799 800 `````` + v_invest_LP(unit)\${unit_investLP(unit)} * p_gnu(grid, node, unit, 'unitSize') + v_invest_MIP(unit)\${unit_investMIP(unit)} * p_gnu(grid, node, unit, 'unitSize') `````` Niina Helistö committed Nov 01, 2018 801 `````` ] `````` Niina Helistö committed Nov 02, 2018 802 803 804 805 `````` * p_unit(unit, 'availability') // Taking into account availability... * [ // ... and capacity factor for flow units + sum(flowUnit(flow, unit), `````` Erkka Rinne committed Oct 24, 2019 806 `````` + ts_cf_(flow, node, s, f, t) `````` Niina Helistö committed Nov 02, 2018 807 808 `````` ) // END sum(flow) + 1\${not unit_flow(unit)} `````` Niina Helistö committed Nov 01, 2018 809 810 811 `````` ] // How to consider reserveReliability in the case of investments when we typically only have "realized" time steps? ; `````` Niina Helistö committed Sep 06, 2019 812 ``````* --- Online Reserve Provision of Units with Online Variables ----------------- `````` Ciara O'Dwyer committed Sep 02, 2019 813 `````` `````` Niina Helistö committed Oct 07, 2019 814 815 816 817 818 ``````q_reserveProvisionOnline(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) and not sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node, group), ft_reservesFixed(group, restype, f+df_reservesGroup(group, restype, f, t), t)) `````` Niina Helistö committed Sep 06, 2019 819 `````` and uft_online(unit, f ,t) `````` Niina Helistö committed Oct 07, 2019 820 `````` and not gnuOfflineRescapable(restype, grid, node, unit) `````` Ciara O'Dwyer committed Sep 02, 2019 821 822 `````` }.. `````` Niina Helistö committed Oct 07, 2019 823 `````` + v_reserve(restype, up_down, grid, node, unit, s, f+df_reserves(grid, node, restype, f, t), t) `````` Ciara O'Dwyer committed Sep 02, 2019 824 825 826 `````` =L= `````` Niina Helistö committed Oct 07, 2019 827 `````` + p_gnuReserves(grid, node, unit, restype, up_down) `````` 828 `````` * p_gnu(grid, node, unit, 'unitSize') `````` Niina Helistö committed Sep 06, 2019 829 830 831 `````` * [ + 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)} `````` Ciara O'Dwyer committed Sep 02, 2019 832 833 834 835 836 `````` ] * p_unit(unit, 'availability') // Taking into account availability... * [ // ... and capacity factor for flow units + sum(flowUnit(flow, unit), `````` Erkka Rinne committed Oct 24, 2019 837 `````` + ts_cf_(flow, node, s, f, t) `````` Ciara O'Dwyer committed Sep 02, 2019 838 839 840 `````` ) // END sum(flow) + 1\${not unit_flow(unit)} ] // How to consider reserveReliability in the case of investments when we typically only have "realized" time steps? `````` Niina Helistö committed Sep 06, 2019 841 `````` `````` Ciara O'Dwyer committed Sep 02, 2019 842 843 844 ``````; `````` Topi Rasku committed Oct 11, 2017 845 846 ``````* --- Unit Startup and Shutdown ----------------------------------------------- `````` Topi Rasku committed Apr 04, 2019 847 848 849 850 ``````q_startshut(ms(m, s), uft_online(unit, f, t)) \${ msft(m, s, f, t) }.. `````` Niina Helistö committed Aug 09, 2018 851 `````` // Units currently online `````` Erkka Rinne committed Nov 02, 2018 852 853 `````` + 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 854 855 `````` // Units previously online `````` Niina Helistö committed Aug 09, 2018 856 `````` // The same units `````` Erkka Rinne committed Nov 02, 2018 857 `````` - 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 858 `````` and not uft_aggregator_first(unit, f, t) } // This reaches to tFirstSolve when dt = -1 `````` Erkka Rinne committed Nov 02, 2018 859 `````` - 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 860 861 862 863 `````` 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 864 865 `````` + 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 866 `````` )\${uft_aggregator_first(unit, f, t)} // END sum(unit_) `````` Topi Rasku committed Nov 02, 2017 867 `````` `````` Juha Kiviluoma committed Apr 06, 2018 868 869 `````` =E= `````` Topi Rasku committed Oct 11, 2017 870 `````` // Unit startup and shutdown `````` Juha Kiviluoma committed Jul 31, 2018 871 `````` `````` Niina Helistö committed Aug 09, 2018 872 `````` // 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 873 `````` + sum(unitStarttype(unit, starttype), `````` Topi Rasku committed Apr 04, 2019 874 `````` + 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 875 `````` \${ uft_onlineLP_withPrevious(unit, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t)) } `````` Topi Rasku committed Apr 04, 2019 876 `````` + 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 877 `````` \${ uft_onlineMIP_withPrevious(unit, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t)) } `````` Niina Helistö committed Aug 09, 2018 878 `````` )\${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 879 `````` `````` Niina Helistö committed Aug 09, 2018 880 881 882 883 `````` // 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 884 `````` `````` Niina Helistö committed Aug 09, 2018 885 `````` // Shutdown of units at time t `````` Topi Rasku committed Apr 04, 2019 886 887 888 889 `````` - v_shutdown_LP(unit, s, f, t) \${ uft_onlineLP(unit, f, t) } - v_shutdown_MIP(unit, s, f, t) \${ uft_onlineMIP(unit, f, t) } `````` 890 ``````; `````` Topi Rasku committed Oct 11, 2017 891 `````` `````` 892 ``````*--- Startup Type ------------------------------------------------------------- `````` Topi Rasku committed Nov 06, 2017 893 ``````// !!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! `````` Topi Rasku committed Nov 06, 2017 894 895 896 ``````// 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. `````` 897 `````` `````` Topi Rasku committed Apr 04, 2019 898 899 900 901 ``````q_startuptype(ms(m, s), starttypeConstrained(starttype), uft_online(unit, f, t)) \${ msft(m, s, f, t) and unitStarttype(unit, starttype) } .. `````` 902 903 `````` // Startup type `````` Topi Rasku committed Apr 04, 2019 904 905 `````` + 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) } `````` 906 907 908 909 `````` =L= // Subunit shutdowns within special startup timeframe `````` Topi Rasku committed Apr 04, 2019 910 911 912 913 914 915 916 `````` + 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 917 918 919 `````` ) // END sum(counter) // NOTE: for aggregator units, shutdowns for aggregated units are not considered `````` 920 ``````; `````` 921 `````` `````` Juha Kiviluoma committed Apr 03, 2018 922 `````` `````` 923 924 ``````*--- Online Limits with Startup Type Constraints and Investments -------------- `````` Topi Rasku committed Apr 04, 2019 925 926 927 928 929 930 931 932 933 ``````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) }} .. `````` 934 `````` // Online variables `````` Erkka Rinne committed Nov 02, 2018 935 936 `````` + 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)} `````` 937 938 939 940 941 942 `````` =L= // Number of existing units + p_unit(unit, 'unitCount') `````` Niina Helistö committed May 25, 2018 943 `````` // Number of units unable to become online due to restrictions `````` Topi Rasku committed Apr 04, 2019 944 945 946 947 948 949 950 `````` - 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 951 952 953 `````` ) // 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 954 `````` - sum(unitAggregator_unit(unit, unit_), `````` Topi Rasku committed Apr 04, 2019 955 956 957 958 959 960 961 `````` + 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``````