Commit cbcbc4ad authored by Erkka Rinne's avatar Erkka Rinne
Browse files

Merge branch 'release/1.0.5'

parents 2096c357 29ef67bb
......@@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
## [1.0.5] - 2019-02-14
### Fixed
- Probabilities were not updated after using scenario reduction
### Added
- Enable long-term samples that extend several years by using planning horizon
which is longer than one scenario (e.g. 3 years). Note: Cannot use all data for
samples as last years need to be reserved for the planning horizon.
## [1.0.4] - 2019-02-11
### Fixed
......@@ -46,7 +55,8 @@ All notable changes to this project will be documented in this file.
[Unreleased]: https://gitlab.vtt.fi/backbone/backbone/compare/v1.0.4...dev
[Unreleased]: https://gitlab.vtt.fi/backbone/backbone/compare/v1.0.5...dev
[1.0.5]: https://gitlab.vtt.fi/backbone/backbone/compare/v1.0.4...v1.0.5
[1.0.4]: https://gitlab.vtt.fi/backbone/backbone/compare/v1.0.3...v1.0.4
[1.0.3]: https://gitlab.vtt.fi/backbone/backbone/compare/v1.0.2...v1.0.3
[1.0.2]: https://gitlab.vtt.fi/backbone/backbone/compare/v1.0...v1.0.2
......@@ -23,7 +23,7 @@ Model schedule /
q_obj
q_balance
q_resDemand
q_resDemandLargestInfeedUnit
* q_resDemandLargestInfeedUnit
// Unit Operation
q_maxDownward
......
......@@ -17,7 +17,9 @@ $offtext
* sets
ft
sft
ft_realized
sft_realized
t_active
t_current
t_full
......
......@@ -137,7 +137,7 @@ r_resDemandMarginal
r_nuTotalReserve
r_nuTotalReserveShare
r_nTotalReserve
r_resDemandLargestInfeedUnit
* --- Investment Result Symbols -----------------------------------------------
// Interesting investment results
......
......@@ -187,6 +187,7 @@ $if exist 'params.inc' $include 'params.inc'
// Features
Set active(mType, feature) "Set membership tells active model features";
option clear = active;
* =============================================================================
* --- Parameter Set Definitions -----------------------------------------------
......
......@@ -89,6 +89,7 @@ Sets
t_active(t) "Set of active t:s within the current solve horizon, including necessary history"
t_invest(t) "Time steps when investments can be made"
tt(t) "Temporary subset for time steps used for calculations"
tt_(t) "Another temporary subset for time steps used for calculations"
tt_block(counter, t) "Temporary time step subset for storing the time interval blocks"
tt_interval(t) "Temporary time steps when forming the ft structure, current sample"
tt_forecast(t) "Temporary subset for time steps used for forecast updating during solve loop"
......
......@@ -139,6 +139,7 @@ Parameters
r_nuTotalReserve(restype, up_down, node, unit) "Total nu reserve provision over the simulation (MW*h)"
r_nuTotalReserveShare(restype, up_down, node, unit) "Total nu/n reserve provision share over the simulation"
r_nTotalReserve(restype, up_down, node) "Total reserve provisions in nodes over the simulation (MW*h)"
r_resDemandLargestInfeedUnit(grid, f, t, restype, up_down, node) "Reserve Demand from the loss of largest infeed unit"
* --- Investment Results ------------------------------------------------------
......@@ -176,7 +177,7 @@ Option clear = r_shutdown;
Option clear = r_invest;
Option clear = r_investTransfer;
Option clear = r_qResDemand;
Option clear = r_resDemandLargestInfeedUnit;
* =============================================================================
* --- Diagnostics Results Arrays ----------------------------------------------
* =============================================================================
......
......@@ -137,10 +137,10 @@ q_resDemand(restypeDirectionNode(restype, up_down, node), sft(s, f, t))
) // END sum(nuft)
// Reserve provisions to another nodes via transfer links
+ sum(gn2n_directional(grid, node, node_)${restypeDirectionNodeNode(restype, up_down, node_, node)}, // If trasferring reserves to another node, increase your own reserves by same amount
+ sum(gn2n_directional(grid, node, node_)${restypeDirectionNodeNode(restype, up_down, node, node_)}, // If trasferring reserves to another node, increase your own reserves by same amount
+ v_resTransferRightward(restype, up_down, node, node_, s, f+df_reserves(node, restype, f, t), t)
) // END sum(gn2n_directional)
+ sum(gn2n_directional(grid, node_, node)${restypeDirectionNodeNode(restype, up_down, node_, node)}, // If trasferring reserves to another node, increase your own reserves by same amount
+ sum(gn2n_directional(grid, node_, node)${restypeDirectionNodeNode(restype, up_down, node, node_)}, // If trasferring reserves to another node, increase your own reserves by same amount
+ v_resTransferLeftward(restype, up_down, node_, node, s, f+df_reserves(node, restype, f, t), t)
) // END sum(gn2n_directional)
......@@ -155,6 +155,7 @@ q_resDemand(restypeDirectionNode(restype, up_down, node), sft(s, f, t))
q_resDemandLargestInfeedUnit(grid, restypeDirectionNode(restype, 'up', node), unit_fail(unit_), sft(s, f, t))
${ ord(t) < tSolveFirst + p_nReserves(node, restype, 'reserve_length')
and gn(grid, node)
and not [ restypeReleasedForRealization(restype)
and ft_realized(f, t)
]
......
......@@ -650,5 +650,17 @@ loop(m, // Not ideal, but multi-model functionality is not yet implemented
put log '!!! Warning: Trajectories used on aggregated time steps! This could result in significant distortion of the trajectories.';
); // END if()
* --- Check that the first interval block is compatible with t_jump' ----------
if (mod(mSettings(m, 't_jump'), mInterval(m, 'stepsPerInterval', 'c000')) <> 0,
put log '!!! Abort: t_jump should be divisible by the first interval!' /;
abort "'t_jump' should be divisible by the first interval!";
); // END if()
if (mInterval(m, 'lastStepInIntervalBlock', 'c000') < mSettings(m, 't_jump'),
put log '!!! Abort: The first interval block should not be shorter than t_jump!' /;
abort "The first interval block should not be shorter than 't_jump'!";
); // END if()
); // END loop(m)
......@@ -551,15 +551,6 @@ loop(uft_online(unit, f, t)${ p_u_shutdownTimeIntervals(unit) },
= yes;
); // END loop(uf_online)
* -----------------------------------------------------------------------------
* --- Probabilities -----------------------------------------------------------
* -----------------------------------------------------------------------------
// Update probabilities
Option clear = p_msft_probability;
p_msft_probability(msft(mSolve, s, f, t))
= p_mfProbability(mSolve, f) / sum(f_${ft(f_, t)}, p_mfProbability(mSolve, f_)) * p_msProbability(mSolve, s);
* -----------------------------------------------------------------------------
* --- Displacements for start-up and shutdown decisions -----------------------
* -----------------------------------------------------------------------------
......
......@@ -294,6 +294,9 @@ loop(cc(counter),
// Retrieve interval block time steps
option clear = tt_interval;
tt_interval(t) = tt_block(counter, t);
// Make a temporary clone of tt_interval(t)
option clear = tt_;
tt_(tt_interval) = yes;
// If stepsPerInterval equals one, simply use all the steps within the block
if(mInterval(mSolve, 'stepsPerInterval', counter) = 1,
......@@ -311,9 +314,11 @@ $ontext
= ts_effGroupUnit(effSelector, unit, param_eff, f_solve, t+dt_circular(t));
$offtext
ts_cf_(flowNode(flow, node), f_solve, t, s)$msf(mSolve, s, f_solve)
= ts_cf(flow, node, f_solve, t + (dt_sampleOffset(flow, node, 'ts_cf', s) + dt_circular(t)));
= ts_cf(flow, node, f_solve, t + (dt_sampleOffset(flow, node, 'ts_cf', s)
+ dt_circular(t)$(not longtermSamples(flow, node, 'ts_cf'))));
ts_influx_(gn(grid, node), f_solve, t, s)$msf(mSolve, s, f_solve)
= ts_influx(grid, node, f_solve, t + (dt_sampleOffset(grid, node, 'ts_influx', s) + dt_circular(t)));
= ts_influx(grid, node, f_solve, t + (dt_sampleOffset(grid, node, 'ts_influx', s)
+ dt_circular(t)$(not longtermSamples(grid, node, 'ts_influx'))));
// Reserve demand relevant only up until reserve_length
ts_reserveDemand_(restypeDirectionNode(restype, up_down, node), f_solve, t)
${ord(t) <= tSolveFirst + p_nReserves(node, restype, 'reserve_length')}
......@@ -321,7 +326,8 @@ $offtext
ts_node_(gn_state(grid, node), param_gnBoundaryTypes, f_solve, t, s)
${p_gnBoundaryPropertiesForStates(grid, node, param_gnBoundaryTypes, 'useTimeseries')
and msf(mSolve, s, f_solve)}
= ts_node(grid, node, param_gnBoundaryTypes, f_solve, t + (dt_sampleOffset(grid, node, param_gnBoundaryTypes, s) + dt_circular(t)));
= ts_node(grid, node, param_gnBoundaryTypes, f_solve, t + (dt_sampleOffset(grid, node, param_gnBoundaryTypes, s)
+ dt_circular(t)$(not longtermSamples(grid, node, 'ts_node'))));
// Fuel price time series
ts_fuelPrice_(fuel, t)
= ts_fuelPrice(fuel, t+dt_circular(t));
......@@ -336,10 +342,9 @@ $offtext
loop(ft(f_solve, tt_interval(t)),
// Select t:s within the interval
Option clear = tt;
tt(t_)
${tt_interval(t_)
and ord(t_) >= ord(t)
and ord(t_) < ord(t) + mInterval(mSolve, 'stepsPerInterval', counter)
tt(tt_(t_))
${ ord(t_) >= ord(t)
and ord(t_) < ord(t) + mInterval(mSolve, 'stepsPerInterval', counter)
}
= yes;
ts_unit_(unit_timeseries(unit), param_unit, f_solve, t)
......@@ -355,10 +360,12 @@ $ontext
/ mInterval(mSolve, 'stepsPerInterval', counter);
$offtext
ts_influx_(gn(grid, node), f_solve, t, s)$msf(mSolve, s, f_solve)
= sum(tt(t_), ts_influx(grid, node, f_solve, t_ + (dt_sampleOffset(grid, node, 'ts_influx', s) + dt_circular(t_))))
= sum(tt(t_), ts_influx(grid, node, f_solve, t_ + (dt_sampleOffset(grid, node, 'ts_influx', s)
+ dt_circular(t_)$(not longtermSamples(grid, node, 'ts_influx')))))
/ mInterval(mSolve, 'stepsPerInterval', counter);
ts_cf_(flowNode(flow, node), f_solve, t, s)$msf(mSolve, s, f_solve)
= sum(tt(t_), ts_cf(flow, node, f_solve, t_ + (dt_sampleOffset(flow, node, 'ts_cf', s) + dt_circular(t_))))
= sum(tt(t_), ts_cf(flow, node, f_solve, t_ + (dt_sampleOffset(flow, node, 'ts_cf', s)
+ dt_circular(t_)$(not longtermSamples(flow, node, 'ts_cf')))))
/ mInterval(mSolve, 'stepsPerInterval', counter);
// Reserves relevant only until reserve_length
ts_reserveDemand_(restypeDirectionNode(restype, up_down, node), f_solve, t)
......@@ -369,13 +376,16 @@ $offtext
${p_gnBoundaryPropertiesForStates(grid, node, param_gnBoundaryTypes, 'useTimeseries')
and msf(mSolve, s, f_solve)}
// Take average if not a limit type
= (sum(tt(t_), ts_node(grid, node, param_gnBoundaryTypes, f_solve, t_ + (dt_sampleOffset(grid, node, param_gnBoundaryTypes, s) + dt_circular(t_))))
= (sum(tt(t_), ts_node(grid, node, param_gnBoundaryTypes, f_solve, t_ + (dt_sampleOffset(grid, node, param_gnBoundaryTypes, s)
+ dt_circular(t_)$(not longtermSamples(grid, node, 'ts_node')))))
/ mInterval(mSolve, 'stepsPerInterval', counter))$(not (sameas(param_gnBoundaryTypes, 'upwardLimit') or sameas(param_gnBoundaryTypes, 'downwardLimit')))
// Maximum lower limit
+ smax(tt(t_), ts_node(grid, node, param_gnBoundaryTypes, f_solve, t_ + (dt_sampleOffset(grid, node, param_gnBoundaryTypes, s) + dt_circular(t_))))
+ smax(tt(t_), ts_node(grid, node, param_gnBoundaryTypes, f_solve, t_ + (dt_sampleOffset(grid, node, param_gnBoundaryTypes, s)
+ dt_circular(t_)$(not longtermSamples(grid, node, 'ts_node')))))
$sameas(param_gnBoundaryTypes, 'downwardLimit')
// Minimum upper limit
+ smin(tt(t_), ts_node(grid, node, param_gnBoundaryTypes, f_solve, t_ + (dt_sampleOffset(grid, node, param_gnBoundaryTypes, s) + dt_circular(t_))))
+ smin(tt(t_), ts_node(grid, node, param_gnBoundaryTypes, f_solve, t_ + (dt_sampleOffset(grid, node, param_gnBoundaryTypes, s)
+ dt_circular(t_)$(not longtermSamples(grid, node, 'ts_node')))))
$sameas(param_gnBoundaryTypes, 'upwardLimit');
// Fuel price time series
ts_fuelPrice_(fuel, t)
......@@ -421,6 +431,14 @@ if(active(mSolve, 'scenred'),
$$include 'inc/scenred.gms'
);
* --- Update probabilities ----------------------------------------------------
Option clear = p_msft_probability;
p_msft_probability(msft(mSolve, s, f, t))
= p_mfProbability(mSolve, f)
/ sum(f_${ft(f_, t)},
p_mfProbability(mSolve, f_)) * p_msProbability(mSolve, s);
* --- Smooting of stochastic scenarios ----------------------------------------
$ontext
First calculate standard deviation for over all samples, then smoothen the scenarios
......
......@@ -441,12 +441,12 @@ loop((mft_start(mSolve, f, t), ms_initial(mSolve, s)),
else // For all other solves, fix the initial state values based on previous results.
// State and online variable initial values for the subsequent solves
v_state.fx(gn_state(grid, node), s, f, t)
= r_state(grid, node, f, t);
v_state.fx(gn_state(grid, node), s, f, t + (1 - mInterval(mSolve, 'stepsPerInterval', 'c000')))
= r_state(grid, node, f, t + (1 - mInterval(mSolve, 'stepsPerInterval', 'c000')));
// Generation initial value (needed at least for ramp constraints)
v_gen.fx(gnu(grid, node, unit), s, f, t)
= r_gen(grid, node, unit, f, t);
v_gen.fx(gnu(grid, node, unit), s, f, t + (1 - mInterval(mSolve, 'stepsPerInterval', 'c000')))
= r_gen(grid, node, unit, f, t + (1 - mInterval(mSolve, 'stepsPerInterval', 'c000')));
); // END if(tSolveFirst)
) // END loop(mft_start)
......
......@@ -60,8 +60,7 @@ loop(sft_realized(s, f, t),
// Loop over reserve horizon, as the reserve variables use a different ft-structure due to commitment
loop((restypeDirectionNode(restype, up_down, node), sft(s, f, t))
${ df_reserves(node, restype, f, t)
and ord(t) <= tSolveFirst + p_nReserves(node, restype, 'reserve_length')
${ ord(t) <= tSolveFirst + p_nReserves(node, restype, 'reserve_length')
and ord(t) > mSettings(mSolve, 't_start') + mSettings(mSolve, 't_initializationPeriod')
},
......@@ -77,16 +76,22 @@ loop((restypeDirectionNode(restype, up_down, node), sft(s, f, t))
* p_nuRes2Res(node, unit, restype_, up_down, restype)
);
// Reserve transfer capacity
// Reserve requirement due to N-1 reserve constraint
r_resDemandLargestInfeedUnit(grid, f+df_reserves(node, restype, f, t), t, restype, up_down, node)
= smax(unit_fail(unit_), v_gen.l(grid, node, unit_, s, f, t) * p_nuReserves(node, unit_, restype, 'portion_of_infeed_to_reserve'));
// Reserve transfer capacity for links defined out from this node
r_resTransferRightward(restype, up_down, node, to_node, f+df_reserves(node, restype, f, t), t)
${ restypeDirectionNode(restype, up_down, to_node)
${ sum(grid, gn2n_directional(grid, node, to_node))
and restypeDirectionNodeNode(restype, up_down, node, to_node)
}
= v_resTransferRightward.l(restype, up_down, node, to_node, s, f+df_reserves(node, restype, f, t), t);
r_resTransferLeftward(restype, up_down, node, to_node, f+df_reserves(node, restype, f, t), t)
${ restypeDirectionNode(restype, up_down, to_node)
r_resTransferLeftward(restype, up_down, node, to_node, f+df_reserves(to_node, restype, f, t), t)
${ sum(grid, gn2n_directional(grid, node, to_node))
and restypeDirectionNodeNode(restype, up_down, to_node, node)
}
= v_resTransferLeftward.l(restype, up_down, node, to_node, s, f+df_reserves(node, restype, f, t), t);
= v_resTransferLeftward.l(restype, up_down, node, to_node, s, f+df_reserves(to_node, restype, f, t), t);
// Dummy reserve demand changes
r_qResDemand(restype, up_down, node, f+df_reserves(node, restype, f, t), t)
......@@ -158,6 +163,12 @@ r_qGen(inc_dec, gn(grid, node), f, t)
}
= vq_gen.l(inc_dec, grid, node, s, f, t)
;
// Dummy capacity
r_qCapacity(gn(grid, node), f, t)
${ ord(t) > mSettings(mSolve, 't_start') + mSettings(mSolve, 't_initializationPeriod')
}
= vq_capacity.l(grid, node, s, f, t)
;
);
* =============================================================================
......
......@@ -9,7 +9,7 @@
"defModels/*.gms",
"defOutput/*.inc"],
"cmdline_args": "",
"datafiles": ["input/InputData.gdx"],
"datafiles": ["input/inputData.gdx"],
"datafiles_opt": ["input/*.gms",
"input/*.gdx",
"input/*.inc",
......
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