Commit 3941510c authored by Niina Helistö's avatar Niina Helistö
Browse files

Adding two new parameters under param_policy: reserve_activation_duration and...

Adding two new parameters under param_policy: reserve_activation_duration and reserve_reactivation_time. The parameters are now included in q_stateUpwardLimit, q_stateDownwardLimit and q_boundStateMaxDiff. Default value for both parameters is 1 (hour) and reserve_reactivation_time should be greater than or equal to reserve_activation_duration.

Issue #129.
parent 2d1df7a1
......@@ -367,12 +367,14 @@ param_policy "Set of possible data parameters for groups or grid, node, regulati
staticInertia "A flag to indicate static inertia constraint should be implemented - q_inertiaMin"
dynamicInertia "A flag to indicate dynamic inertia constraint should be implemented - q_rateOfChangeOfFrequencyUnit/Transfer"
// Reserve related parameters, currently without a proper parameter set
update_frequency "Frequency of updating reserve contributions"
update_offset "Optional offset for delaying the reserve update frequency"
update_frequency "Frequency of updating reserve contributions (number of timesteps)"
update_offset "Optional offset for delaying the reserve update frequency (number of timesteps)"
gate_closure "Number of timesteps ahead of dispatch that reserves are fixed"
* use_time_series "Flag for using time series data. !!! REDUNDANT WITH useTimeseries, PENDING REMOVAL !!!"
useTimeSeries "Flag for using time series data"
reserve_length "Length of reserve horizon"
reserve_length "Length of reserve horizon (number of timesteps)"
reserve_activation_duration "How long the reserve should be provided once activated (h)"
reserve_reactivation_time "How soon the unit providing reserve needs to be able to reactivate after the start of the previous activation (h)"
reserveReliability "Reliability parameter of reserve provisions"
reserve_increase_ratio "Unit output is multiplied by this factor to get the increase in reserve demand"
portion_of_infeed_to_reserve "Proportion of the generation of a tripping unit that needs to be covered by reserves from other units"
......
......@@ -399,6 +399,23 @@ flowNode(flow, node)${ sum((f, t), ts_cf(flow, node, f, t))
// NOTE! Reserves can be disabled through the model settings file.
// The sets are disabled in "3a_periodicInit.gms" accordingly.
* --- Correct values for critical reserve related parameters - Part 1 ---------
// Reserve activation duration assumed to be 1 hour if not provided in data
p_groupReserves(group, restype, 'reserve_activation_duration')
${ not p_groupReserves(group, restype, 'reserve_activation_duration')
and p_groupReserves(group, restype, 'reserve_length')
}
= 1;
// Reserve reactivation time assumed to be 1 hour if not provided in data
p_groupReserves(group, restype, 'reserve_reactivation_time')
${ not p_groupReserves(group, restype, 'reserve_reactivation_time')
and p_groupReserves(group, restype, 'reserve_length')
}
= 1;
* --- Copy reserve data and create necessary sets -----------------------------
// Copy data from p_groupReserves to p_gnReserves
loop(gnGroup(grid, node, group)${sum(restype, p_groupReserves(group, restype, 'reserve_length'))},
p_gnReserves(grid, node, restype, param_policy) = p_groupReserves(group, restype, param_policy);
......@@ -454,7 +471,7 @@ restypeDirectionGridNodeGroup(restypeDirection(restype, up_down), gnGroup(grid,
}
= yes;
* --- Correct values for critical reserve related parameters ------------------
* --- Correct values for critical reserve related parameters - Part 2 ---------
// Reserve reliability assumed to be perfect if not provided in data
p_gnuReserves(gnu(grid, node, unit), restype, 'reserveReliability')
......@@ -586,14 +603,22 @@ loop( unitStarttype(unit, starttypeConstrained),
* --- Check reserve related data ----------------------------------------------
// Check that reserve_length is long enough for properly commitment of reserves
loop( restypeDirectionGridNode(restype, up_down, grid, node),
// Check that reserve_length is long enough for properly commitment of reserves
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 /;
loop( restypeDirectionGroup(restype, up_down, group),
// Check that reserve_length is long enough for proper commitment of reserves
if(p_groupReserves(group, restype, 'reserve_length') < p_groupReserves(group, restype, 'update_frequency') + p_groupReserves(group, restype, 'gate_closure'),
put log '!!! Error occurred on group ', group.tl:0 /;
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!"
); // END if
// Check that the duration of reserve activation is less than the reserve reactivation time
if(p_groupReserves(group, restype, 'reserve_reactivation_time') < p_groupReserves(group, restype, 'reserve_activation_duration'),
put log '!!! Error occurred on group ', group.tl:0 /;
put log '!!! Abort: The reserve_reactivation_time should be greater than or equal to the reserve_activation_duration!' /;
abort "The reserve_reactivation_time should be greater than or equal to the reserve_activation_duration!"
); // END if
); // END loop(restypeDirectionGroup)
loop( restypeDirectionGridNode(restype, up_down, grid, node),
// Check for each restype that a node does not belong to multiple groups
if(sum(restypeDirectionGridNodeGroup(restype, up_down, grid, node, group), 1) > 1,
put log '!!! Error occurred on node ', node.tl:0 /;
......@@ -606,7 +631,7 @@ loop( restypeDirectionGridNode(restype, up_down, grid, node),
put log '!!! Abort: A node with reserve provision/transfer capability has to belong to a reserve node group!' /;
abort "A node with reserve provision/transfer capability has to belong to a reserve node group!"
); // END if
); // END loop(restypeDirectionNode)
); // END loop(restypeDirectionGridNode)
// Check that reserve overlaps are possible
loop( (gnu(grid, node, unit), restypeDirection(restype, up_down)),
......
......@@ -2292,6 +2292,8 @@ q_stateUpwardLimit(gn_state(grid, node), msft(m, s, f, t))
// Downward reserves from units that output energy to the node
+ sum(gnuRescapable(restype, 'down', grid_, node_input, unit)${ ord(t) < tSolveFirst + p_gnReserves(grid_, node_input, restype, 'reserve_length') },
+ v_reserve(restype, 'down', grid_, node_input, unit, s, f+df_reserves(grid_, node_input, restype, f, t), t)
* p_gnReserves(grid_, node_input, restype, 'reserve_activation_duration')
/ p_gnReserves(grid_, node_input, restype, 'reserve_reactivation_time')
/ sum(suft(effGroup, unit, f, t),
+ p_effGroupUnit(effGroup, unit, 'slope')${not ts_effGroupUnit(effGroup, unit, 'slope', f, t)}
+ ts_effGroupUnit(effGroup, unit, 'slope', f, t) // Efficiency approximated using maximum slope of effGroup?
......@@ -2304,6 +2306,8 @@ q_stateUpwardLimit(gn_state(grid, node), msft(m, s, f, t))
// Downward reserves from units that use the node as energy input
+ sum(gnuRescapable(restype, 'down', grid_, node_output, unit)${ ord(t) < tSolveFirst + p_gnReserves(grid_, node_output, restype, 'reserve_length') },
+ v_reserve(restype, 'down', grid_, node_output, unit, s, f+df_reserves(grid_, node_output, restype, f, t), t)
* p_gnReserves(grid_, node_output, restype, 'reserve_activation_duration')
/ p_gnReserves(grid_, node_output, restype, 'reserve_reactivation_time')
* sum(suft(effGroup, unit, f, t),
+ p_effGroupUnit(effGroup, unit, 'slope')${not ts_effGroupUnit(effGroup, unit, 'slope', f, t)}
+ ts_effGroupUnit(effGroup, unit, 'slope', f, t) // Efficiency approximated using maximum slope of effGroup?
......@@ -2356,6 +2360,8 @@ q_stateDownwardLimit(gn_state(grid, node), msft(m, s, f, t))
// Upward reserves from units that output energy to the node
+ sum(gnuRescapable(restype, 'up', grid_, node_input, unit)${ ord(t) < tSolveFirst + p_gnReserves(grid_, node_input, restype, 'reserve_length') },
+ v_reserve(restype, 'up', grid_, node_input, unit, s, f+df_reserves(grid_, node_input, restype, f, t), t)
* p_gnReserves(grid_, node_input, restype, 'reserve_activation_duration')
/ p_gnReserves(grid_, node_input, restype, 'reserve_reactivation_time')
/ sum(suft(effGroup, unit, f, t),
+ p_effGroupUnit(effGroup, unit, 'slope')${not ts_effGroupUnit(effGroup, unit, 'slope', f, t)}
+ ts_effGroupUnit(effGroup, unit, 'slope', f, t) // Efficiency approximated using maximum slope of effGroup?
......@@ -2368,6 +2374,8 @@ q_stateDownwardLimit(gn_state(grid, node), msft(m, s, f, t))
// Upward reserves from units that use the node as energy input
+ sum(gnuRescapable(restype, 'up', grid_, node_output, unit)${ ord(t) < tSolveFirst + p_gnReserves(grid_, node_output, restype, 'reserve_length') },
+ v_reserve(restype, 'up', grid_, node_output, unit, s, f+df_reserves(grid_, node_output, restype, f, t), t)
* p_gnReserves(grid_, node_output, restype, 'reserve_activation_duration')
/ p_gnReserves(grid_, node_output, restype, 'reserve_reactivation_time')
* sum(suft(effGroup, unit, f, t),
+ p_effGroupUnit(effGroup, unit, 'slope')${not ts_effGroupUnit(effGroup, unit, 'slope', f, t)}
+ ts_effGroupUnit(effGroup, unit, 'slope', f, t) // Efficiency approximated using maximum slope of effGroup?
......@@ -2398,6 +2406,8 @@ q_boundStateMaxDiff(gnn_boundState(grid, node, node_), msft(m, s, f, t)) ..
and ord(t) < tSolveFirst + p_gnReserves(grid_, node, restype, 'reserve_length')
},
+ v_reserve(restype, 'down', grid_, node_input, unit, s, f+df_reserves(grid_, node_input, restype, f, t), t)
* p_gnReserves(grid_, node_input, restype, 'reserve_activation_duration')
/ p_gnReserves(grid_, node_input, restype, 'reserve_reactivation_time')
/ sum(suft(effGroup, unit, f, t),
+ p_effGroupUnit(effGroup, unit, 'slope')${not ts_effGroupUnit(effGroup, unit, 'slope', f, t)}
+ ts_effGroupUnit(effGroup, unit, 'slope', f, t) // Efficiency approximated using maximum slope of effGroup?
......@@ -2411,6 +2421,8 @@ q_boundStateMaxDiff(gnn_boundState(grid, node, node_), msft(m, s, f, t)) ..
and ord(t) < tSolveFirst + p_gnReserves(grid_, node, restype, 'reserve_length')
},
+ v_reserve(restype, 'down', grid_, node_output, unit, s, f+df_reserves(grid_, node_output, restype, f, t), t)
* p_gnReserves(grid_, node_output, restype, 'reserve_activation_duration')
/ p_gnReserves(grid_, node_output, restype, 'reserve_reactivation_time')
* sum(suft(effGroup, unit, f, t),
+ p_effGroupUnit(effGroup, unit, 'slope')${not ts_effGroupUnit(effGroup, unit, 'slope', f, t)}
+ ts_effGroupUnit(effGroup, unit, 'slope', f, t) // Efficiency approximated using maximum slope of effGroup?
......@@ -2443,6 +2455,8 @@ q_boundStateMaxDiff(gnn_boundState(grid, node, node_), msft(m, s, f, t)) ..
and ord(t) < tSolveFirst + p_gnReserves(grid_, node, restype, 'reserve_length')
},
+ v_reserve(restype, 'up', grid_, node_input, unit, s, f+df_reserves(grid_, node_input, restype, f, t), t)
* p_gnReserves(grid_, node_input, restype, 'reserve_activation_duration')
/ p_gnReserves(grid_, node_input, restype, 'reserve_reactivation_time')
/ sum(suft(effGroup, unit, f, t),
+ p_effGroupUnit(effGroup, unit, 'slope')${not ts_effGroupUnit(effGroup, unit, 'slope', f, t)}
+ ts_effGroupUnit(effGroup, unit, 'slope', f, t) // Efficiency approximated using maximum slope of effGroup?
......@@ -2456,6 +2470,8 @@ q_boundStateMaxDiff(gnn_boundState(grid, node, node_), msft(m, s, f, t)) ..
and ord(t) < tSolveFirst + p_gnReserves(grid_, node, restype, 'reserve_length')
},
+ v_reserve(restype, 'up', grid_, node_output, unit, s, f+df_reserves(grid_, node_output, restype, f, t), t)
* p_gnReserves(grid_, node_output, restype, 'reserve_activation_duration')
/ p_gnReserves(grid_, node_output, restype, 'reserve_reactivation_time')
* sum(suft(effGroup, unit, f, t),
+ p_effGroupUnit(effGroup, unit, 'slope')${not ts_effGroupUnit(effGroup, unit, 'slope', f, t)}
+ ts_effGroupUnit(effGroup, unit, 'slope', f, t) // Efficiency approximated using maximum slope of effGroup?
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment