Commit 4ec02a9b authored by Niina Helistö's avatar Niina Helistö
Browse files

Adding the grid dimension to the reserve parameters and variables. Changes...

Adding the grid dimension to the reserve parameters and variables. Changes required to the input files. Removing the obsolete nuft set. Issue #69.
parent 67f18153
...@@ -134,10 +134,11 @@ r_resTransferLeftward ...@@ -134,10 +134,11 @@ r_resTransferLeftward
// Interesting reserve results // Interesting reserve results
r_resDemandMarginal r_resDemandMarginal
r_nuTotalReserve r_gnuTotalReserve
r_nuTotalReserveShare r_gnuTotalReserveShare
r_nTotalReserve r_groupTotalReserve
r_resDemandLargestInfeedUnit r_resDemandLargestInfeedUnit
* --- Investment Result Symbols ----------------------------------------------- * --- Investment Result Symbols -----------------------------------------------
// Interesting investment results // Interesting investment results
...@@ -152,7 +153,7 @@ r_gnTotalqGen ...@@ -152,7 +153,7 @@ r_gnTotalqGen
r_gTotalqGen r_gTotalqGen
r_qResDemand r_qResDemand
r_qResMissing r_qResMissing
r_nTotalqResDemand r_groupTotalqResDemand
r_qCapacity r_qCapacity
r_solveStatus r_solveStatus
......
...@@ -78,11 +78,11 @@ Sets ...@@ -78,11 +78,11 @@ Sets
* --- Reserve types ----------------------------------------------------------- * --- Reserve types -----------------------------------------------------------
restype "Reserve types" restype "Reserve types"
restypeDirection(restype, up_down) "Different combinations of reserve types and directions" restypeDirection(restype, up_down) "Different combinations of reserve types and directions"
restypeDirectionNode(restype, up_down, node) "Nodes with reserve requirements" restypeDirectionGridNode(restype, up_down, grid, node) "Nodes with reserve requirements"
resTypeDirectionNodeNode(restype, up_down, node, node) "Node node connections that can transfer reserves" resTypeDirectionGridNodeNode(restype, up_down, grid, node, node) "Node node connections that can transfer reserves"
restypeDirectionGroup(restype, up_down, group) restypeDirectionGroup(restype, up_down, group)
restypeDirectionGridNodeGroup(restype, up_down, grid, node, group) restypeDirectionGridNodeGroup(restype, up_down, grid, node, group)
nuRescapable(restype, up_down, node, unit) "Units capable and available to provide particular reserves" gnuRescapable(restype, up_down, grid, node, unit) "Units capable and available to provide particular reserves"
restypeReleasedForRealization(restype) "Reserve types that are released for the realized time intervals" restypeReleasedForRealization(restype) "Reserve types that are released for the realized time intervals"
* --- Sets to define time, forecasts and samples ------------------------------ * --- Sets to define time, forecasts and samples ------------------------------
...@@ -143,7 +143,7 @@ $if defined scenario ...@@ -143,7 +143,7 @@ $if defined scenario
uft_startupTrajectory(unit, f, t) "Units with start-up trajectories on intervals" uft_startupTrajectory(unit, f, t) "Units with start-up trajectories on intervals"
uft_shutdownTrajectory(unit, f, t) "Units with shutdown trajectories on intervals" uft_shutdownTrajectory(unit, f, t) "Units with shutdown trajectories on intervals"
uft_aggregator_first(unit, f, t) "The first intervals when aggregator units are active" uft_aggregator_first(unit, f, t) "The first intervals when aggregator units are active"
nuft(node, unit, f, t) "Enables aggregation of nodes and units for later intervals" * nuft(node, unit, f, t) "Enables aggregation of nodes and units for later intervals"
gnuft(grid, node, unit, f, t) "Enables aggregation of nodes and units for later intervals" gnuft(grid, node, unit, f, t) "Enables aggregation of nodes and units for later intervals"
gnuft_ramp(grid, node, unit, f, t) "Units with ramp requirements or costs" gnuft_ramp(grid, node, unit, f, t) "Units with ramp requirements or costs"
gnuft_rampCost(grid, node, unit, slack, f, t) "Units with ramp costs" gnuft_rampCost(grid, node, unit, slack, f, t) "Units with ramp costs"
......
...@@ -51,13 +51,13 @@ Parameters ...@@ -51,13 +51,13 @@ Parameters
p_gnu(grid, node, unit, param_gnu) "Unit data where energy type matters" p_gnu(grid, node, unit, param_gnu) "Unit data where energy type matters"
p_gnuBoundaryProperties(grid, node, unit, slack, param_gnuBoundaryProperties) "Properties for unit boundaries where energy type matters" p_gnuBoundaryProperties(grid, node, unit, slack, param_gnuBoundaryProperties) "Properties for unit boundaries where energy type matters"
p_unit(unit, param_unit) "Unit data where energy type does not matter" p_unit(unit, param_unit) "Unit data where energy type does not matter"
p_nReserves(node, restype, *) "Data defining the reserve rules in each node" p_gnReserves(grid, node, restype, *) "Data defining the reserve rules in each node"
p_groupReserves(group, restype, *) "Data defining the reserve rules in each node group" p_groupReserves(group, restype, *) "Data defining the reserve rules in each node group"
p_groupReserves3D(group, restype, up_down, param_policy) "Reserve policy in each node group separately for each reserve type and direction" p_groupReserves3D(group, restype, up_down, param_policy) "Reserve policy in each node group separately for each reserve type and direction"
p_groupReserves4D(group, restype, up_down, group, param_policy) "Reserve policy in each node group separately for each reserve type and direction, also linking to another group" p_groupReserves4D(group, restype, up_down, group, param_policy) "Reserve policy in each node group separately for each reserve type and direction, also linking to another group"
p_nuReserves(node, unit, restype, *) "Reserve provision data for units" p_gnuReserves(grid, node, unit, restype, *) "Reserve provision data for units"
p_nnReserves(node, node, restype, up_down) "Reserve provision data for node node connections" p_gnnReserves(grid, node, node, restype, up_down) "Reserve provision data for node node connections"
p_nuRes2Res(node, unit, restype, up_down, restype) "The first type of reserve can be used also in the second reserve category (with a possible multiplier)" p_gnuRes2Res(grid, node, unit, restype, up_down, restype) "The first type of reserve can be used also in the second reserve category (with a possible multiplier)"
p_gnPolicy(grid, node, param_policy, *) "Policy data for grid, node" p_gnPolicy(grid, node, param_policy, *) "Policy data for grid, node"
p_groupPolicy(group, param_policy) "Two-dimensional policy data for groups" p_groupPolicy(group, param_policy) "Two-dimensional policy data for groups"
p_groupPolicy3D(group, param_policy, *) "Three-dimensional policy data for groups" p_groupPolicy3D(group, param_policy, *) "Three-dimensional policy data for groups"
...@@ -127,7 +127,7 @@ Parameters ...@@ -127,7 +127,7 @@ Parameters
// Forecast displacement arrays // Forecast displacement arrays
df(f, t) "Displacement needed to reach the realized forecast on the current time step" df(f, t) "Displacement needed to reach the realized forecast on the current time step"
df_central(f, t) "Displacement needed to reach the central forecast - this is needed when the forecast tree gets reduced in dynamic equations" df_central(f, t) "Displacement needed to reach the central forecast - this is needed when the forecast tree gets reduced in dynamic equations"
df_reserves(node, restype, f, t) "Forecast index displacement needed to reach the realized forecast when committing reserves" df_reserves(grid, node, restype, f, t) "Forecast index displacement needed to reach the realized forecast when committing reserves"
df_reservesGroup(group, restype, f, t) "Forecast index displacement needed to reach the realized forecast when committing reserves" df_reservesGroup(group, restype, f, t) "Forecast index displacement needed to reach the realized forecast when committing reserves"
df_scenario(f, t) "Forecast index displacement needed to get central forecast data for long-term scenarios" df_scenario(f, t) "Forecast index displacement needed to get central forecast data for long-term scenarios"
......
...@@ -130,17 +130,17 @@ Parameters ...@@ -130,17 +130,17 @@ Parameters
* --- Reserve Provision Results ----------------------------------------------- * --- Reserve Provision Results -----------------------------------------------
// Reserve provision results required for model structure // Reserve provision results required for model structure
r_reserve(restype, up_down, node, unit, f, t) "Unit capacity reserved for providing reserve of specific type (MW)" r_reserve(restype, up_down, grid, node, unit, f, t) "Unit capacity reserved for providing reserve of specific type (MW)"
r_resTransferRightward(restype, up_down, node, node, f, t) "Electricity transmission capacity from the first node to the second node reserved for providing reserves (MW)" r_resTransferRightward(restype, up_down, grid, node, node, f, t) "Electricity transmission capacity from the first node to the second node reserved for providing reserves (MW)"
r_resTransferLeftward(restype, up_down, node, node, f, t) "Electricity transmission capacity from the second node to the first node reserved for providing reserves (MW)" r_resTransferLeftward(restype, up_down, grid, node, node, f, t) "Electricity transmission capacity from the second node to the first node reserved for providing reserves (MW)"
r_reserve2Reserve(restype, up_down, node, unit, restype, f, t) "Reserve provided for another reserve category (MW) (also included in r_reserve - this is just for debugging)" r_reserve2Reserve(restype, up_down, grid, node, unit, restype, f, t) "Reserve provided for another reserve category (MW) (also included in r_reserve - this is just for debugging)"
// Interesting reserve results // Interesting reserve results
r_resDemandMarginal(restype, up_down, group, f, t) "Marginal values of the q_resDemand equation" r_resDemandMarginal(restype, up_down, group, f, t) "Marginal values of the q_resDemand equation"
r_nuTotalReserve(restype, up_down, node, unit) "Total nu reserve provision over the simulation (MW*h)" r_gnuTotalReserve(restype, up_down, grid, node, unit) "Total gnu reserve provision over the simulation (MW*h)"
r_nuTotalReserveShare(restype, up_down, node, unit) "Total nu/n reserve provision share over the simulation" r_gnuTotalReserveShare(restype, up_down, grid, node, unit) "Total gnu/group reserve provision share over the simulation"
r_nTotalReserve(restype, up_down, node) "Total reserve provisions in nodes over the simulation (MW*h)" r_groupTotalReserve(restype, up_down, group) "Total reserve provisions in groups over the simulation (MW*h)"
r_resDemandLargestInfeedUnit(grid, f, t, restype, up_down, node) "Reserve Demand from the loss of largest infeed unit" r_resDemandLargestInfeedUnit(restype, up_down, group, f, t) "Reserve Demand from the loss of largest infeed unit"
* --- Investment Results ------------------------------------------------------ * --- Investment Results ------------------------------------------------------
...@@ -156,7 +156,7 @@ Parameters ...@@ -156,7 +156,7 @@ Parameters
r_gTotalqGen(inc_dec, grid) "Total dummy energy generation/consumption in g over the simulation (MWh)." r_gTotalqGen(inc_dec, grid) "Total dummy energy generation/consumption in g over the simulation (MWh)."
r_qResDemand(restype, up_down, group, f, t) "Dummy to decrease demand for a reserve (MW) before reserve commitment" r_qResDemand(restype, up_down, group, f, t) "Dummy to decrease demand for a reserve (MW) before reserve commitment"
r_qResMissing(restype, up_down, group, f, t) "Dummy to decrease demand for a reserve (MW) after reserve commitment" r_qResMissing(restype, up_down, group, f, t) "Dummy to decrease demand for a reserve (MW) after reserve commitment"
r_nTotalqResDemand(restype, up_down, group) "Total dummy reserve provisions in n over the simulation" r_groupTotalqResDemand(restype, up_down, group) "Total dummy reserve provisions in the group over the simulation"
r_qCapacity(grid, node, f, t) "Dummy capacity to ensure capacity margin equation feasibility (MW)" r_qCapacity(grid, node, f, t) "Dummy capacity to ensure capacity margin equation feasibility (MW)"
r_solveStatus(t, solve_info) "Information about the solve" r_solveStatus(t, solve_info) "Information about the solve"
......
...@@ -45,9 +45,9 @@ $ifthen exist '%input_dir%/inputData.gdx' ...@@ -45,9 +45,9 @@ $ifthen exist '%input_dir%/inputData.gdx'
$$loaddc p_groupReserves $$loaddc p_groupReserves
$$loaddc p_groupReserves3D $$loaddc p_groupReserves3D
$$loaddc p_groupReserves4D $$loaddc p_groupReserves4D
$$loaddc p_nuReserves $$loaddc p_gnuReserves
$$loaddc p_nnReserves $$loaddc p_gnnReserves
$$loaddc p_nuRes2Res $$loaddc p_gnuRes2Res
$$loaddc ts_reserveDemand $$loaddc ts_reserveDemand
$$loaddc p_gnBoundaryPropertiesForStates $$loaddc p_gnBoundaryPropertiesForStates
$$loaddc p_gnPolicy $$loaddc p_gnPolicy
...@@ -94,7 +94,7 @@ gngnu_constrainedOutputRatio ...@@ -94,7 +94,7 @@ gngnu_constrainedOutputRatio
restype restype
restypeReleasedForRealization restypeReleasedForRealization
p_gnn p_gnn
p_nnReserves p_gnnReserves
p_gnuBoundaryProperties p_gnuBoundaryProperties
ts_node ts_node
ts_reserveDemand ts_reserveDemand
...@@ -402,31 +402,31 @@ flowNode(flow, node)${ sum((f, t), ts_cf(flow, node, f, t)) ...@@ -402,31 +402,31 @@ flowNode(flow, node)${ sum((f, t), ts_cf(flow, node, f, t))
// NOTE! Reserves can be disabled through the model settings file. // NOTE! Reserves can be disabled through the model settings file.
// The sets are disabled in "3a_periodicInit.gms" accordingly. // The sets are disabled in "3a_periodicInit.gms" accordingly.
// Copy data from p_groupReserves to p_nReserves // Copy data from p_groupReserves to p_gnReserves
loop(gnGroup(grid, node, group)${sum(restype, p_groupReserves(group, restype, 'reserve_length'))}, loop(gnGroup(grid, node, group)${sum(restype, p_groupReserves(group, restype, 'reserve_length'))},
p_nReserves(node, restype, param_policy) = p_groupReserves(group, restype, param_policy); p_gnReserves(grid, node, restype, param_policy) = p_groupReserves(group, restype, param_policy);
p_nReserves(node, restype, up_down) = p_groupReserves(group, restype, up_down); p_gnReserves(grid, node, restype, up_down) = p_groupReserves(group, restype, up_down);
); );
// Units with reserve provision capabilities // Units with reserve provision capabilities
nuRescapable(restypeDirection(restype, up_down), nu(node, unit)) gnuRescapable(restypeDirection(restype, up_down), gnu(grid, node, unit))
$ { p_nuReserves(node, unit, restype, up_down) $ { p_gnuReserves(grid, node, unit, restype, up_down)
} }
= yes; = yes;
// Node-node connections with reserve transfer capabilities // Node-node connections with reserve transfer capabilities
restypeDirectionNodeNode(restypeDirection(restype, up_down), node, node_) restypeDirectionGridNodeNode(restypeDirection(restype, up_down), gn2n(grid, node, node_))
$ { p_nnReserves(node, node_, restype, up_down) $ { p_gnnReserves(grid, node, node_, restype, up_down)
} }
= yes; = yes;
// Nodes with reserve requirements, units capable of providing reserves, or reserve capable connections // Nodes with reserve requirements, units capable of providing reserves, or reserve capable connections
restypeDirectionNode(restypeDirection(restype, up_down), node) restypeDirectionGridNode(restypeDirection(restype, up_down), gn(grid, node))
$ { p_nReserves(node, restype, up_down) $ { p_gnReserves(grid, node, restype, up_down)
or p_nReserves(node, restype, 'use_time_series') or p_gnReserves(grid, node, restype, 'use_time_series')
or sum(nu(node, unit), p_nuReserves(node, unit, restype, 'portion_of_infeed_to_reserve')) or sum(gnu(grid, node, unit), p_gnuReserves(grid, node, unit, restype, 'portion_of_infeed_to_reserve'))
or sum(nu(node, unit), nuRescapable(restype, up_down, node, unit)) or sum(gnu(grid, node, unit), gnuRescapable(restype, up_down, grid, node, unit))
or sum(gn2n(grid, node, to_node), restypeDirectionNodeNode(restype, up_down, node, to_node)) or sum(gn2n(grid, node, to_node), restypeDirectionGridNodeNode(restype, up_down, grid, node, to_node))
} }
= yes; = yes;
...@@ -443,19 +443,19 @@ restypeDirectionGridNodeGroup(restypeDirection(restype, up_down), gnGroup(grid, ...@@ -443,19 +443,19 @@ restypeDirectionGridNodeGroup(restypeDirection(restype, up_down), gnGroup(grid,
* --- Correct values for critical reserve related parameters ------------------ * --- Correct values for critical reserve related parameters ------------------
// Reserve reliability assumed to be perfect if not provided in data // Reserve reliability assumed to be perfect if not provided in data
p_nuReserves(nu(node, unit), restype, 'reserveReliability') p_gnuReserves(gnu(grid, node, unit), restype, 'reserveReliability')
${ not p_nuReserves(node, unit, restype, 'reserveReliability') ${ not p_gnuReserves(grid, node, unit, restype, 'reserveReliability')
and sum(up_down, nuRescapable(restype, up_down, node, unit)) and sum(up_down, gnuRescapable(restype, up_down, grid, node, unit))
} }
= 1; = 1;
// Reserve provision overlap decreases the capacity of the overlapping category // Reserve provision overlap decreases the capacity of the overlapping category
p_nuReserves(nu(node, unit), restype, up_down) p_gnuReserves(gnu(grid, node, unit), restype, up_down)
${ nuRescapable(restype, up_down, node, unit) } ${ gnuRescapable(restype, up_down, grid, node, unit) }
= p_nuReserves(node, unit, restype, up_down) = p_gnuReserves(grid, node, unit, restype, up_down)
- sum(restype_${ p_nuRes2Res(node, unit, restype_, up_down, restype) }, - sum(restype_${ p_gnuRes2Res(grid, node, unit, restype_, up_down, restype) },
+ p_nuReserves(node, unit, restype_, up_down) + p_gnuReserves(grid, node, unit, restype_, up_down)
* p_nuRes2Res(node, unit, restype_, up_down, restype) * p_gnuRes2Res(grid, node, unit, restype_, up_down, restype)
); // END sum(restype_) ); // END sum(restype_)
* ============================================================================= * =============================================================================
...@@ -563,9 +563,9 @@ loop( unitStarttype(unit, starttypeConstrained), ...@@ -563,9 +563,9 @@ loop( unitStarttype(unit, starttypeConstrained),
* --- Check reserve related data ---------------------------------------------- * --- Check reserve related data ----------------------------------------------
// Check that reserve_length is long enough for properly commitment of reserves // Check that reserve_length is long enough for properly commitment of reserves
loop( restypeDirectionNode(restype, up_down, node), loop( restypeDirectionGridNode(restype, up_down, grid, node),
// Check that reserve_length is long enough for properly commitment of reserves // Check that reserve_length is long enough for properly commitment of reserves
if(p_nReserves(node, restype, 'reserve_length') < p_nReserves(node, restype, 'update_frequency') + p_nReserves(node, restype, 'gate_closure'), if(p_gnReserves(grid, node, restype, 'reserve_length') < p_gnReserves(grid, node, restype, 'update_frequency') + p_gnReserves(grid, node, restype, 'gate_closure'),
put log '!!! Error occurred on node ', node.tl:0 /; put log '!!! Error occurred on node ', node.tl:0 /;
put log '!!! Abort: The reserve_length parameter should be longer than update_frequency + gate_closure to fix the reserves properly!' /; put log '!!! Abort: The reserve_length parameter should be longer than update_frequency + gate_closure to fix the reserves properly!' /;
abort "The 'reserve_length' parameter should be longer than 'update_frequency' + 'gate_closure' to fix the reserves properly!" abort "The 'reserve_length' parameter should be longer than 'update_frequency' + 'gate_closure' to fix the reserves properly!"
...@@ -585,13 +585,13 @@ loop( restypeDirectionNode(restype, up_down, node), ...@@ -585,13 +585,13 @@ loop( restypeDirectionNode(restype, up_down, node),
); // END loop(restypeDirectionNode) ); // END loop(restypeDirectionNode)
// Check that reserve overlaps are possible // Check that reserve overlaps are possible
loop( (nu(node, unit), restypeDirection(restype, up_down)), loop( (gnu(grid, node, unit), restypeDirection(restype, up_down)),
if( p_nuReserves(node, unit, restype, up_down) < 0, if( p_gnuReserves(grid, node, unit, restype, up_down) < 0,
put log '!!! Error occurred on unit ', unit.tl:0 /; put log '!!! Error occurred on unit ', unit.tl:0 /;
put log '!!! Abort: Overlapping reserve capacities in p_nuRes2Res can result in excess reserve production!' /; put log '!!! Abort: Overlapping reserve capacities in p_gnuRes2Res can result in excess reserve production!' /;
abort "Overlapping reserve capacities in p_nuRes2Res can result in excess reserve production!" abort "Overlapping reserve capacities in p_gnuRes2Res can result in excess reserve production!"
); // END if(p_nuReserves) ); // END if(p_gnuReserves)
); // END loop((nu,restypeDirection)) ); // END loop((gnu,restypeDirection))
* ============================================================================= * =============================================================================
......
...@@ -43,9 +43,9 @@ Positive variables ...@@ -43,9 +43,9 @@ Positive variables
v_spill(grid, node, s, f, t) "Spill of energy from storage node during an interval (MWh)" v_spill(grid, node, s, f, t) "Spill of energy from storage node during an interval (MWh)"
v_transferRightward(grid, node, node, s, f, t) "Average electricity transmission level from the first node to the second node during an interval (MW)" v_transferRightward(grid, node, node, s, f, t) "Average electricity transmission level from the first node to the second node during an interval (MW)"
v_transferLeftward(grid, node, node, s, f, t) "Average electricity transmission level from the second node to the first node during an interval (MW)" v_transferLeftward(grid, node, node, s, f, t) "Average electricity transmission level from the second node to the first node during an interval (MW)"
v_resTransferRightward(restype, up_down, node, node, s, f, t) "Electricity transmission capacity from the first node to the second node reserved for providing reserves (MW)" v_resTransferRightward(restype, up_down, grid, node, node, s, f, t) "Electricity transmission capacity from the first node to the second node reserved for providing reserves (MW)"
v_resTransferLeftward(restype, up_down, node, node, s, f, t) "Electricity transmission capacity from the second node to the first node reserved for providing reserves (MW)" v_resTransferLeftward(restype, up_down, grid, node, node, s, f, t) "Electricity transmission capacity from the second node to the first node reserved for providing reserves (MW)"
v_reserve(restype, up_down, node, unit, s, f, t) "Unit capacity reserved for providing reserve of specific type (MW)" v_reserve(restype, up_down, grid, node, unit, s, f, t) "Unit capacity reserved for providing reserve of specific type (MW)"
v_investTransfer_LP(grid, node, node, t) "Invested transfer capacity (MW)" v_investTransfer_LP(grid, node, node, t) "Invested transfer capacity (MW)"
v_online_LP(unit, s, f, t) "Number of sub-units online for 'units' with unit commitment restrictions (LP variant)" v_online_LP(unit, s, f, t) "Number of sub-units online for 'units' with unit commitment restrictions (LP variant)"
v_invest_LP(unit, t) "Number of invested 'sub-units' (LP variant)" v_invest_LP(unit, t) "Number of invested 'sub-units' (LP variant)"
......
...@@ -63,7 +63,7 @@ equations ...@@ -63,7 +63,7 @@ equations
// Unit Operation // Unit Operation
q_maxDownward(grid, node, unit, mType, s, f, t) "Downward commitments will not undercut power plant minimum load constraints or maximum elec. consumption" q_maxDownward(grid, node, unit, mType, s, f, t) "Downward commitments will not undercut power plant minimum load constraints or maximum elec. consumption"
q_maxUpward(grid, node, unit, mType, s, f, t) "Upward commitments will not exceed maximum available capacity or consumed power" q_maxUpward(grid, node, unit, mType, s, f, t) "Upward commitments will not exceed maximum available capacity or consumed power"
q_reserveProvision(restype, up_down, node, unit, s, f, t) "Reserve provision limited for units" q_reserveProvision(restype, up_down, grid, node, unit, s, f, t) "Reserve provision limited for units"
q_startshut(mType, s, unit, f, t) "Online capacity now minus online capacity in the previous interval is equal to started up minus shut down capacity" q_startshut(mType, s, unit, f, t) "Online capacity now minus online capacity in the previous interval is equal to started up minus shut down capacity"
q_startuptype(mType, s, starttype, unit, f, t) "Startup type depends on the time the unit has been non-operational" q_startuptype(mType, s, starttype, unit, f, t) "Startup type depends on the time the unit has been non-operational"
q_onlineOnStartUp(s, unit, f, t) "Unit must be online after starting up" q_onlineOnStartUp(s, unit, f, t) "Unit must be online after starting up"
...@@ -95,8 +95,8 @@ equations ...@@ -95,8 +95,8 @@ equations
q_transferLeftwardLimit(grid, node, node, s, f, t) "Transfer of energy and capacity reservations to the leftward direction are less than the transfer capacity" q_transferLeftwardLimit(grid, node, node, s, f, t) "Transfer of energy and capacity reservations to the leftward direction are less than the transfer capacity"
q_resTransferLimitRightward(grid, node, node, s, f, t) "Transfer of energy and capacity reservations are less than the transfer capacity to the rightward direction" q_resTransferLimitRightward(grid, node, node, s, f, t) "Transfer of energy and capacity reservations are less than the transfer capacity to the rightward direction"
q_resTransferLimitLeftward(grid, node, node, s, f, t) "Transfer of energy and capacity reservations are less than the transfer capacity to the leftward direction" q_resTransferLimitLeftward(grid, node, node, s, f, t) "Transfer of energy and capacity reservations are less than the transfer capacity to the leftward direction"
q_reserveProvisionRightward(restype, up_down, node, node, s, f, t) "Rightward reserve provision limited" q_reserveProvisionRightward(restype, up_down, grid, node, node, s, f, t) "Rightward reserve provision limited"
q_reserveProvisionLeftward(restype, up_down, node, node, s, f, t) "Leftward reserve provision limited" q_reserveProvisionLeftward(restype, up_down, grid, node, node, s, f, t) "Leftward reserve provision limited"
// State Variables // State Variables
q_stateSlack(grid, node, slack, s, f, t) "Slack variable greater than the difference between v_state and the slack boundary" q_stateSlack(grid, node, slack, s, f, t) "Slack variable greater than the difference between v_state and the slack boundary"
......
This diff is collapsed.
...@@ -580,19 +580,19 @@ loop(unit, ...@@ -580,19 +580,19 @@ loop(unit,
loop(m, loop(m,
// Disable node reserve requirements // Disable node reserve requirements
restypeDirectionNode(restype, up_down, node) restypeDirectionGridNode(restype, up_down, grid, node)
${ not mSettingsReservesInUse(m, restype, up_down) ${ not mSettingsReservesInUse(m, restype, up_down)
} }
= no; = no;
// Disable node-node reserve connections // Disable node-node reserve connections
restypeDirectionNodeNode(restype, up_down, node, node_) restypeDirectionGridNodeNode(restype, up_down, grid, node, node_)
${ not mSettingsReservesInUse(m, restype, up_down) ${ not mSettingsReservesInUse(m, restype, up_down)
} }
= no; = no;
// Disable reserve provision capability from units // Disable reserve provision capability from units
nuRescapable(restype, up_down, node, unit) gnuRescapable(restype, up_down, grid, node, unit)
${ not mSettingsReservesInUse(m, restype, up_down) ${ not mSettingsReservesInUse(m, restype, up_down)
} }
= no; = no;
...@@ -621,7 +621,9 @@ p_slackDirection(downwardSlack) = -1; ...@@ -621,7 +621,9 @@ p_slackDirection(downwardSlack) = -1;
* --- Using default value for reserves update frequency ----------------------- * --- Using default value for reserves update frequency -----------------------
loop(m, loop(m,
p_nReserves(node, restype, 'update_frequency')${ not p_nReserves(node, restype, 'update_frequency') } p_groupReserves(group, restype, 'update_frequency')${ not p_groupReserves(group, restype, 'update_frequency') }
= mSettings(m, 't_jump');
p_gnReserves(grid, node, restype, 'update_frequency')${ not p_gnReserves(grid, node, restype, 'update_frequency') }
= mSettings(m, 't_jump'); = mSettings(m, 't_jump');
); );
...@@ -654,28 +656,28 @@ loop(m, // Not ideal, but multi-model functionality is not yet implemented ...@@ -654,28 +656,28 @@ loop(m, // Not ideal, but multi-model functionality is not yet implemented
* --- Reserve structure checks ------------------------------------------------ * --- Reserve structure checks ------------------------------------------------
loop(restypeDirectionNode(restype, up_down, node), loop(restypeDirectionGroup(restype, up_down, group),
// Check that 'update_frequency' is longer than 't_jump' // Check that 'update_frequency' is longer than 't_jump'
if(p_nReserves(node, restype, 'update_frequency') < mSettings(m, 't_jump'), if(p_groupReserves(group, restype, 'update_frequency') < mSettings(m, 't_jump'),
put log '!!! Error occurred on p_nReserves ' node.tl:0 ',' restype.tl:0 /; put log '!!! Error occurred on p_groupReserves ' group.tl:0 ',' restype.tl:0 /;
put log '!!! Abort: The update_frequency parameter should be longer than or equal to t_jump!' /; put log '!!! Abort: The update_frequency parameter should be longer than or equal to t_jump!' /;
abort "The 'update_frequency' parameter should be longer than or equal to 't_jump'!"; abort "The 'update_frequency' parameter should be longer than or equal to 't_jump'!";
); // END if('update_frequency' < 't_jump') ); // END if('update_frequency' < 't_jump')
// Check that 'update_frequency' is divisible by 't_jump' // Check that 'update_frequency' is divisible by 't_jump'
if(mod(p_nReserves(node, restype, 'update_frequency'), mSettings(m, 't_jump')) <> 0, if(mod(p_groupReserves(group, restype, 'update_frequency'), mSettings(m, 't_jump')) <> 0,
put log '!!! Error occurred on p_nReserves ' node.tl:0 ',' restype.tl:0 /; put log '!!! Error occurred on p_groupReserves ' group.tl:0 ',' restype.tl:0 /;
put log '!!! Abort: The update_frequency parameter should be divisible by t_jump!' /; put log '!!! Abort: The update_frequency parameter should be divisible by t_jump!' /;
abort "The 'update_frequency' parameter should be divisible by 't_jump'!"; abort "The 'update_frequency' parameter should be divisible by 't_jump'!";
); // END if(mod('update_frequency')) ); // END if(mod('update_frequency'))
// Check if the first interval is long enough for proper commitment of reserves // Check if the first interval is long enough for proper commitment of reserves
if(mInterval(m, 'lastStepInIntervalBlock', 'c000') < p_nReserves(node, restype, 'update_frequency') + p_nReserves(node, restype, 'gate_closure'), if(mInterval(m, 'lastStepInIntervalBlock', 'c000') < p_groupReserves(group, restype, 'update_frequency') + p_groupReserves(group, restype, 'gate_closure'),
put log '!!! Error occurred on p_nReserves ' node.tl:0 ',' restype.tl:0 /; put log '!!! Error occurred on p_groupReserves ' group.tl:0 ',' restype.tl:0 /;
put log '!!! Abort: The first interval block should not be shorter than update_frequency + gate_closure for proper commitment of reserves!' /; put log '!!! Abort: The first interval block should not be shorter than update_frequency + gate_closure for proper commitment of reserves!' /;
abort "The first interval block should not be shorter than 'update_frequency' + 'gate_closure' for proper commitment of reserves!"; abort "The first interval block should not be shorter than 'update_frequency' + 'gate_closure' for proper commitment of reserves!";
); // END if ); // END if
); // END loop(restypeDirectionNode) ); // END loop(restypeDirectionGroup)
* --- Check that there aren't more effLevels defined than exist in data ------- * --- Check that there aren't more effLevels defined than exist in data -------
......
...@@ -472,10 +472,15 @@ df_central(ft(f,t))${ ord(t) > tSolveFirst + currentForecastLength - p_stepLen ...@@ -472,10 +472,15 @@ df_central(ft(f,t))${ ord(t) > tSolveFirst + currentForecastLength - p_stepLen
// Forecast index displacement between realized and forecasted intervals, required for locking reserves ahead of (dispatch) time. // Forecast index displacement between realized and forecasted intervals, required for locking reserves ahead of (dispatch) time.
Option clear = df_reserves; Option clear = df_reserves;
df_reserves(node, restype, ft(f, t)) df_reserves(grid, node, restype, ft(f, t))
${ p_nReserves(node, restype, 'update_frequency') ${ p_gnReserves(grid, node, restype, 'update_frequency')
and p_nReserves(node, restype, 'gate_closure') and p_gnReserves(grid, node, restype, 'gate_closure')
and ord(t) <= tSolveFirst + p_nReserves(node, restype, 'gate_closure') + p_nReserves(node, restype, 'update_frequency') - mod(tSolveFirst - 1 + p_nReserves(node, restype, 'gate_closure') + p_nReserves(node, restype, 'update_frequency') - p_nReserves(node, restype, 'update_offset'), p_nReserves(node, restype, 'update_frequency')) and ord(t) <= tSolveFirst + p_gnReserves(grid, node, restype, 'gate_closure')
+ p_gnReserves(grid, node, restype, 'update_frequency')
- mod(tSolveFirst - 1 + p_gnReserves(grid, node, restype, 'gate_closure')
+ p_gnReserves(grid, node, restype, 'update_frequency')
- p_gnReserves(grid, node, restype, 'update_offset'),
p_gnReserves(grid, node, restype, 'update_frequency'))
} }
= sum(f_${ mf_realization(mSolve, f_) }, ord(f_) - ord(f)) + Eps; // The Eps ensures that checks to see if df_reserves exists return positive even if the displacement is zero. = sum(f_${ mf_realization(mSolve, f_) }, ord(f_) - ord(f)) + Eps; // The Eps ensures that checks to see if df_reserves exists return positive even if the displacement is zero.
Option clear = df_reservesGroup; Option clear = df_reservesGroup;
...@@ -554,14 +559,9 @@ loop(unit${unit_aggregator(unit)}, ...@@ -554,14 +559,9 @@ loop(unit${unit_aggregator(unit)},
uft_aggregator_first(uft(unit, f, t))${ord(t) = tmp} = yes; uft_aggregator_first(uft(unit, f, t))${ord(t) = tmp} = yes;
); );
// Active units in nodes on each ft
Option clear = nuft;
nuft(nu(node, unit), ft(f, t))${ uft(unit, f, t) }
= yes
;
// Active (grid, node, unit) on each ft // Active (grid, node, unit) on each ft
Option clear = gnuft; Option clear = gnuft;
gnuft(gn(grid, node), uft(unit, f, t))${ nuft(node, unit, f, t) } gnuft(gn(grid, node), uft(unit, f, t))${ gnu(grid, node, unit) }
= yes = yes
; ;
// Active (grid, node, unit, slack, up_down) on each ft step with ramp restrictions // Active (grid, node, unit, slack, up_down) on each ft step with ramp restrictions
......
...@@ -316,91 +316,90 @@ v_transferLeftward.up(gn2n_directional(grid, node, node_), sft(s, f, t))${ not ...@@ -316,91 +316,90 @@ v_transferLeftward.up(gn2n_directional(grid, node, node_), sft(s, f, t))${ not
* --- Reserve Provision Boundaries -------------------------------------------- * --- Reserve Provision Boundaries --------------------------------------------
// Loop over the forecasts to minimize confusion regarding the df_reserves forecast displacement // Loop over the forecasts to minimize confusion regarding the df_reserves forecast displacement
// NOTE! The loop over gn is not ideal, but the reserve variables are currently lacking the grid dimension. loop((restypeDirectionGridNode(restype, up_down, grid, node), sft(s, f, t))${ ord(t) <= tSolveFirst + p_gnReserves(grid, node, restype, 'reserve_length') },
loop((restypeDirectionNode(restype, up_down, node), gn(grid, node), sft(s, f, t))${ ord(t) <= tSolveFirst + p_nReserves(node, restype, 'reserve_length') },
// Reserve provision limits without investments // Reserve provision limits without investments
// Reserve provision limits based on resXX_range (or possibly available generation in case of unit_flow) // Reserve provision limits based on resXX_range (or possibly available generation in case of unit_flow)
v_reserve.up(nuRescapable(restype, up_down, node, unit), s, f+df_reserves(node, restype, f, t), t) v_reserve.up(gnuRescapable(restype, up_down, grid, node, unit), s, f+df_reserves(grid, node, restype, f, t), t)
${ nuft(node, unit, f, t) // nuft is not displaced by df_reserves, as the unit exists on normal ft. ${ gnuft(grid, node, unit, f, t) // gnuft is not displaced by df_reserves, as the unit exists on normal ft.
and not (unit_investLP(unit) or unit_investMIP(unit)) and not (unit_investLP(unit) or unit_investMIP(unit))
and not sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node, group), and not sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node, group),
ft_reservesFixed(group, restype, f+df_reserves(node, restype, f, t), t) ft_reservesFixed(group, restype, f+df_reserves(grid, node, restype, f, t), t)
) )
} }
= min ( p_nuReserves(node, unit, restype, up_down) * [ p_gnu(grid, node, unit, 'maxGen') + p_gnu(grid, node, unit, 'maxCons') ], // Generator + consuming unit res_range limit = min ( p_gnuReserves(grid, node, unit, restype, up_down) * [ p_gnu(grid, node, unit, 'maxGen') + p_gnu(grid, node, unit, 'maxCons') ], // Generator + consuming unit res_range limit
v_gen.up(grid, node, unit, s, f, t) - v_gen.lo(grid, node, unit, s, f, t) // Generator + consuming unit available unit_elec. output delta v_gen.up(grid, node, unit, s, f, t) - v_gen.lo(grid, node, unit, s, f, t) // Generator + consuming unit available unit_elec. output delta
) // END min ) // END min
; ;
// Reserve transfer upper bounds based on input p_nnReserves data, if investments are disabled // Reserve transfer upper bounds based on input p_nnReserves data, if investments are disabled
v_resTransferRightward.up(restypeDirectionNodeNode(restype, up_down, node, node_), s, f+df_reserves(node, restype, f, t), t) v_resTransferRightward.up(restypeDirectionGridNodeNode(restype, up_down, grid, node, node_), s, f+df_reserves(grid, node, restype, f, t), t)
${ not p_gnn(grid, node, node_, 'transferCapInvLimit') ${ not p_gnn(grid, node, node_, 'transferCapInvLimit')
and gn2n_directional(grid, node, node_) and gn2n_directional(grid, node, node_)
and not [ sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node, group), and not [ sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node, group),
ft_reservesFixed(group, restype, f+df_reserves(node, restype, f, t), t) ft_reservesFixed(group, restype, f+df_reserves(grid, node, restype, f, t), t)
) // This set contains the combination of reserve types and time intervals that should be fixed ) // This set contains the combination of reserve types and time intervals that should be fixed
or sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node_, group), or sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node_, group),
ft_reservesFixed(group, restype, f+df_reserves(node_, restype, f, t), t) ft_reservesFixed(group, restype, f+df_reserves(grid, node_, restype, f, t), t)
) // Commit reserve transfer as long as either end commits. ) // Commit reserve transfer as long as either end commits.
] ]
} }
= p_gnn(grid, node, node_, 'transferCap') = p_gnn(grid, node, node_, 'transferCap')
* p_nnReserves(node, node_, restype, up_down); * p_gnnReserves(grid, node, node_, restype, up_down);
v_resTransferLeftward.up(restypeDirectionNodeNode(restype, up_down, node, node_), s, f+df_reserves(node, restype, f, t), t) v_resTransferLeftward.up(restypeDirectionGridNodeNode(restype, up_down, grid, node, node_), s, f+df_reserves(grid, node, restype, f, t), t)
${ not p_gnn(grid, node, node_, 'transferCapInvLimit') ${ not p_gnn(grid, node, node_, 'transferCapInvLimit')
and gn2n_directional(grid, node, node_) and gn2n_directional(grid, node, node_)
and not [ sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node, group), and not [ sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node, group),
ft_reservesFixed(group, restype, f+df_reserves(node, restype, f, t), t) ft_reservesFixed(group, restype, f+df_reserves(grid, node, restype, f, t), t)
) // This set contains the combination of reserve types and time intervals that should be fixed ) // This set contains the combination of reserve types and time intervals that should be fixed
or sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node_, group), or sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node_, group),
ft_reservesFixed(group, restype, f+df_reserves(node_, restype, f, t), t) ft_reservesFixed(group, restype, f+df_reserves(grid, node_, restype, f, t), t)
) // Commit reserve transfer as long as either end commits. ) // Commit reserve transfer as long as either end commits.
] ]
} }
= p_gnn(grid, node, node_, 'transferCap') = p_gnn(grid, node, node_, 'transferCap')
* p_nnReserves(node, node_, restype, up_down); * p_gnnReserves(grid, node, node_, restype, up_down);
// Fix non-flow unit reserves at the gate closure of reserves // Fix non-flow unit reserves at the gate closure of reserves
v_reserve.fx(nuRescapable(restype, up_down, node, unit), s, f+df_reserves(node, restype, f, t), t) v_reserve.fx(gnuRescapable(restype, up_down, grid, node, unit), s, f+df_reserves(grid, node, restype, f, t), t)
$ { sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node, group), $ { sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node, group),
ft_reservesFixed(group, restype, f+df_reserves(node, restype, f, t), t) ft_reservesFixed(group, restype, f+df_reserves(grid, node, restype, f, t), t)
) // This set contains the combination of reserve types and time intervals that should be fixed based on previous solves ) // This set contains the combination of reserve types and time intervals that should be fixed based on previous solves
and not unit_flow(unit) // NOTE! Units using flows can change their reserve (they might not have as much available in real time as they had bid) and not unit_flow(unit) // NOTE! Units using flows can change their reserve (they might not have as much available in real time as they had bid)
} }
= r_reserve(restype, up_down, node, unit, f+df_reserves(node, restype, f, t), t); = r_reserve(restype, up_down, grid, node, unit, f+df_reserves(grid, node, restype, f, t), t);
// Fix transfer of reserves at the gate closure of reserves, LOWER BOUND ONLY! // Fix transfer of reserves at the gate closure of reserves, LOWER BOUND ONLY!
v_resTransferRightward.fx(restype, up_down, node, node_, s, f+df_reserves(node, restype, f, t), t) v_resTransferRightward.fx(restype, up_down, grid, node, node_, s, f+df_reserves(grid, node, restype, f, t), t)
$ { gn2n_directional(grid, node, node_) $ { gn2n_directional(grid, node, node_)
and [ sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node, group), and [ sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node, group),
ft_reservesFixed(group, restype, f+df_reserves(node, restype, f, t), t) ft_reservesFixed(group, restype, f+df_reserves(grid, node, restype, f, t), t)
) // This set contains the combination of reserve types and time intervals that should be fixed ) // This set contains the combination of reserve types and time intervals that should be fixed
or sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node_, group), or sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node_, group),
ft_reservesFixed(group, restype, f+df_reserves(node_, restype, f, t), t) ft_reservesFixed(group, restype, f+df_reserves(grid, node_, restype, f, t), t)