Commit a2e4270f authored by Niina Helistö's avatar Niina Helistö
Browse files

Adding shutdown trajectories for generating units.

parent 2ab312f0
......@@ -52,6 +52,10 @@ p_u_maxOutputInLastRunUpInterval
p_u_runUpTimeIntervals
dt_toStartup
p_ut_runUp
p_u_maxOutputInFirstShutdownInterval
p_u_shutdownTimeIntervals
dt_toShutdown
p_ut_shutdown
* Variables
v_obj
......
......@@ -284,6 +284,7 @@ param_unit "Set of possible data parameters for units" /
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)"
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"
minShutdownHours "Minimum shut down time (h), prevents starting up again after the defined amount of time has passed"
SO2 "SO2 emissions (tonne per MWh_fuel)"
......
......@@ -64,6 +64,10 @@ Parameters
p_u_runUpTimeIntervals(unit) "Time intervals required for the run-up phase"
p_u_runUpTimeIntervalsCeil(unit) "Ceiling of time intervals required for the run-up phase"
p_ut_runUp(unit, t) "Output for the time intervals 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_u_shutdownTimeIntervals(unit) "Time intervals required for the shutdown phase"
p_u_shutdownTimeIntervalsCeil(unit) "Ceiling of time intervals required for the shutdown phase"
p_ut_shutdown(unit, t) "Output for the time intervals where the unit is being shut down from the minimum load (minimum output in the first interval) (p.u.)"
// Time dependent unit & fuel parameters
ts_unit(unit, *, f, t) "Time dependent unit data, where energy type doesn't matter"
ts_effUnit(effSelector, unit, effSelector, *, f, t) "Time dependent data for piece-wise linear efficiency blocks"
......@@ -91,6 +95,7 @@ Parameters
dt_next(t) "Displacement needed to reach the next time period (in time periods)"
dtt(t, t) "Displacement needed to reach any previous time period (in time periods)"
dt_toStartup(unit, t) "Displacement from the current time period to the time period where the unit has been started up in case online variable changes from 0 to 1"
dt_toShutdown(unit, t) "Displacement from the current time period to the time period where the shutdown phase was started in case generation becomes 0"
dt_starttypeUnitCounter(starttype, unit, counter) "Displacement needed to account for starttype constraints"
dt_downtimeUnitCounter(unit, counter) "Displacement needed to account for downtime constraints"
dt_uptimeUnitCounter(unit, counter) "Displacement needed to account for uptime constraints"
......
......@@ -193,6 +193,22 @@ q_maxDownward(m, gnuft(grid, node, unit, f, t))${ [ ord(t) < tSolveFirst + m
) // END sum(unitStarttype)
)$p_u_runUpTimeIntervals(unit) // END sum(t_)
// Units that are in the shutdown phase need to keep up with the shutdown ramp rate (contained in p_ut_shutdown)
+ p_gnu(grid, node, unit, 'unitSizeGen')
* sum(t_activeNoReset(t_)${ ord(t_) >= ord(t) + dt_next(t) + dt_toShutdown(unit, t + dt_next(t))
and ord(t_) < ord(t) and uft_online(unit, f, t)},
+ v_shutdown(unit, f+df_central(f,t), t_)
* sum(t_full(t__)${ord(t__) = ord(t) - ord(t_) + 1},
+ p_ut_shutdown(unit, t__)
) // END sum(t__)
)$p_u_shutdownTimeIntervals(unit) // END sum(t_)
// Units that are in the first time interval of the shutdown phase are limited by the minimum load (contained in p_ut_shutdown(unit, 't00000'))
+ p_gnu(grid, node, unit, 'unitSizeGen')
* (
+ v_shutdown(unit, f+df_central(f,t), t)${uft_online(unit, f, t)}
* sum(t_full(t__)${ord(t__) = 1}, p_ut_shutdown(unit, t__))
)$p_u_shutdownTimeIntervals(unit) // END * p_gnu(unitSizeGen)
// Consuming units, greater than maxCons
// Available capacity restrictions
- p_unit(unit, 'availability')
......@@ -315,6 +331,22 @@ q_maxUpward(m, gnuft(grid, node, unit, f, t))${ [ ord(t) < tSolveFirst + mSett
+ v_startup(unit, starttype, f+df_central(f,t), t_) * p_u_maxOutputInLastRunUpInterval(unit)
) // END sum(unitStarttype)
)$p_u_runUpTimeIntervals(unit) // END sum(t_)
// Units that are in the shutdown phase need to keep up with the shutdown ramp rate (contained in p_ut_shutdown)
+ p_gnu(grid, node, unit, 'unitSizeGen')
* sum(t_activeNoReset(t_)${ ord(t_) >= ord(t) + dt_next(t) + dt_toShutdown(unit, t + dt_next(t))
and ord(t_) < ord(t) and uft_online(unit, f, t)},
+ v_shutdown(unit, f+df_central(f,t), t_)
* sum(t_full(t__)${ord(t__) = ord(t) - ord(t_) + 1},
+ p_ut_shutdown(unit, t__)
) // END sum(t__)
)$p_u_shutdownTimeIntervals(unit) // END sum(t_)
// Units that are in the first time interval of the shutdown phase are limited by p_u_maxOutputInFirstShutdownInterval
+ p_gnu(grid, node, unit, 'unitSizeGen')
* (
+ v_shutdown(unit, f+df_central(f,t), t)${uft_online(unit, f, t)}
* p_u_maxOutputInFirstShutdownInterval(unit)
)$p_u_shutdownTimeIntervals(unit) // END * p_gnu(unitSizeGen)
;
* --- Unit Startup and Shutdown -----------------------------------------------
......@@ -549,8 +581,31 @@ q_rampDownLimit(m, s, gnuft_ramp(grid, node, unit, f, t))${ ord(t) > msStart(m,
* p_gnu(grid, node, unit, 'maxRampDown')
* 60 // Unit conversion from [p.u./min] to [p.u./h]
// Shutdown of generation units from full load
- v_shutdown(unit, f+df_central(f,t), t)${uft_online(unit, f, t) and gnu_output(grid, node, unit)}
- v_shutdown(unit, f+df_central(f,t), t)${uft_online(unit, f, t) and gnu_output(grid, node, unit) and not p_u_shutdownTimeIntervals(unit)}
* p_gnu(grid, node, unit, 'unitSizeTot')
// Units that are in the shutdown phase need to keep up with the shutdown ramp rate (contained in p_ut_shutdown)
- p_gnu(grid, node, unit, 'unitSizeGen')
* sum(t_activeNoReset(t_)${ ord(t_) >= ord(t) + dt_toShutdown(unit, t)
and ord(t_) < ord(t) + dt(t) and uft_online(unit, f, t)},
+ v_shutdown(unit, f+df_central(f,t), t_)
* p_unit(unit, 'rampSpeedFromMinLoad')
* 60 // Unit conversion from [p.u./min] to [p.u./h]
)$p_u_shutdownTimeIntervals(unit) // END sum(t_)
// Units that are in the first time interval of the shutdown phase are limited by the p_u_maxOutputInFirstShutdownInterval
- p_gnu(grid, node, unit, 'unitSizeGen')
* (
+ v_shutdown(unit, f+df_central(f,t), t + dt(t))${uft_online(unit, f, t)}
* max(p_unit(unit, 'rampSpeedFromMinLoad'), p_gnu(grid, node, unit, 'maxRampDown')) // could also be weighted average from 'maxRampDown' and 'rampSpeedFromMinLoad'
* 60 // Unit conversion from [p.u./min] to [p.u./h]
)$p_u_shutdownTimeIntervals(unit) // END * p_gnu(unitSizeGen)
// Units just starting the shutdown phase are limited by the maxRampDown
- p_gnu(grid, node, unit, 'unitSizeGen')
* (
+ v_shutdown(unit, f+df_central(f,t), t)${uft_online(unit, f, t)}
* p_gnu(grid, node, unit, 'maxRampDown')
* 60 // Unit conversion from [p.u./min] to [p.u./h]
)$p_u_shutdownTimeIntervals(unit) // END * p_gnu(unitSizeGen)
;
* --- Ramps separated into upward and downward ramps --------------------------
......@@ -603,7 +658,7 @@ q_rampSlack(m, s, gnuft_rampCost(grid, node, unit, slack, f, t))${ ord(t) > msS
* p_gnuBoundaryProperties(grid, node, unit, slack, 'rampLimit')
* 60 // Unit conversion from [p.u./min] to [p.u./h]
// Units that are in the run-up phase need to keep up with the run-up ramp rate (contained in p_ut_runUp)
// Ramping of units that are in the run-up phase
+ p_gnu(grid, node, unit, 'unitSizeGen')
* sum(t_activeNoReset(t_)${ ord(t_) >= ord(t) + dt_next(t) + dt_toStartup(unit, t + dt_next(t))
and ord(t_) <= ord(t) and uft_online(unit, f, t)},
......@@ -620,11 +675,20 @@ q_rampSlack(m, s, gnuft_rampCost(grid, node, unit, slack, f, t))${ ord(t) > msS
* p_gnuBoundaryProperties(grid, node, unit, slack, 'rampLimit')
* 60 // Unit conversion from [p.u./min] to [p.u./h]
// Shutdown of generation units from full load
// Shutdown of generation units from full load and ramping of units in the beginning of the shutdown phase
+ v_shutdown(unit, f+df_central(f,t), t)${uft_online(unit, f, t) and gnu_output(grid, node, unit)}
* p_gnu(grid, node, unit, 'unitSizeTot')
* p_gnuBoundaryProperties(grid, node, unit, slack, 'rampLimit')
* 60 // Unit conversion from [p.u./min] to [p.u./h]
// Ramping of units that are in the shutdown phase
+ p_gnu(grid, node, unit, 'unitSizeGen')
* sum(t_activeNoReset(t_)${ ord(t_) >= ord(t) + dt_toShutdown(unit, t)
and ord(t_) <= ord(t) + dt(t) and uft_online(unit, f, t)},
+ v_shutdown(unit, f+df_central(f,t), t_)
* p_gnuBoundaryProperties(grid, node, unit, slack, 'rampLimit')
* 60 // Unit conversion from [p.u./min] to [p.u./h]
)$p_u_shutdownTimeIntervals(unit) // END sum(t_)
;
* --- Fixed Output Ratio ------------------------------------------------------
......@@ -673,7 +737,60 @@ q_conversionDirectInputOutput(suft(effDirect(effGroup), unit, f, t)) ..
+ v_fuelUse(fuel, unit, f, t)
) // END sum(uFuel)
// Is main fuel used also in the run-up phase when having directOnMIP or directOnLP?
// Main fuel is not used during run-up and shutdown phases
+ [
// Units that are in the run-up phase need to keep up with the run-up ramp rate (contained in p_ut_runUp)
+ sum(gnu_output(grid, node, unit)$p_u_runUpTimeIntervals(unit),
+ p_gnu(grid, node, unit, 'unitSizeGen')
) // END sum(gnu_output)
* sum(t_activeNoReset(t_)${ ord(t_) > ord(t) + dt_next(t) + dt_toStartup(unit, t + dt_next(t))
and ord(t_) <= ord(t) and uft_online(unit, f, t)
},
+ sum(unitStarttype(unit, starttype),
+ v_startup(unit, starttype, f+df_central(f,t), t_)
* sum(t_full(t__)${ ord(t__) = p_u_runUpTimeIntervalsCeil(unit) - ord(t) - dt_next(t) + 1 + ord(t_) }, // last step in the interval
+ p_ut_runUp(unit, t__)
) // END sum(t__)
) // END sum(unitStarttype)
) // END sum(t_)
// Units that are in the last time interval of the run-up phase are limited by the minimum load (contained in p_ut_runUp(unit, 't00000'))
+ sum(gnu_output(grid, node, unit)$p_u_runUpTimeIntervals(unit),
+ p_gnu(grid, node, unit, 'unitSizeGen')
) // END sum(gnu_output)
* sum(t_activeNoReset(t_)${ ord(t_) = ord(t) + dt_next(t) + dt_toStartup(unit, t + dt_next(t))
and uft_online(unit, f, t)
},
+ sum(unitStarttype(unit, starttype),
+ v_startup(unit, starttype, f+df_central(f,t), t_)
* sum(t_full(t__)${ord(t__) = 1}, p_ut_runUp(unit, t__))
) // END sum(unitStarttype)
) // END sum(t_)
// Units that are in the shutdown phase need to keep up with the shutdown ramp rate (contained in p_ut_shutdown)
+ sum(gnu_output(grid, node, unit)$p_u_shutdownTimeIntervals(unit),
+ p_gnu(grid, node, unit, 'unitSizeGen')
) // END sum(gnu_output)
* sum(t_activeNoReset(t_)${ ord(t_) >= ord(t) + dt_next(t) + dt_toShutdown(unit, t + dt_next(t))
and ord(t_) < ord(t) and uft_online(unit, f, t)},
+ v_shutdown(unit, f+df_central(f,t), t_)
* sum(t_full(t__)${ord(t__) = ord(t) - ord(t_) + 1},
+ p_ut_shutdown(unit, t__)
) // END sum(t__)
) // END sum(t_)
// Units that are in the first time interval of the shutdown phase are limited by the minimum load (contained in p_ut_shutdown(unit, 't00000'))
+ sum(gnu_output(grid, node, unit)$p_u_shutdownTimeIntervals(unit),
+ p_gnu(grid, node, unit, 'unitSizeGen')
) // END sum(gnu_output)
* (
+ v_shutdown(unit, f+df_central(f,t), t)${uft_online(unit, f, t)}
* sum(t_full(t__)${ord(t__) = 1}, p_ut_shutdown(unit, t__))
) // END * p_gnu(unitSizeGen)
] // END run-up and shutdown phases
* [ // Heat rate
+ p_effUnit(effGroup, unit, effGroup, 'slope')${ not ts_effUnit(effGroup, unit, effGroup, 'slope', f, t) }
+ ts_effUnit(effGroup, unit, effGroup, 'slope', f, t)
] // END * v_gen
=E=
......@@ -796,6 +913,26 @@ q_conversionSOS2IntermediateOutput(suft(effLambda(effGroup), unit, f, t)) ..
) // END sum(unitStarttype)
) // END sum(t_)
// Units that are in the shutdown phase need to keep up with the shutdown ramp rate (contained in p_ut_shutdown)
+ sum(gnu_output(grid, node, unit)$p_u_shutdownTimeIntervals(unit),
+ p_gnu(grid, node, unit, 'unitSizeGen')
) // END sum(gnu_output)
* sum(t_activeNoReset(t_)${ ord(t_) >= ord(t) + dt_next(t) + dt_toShutdown(unit, t + dt_next(t))
and ord(t_) < ord(t) and uft_online(unit, f, t)},
+ v_shutdown(unit, f+df_central(f,t), t_)
* sum(t_full(t__)${ord(t__) = ord(t) - ord(t_) + 1},
+ p_ut_shutdown(unit, t__)
) // END sum(t__)
) // END sum(t_)
// Units that are in the first time interval of the shutdown phase are limited by the minimum load (contained in p_ut_shutdown(unit, 't00000'))
+ sum(gnu_output(grid, node, unit)$p_u_shutdownTimeIntervals(unit),
+ p_gnu(grid, node, unit, 'unitSizeGen')
) // END sum(gnu_output)
* (
+ v_shutdown(unit, f+df_central(f,t), t)${uft_online(unit, f, t)}
* sum(t_full(t__)${ord(t__) = 1}, p_ut_shutdown(unit, t__))
) // END * p_gnu(unitSizeGen)
=E=
// Energy output into v_gen
......
......@@ -327,6 +327,39 @@ loop(m,
) // END loop(unit)
); // END loop(m)
loop(m,
loop(unit$(p_unit(unit, 'rampSpeedFromMinLoad') and p_unit(unit,'op00')),
// Calculate time intervals needed for the shutdown phase
tmp = [ p_unit(unit,'op00') / (p_unit(unit, 'rampSpeedFromMinLoad') * 60) ] / mSettings(m, 'intervalInHours');
p_u_shutdownTimeIntervals(unit) = tmp;
p_u_shutdownTimeIntervalsCeil(unit) = ceil(p_u_shutdownTimeIntervals(unit))
// Calculate output during the shutdown phase
loop(t${ord(t)<=p_u_shutdownTimeIntervalsCeil(unit)},
p_ut_shutdown(unit, t) =
+ p_unit(unit, 'rampSpeedFromMinLoad') * (ceil(p_u_shutdownTimeIntervals(unit) - ord(t) + 1))
* 60 // Unit conversion from [p.u./min] to [p.u./h]
* mSettings(m, 'intervalInHours')
);
// Combine output in the second interval and the weighted average of rampSpeedFromMinLoad and maxRampDown
p_u_maxOutputInFirstShutdownInterval(unit) =
(
+ p_unit(unit, 'rampSpeedFromMinLoad') * (tmp-floor(tmp)) * mSettings(m, 'intervalInHours')
+ smin(gnu(grid, node, unit), p_gnu(grid, node, unit, 'maxRampDown')) * (ceil(tmp)-tmp) * mSettings(m, 'intervalInHours')
)
* 60 // Unit conversion from [p.u./min] to [p.u./h]
+ sum(t${ord(t) = 2}, p_ut_shutdown(unit, t));
// Maximum output in the first time interval of the shutdown phase can't exceed the maximum capacity
p_u_maxOutputInFirstShutdownInterval(unit) = min(p_u_maxOutputInFirstShutdownInterval(unit), 1);
// Minimum output in the first time interval of the shutdown phase equals minimum load
p_ut_shutdown(unit, t)${ord(t) = 1} = p_unit(unit,'op00');
) // END loop(unit)
); // END loop(m)
loop(m,
// Loop over units with online approximations in the model
loop(effLevelGroupUnit(effLevel, effOnline(effGroup), unit)${mSettingsEff(m, effLevel)},
......
......@@ -503,3 +503,31 @@ loop(unit$(p_u_runUpTimeIntervals(unit)),
);
);
);
* -----------------------------------------------------------------------------
* --- Displacements for shutdown decisions ------------------------------------
* -----------------------------------------------------------------------------
// Calculate dt_toShutdown: in case the generation of the unit becomes zero in
// the current time period, displacement needed to reach the time period where
// the shutdown decisions was made
Option clear = dt_toShutdown;
loop(unit$(p_u_shutdownTimeIntervals(unit)),
loop(t_active(t),
tmp = 1;
loop(t_activeNoReset(t_)${ ord(t_) > ord(t) - p_u_shutdownTimeIntervals(unit) // time periods after the shutdown decision
and ord(t_) <= ord(t) // time periods before and including the current time period
and tmp = 1
},
if (-dtt(t,t_) < p_u_shutdownTimeIntervals(unit), // if the displacement between the two time periods is smaller than the number of time periods required for shutdown phase
dt_toShutdown(unit, t) = dtt(t,t_ + dt_noReset(t_)); // the displacement to the active or realized time period just before the time period found
tmp = 0;
);
);
if (tmp = 1,
dt_toShutdown(unit, t) = dt(t);
tmp=0;
);
);
);
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