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

Merge branch 'release/1.0.6'

parents cbcbc4ad 9e02be36
......@@ -3,6 +3,24 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
## [1.0.6] - 2019-03-27
### Fixed
- Major bug in state variable reserve equations
- Scenario smoothing alogirithm
### Changed
- Speedup for timeseries calculations
### Added
- New model setting `mSettings(mType, 'onlyExistingForecasts') = 0|1` to control
the reading of forecasts. Set to 1 to only read forecast data that exists in
the file. Note that zeros need to be saved as Eps when using this.
- Proper stochastic programming for the long-term scenarios period. Possible also
to create a stochastic tree from the original data.
- Clickable link to *sr.log* in the process window in case of SCENRED2 error
- New diagnostic parameter for timeseries scenarios `d_ts_scenarios`
## [1.0.5] - 2019-02-14
### Fixed
- Probabilities were not updated after using scenario reduction
......@@ -55,7 +73,8 @@ All notable changes to this project will be documented in this file.
[Unreleased]: https://gitlab.vtt.fi/backbone/backbone/compare/v1.0.5...dev
[Unreleased]: https://gitlab.vtt.fi/backbone/backbone/compare/v1.0.6...dev
[1.0.6]: https://gitlab.vtt.fi/backbone/backbone/compare/v1.0.5...v1.0.6
[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
......
......@@ -45,6 +45,11 @@ Model building /
* q_conversionSOS2InputIntermediate
* q_conversionSOS2Constraint
* q_conversionSOS2IntermediateOutput
* q_conversionIncHR
* q_conversionIncHRMaxGen
* q_conversionIncHRBounds
* q_conversionIncHR_help1
* q_conversionIncHR_help2
* q_fuelUseLimit
// Energy Transfer
......
......@@ -117,6 +117,13 @@ if (mType('building'),
// Define the length of the initialization period. Results outputting starts after the period. Uses ord(t) > t_start + t_initializationPeriod in the code.
mSettings('building', 't_initializationPeriod') = 0; // r_state and r_online are stored also for the last step in the initialization period, i.e. ord(t) = t_start + t_initializationPeriod
* --- Define the use of additional constraints for units with incremental heat rates
// How to use q_conversionIncHR_help1 and q_conversionIncHR_help2
mSettings('building', 'incHRAdditionalConstraints') = 0;
// 0 = use the constraints but only for units with non-convex fuel use
// 1 = use the constraints for all units represented using incremental heat rates
* --- Control the solver ------------------------------------------------------
// Control the use of advanced basis
......
......@@ -47,6 +47,11 @@ Model invest /
q_conversionSOS2InputIntermediate
q_conversionSOS2Constraint
q_conversionSOS2IntermediateOutput
q_conversionIncHR
q_conversionIncHRMaxGen
q_conversionIncHRBounds
q_conversionIncHR_help1
q_conversionIncHR_help2
q_fuelUseLimit
// Energy Transfer
......
......@@ -41,11 +41,9 @@ if (mType('invest'),
// Number of samples used by the model
mSettings('invest', 'samples') = 3;
// Define Initial and Central samples
// Clear Initial and Central samples
ms_initial('invest', s) = no;
ms_initial('invest', 's000') = yes;
ms_central('invest', s) = no;
ms_central('invest', 's000') = yes;
// Define time span of samples
msStart('invest', 's000') = 1;
......@@ -123,6 +121,13 @@ if (mType('invest'),
// Define the length of the initialization period. Results outputting starts after the period. Uses ord(t) > t_start + t_initializationPeriod in the code.
mSettings('invest', 't_initializationPeriod') = 0; // r_state and r_online are stored also for the last step in the initialization period, i.e. ord(t) = t_start + t_initializationPeriod
* --- Define the use of additional constraints for units with incremental heat rates
// How to use q_conversionIncHR_help1 and q_conversionIncHR_help2
mSettings('invest', 'incHRAdditionalConstraints') = 0;
// 0 = use the constraints but only for units with non-convex fuel use
// 1 = use the constraints for all units represented using incremental heat rates
* --- Control the solver ------------------------------------------------------
// Control the use of advanced basis
......
......@@ -47,6 +47,11 @@ Model schedule /
q_conversionSOS2InputIntermediate
q_conversionSOS2Constraint
q_conversionSOS2IntermediateOutput
q_conversionIncHR
q_conversionIncHRMaxGen
q_conversionIncHRBounds
q_conversionIncHR_help1
q_conversionIncHR_help2
q_fuelUseLimit
// Energy Transfer
......
......@@ -50,28 +50,27 @@ if (mType('schedule'),
// Define Initial and Central samples
ms_initial('schedule', s) = no;
ms_initial('schedule', 's000') = yes;
ms_central('schedule', s) = no;
ms_central('schedule', 's000') = yes;
// Define time span of samples
msStart('schedule', 's000') = 1;
msEnd('schedule', 's000') = msStart('schedule', 's000') + mSettings('schedule', 't_horizon');
// If using long-term samples, uncomment
//msEnd('schedule', 's000') = msStart('schedule', 's000')
// + mSettings('schedule', 't_forecastLengthUnchanging');
//loop(s $(ord(s) > 1),
// msStart('schedule', s) = msStart('schedule', 's000')
// + mSettings('schedule', 't_forecastLengthUnchanging');
// msEnd('schedule', s) = msStart('schedule', 's000')
// + mSettings('schedule', 't_horizon');
//);
// Define the probability (weight) of samples
p_msProbability('schedule', s) = 0;
p_msProbability('schedule', 's000') = 1;
// If using long-term samples, uncomment
//ms_central('schedule', 's001') = yes;
//
//msEnd('schedule', 's000') = msStart('schedule', 's000') + 168;
//msStart('schedule', 's001') = msEnd('schedule', 's000');
//msEnd('schedule', 's001') = msStart('schedule', 's000')
// + mSettings('schedule', 't_horizon');
//
//p_msProbability('schedule', 's001') = 1;
//);
// Define which nodes use long-term samples
loop(gn(grid, node)$sameas(grid, 'hydro'),
//longtermSamples('hydro', node, 'ts_influx') = yes;
......@@ -172,6 +171,13 @@ if (mType('schedule'),
// Define the length of the initialization period. Results outputting starts after the period. Uses ord(t) > t_start + t_initializationPeriod in the code.
mSettings('schedule', 't_initializationPeriod') = 0; // r_state and r_online are stored also for the last step in the initialization period, i.e. ord(t) = t_start + t_initializationPeriod
* --- Define the use of additional constraints for units with incremental heat rates
// How to use q_conversionIncHR_help1 and q_conversionIncHR_help2
mSettings('schedule', 'incHRAdditionalConstraints') = 0;
// 0 = use the constraints but only for units with non-convex fuel use
// 1 = use the constraints for all units represented using incremental heat rates
* --- Control the solver ------------------------------------------------------
// Control the use of advanced basis
......
......@@ -70,6 +70,7 @@ p_uCounter_shutdownMax
* Variables
v_obj
v_gen
v_gen_inc
v_genRamp
v_transfer
v_state
......@@ -90,6 +91,7 @@ v_investTransfer_LP
v_investTransfer_MIP
v_invest_LP
v_invest_MIP
v_help_inc
* equations
q_obj
......@@ -117,6 +119,11 @@ v_invest_MIP
q_conversionSOS2InputIntermediate
q_conversionSOS2Constraint
q_conversionSOS2IntermediateOutput
q_conversionIncHR
q_conversionIncHRMaxGen
q_conversionIncHRBounds
q_conversionIncHR_help1
q_conversionIncHR_help2
q_fuelUseLimit
// Energy Transfer
......
......@@ -163,6 +163,7 @@ d_eff
d_capacityFactor
d_nodeState
d_influx
d_state
$endif.diag
// Metadata and settings
......
......@@ -50,7 +50,9 @@ Sets
t_forecastStart, // Time step for first reading the forecasts (not necessarily t_start)
t_forecastJump, // Number of time steps between each update of the forecasts
t_improveForecast "Number of time steps ahead of time on which the forecast is improved on each solve"
sampleLength "Length of sample in time steps for creating stocahstic scenarios from time series data"
onlyExistingForecasts "Use only existing forecast values when reading updated forecasts. Note: zero values need to be saved as Eps in the gdx file."
scenarios "Number of long-term scenarios used"
scenarioLength "Length of scenario in time steps for creating stocahstic scenarios from time series data"
// Features
t_trajectoryHorizon, // Length of the horizon when start-up and shutdown trajectories are considered (in time steps)
......@@ -58,6 +60,8 @@ Sets
dataLength, // The maximum number of time steps in any input data time series (recommended for correctly circulating data)
red_num_leaves "Desired number of preserved scenarios or leaves (SCENRED)"
red_percentage "Desired relative distance (accuracy) of scenario reduction (SCENRED)"
incHRAdditionalConstraints // Method to include the two additional constraints for incremental heat rates;
// 0 = include for units with non-convex fuel use, 1 = include for all units
/
// Solve info
......@@ -98,7 +102,7 @@ Sets
effLevel "Pre-defined levels for efficiency representation that can start from t_solve + x"
/ level1*level9 /
effSelector "Select equations and lambdas/slope for efficiency calculations"
/ lambda01*lambda12, directOff, directOnLP, directOnMIP / // NOTE! Lambdas required first!
/ lambda01*lambda12, directOff, directOnLP, directOnMIP , incHR/ // NOTE! Lambdas required first!
effDirect(effSelector) "Using direct input to output equation"
/ directOff, directOnLP, directOnMIP /
effDirectOff(effSelector) "Using direct input to output equation without online variable, i.e. constant efficiency"
......@@ -107,8 +111,10 @@ Sets
/ directOnLP, directOnMIP /
effLambda(effSelector) "Lambdas in use for part-load efficiency representation"
/ lambda01*lambda12 /
effIncHR(effSelector) "Using incremental heat rate equation"
/ incHR /
effOnline(effSelector) "Efficiency selectors that use online variables"
/ directOnLP, directOnMIP, lambda01*lambda12 / // IMPORTANT! Online variables are generated based on this, so keep it up to date!
/ directOnLP, directOnMIP, lambda01*lambda12 ,incHR / // IMPORTANT! Online variables are generated based on this, so keep it up to date!
* --- General and Directional Sets --------------------------------------------
......@@ -147,8 +153,8 @@ Sets
* extraRes "Use extra tertiary reserves for error in elec. load during time step" // NOT IMPLEMENTED
* rampSched "Use power based scheduling" // PARTIALLY IMPLEMENTED
scenRed "Reduce number of long-tem scenarios using GAMS SCENRED2"
/
checkUnavailability "Take into account ts_unit unavailability data"
/
* --- Set to declare time series that will be read between solves ------------------------------------------------------
timeseries "Names of time series that could be loop read from files between solves" /
ts_unit
......@@ -275,6 +281,7 @@ param_unit "Set of possible data parameters for units" /
availability "Availability of given energy conversion technology (p.u.)"
useInitialOnlineStatus "A flag to fix the online status of a unit for the first time step (binary)"
initialOnlineStatus "Initial online status of the unit in the first time step (0-1)"
unavailability "Unavailability of given energy conversion technology (p.u.)"
omCosts "Variable operation and maintenance costs (EUR/MWh)"
startCostCold "Variable start-up costs for cold starts excluding fuel costs (EUR/MW)"
startCostWarm "Variable start-up costs for warm starts excluding fuel costs (EUR/MW)"
......@@ -284,6 +291,7 @@ param_unit "Set of possible data parameters for units" /
startFuelConsHot "Consumption of start-up fuel per hot subunit started up (MWh_fuel/MW)"
startColdAfterXhours "Offline hours after which the start-up will be a cold start (h)"
startWarmAfterXhours "Offline hours after which the start-up will be a warm start (h)"
shutdownCost "Cost of shutting down the unit"
rampSpeedToMinLoad "Ramping speed from start-up to minimum load (p.u./min)"
rampSpeedFromMinLoad "Ramping speed from shutdown decision to zero load (p.u./min)"
minOperationHours "Minimum operation time (h), prevents shutdown after startup until the defined amount of time has passed"
......@@ -295,7 +303,10 @@ param_unit "Set of possible data parameters for units" /
eff00 * eff12 "Efficiency of the unit to convert input to output/intermediate product"
opFirstCross "The operating point where the real efficiency curve and approximated efficiency curve cross"
op00 * op12 "Right border of the efficiency point"
hr00 * hr12 "Incremental heat rates (GJ/MWh)"
hrop00 * hrop12 "Right border of the incremental heat rates"
section "Possibility to define a no load fuel use for units with zero minimum output"
hrsection "no load fuel use to be defined when using incremental heat rates"
level1 * level9 "Level of simplification in the part-load efficiency representation"
useTimeseries "A flag to use time series form input for unit parameters whenever possible"
investMIP "A flag to make integer investment instead of continous investment"
......@@ -316,6 +327,12 @@ param_fuel "Parameters for fuels" /
startup "Startup fuel of the unit, if exists. Can be the same as main fuel - consumption using startupFuelCons"
/
param_fuelPrice "Paramters for fuel prices" /
fuelPrice "Fuel price (EUR/MWh)"
useConstant "Flag to use constant data for fuels"
useTimeSeries "Flag to use time series form data for fuels"
/
param_unitFuel "Parameters for fuel limits in units" /
maxFuelCons "Maximum absolute fuel consumption in a unit - not used for start-up fuels"
maxFuelFraction "Maximum share of a fuel in the consumption mix" //only for main fuels
......@@ -353,15 +370,18 @@ eff(param_unit) "Effiency for the corresponding operating point ('op') in the ef
/eff00*eff12/ // IMPORTANT! Has to equal the same param_unit!
lambda "Lambda approximation indeces"
/lambda01*lambda12/ // IMPORTANT! Has to equal effLambda!
hrop(param_unit) "Operating points in the incremental heat rate curves, also functions as index for data points"
/hrop00*hrop12/ // IMPORTANT! Has to equal the same param_unit!
hr(param_unit) "Heat rate for the corresponding operating point ('hrop') in the heat rate curves, also used for data indexing"
/hr00*hr12/ // IMPORTANT! Has to equal the same param_unit!
* --- Counters and Directional Sets -------------------------------------------
// Slack categories
slack(param_gnBoundaryTypes) "Categories for slack variables"
/ upwardSlack01*upwardSlack20, downwardSlack01*downwardSlack20 /
upwardSlack(slack) "Set of upward slacks"
upwardSlack(param_gnBoundaryTypes) "Set of upward slacks"
/ upwardSlack01*upwardSlack20 /
downwardSlack(slack) "Set of downward slacks"
downwardSlack(param_gnBoundaryTypes) "Set of downward slacks"
/ downwardSlack01*downwardSlack20 /
// Flags for boundaries
......
......@@ -49,6 +49,7 @@ Sets
unit_investLP(unit) "Units with continuous investments allowed"
unit_investMIP(unit) "Units with integer investments allowed"
unit_timeseries(unit) "Units with time series enabled"
unit_incHRAdditionalConstraints(unit) "Units that use the two additional incremental heat rate constraints"
* --- Nodes -------------------------------------------------------------------
node_spill(node) "Nodes that can spill; used to remove v_spill variables where not relevant"
......@@ -105,12 +106,14 @@ Sets
msf(mType, s, f) "Combination of samples and forecasts in the models"
msft(mType, s, f, t) "Combination of models, samples, forecasts and t's"
sft(s, f, t) "Combination of samples, forecasts and t's in the current model solve"
fts(f, t, s) "Like `sft` but different order"
sft_realized(s, f, t) "Realized sft"
sft_realizedNoReset(s, f, t) "Full set of realized sft, facilitates calculation of results"
msft_realizedNoReset(mType, s, f, t) "Combination of realized samples, forecasts and t:s in the current model solve and previously realized t:s"
mft_start(mType, f, t) "Start point of the current model solve"
mf_realization(mType, f) "fRealization of the forecasts"
mf_central(mType, f) "Forecast that continues as sample(s) after the forecast horizon ends"
mf_scenario(mType, f) "Forecast label that is used for long-term scenario data"
ms_initial(mType, s) "Sample that presents the realized/forecasted period"
ms_central(mType, s) "Sample that continues the central forecast after the forecast horizon ends"
mft_lastSteps(mType, f, t) "Last interval of the current model solve"
......@@ -119,11 +122,11 @@ Sets
t_latestForecast(t) "t for the latest forecast that is available"
gnss_bound(grid, node, s, s) "Bound the samples so that the node state at the last interval of the first sample equals the state at the first interval of the second sample"
uss_bound(unit, s, s) "Bound the samples so that the unit online state at the last interval of the first sample equals the state at the first interval of the second sample"
s_parallel(s) "Samples which are treated as parallel"
s_active(s) "Samples with non-zero probability in the current model solve"
ss(s, s) "Previous sample of sample"
s_prev(s) "Temporary set for previous sample"
longtermSamples(*, node, *) "Which grid/flow, node and timeseries/param have data for long-term scenarios"
s_scenario(s, scenario) "Which samples belong to which scenarios"
gn_scenarios(*, node, *) "Which grid/flow, node and timeseries/param have data for long-term scenarios"
* --- Sets used for the changing unit aggregation and efficiency approximations
uft(unit, f, t) "Active units on intervals, enables aggregation of units for later intervals"
......@@ -165,7 +168,9 @@ Option clear = modelSolves;
Option clear = ms;
Option clear = mf;
mf_realization(mType, 'f00') = yes;
Option clear = longtermSamples;
Option clear = mf_scenario;
Option clear = gn_scenarios;
Option clear = mTimeseries_loop_read;
alias(m, mSolve);
alias(t, t_, t__, tSolve, tFuel);
......@@ -182,7 +187,9 @@ alias(effDirectOn, effDirectOn_);
alias(effLambda, effLambda_);
alias(lambda, lambda_, lambda__);
alias(op, op_, op__);
alias(hrop, hrop_, hrop__);
alias(eff, eff_, eff__);
alias(hr, hr_, hr__);
alias(fuel, fuel_);
alias(effLevel, effLevel_);
alias(restype, restype_);
......
......@@ -27,6 +27,7 @@ Scalars
currentForecastLength "Length of the forecast in the curren solve, minimum of unchanging and decreasing forecast lengths"
count "General counter"
count_lambda, count_lambda2 "Counter for lambdas"
count_sample "Counter for samples"
cum_slope "Cumulative for slope"
cum_lambda "Cumulative for lambda"
heat_rate "Heat rate temporary parameter"
......@@ -57,6 +58,7 @@ Parameters
p_gnPolicy(grid, node, param_policy, *) "Policy data for grid, node"
p_groupPolicy(group, param_policy) "Two-dimensional policy data for groups"
p_groupPolicy3D(group, param_policy, *) "Three-dimensional policy data for groups"
p_fuelPrice(fuel, param_fuelPrice) "Fuel price parameters"
p_fuelEmission(fuel, emission) "Fuel emission content"
p_uFuel(unit, param_fuel, fuel, param_unitFuel) "Parameters interacting between units and fuels"
p_unitFuelEmissionCost(unit, fuel, emission) "Emission costs for each unit, calculated from input data"
......@@ -71,6 +73,7 @@ Parameters
p_uCounter_runUpMin(unit, counter) "Minimum output for the time steps where the unit is being started up to the minimum load (minimum output in the last interval) (p.u.)"
p_uCounter_runUpMax(unit, counter) "Maximum output for the time steps where the unit is being started up to the minimum load (minimum output in the last interval) (p.u.)"
p_u_maxOutputInFirstShutdownInterval(unit) "Maximum output in the first interval for the shutdown from min. load (p.u.)"
p_uShutdown(unit, cost_consumption) "Shutdown cost per unit"
p_u_shutdownTimeIntervals(unit) "Time steps required for the shutdown phase"
p_u_shutdownTimeIntervalsCeil(unit) "Floor of time steps required for the shutdown phase"
p_uCounter_shutdownMin(unit, counter) "Minimum output for the time steps where the unit is being shut down from the minimum load (minimum output in the first interval) (p.u.)"
......@@ -89,10 +92,10 @@ Parameters
Parameters
p_msWeight(mType, s) "Weight of sample"
p_msProbability(mType, s) "Probability to reach sample conditioned on anchestor samples"
p_msProbability_orig(mType, s) "Original probabilities of samples in model"
p_mfProbability(mType, f) "Probability of forecast"
p_msft_probability(mType, s, f, t) "Probability of forecast"
p_sProbability(s) "Probability of sample"
p_scenProbability(scenario) "Probability of scenarios"
;
Scalar p_sWeightSum "Sum of sample weights";
......@@ -110,12 +113,13 @@ Parameters
dt_downtimeUnitCounter(unit, counter) "Displacement needed to account for downtime constraints (in time steps)"
dt_uptimeUnitCounter(unit, counter) "Displacement needed to account for uptime constraints (in time steps)"
dt_trajectory(counter) "Run-up/shutdown trajectory time index displacement"
dt_sampleOffset(*, node, *, s) "Time offset to make periodic time series data (for grid/flow, unit, label) to go into different samples"
dt_scenarioOffset(*, node, *, s) "Time offset to make periodic time series data (for grid/flow, unit, label) to go into different scenarios"
// Forecast displacement arrays
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_reserves(node, 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"
// Sample displacement arrays
ds(s, t) "Displacement needed to reach the sample of previous time step"
......@@ -127,7 +131,7 @@ Parameters
ddf_(f) "Temporary forecast displacement array"
// Other
p_slackDirection(slack) "+1 for upward slacks and -1 for downward slacks"
p_slackDirection(param_gnBoundaryTypes) "+1 for upward slacks and -1 for downward slacks"
tForecastNext(mType) "When the next forecast will be available (ord time)"
aaSolveInfo(mType, t, solveInfoAttributes) "Stores information about the solve status"
msStart(mType, s) "Start point of samples: first time step in the sample"
......@@ -166,18 +170,19 @@ Parameters
ts_unavailability_update(unit, t)
// Help parameters for calculating smoothening of time series
ts_influx_mean(grid, node, f, t) "Mean of ts_influx over samples"
ts_influx_std(grid, node, f, t) "Standard deviation of ts_influx over samples"
ts_cf_mean(flow, node, f, t) "Mean of ts_cf over samples (p.u.)"
ts_cf_std(flow, node, f, t) "Standard deviation of ts_cf over samples (p.u.)"
ts_influx_std(grid, node, t) "Standard deviation of ts_influx over samples"
ts_cf_std(flow, node, t) "Standard deviation of ts_cf over samples (p.u.)"
p_autocorrelation(*, node, timeseries) "Autocorrelation of time series for the grid/flow, node and time series type (lag = 1 time step)"
// Bounds for scenario smoothening
p_tsMinValue(node, timeseries)
p_tsMaxValue(node, timeseries)
p_tsMinValue(*, node, timeseries) "Minimum allowed value of timeseries for grid/flow and node"
p_tsMaxValue(*, node, timeseries) "Maximum allowed value of timeseries in grid/flow and node"
;
* Reset values for some parameters
Options clear = ts_influx_std, clear = ts_cf_std;
* --- Other time dependent parameters -----------------------------------------
Parameters
p_storageValue(grid, node, t) "Value of stored something at the end of a time step"
......
......@@ -24,7 +24,7 @@ Parameters
* --- Cost Results ------------------------------------------------------------
// Total Objective Function
r_totalObj "Total cost over the simulation (EUR)" / 0 /
r_totalObj(t) "Total accumulated value of the objective function over all solves"
// Unit Operational Cost Components
r_gnuVOMCost(grid, node, unit, f, t) "Variable O&M costs for energy outputs (MEUR)"
......@@ -32,6 +32,7 @@ Parameters
r_uFuelEmissionCost(fuel, unit, f, t) "Unit fuel & emission costs for normal operation (MEUR)"
r_uTotalFuelEmissionCost(fuel, unit) "Total unit fuel & emission costs over the simulation for normal operation (MEUR)"
r_uStartupCost(unit, f, t) "Unit startup VOM, fuel, & emission costs (MEUR)"
r_uShutdownCost(unit, f, t) "Unit startup VOM, fuel, & emission costs (MEUR)"
r_uTotalStartupCost(unit) "Total unit startup costs over the simulation (MEUR)"
// Nodal Cost Components
......@@ -165,6 +166,7 @@ Scalar r_realizedLast "Order of last realised time step";
* --- Initialize a few of the results arrays, required by model structure -----
Option clear = r_totalObj;
Option clear = r_state;
Option clear = r_online;
Option clear = r_reserve;
......@@ -178,6 +180,7 @@ Option clear = r_invest;
Option clear = r_investTransfer;
Option clear = r_qResDemand;
Option clear = r_resDemandLargestInfeedUnit;
* =============================================================================
* --- Diagnostics Results Arrays ----------------------------------------------
* =============================================================================
......@@ -190,5 +193,7 @@ Parameters
d_capacityFactor(flow, node, s, f, t) "Diagnostic capacity factors (accounting for GAMS plotting error)"
d_nodeState(grid, node, param_gnBoundaryTypes, s, f, t) "Diagnostic temperature forecasts (accounting for GAMS plotting error)"
d_influx(grid, node, s, f, t) "Diagnostic influx forecasts (accounting for GAMS plotting error)"
d_state(grid, node, scenario, f, t) "Diagnostic state results in each scenario"
d_ts_scenarios(timeseries, *, node, scenario, f, t) "Diagnostic time series values in scenarios"
;
$endif.diag
......@@ -54,6 +54,7 @@ $loaddc gngnu_constrainedOutputRatio
$loaddc emission
$loaddc p_fuelEmission
$loaddc ts_cf
*$loaddc p_fuelPrice // Disabled for convenience, see line 278-> ("Determine Fuel Price Representation")
$loaddc ts_fuelPriceChange
$loaddc ts_influx
$loaddc ts_node
......@@ -248,6 +249,12 @@ p_uStartup(unit, 'cold', 'consumption')
= p_unit(unit, 'startFuelConsCold')
* sum(gnu_output(grid, node, unit), p_gnu(grid, node, unit, 'unitSizeGen'));
//shutdown cost parameters
p_uShutdown(unit, 'cost')
= p_unit(unit, 'shutdownCost')
* sum(gnu_output(grid, node, unit), p_gnu(grid, node, unit, 'unitSizeGen'));
// Determine unit emission costs
p_unitFuelEmissionCost(unit_fuel, fuel, emission)${ sum(param_fuel, uFuel(unit_fuel, param_fuel, fuel)) }
= p_fuelEmission(fuel, emission)
......@@ -268,6 +275,29 @@ p_unitFuelEmissionCost(unit_fuel, fuel, emission)${ sum(param_fuel, uFuel(unit_f
p_uFuel(uFuel(unit_fuel, 'startup', fuel), 'fixedFuelFraction')${ not p_uFuel(unit_fuel, 'startup', fuel, 'fixedFuelFraction') }
= 1;
* =============================================================================
* --- Determine Fuel Price Representation -------------------------------------
* =============================================================================
// Use either constant or time series for fuel prices depending on 'ts_fuelPriceChange'
// Should be handled separately by 'p_fuelPrice' also being included in the input data,
// but this is more convenient for now as no changes to inputs are required
// Determine if fuel prices require a time series representation or not
loop(fuel,
// Find the steps with changing fuel prices
option clear = tt;
tt(t)${ ts_fuelPriceChange(fuel, t) } = yes;
// If only up to a single value
if(sum(tt, 1) <= 1,
p_fuelPrice(fuel, 'useConstant') = 1; // Use a constant for fuel prices
p_fuelPrice(fuel, 'fuelPrice') = sum(tt, ts_fuelpriceChange(fuel, tt)) // Determine the price as the only value in the time series
// If multiple values found, use time series
else
p_fuelPrice(fuel, 'useTimeSeries') = 1;
); // END if(sum(tt))
); // END loop(fuel)
* =============================================================================
* --- Generate Node Related Sets Based on Input Data --------------------------
* =============================================================================
......@@ -505,9 +535,11 @@ loop( (nu(node, unit), restypeDirection(restype, up_down)),
* =============================================================================
* --- Default values ---------------------------------------------------------
* =============================================================================
loop((gn(grid, node), timeseries),
p_autocorrelation(grid, node, timeseries) = 0;
p_tsMinValue(node, timeseries) = -Inf;
p_tsMaxValue(node, timeseries) = Inf;
loop(timeseries$(not sameas(timeseries, 'ts_cf')),
p_autocorrelation(gn, timeseries) = 0;
p_tsMinValue(gn, timeseries) = -Inf;
p_tsMaxValue(gn, timeseries) = Inf;
);
p_autocorrelation(flowNode, 'ts_cf') = 0;
p_tsMinValue(flowNode, 'ts_cf') = 0;
p_tsMaxValue(flowNode, 'ts_cf') = 1;
......@@ -27,6 +27,9 @@ Integer variables
v_invest_MIP(unit, t) "Number of invested sub-units"
v_investTransfer_MIP(grid, node, node, t) "Number of invested transfer links"
;
Binary variables
v_help_inc(grid, node, unit, hr, s, f, t) "Helper variable to ensure that the first heat rate segments are used first"
;
SOS2 variables
v_sos2(unit, s, f, t, effSelector) "Intermediate lambda variable for SOS2 based piece-wise linear efficiency curve"
;
......@@ -44,6 +47,7 @@ Positive variables
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_invest_LP(unit, t) "Number of invested 'sub-units' (LP variant)"
v_gen_inc(grid, node, unit, hr, s, f, t) "Energy generation in hr block in an interval (MW)"
;
* --- Feasibility control -----------------------------------------------------
......
......@@ -23,10 +23,12 @@ $offtext
Scalars
PENALTY "Default equation violation penalty"
BIG_M "A large number used together with with binary variables in some equations"
;
$If set penalty PENALTY=%penalty%;
$If not set penalty PENALTY=1e9;
BIG_M = 1e5;
Parameters
PENALTY_BALANCE(grid, node) "Penalty on violating energy balance eq. (EUR/MWh)"
......@@ -54,8 +56,8 @@ equations
q_resDemand(restype, up_down, node, s, f, t) "Procurement for each reserve type is greater than demand"
q_resDemandLargestInfeedUnit(grid, restype, up_down, node, unit, s, f, t) "N-1 Reserve"
// Unit Operation
q_maxDownward(mType, s, grid, node, unit, f, t) "Downward commitments will not undercut power plant minimum load constraints or maximum elec. consumption"
q_maxUpward(mType, s, grid, node, unit, f, t) "Upward commitments will not exceed maximum available capacity or consumed power"
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_reserveProvision(restype, up_down, 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_startuptype(mType, s, starttype, unit, f, t) "Startup type depends on the time the unit has been non-operational"
......@@ -75,6 +77,11 @@ equations
q_conversionSOS2InputIntermediate(s, effSelector, unit, f, t) "Intermediate output when using SOS2 variable based part-load piece-wise linearization"
q_conversionSOS2Constraint(s, effSelector, unit, f, t) "Sum of v_sos2 has to equal v_online"
q_conversionSOS2IntermediateOutput(s, effSelector, unit, f, t) "Output is forced equal with v_sos2 output"
q_conversionIncHR(s, effSelector, unit, f, t) "Conversion of inputs to outputs for incremental heat rates"
q_conversionIncHRMaxGen(grid, node,s, effSelector, unit, f, t) "Max Generating level"
q_conversionIncHRBounds(grid, node, s, hr, effSelector, unit, f, t) "Heat rate bounds"
q_conversionIncHR_help1(grid, node, s, hr, effSelector, unit, f, t) "Helper equation 1 to ensure that the first heat rate segments are used first"
q_conversionIncHR_help2(grid, node, s, hr, effSelector, unit, f, t) "Helper equation 2 to ensure that the first heat rate segments are used first"
q_fuelUseLimit(s, fuel, unit, f, t) "Fuel use cannot exceed limits"
// Energy Transfer
......
......@@ -44,7 +44,8 @@ q_obj ..
+ sum(uFuel(unit, 'main', fuel)${uft(unit, f, t)},
+ v_fuelUse(fuel, unit, s, f, t)
* [
+ ts_fuelPrice_(fuel ,t)
+ p_fuelPrice(fuel, 'fuelPrice')${ p_fuelPrice(fuel, 'useConstant') }
+ ts_fuelPrice_(fuel ,t)${ p_fuelPrice(fuel, 'useTimeSeries') }
+ sum(emission, // Emission taxes
+ p_unitFuelEmissionCost(unit, fuel, emission)
)
......@@ -97,7 +98,8 @@ q_obj ..
+ p_uStartup(unit, starttype, 'consumption')
* p_uFuel(unit, 'startup', fuel, 'fixedFuelFraction')
* [
+ ts_fuelPrice_(fuel, t)
+ p_fuelPrice(fuel, 'fuelPrice')${ p_fuelPrice(fuel, 'useConstant') }
+ ts_fuelPrice_(fuel, t)${ p_fuelPrice(fuel, 'useTimeseries') }
+ sum(emission, // Emission taxes of startup fuel use
+ p_unitFuelEmissionCost(unit, fuel, emission)
) // END sum(emission)
......@@ -107,6 +109,11 @@ q_obj ..
) // END sum(starttype)
) // END sum(uft_online)
// Shut-down costs, initial shutdown free?
+ sum(uft_online(unit, f, t),
+ v_shutdown(unit, s, f, t) * p_uShutdown(unit, 'cost')
) // END sum(uft_online)
// Ramping costs
+ sum(gnuft_rampCost(grid, node, unit, slack, f, t),
+ p_gnuBoundaryProperties(grid, node, unit, slack, 'rampCost')
......
This diff is collapsed.
......@@ -56,28 +56,17 @@ $offtext
// Select samples for the model
if (not sum(s, ms(m, s)), // unless they have been provided as input
ms(m, s)$(ord(s) <= mSettings(m, 'samples')) = yes;