Commit 0913d330 authored by Juha Kiviluoma's avatar Juha Kiviluoma
Browse files

Big changes.

1) Units and nodes can be aggregated in later time steps
2) Piecewise linear implementations (SOS1 and SOS2) for part-load conversion efficiency
3) Piecewise linear implementation can change in later time periods
parent 38bb9c77
......@@ -17,3 +17,4 @@ Backbone.dat
diffile.gdx
defModels/schedule.gms
defModels/storage.gms
EfficiencyPiecewise.xlsx
$title Backbone
$ontext
Backbone - chronological energy systems model
===============================================================================
==========================================================================
Created by:
Juha Kiviluoma <juha.kiviluoma@vtt.fi>
Erkka Rinne <erkka.rinne@vtt.fi>
Topi Rasku <topi.rasku@vtt.fi>
- Based on Stochastic Model Predictive Control method [1].
- Enables multiple different models (m) to be implemented by changing the temporal
structure of the model.
- Enables multiple different models (m) to be implemented by changing
the temporal structure of the model.
- Time steps (t) can vary in length.
- Short term forecast stochasticity (f) and longer term statistical uncertainty (s).
- Can handle ramp based dispatch in addition to energy blocks.
......@@ -52,6 +53,8 @@ $onempty // Allow empty data definitions
files log /''/, gdx, f_info /'output\info.txt'/;
options
optca = 0
optcr = 0
profile = 8
solvelink = %Solvelink.Loadlibrary%
bratio = 1
......@@ -81,6 +84,7 @@ $include 'input\3a_modelsInit.gms' // Sets that are defined over the whole mode
loop(modelSolves(mSolve, tSolve),
$$include 'input\3b_modelsLoop.gms' // Set sets that define model scope
$$include 'inc\3c_setVariableLimits.gms' // Set new variable limits (.lo and .up)
$$ifi '%debug%' == 'yes' execute_unload 'output\debug.gdx'; // Output debugging information
$$include 'inc\3d_solve.gms' // Solve model(s)
put log;
put schedule.resGen;
......
......@@ -41,4 +41,174 @@ loop(m$(continueLoop),
and ord(t) <= mSettings(m, 't_end') + max(mSettings(m, 't_forecastLength'), mSettings(m, 't_horizon'))
) = -ts_length;
continueLoop = 0;
);
\ No newline at end of file
);
loop(m,
tmp = 0;
continueLoop = 1;
loop(counter$continueLoop,
if(not mInterval(m, 'intervalEnd', counter),
continueLoop = 0;
else
abort$(mod(mInterval(m, 'intervalEnd', counter) - mInterval(m, 'intervalEnd', counter-1), mInterval(m, 'intervalLength', counter))) "IntervalLength is not evenly divisible within the interval", m, continueLoop;
continueLoop = continueLoop + 1;
);
);
);
* Parse through effLevelSelectorUnit and convert selected effSelectors into sets representing those selections
loop(unit,
cum_lambda = 0;
cum_slope = 0;
loop(effLevel$sum(m, mSettingsEff(m, effLevel)),
// effSelector using DirectOn
if (sum(effSelector$effDirectOn(effSelector), effLevelGroupUnit(effLevel, effSelector, unit)),
loop(effSelector$effDirectOn(effSelector),
if(effLevelGroupUnit(effLevel, effSelector, unit),
effGroup(effSelector) = yes;
effGroupSelector(effSelector, effSelector) = yes;
effLevelSelectorUnit(effLevel, effSelector, unit) = yes;
);
);
);
// effSelector using DirectOff
if (sum(effSelector$effDirectOff(effSelector), effLevelGroupUnit(effLevel, effSelector, unit)),
loop(effSelector$effDirectOff(effSelector),
if(effLevelGroupUnit(effLevel, effSelector, unit),
effGroup(effSelector) = yes;
effGroupSelector(effSelector, effSelector) = yes;
effLevelSelectorUnit(effLevel, effSelector, unit) = yes;
);
);
);
// effSelectors using Lambda
if (sum(effSelector_$effLambda(effSelector_), effLevelGroupUnit(effLevel, effSelector_, unit)),
count = 0;
loop(effSelector$effLambda(effSelector),
count = count + 1;
if(effLevelGroupUnit(effLevel, effSelector, unit),
count_lambda = count;
cum_lambda = cum_lambda + count_lambda;
effGroup(effSelector) = yes;
);
);
count = 0;
loop(effSelector$effLambda(effSelector),
count = count + 1;
if( count > cum_lambda - count_lambda and count <= cum_lambda,
effLevelSelectorUnit(effLevel, effSelector, unit) = yes;
effGroupSelectorUnit(effGroup, effSelector, unit)$effLevelGroupUnit(effLevel, effGroup, unit) = yes;
);
if ( count = count_lambda,
count_lambda2 = 0;
loop(effSelector_$effLambda(effSelector_),
count_lambda2 = count_lambda2 + 1;
if (count_lambda2 > cum_lambda - count_lambda and count_lambda2 <= cum_lambda,
effGroupSelector(effSelector, effSelector_) = yes;
);
);
);
);
);
// effSelectors using Slope
if (sum(effSelector_$effSlope(effSelector_), effLevelGroupUnit(effLevel, effSelector_, unit)),
count = 0;
loop(effSelector$effSlope(effSelector),
count = count + 1;
if(effLevelGroupUnit(effLevel, effSelector, unit),
count_slope = count;
cum_slope = cum_slope + count_slope;
effGroup(effSelector) = yes;
);
);
count = 0;
loop(effSelector$effSlope(effSelector),
count = count + 1;
if( count > cum_slope - count_slope and count <= cum_slope,
effLevelSelectorUnit(effLevel, effSelector, unit) = yes;
effGroupSelectorUnit(effGroup, effSelector, unit)$effLevelGroupUnit(effLevel, effGroup, unit) = yes;
);
if (count = count_slope,
count_slope2 = 0;
loop(effSelector_$effSlope(effSelector_),
count_slope2 = count_slope2 + 1;
if( count_slope2 > cum_slope - count_slope and count_slope2 <= cum_slope,
//effSelectorFirstSlope(effSelector, effSelector_) = yes;
effGroupSelector(effSelector, effSelector_) = yes;
);
);
);
if( count = cum_slope - count_slope + 1,
effLevelSelectorFirst(effLevel, effSelector) = yes;
);
);
);
// Calculate parameters for units using direct input output conversion with online variable
loop(effSelector$sum(effDirectOn$effGroupSelector(effDirectOn, effSelector), 1),
p_effUnit(effSelector, unit, 'lb') = p_unit(unit, 'rb00');
p_effUnit(effSelector, unit, 'rb') = p_unit(unit, 'rb01');
p_effUnit(effSelector, unit, 'section')$(not p_unit(unit, 'eff01')) = 0;
p_effUnit(effSelector, unit, 'slope')$(not p_unit(unit, 'eff01')) = 1 / p_unit(unit, 'eff00');
p_effUnit(effSelector, unit, 'section')$p_unit(unit, 'eff01') =
+ 1 / p_unit(unit, 'eff01')
- [p_unit(unit, 'rb01') - 0]
/ [p_unit(unit, 'rb01') - p_unit(unit, 'rb00')]
* [1 / p_unit(unit, 'eff01') * p_unit(unit, 'rb01') - 1 / p_unit(unit, 'eff00') * p_unit(unit, 'rb00')];
p_effUnit(effSelector, unit, 'slope')$p_unit(unit, 'eff01') =
+ 1 / p_unit(unit, 'eff01') - p_effUnit(effSelector, unit, 'section');
);
// Calculate parameters for units using direct input output conversion without online variable
loop(effSelector$sum(effDirectOff$effGroupSelector(effDirectOff, effSelector), 1),
p_effUnit(effSelector, unit, 'rb') = 1;
p_effUnit(effSelector, unit, 'lb') = 0;
p_effUnit(effSelector, unit, 'section')$(not p_unit(unit, 'eff01')) = 0;
p_effUnit(effSelector, unit, 'slope')$(not p_unit(unit, 'eff01')) = 1 / p_unit(unit, 'eff00');
p_effUnit(effSelector, unit, 'section')$p_unit(unit, 'eff01') = 0;
p_effUnit(effSelector, unit, 'slope')$p_unit(unit, 'eff01') = 1 / p_unit(unit, 'eff01');
);
// Make calculations for different parts of the piecewise curve in the case of using slope
count_slope2 = 0;
loop(effSelector$(effSlope(effSelector) and effLevelSelectorUnit(effLevel, effSelector, unit)),
p_effUnit(effSelector, unit, 'rb') = ((count_slope - count_slope2 - 1) * p_unit(unit, 'rb00') + (count_slope2 + 1) * p_unit(unit, 'rb01')) / count_slope;
p_effUnit(effSelector, unit, 'lb') = ((count_slope - count_slope2) * p_unit(unit, 'rb00') + count_slope2 * p_unit(unit, 'rb01')) / count_slope;
//if(count_slope2 = 0,
//p_effUnit(effSelector, unit, 'slope') = ((count_slope-1 - count_slope2) * (1 / p_unit(unit, 'eff00')) + count_slope2 * (1 / p_unit(unit, 'eff01'))) / (count_slope - 1);
//tmp = p_effUnit(effSelector, unit, 'slope');
//else
p_effUnit(effSelector, unit, 'slope')
= ((count_slope-1 - count_slope2) * (1 / p_unit(unit, 'eff00')) + (count_slope2 + 1) * (1 / p_unit(unit, 'eff01'))) / count_slope;
// - tmp;
//);
count_slope2 = count_slope2 + 1;
);
// Calculate lambdas
count_lambda2 = 0;
loop(effSelector$(effLambda(effSelector) and effLevelSelectorUnit(effLevel, effSelector, unit)),
p_effUnit(effSelector, unit, 'rb') = ((count_lambda-1 - count_lambda2) * p_unit(unit, 'rb00') + count_lambda2 * p_unit(unit, 'rb01')) / (count_lambda - 1);
//no lb for lambdas, since number of borders same as number of slopes p_effUnit(effSelector, unit, 'lb') = ((count_lambda-1 - count_lambda2 + 1) * p_unit(unit, 'rb00') + (count_lambda2 - 1) * p_unit(unit, 'rb01')) / (count_lambda - 1);
p_effUnit(effSelector, unit, 'slope')$effLevelSelectorUnit(effLevel, effSelector, unit)
= ((count_lambda-1 - count_lambda2) * (1 / p_unit(unit, 'eff00')) + count_lambda2 * (1 / p_unit(unit, 'eff01'))) / (count_lambda - 1);
count_lambda2 = count_lambda2 + 1;
);
);
);
* Ensure that efficiency levels extend to the end of the model horizon
loop(m,
continueLoop = 0;
loop(effLevel$mSettingsEff(m, effLevel),
continueLoop = continueLoop + 1;
);
loop(effLevel$(ord(effLevel) = continueLoop),
if (mSettingsEff(m, effLevel) <> mSettings(m, 't_horizon'),
mSettingsEff(m, effLevel + 1) = mSettings(m, 't_horizon');
);
);
);
......@@ -19,9 +19,7 @@ $offOrder
and ord(t) < min(tSolveFirst + mInterval(mSolve, 'intervalEnd', counter), tSolveLast + 1)
) = yes; // Set of t's where the interval is 1 (right border defined by intervalEnd) - but do not go beyond tSolveLast
ts_energyDemand_(gn(grid, node), fSolve, t)$tInterval(t) = ts_energyDemand(grid, node, fSolve, t+ct(t));
ts_inflow_(unit_hydro, fSolve, t)$tInterval(t) = ts_inflow(unit_hydro, fSolve, t+ct(t));
ts_inflow_(storage_hydro, fSolve, t)$tInterval(t) = ts_inflow(storage_hydro, fSolve, t+ct(t));
ts_import_(gn(grid, node), t)$tInterval(t) = ts_import(grid, node, t+ct(t));
ts_absolute_(node, fSolve, t)$tInterval(t) = ts_absolute(node, fSolve, t+ct(t));
ts_cf_(flow, node, fSolve, t)$tInterval(t) = ts_cf(flow, node, fSolve, t+ct(t));
tCounter = mInterval(mSolve, 'intervalEnd', counter); // move tCounter to the next interval setting
p_stepLength(mf(mSolve, fSolve), t)$tInterval(t) = 1; // p_stepLength will hold the length of the interval in model equations
......@@ -29,7 +27,7 @@ $offOrder
pt(t + 1)$tInterval(t) = -1;
elseif mInterval(mSolve, 'intervalLength', counter) > 1, // intervalLength > 1 (not defined if intervalLength < 1)
loop(t$[ord(t) >= tSolveFirst + tCounter and ord(t) < min(tSolveFirst + mInterval(mSolve, 'intervalEnd', counter), tSolveLast + 1)], // Loop t relevant for each interval (interval borders defined by intervalEnd) - but do not go beyond tSolveLast
if (not mod(tCounter, mInterval(mSolve, 'intervalLength', counter)), // Skip those t's that are not at the start of any interval
if (not mod(tCounter - mInterval(mSolve, 'intervalEnd', counter), mInterval(mSolve, 'intervalLength', counter)), // Skip those t's that are not at the start of any interval
intervalLength = min(mInterval(mSolve, 'intervalLength', counter), max(mSettings(mSolve, 't_forecastLength'), mSettings(mSolve, 't_horizon')) - tCounter);
p_stepLength(mf(mSolve, fSolve), t) = intervalLength; // p_stepLength will hold the length of the interval in model equations
if (p_stepLengthNoReset(mSolve, 'f00', t) <> mInterval(mSolve, 'intervalLength', counter), // and skip those t's that have been calculated for the right interval previously
......@@ -41,9 +39,7 @@ $offOrder
p_stepLengthNoReset(mf(mSolve, fSolve), t) = intervalLength;
// Calculate averages for the interval time series data
ts_energyDemand_(gn(grid, node), fSolve, t) = sum{t_$tInterval(t_), ts_energyDemand(grid, node, fSolve, t_+ct(t_))};
ts_inflow_(unit_hydro, fSolve, t) = sum{t_$tInterval(t_), ts_inflow(unit_hydro, fSolve, t_+ct(t_))} / p_stepLength(mSolve, fSolve, t);
ts_inflow_(storage_hydro, fSolve, t) = sum{t_$tInterval(t_), ts_inflow(storage_hydro, fSolve, t_+ct(t_))};
ts_import_(gn(grid, node), t) = sum{t_$tInterval(t_), ts_import(grid, node, t_+ct(t_))};
ts_absolute_(node, fSolve, t) = sum{t_$tInterval(t_), ts_absolute(node, fSolve, t_+ct(t_))} / p_stepLength(mSolve, fSolve, t);
ts_cf_(flow, node, fSolve, t) = sum{t_$tInterval(t_), ts_cf(flow, node, fSolve, t_+ct(t_))} / p_stepLength(mSolve, fSolve, t);
// Set the previous time step displacement
pt(t+intervalLength) = -intervalLength;
......@@ -69,7 +65,7 @@ $onOrder
// Set mft for the modelling period and model forecasts
mft(mSolve,f,t) = no;
mft(mSolve, f, t)$( p_stepLength(mSolve, f, t) and ord(t) < tSolveFirst + mSettings(mSolve, 't_forecastLength' ) ) = yes;
mft(mSolve, f, t)$( p_stepLength(mSolve, f, t) and ord(t) < tSolveFirst + mSettings(mSolve, 't_horizon' ) ) = yes;
* mft(mSolve, f, t)${ [ord(t) >= ord(tSolve)]
* $$ifi '%rampSched%' == 'yes' and [ord(t) <=
* $$ifi not '%rampSched%' == 'yes' and [ord(t) <
......@@ -107,20 +103,35 @@ $onOrder
ft_realizedLast(f,t) = no;
ft_realizedLast(f,t)$[fRealization(f) and ord(t) = ord(tSolve) + mSettings(mSolve, 't_jump')] = yes;
nuft(node, unit, f, t) = no;
nuft(node, unit, f, t)$[ ft(f, t)
and ord(t) <= mSettings(mSolve, 't_aggregate')
and not unit_aggregate(unit)
] = yes;
uft(unit, f, t) = no;
uft(unit, f, t)$[ ft(f, t)
and ord(t) <= mSettings(mSolve, 't_aggregate')
and not unit_aggregate(unit)
] = yes;
uft(unit, f, t)$[ ft(f, t)
and ord(t) > mSettings(mSolve, 't_aggregate')
and (unit_aggregate(unit) or unit_noAggregate(unit))
] = yes;
nuft(node, unit, f, t)$[ ft(f, t)
and ord(t) > mSettings(mSolve, 't_aggregate')
and (unit_aggregate(unit) or unit_noAggregate(unit))
] = yes;
nuft(node, unit, f, t) = no;
nuft(node, unit, f, t)$(nu(node, unit) and uft(unit, f, t)) = yes;
gnuft(grid, node, unit, f, t) = no;
gnuft(grid, node, unit, f, t)$(gn(grid, node) and nuft(node, unit, f, t)) = yes;
loop(effLevel$mSettingsEff(mSolve, effLevel),
tInterval(t) = no;
tInterval(t)$(ord(effLevel) = 1 and ord(t) = tSolveFirst) = yes;
tInterval(t)$( ord(t) >= tSolveFirst + mSettingsEff(mSolve, effLevel)
and ord(t) < tSolveFirst + mSettingsEff(mSolve, effLevel+1)
) = yes;
loop(effLevelGroupUnit(effLevel, effGroup, unit),
suft(effGroup, unit, f, tInterval(t))$(effLevelGroupUnit(effLevel, effGroup, unit) and uft(unit, f, tInterval)) = yes;
);
);
sufts(effGroup, unit, f, t, effSelector)$(effGroupSelector(effGroup, effSelector) and suft(effGroup, unit, f, t)) = yes;
pf(ft(f,t))$(ord(t) eq ord(tSolve) + 1) = 1 - ord(f);
......
......@@ -2,21 +2,25 @@ if (mType('schedule'),
m('schedule') = yes;
mSettings('schedule', 't_start') = 1; // Ord of first solve (i.e. >0)
mSettings('schedule', 't_horizon') = 8760;
mSettings('schedule', 't_jump') = 24;
mSettings('schedule', 't_jump') = 48;
mSettings('schedule', 't_forecastLength') = 8760;
mSettings('schedule', 't_end') = 168;
mSettings('schedule', 't_end') = 80;
mSettings('schedule', 'samples') = 1;
mSettings('schedule', 'forecasts') = 0;
mSettings('schedule', 't_aggregate') = 72;
mSettingsEff('schedule', 'level1') = 1;
mSettingsEff('schedule', 'level2') = 24;
mSettingsEff('schedule', 'level3') = 48;
mSettingsEff('schedule', 'level4') = 168;
mf('schedule', f)$[ord(f)-1 <= mSettings('schedule', 'forecasts')] = yes;
mInterval('schedule', 'intervalLength', 'c000') = 1;
mInterval('schedule', 'intervalEnd', 'c000') = 48;
mInterval('schedule', 'intervalEnd', 'c000') = 168;
mInterval('schedule', 'intervalLength', 'c001') = 3;
mInterval('schedule', 'intervalEnd', 'c001') = 96;
mInterval('schedule', 'intervalEnd', 'c001') = 336;
mInterval('schedule', 'intervalLength', 'c002') = 6;
mInterval('schedule', 'intervalEnd', 'c002') = 168;
mInterval('schedule', 'intervalEnd', 'c002') = 1680;
mInterval('schedule', 'intervalLength', 'c003') = 24;
mInterval('schedule', 'intervalEnd', 'c003') = 4*168;
mInterval('schedule', 'intervalEnd', 'c003') = 4392;
mInterval('schedule', 'intervalLength', 'c004') = 168;
mInterval('schedule', 'intervalEnd', 'c004') = 8760;
active('storageValue') = yes;
......@@ -43,17 +47,17 @@ Model schedule /
q_resDemand
q_maxDownward
q_maxUpward
q_storageDynamics
q_storageConversion
q_bindStorage
q_startup
q_bindOnline
q_fuelUse
q_conversion
q_conversionDirectInputOutput
q_conversionSOS1InputIntermediate
q_conversionSOS1Constraint
q_conversionSOS1IntermediateOutput
q_conversionSOS2InputIntermediate
q_conversionSOS2Constraint
q_conversionSOS2IntermediateOutput
q_outputRatioFixed
q_outputRatioConstrained
q_stoMinContent
q_stoMaxContent
q_transferLimit
q_maxStateSlack
q_minStateSlack
......
......@@ -2,12 +2,35 @@
Sets // Model related selections
mType "model types in the Backbone" /invest, storage, schedule, realtime/
mSetting "setting categories for models" /t_start, t_jump, t_horizon, t_forecastLength, t_end, samples, forecasts, intervalEnd, intervalLength, t_aggregate/
counter "general counter set" /c000*c999/;
counter "general counter set" /c000*c999/
slope "Part-load efficiency"
/slope00*slope12/
rb "Right borders of efficiency curves"
/rb00*rb12/
lb "Left borders of efficiency curves"
/lb00*lb12/
effSelector "Select equations and lambdas/slope for efficiency calculations"
/ directOff, directOn, slope01*slope12, lambda01*lambda12 /
effDirect(effSelector) "Using direct input to output equation"
/ directOff, directOn /
effDirectOff(effSelector) "Using direct input to output equation without online variable, i.e. constant efficiency"
/ directOff /
effDirectOn(effSelector) "Using direct input to output equation with online variable"
/ directOn /
effSlope(effSelector) "Slope in use for part-load efficiency representation"
/ slope01*slope12 /
effLambda(effSelector) "Lambdas in use for part-load efficiency representation"
/ lambda01*lambda12 /
effLevel "Pre-defined levels for efficiency representation that can start from t_solve + x"
/ level1*level9 /
;
* Numeric parameters
Parameter
mSettings(mType, mSetting)
mSettingsEff(mtype, effLevel)
mInterval(mType, mSetting, counter)
t_skip_counter
;
......@@ -43,5 +66,102 @@ $if set extraRes active('extraRes') = %extraRes%;
$if set rampSched active('rampSched') = %rampSched%;
* --- Set definitions for parameters -----------------------------------------------------
Sets
param_gn "Set of possible data parameters for grid, node" /
maxState "Absolute maximum state of the node (unit depends on energyCapacity)"
maxStateSlack "Desired maximum state of the node (unit depends on energyCapacity)"
minState "Absolute minimum energy in the node (unit depends on energyCapacity)"
minStateSlack "Desired minimum desired state of the node (unit depends on energyCapacity)"
fixState "Fixed state of the node (unit depends on energyCapacity)"
energyCapacity "Energy capacity of the node (MWh/?, allows for changing the quality of the node state variables)"
maxSpill "Maximum spill rate from the node (MWh/h)"
minSpill "Minimum spill rate from the node (MWh/h)"
chargingEff "Average charging efficiency (p.u)"
dischargingEff "Average discharging efficiency (p.u.)"
selfDischarge "Self discharge of the node (p.u.)"
/
param_gnn "Set of possible data parameters for grid, node, node (nodal interconnections)" /
transferCap "Transfer capacity limits"
transferLoss "Transfer losses"
diffCoeff "Coefficients for energy diffusion between nodes"
boundStateOffset "Offset parameter for relatively bound node states"
/
param_gnu "Set of possible data parameters for grid, node, unit" /
maxGen "Maximum output capacity (MW)"
maxCons "Maximum loading capacity (MW)"
cB "Share of output"
cV "Reduction in primary output when increasing secondary output, e.g. reduction of electricity generation due to heat generation in extraction CHP (MWh_e/MWh_h)"
eff00 * eff12 "Efficiency of the unit to convert to certain output or from certain input at different operating points"
rb00 * rb12 "Right border of the efficiency point"
section00 "Input (fuel) consumption at min. load (or at zero)"
slope00 * slope12 "Additive input (fuel) consumption slope"
/
param_nu "Set of possible data parameters for node, unit" /
unitCount "Number of units if aggregated"
unitCapacity "A proxy for the unit size in case the maxGens cannot be just added up by default"
omCosts "Variable operation and maintenance costs (/MWh)"
startupCost "Variable start-up costs excluding energy costs (/MWh)"
startupFuelCons "Consumption of start-up fuel per capacity started up (MWh_fuel/MW)"
availability "Availability of given energy conversion technology (p.u.)"
coldStart "Start-up time from cold to warm (h)"
warmStart "Start-up time from warm to hot (h)"
hotStart "Start-up time from hot to minLoad (h)"
fullLoadEff "Efficiency at full load (electric efficiency for CHP units)"
minLoadEff "Efficiency at minimum load (electric efficiency for CHP units)"
minOperation "Minimum operation time (h)"
minShutDown "Minimum shut down time (h)"
rampUp "Speed to ramp up (p.u. / min)"
SO2 "SO2 emissions (tonne per MWh_fuel)"
NOx "NOx emissions (tonne per MWh_fuel)"
CH4 "CH4 emissions (tonne per MWh_fuel)"
rampCost "Wear and tear cost of ramping (/MW)"
inflow "Total annual inflow to a storage (MWh)"
resTimelim "How long should a storage be able to provide reserve (h)"
eff00 * eff12 "Efficiency of the unit to convert input to output/intermediate product"
rb00 * rb12 "Right border of the efficiency point"
section00 "Input (fuel) consumption at min. load (or at zero)"
slope00 * slope12 "Additive input (fuel) consumption slope"
level1 * level9 "Level of simplification in the part-load efficiency representation"
/
param_fuel "Parameters for fuels" /
emissionIntensity "Intensity of emission from fuel (kg/MWh_fuel)"
main "Main fuel of the unit - unless input fuels defined as grids"
startup "Startup fuel of the unit, if exists. Can be the same as main fuel - consumption using startupFuelCons"
/
param_unitFuel "Parameters for fuel limits in units" /
maxFuelCons "Maximum absolute fuel consumption in a unit"
maxFuelFraction "Maximum share of a fuel in the consumption mix"
/
param_policy "Set of possible data parameters for grid, node, regulation" /
emissionTax "Emission tax (/tonne)"
/
param_union "Different ways inputs and outputs of energy conversion units can be combined" /
fixed "The ratio between different output forms is fixed"
unbound "The ratio of this output is not constrained by other forms of energy"
constrained "The usage is limited by the output of free outputs - in relation to the efficiency limits"
substitute "Inputs and outputs can be substituted"
/
* --- Sets for aggregating output
unittype "Unit technology types" /
nuclear
imports
coal
unit_hydro
CCGT
"pumped storage"
solar
wind
OCGT
dummy
/
;
* --- Geography ---------------------------------------------------------------
Sets
* --- Geography ---------------------------------------------------------------
grid "Forms of energy endogenously presented in the model"
node "Nodes where different types of energy are converted"
node_to_node(node,node) "Transmission links"
;
alias(node, from_node, to_node, node_, node_input);
alias(node, from_node, to_node);
node_to_node(node, node) "Transmission links"
* --- Fuels & resources -------------------------------------------------------
Sets
grid "Forms of energy endogenously presented in the model" /elec, heat/
emission "Emissions"
fuel "Fuels"
flow "Flow based energy resources (time series)"
;
Alias(grid, grid_, grid_output);
Sets param_gn "Set of possible data parameters for grid, node" /
maxState "Absolute maximum state of the node (unit depends on energyCapacity)"
maxStateSlack "Desired maximum state of the node (unit depends on energyCapacity)"
minState "Absolute minimum energy in the node (unit depends on energyCapacity)"
minStateSlack "Desired minimum desired state of the node (unit depends on energyCapacity)"
fixState "Fixed state of the node (unit depends on energyCapacity)"
energyCapacity "Energy capacity of the node (MWh/?, allows for changing the quality of the node state variables)"
/
param_gnn "Set of possible data parameters for grid, node, node (nodal interconnections)" /
transferCap "Transfer capacity limits"
transferLoss "Transfer losses"
diffCoeff "Coefficients for energy diffusion between nodes"
boundStateOffset "Offset parameter for relatively bound node states"
/
param_gnu "Set of possible data parameters for grid, node, unit" /
maxCap "Maximum output capacity (MW)"
maxCharging "Maximum loading capacity (MW)"
cB "Ratio in energy conversion between primary output and secondary outputs, e.g. heat ratio of a CHP-plant (MWh_e/MWh_h)"
cV "Reduction in primary output when increasing secondary output, e.g. reduction of electricity generation due to heat generation in extraction CHP (MWh_e/MWh_h)"
/
param_nu "Set of possible data parameters for node, unit" /
unitCount "Number of units if aggregated"
slope "Slope of the fuel use"
section "Section of the fuel use at zero output"
minLoad "Minimum loading of a unit (p.u)"
omCosts "Variable operation and maintenance costs (/MWh)"
startupCost "Variable start-up costs excluding energy costs (/MWh)"
startupFuelCons "Consumption of start-up fuel per capacity started up (MWh_fuel/MW)"
availability "Availability of given energy conversion technology (p.u.)"
coldStart "Start-up time from cold to warm (h)"
warmStart "Start-up time from warm to hot (h)"
hotStart "Start-up time from hot to minLoad (h)"
fullLoadEff "Efficiency at full load (electric efficiency for CHP units)"
minLoadEff "Efficiency at minimum load (electric efficiency for CHP units)"
minOperation "Minimum operation time (h)"
minShutDown "Minimum shut down time (h)"
rampUp "Speed to ramp up (p.u. / min)"
SO2 "SO2 emissions (tonne per MWh_fuel)"
NOx "NOx emissions (tonne per MWh_fuel)"
CH4 "CH4 emissions (tonne per MWh_fuel)"
rampCost "Wear and tear cost of ramping (/MW)"
inflow "Total annual inflow to a storage (MWh)"
resTimelim "How long should a storage be able to provide reserve (h)"
eff_from "Conversion efficiency from input energy to the conversion process (ratio)"
eff_fo "Conversion efficiency from the conversion process to the output energy (ratio)"
/
param_gnStorage "Set of possible data parameters for grid, node, storage" /
maxSpill "Maximum spill rate from storage (MWh/h)"
minSpill "Minimum spill rate from storage (MWh/h)"
maxContent "Maximum storage content (MWh)"
minContent "Minimum storage content (fraction of maximum)"
chargingEff "Average charging efficiency"
dischargingEff "Average discharging efficiency"
selfDischarge "Self discharge of storages (p.u.)"
/
param_fuel "Parateres for fuels" /
emissionIntensity "Intensity of emission from fuel (kg/MWh_fuel)"
main "Main fuel"
startup "Start-up fuel"
/
param_policy "Set of possible data parameters for grid, node, regulation" /
emissionTax "Emission tax (/tonne)"
/;
* --- Energy generation and consumption ---------------------------------------
Sets
unit "Set of generators, storages and loads"
gn(grid, node) "Nodes of the energy grids"
* NOTE! Should it be possible to permit time-series form upper or lower bounds on states? If so, then gn() needs rethinking.
gn2n(grid, node, node) "Transfer capacity between nodes in specific energy grids"
gnu(grid, node, unit) "Units in specific nodes of particular energy grids"
gnu_input(grid, node, unit) "Forms of energy the unit uses as endogenous inputs"
nu(node, unit) "Units attached to particular nodes. For units with multiple endogenous outputs only single (node, unit) combination allowed - with the primary grid node (affecting e.g. fuel use calculation with cV)"
nnu(node, node, unit) "Units that link two nodes"
gn_state(grid, node) "Nodes with a state variable"
gn_stateSlack(grid, node) "Nodes with a state slack variable"
gnn_state(grid, node, node) "Nodes with state variables interconnected via diffusion"
gnn_boundState(grid, node, node) "Nodes with state variables bound by other nodes"
storage "Storage"
gnStorage(grid, node, storage) "Storage units of certain energy type in specific nodes"
ggnu_fixedOutputRatio(grid, grid, node, unit) "Units with a fixed ratio between two different grids of output (e.g. backpressure)"
ggnu_constrainedOutputRatio(grid, grid, node, unit) "Units with a constrained ratio between two different grids of output (e.g. extraction)"
unit_elec(unit) "Units that generate and/or consume electricity"
unit_heat(unit) "Units that produce and/or consume unit_heat"
unit_VG(unit) "Unit that depend directly on variable energy flows (RoR, solar PV, etc.)"
unit_flow(unit) "Unit that depend directly on variable energy flows (RoR, solar PV, etc.)"
unit_withConstrainedOutputRatio(unit) "Units that use cV factor for their secondary output(s)"
unit_hydro(unit) "Hydropower generators"
* unit_hydro(unit) "Hydropower generators"
unit_fuel(unit) "Units using a commercial fuel"
unit_minLoad(unit) "Units that have unit commitment restrictions (e.g. minimum power level)"
unit_online(unit) "Units that have an online variable"
unit_aggregate(unit) "Aggregate units aggragating several units"
unit_noAggregate(unit) "Units that are not aggregated at all"
unit_slope(unit) "Units with piecewise linear efficiency constraints"
unit_noSlope(unit) "Units without piecewise linear efficiency constraints"
unitUnit_aggregate(unit, unit) "Aggregate unit linked to aggregated units"
flowUnit(flow, *) "Units or storages linked to a certain energy flow time series"
unitFuelParam(unit, fuel, param_fuel) "Fuel(s) used by the unit"
unitStorage(unit, storage) "Units attached to storages"
storage_hydro(storage) "Hydropower reservoirs"
storage_charging(storage) "Storages that cannot be charged (but may have inflow); used to remove v_stoCharge variables where not relevant"
storage_spill(storage) "Storages that cannot spill; used to remove v_spill variables where not relevant"
;
unittypeUnit(unittype, unit) "Link generation technologies to types"
uFuel(unit, param_fuel, fuel) "Units linked with fuels"
slopeUnit(slope, unit) "Piece-wise linear slope used by an unit"
*alias (generator, generator_);
alias(storage, storage_);
* --- Storages ---------------------------------------
* node_reservoir(node) "Hydropower reservoirs"
node_storage(node) "Nodes with storage capability (state variable)"
node_charging(node) "Storages that cannot be charged (but may have inflow); used to remove v_stoCharge variables where not relevant"
node_spill(node) "Storages that cannot spill; used to remove v_spill variables where not relevant"