Commit bf51d464 authored by Topi Rasku's avatar Topi Rasku
Browse files

Issue #32: Run-up and shutdown trajectories overhauled to permit SOS2 ramping...

Issue #32: Run-up and shutdown trajectories overhauled to permit SOS2 ramping on the last/first run-up/shutdown intervals, as well as include main fuel consumption during run-up/shutdown. However, this formulation still fails to consider changing interval lengths.
parent f3085dca
......@@ -57,11 +57,11 @@ p_uStartup
p_u_maxOutputInLastRunUpInterval
p_u_runUpTimeIntervals
dt_toStartup
p_ut_runUp
p_uCounter_runUp
p_u_maxOutputInFirstShutdownInterval
p_u_shutdownTimeIntervals
dt_toShutdown
p_ut_shutdown
p_uCounter_shutdown
* Variables
v_obj
......
......@@ -143,7 +143,9 @@ Sets
effLevelGroupUnit(effLevel, effSelector, unit) "What efficiency selectors are in use for each unit at each efficiency representation level"
effGroupSelectorUnit(effSelector, unit, effSelector) "Group name for efficiency selector set, e.g. Lambda02 contains Lambda01 and Lambda02"
mSettingsReservesInUse(mType, *, up_down) "Reserves that are used in each model type"
unitCounter(unit, counter) "Counter subset used for restricting excessive looping over the counter set when defining unit startup/shutdown/online time restrictions"
unitCounter(unit, counter) "Counter used for restricting excessive looping over the counter set when defining unit startup/shutdown/online time restrictions"
runUpCounter(unit, counter) "Counter used for unit run-up intervals"
shutdownCounter(unit, counter) "Counter used for unit shutdown intervals"
* --- Sets used for grouping of units, transfer links, nodes, etc. ------------
group "A group of units, transfer links, nodes, etc."
......
......@@ -68,11 +68,11 @@ Parameters
p_u_maxRampSpeedInLastRunUpInterval(unit) "Maximum ramp speed in the last interval for the run-up to min. load (p.u.)"
p_u_runUpTimeIntervals(unit) "Time steps required for the run-up phase"
p_u_runUpTimeIntervalsCeil(unit) "Ceiling of time steps required for the run-up phase"
p_ut_runUp(unit, t) "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_runUp(unit, counter) "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_u_shutdownTimeIntervals(unit) "Time steps required for the shutdown phase"
p_u_shutdownTimeIntervalsCeil(unit) "Ceiling of time steps required for the shutdown phase"
p_ut_shutdown(unit, t) "Output for the time steps where the unit is being shut down from the minimum load (minimum output in the first interval) (p.u.)"
p_u_shutdownTimeIntervalsCeil(unit) "Floor of time steps required for the shutdown phase"
p_uCounter_shutdown(unit, counter) "Output for the time steps 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"
......@@ -105,6 +105,7 @@ Parameters
dt_starttypeUnitCounter(starttype, unit, counter) "Displacement needed to account for starttype constraints (in time steps)"
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"
// Forecast displacement arrays
......
This diff is collapsed.
......@@ -413,34 +413,25 @@ loop(m,
// Calculate time intervals needed for the run-up phase
tmp = [ p_unit(unit,'op00') / (p_unit(unit, 'rampSpeedToMinLoad') * 60) ] / mSettings(m, 'stepLengthInHours');
p_u_runUpTimeIntervals(unit) = tmp;
p_u_runUpTimeIntervalsCeil(unit) = ceil(p_u_runUpTimeIntervals(unit))
// Calculate output during the run-up phase
loop(t${ord(t)<=p_u_runUpTimeIntervalsCeil(unit)},
p_ut_runUp(unit, t) =
+ p_unit(unit, 'rampSpeedToMinLoad') * (ceil(p_u_runUpTimeIntervals(unit) - ord(t)) + 0.5)
* 60 // Unit conversion from [p.u./min] to [p.u./h]
* mSettings(m, 'stepLengthInHours')
);
// Combine output in the second last interval and the weighted average of rampSpeedToMinLoad and the smallest non-zero maxRampUp
p_u_maxOutputInLastRunUpInterval(unit) =
(
+ p_unit(unit, 'rampSpeedToMinLoad') * (tmp-floor(tmp)) * mSettings(m, 'stepLengthInHours')
+ smin(gnu(grid, node, unit)${p_gnu(grid, node, unit, 'maxRampUp')}, p_gnu(grid, node, unit, 'maxRampUp')) * (ceil(tmp)-tmp) * mSettings(m, 'stepLengthInHours')
+ p_unit(unit, 'rampSpeedToMinLoad')${not sum(gnu(grid, node, unit), p_gnu(grid, node, unit, 'maxRampUp'))} * (ceil(tmp)-tmp) * mSettings(m, 'stepLengthInHours')
)
* 60 // Unit conversion from [p.u./min] to [p.u./h]
+ sum(t${ord(t) = 2}, p_ut_runUp(unit, t));
// Maximum output in the last time interval of the run-up phase can't exceed the maximum capacity
p_u_maxOutputInLastRunUpInterval(unit) = min(p_u_maxOutputInLastRunUpInterval(unit), 1);
// Maximum ramp speed in the last time interval of the run-phasae is equal to maximum output after the time period minus the output on the previous time period in the run-up phase
p_u_maxRampSpeedInLastRunUpInterval(unit) = p_u_maxOutputInLastRunUpInterval(unit) - sum(t$[ord(t) = 2], p_ut_runUp(unit, t));
// Minimum output in the last time interval of the run-up phase equals minimum load
p_ut_runUp(unit, t)${ord(t) = 1} = p_unit(unit,'op00');
p_u_runUpTimeIntervalsCeil(unit) = ceil(p_u_runUpTimeIntervals(unit));
runUpCounter(unit, counter) // Store the required number of run-up intervals for each unit
${ ord(counter) <= p_u_runUpTimeIntervalsCeil(unit) }
= yes;
dt_trajectory(counter)
${ runUpCounter(unit, counter) }
= - ord(counter) + 1; // Runup starts immediately at v_startup
// Calculate output during the run-up phase; partial intervals calculated using weighted averaging with min load
p_uCounter_runUp(runUpCounter(unit, counter))
= + p_unit(unit, 'rampSpeedToMinLoad')
* ( + min(ord(counter), p_u_runUpTimeIntervals(unit)) // Location on ramp
- 0.5 * min(p_u_runUpTimeIntervals(unit) - ord(counter) + 1, 1) // Average ramp section
)
* min(p_u_runUpTimeIntervals(unit) - ord(counter) + 1, 1) // Portion of time interval spent ramping
* mSettings(m, 'stepLengthInHours') // Ramp length in hours
* 60 // unit conversion from [p.u./min] to [p.u./h]
+ max(ord(counter) - p_u_runUpTimeIntervals(unit), 0) // Portion of time interval spent at min load
* p_unit(unit, 'op00');
); // END loop(unit)
); // END loop(m)
......@@ -452,39 +443,30 @@ loop(m,
// Calculate time intervals needed for the shutdown phase
tmp = [ p_unit(unit,'op00') / (p_unit(unit, 'rampSpeedFromMinLoad') * 60) ] / mSettings(m, 'stepLengthInHours');
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, 'stepLengthInHours')
);
// Combine output in the second interval and the weighted average of rampSpeedFromMinLoad and the smallest non-zero maxRampDown
p_u_maxOutputInFirstShutdownInterval(unit) =
(
+ p_unit(unit, 'rampSpeedFromMinLoad') * (tmp-floor(tmp)) * mSettings(m, 'stepLengthInHours')
+ smin(gnu(grid, node, unit)${p_gnu(grid, node, unit, 'maxRampDown')}, p_gnu(grid, node, unit, 'maxRampDown')) * (ceil(tmp)-tmp) * mSettings(m, 'stepLengthInHours')
+ p_unit(unit, 'rampSpeedFromMinLoad')${not sum(gnu(grid, node, unit), p_gnu(grid, node, unit, 'maxRampDown'))} * (ceil(tmp)-tmp) * mSettings(m, 'stepLengthInHours')
)
* 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');
p_u_shutdownTimeIntervalsCeil(unit) = ceil(p_u_shutdownTimeIntervals(unit));
shutdownCounter(unit, counter) // Store the required number of shutdown intervals for each unit
${ ord(counter) <= p_u_shutDownTimeIntervalsCeil(unit) + 1} // Shutdown phase requires one zero generation interval at it's end due to ramp constraints
= yes;
dt_trajectory(counter)
${ shutdownCounter(unit, counter) }
= - ord(counter) + 1; // Shutdown starts immediately at v_shutdown
// Calculate output during the shutdown phase; partial intervals calculated using weighted average with zero load
p_uCounter_shutdown(shutdownCounter(unit, counter))${ shutdownCounter(unit, counter+1)} // Value is zero at the last shutdown counter
= p_unit(unit, 'op00') // Minimum load load
- p_unit(unit, 'rampSpeedFromMinLoad')
* ( + min(ord(counter), p_u_shutdownTimeIntervals(unit)) // Location on ramp
- 0.5 * min(p_u_shutdownTimeIntervals(unit) - ord(counter) + 1, 1) // Average ramp section
)
* min(p_u_shutdownTimeIntervals(unit) - ord(counter) + 1, 1) // Portion of time interval spent ramping
* mSettings(m, 'stepLengthInHours') // Ramp length in hours
* 60 // unit conversion from [p.u./min] to [p.u./h]
- p_unit(unit, 'op00') * max(ord(counter) - p_u_runUpTimeIntervals(unit), 0); // Portion of time interval spent without generation
) // END loop(unit)
); // END loop(unit)
); // END loop(m)
* --- Unit Startup and Shutdown Counters --------------------------------------
// Initialize unitCounter
Option clear = unitCounter;
* --- Unit Starttype, Uptime and Downtime Counters ----------------------------
loop(m,
// Loop over units with online approximations in the model
......
......@@ -589,24 +589,15 @@ dtt(t_active(t), tt(t_))
// Calculate dt_toStartup: in case the unit becomes online in the current time interval,
// displacement needed to reach the time interval where the unit was started up
Option clear = dt_toStartup;
loop(unit$(p_u_runUpTimeIntervals(unit)),
loop(t_active(t)${sum(f_solve(f), uft_startupTrajectory(unit, f, t))},
tmp = 1;
loop(tt(t_)${ ord(t_) > ord(t) - p_u_runUpTimeIntervals(unit) // time intervals after the start up
and ord(t_) <= ord(t) // time intervals before and including the current time interval
and tmp = 1
},
if (-dtt(t,t_) < p_u_runUpTimeIntervals(unit), // if the displacement between the two time intervals is smaller than the number of time steps required for start-up phase
dt_toStartup(unit, t) = dtt(t,t_ + dt(t_)); // the displacement to the active or realized time interval just before the time interval found
tmp = 0;
);
);
if (tmp = 1,
dt_toStartup(unit, t) = dt(t);
tmp=0;
);
);
);
loop(runUpCounter(unit, 'c000'), // Loop over units with meaningful run-ups
loop(t_active(t),
dt_toStartup(unit, tt(t_)) // tt still used as a clone of t_active (see above)
${ dtt(t_, t) > - p_u_runUpTimeIntervalsCeil(unit)
and dtt(t_, t+dt(t)) <= - p_u_runUpTimeIntervalsCeil(unit)
}
= dtt(t_, t+dt(t));
); // END loop(t_active)
); // END loop(runUpCounter)
* --- Shutdown decisions ------------------------------------------------------
......@@ -614,24 +605,16 @@ loop(unit$(p_u_runUpTimeIntervals(unit)),
// the current time interval, displacement needed to reach the time interval where
// the shutdown decisions was made
Option clear = dt_toShutdown;
loop(unit$(p_u_shutdownTimeIntervals(unit)),
loop(t_active(t)${sum(f_solve(f), uft_shutdownTrajectory(unit, f, t))},
tmp = 1;
loop(tt(t_)${ ord(t_) > ord(t) - p_u_shutdownTimeIntervals(unit) // time intervals after the shutdown decision
and ord(t_) <= ord(t) // time intervals before and including the current time interval
and tmp = 1
},
if (-dtt(t,t_) < p_u_shutdownTimeIntervals(unit), // if the displacement between the two time intervals is smaller than the number of time steps required for shutdown phase
dt_toShutdown(unit, t) = dtt(t,t_ + dt(t_)); // the displacement to the active or realized time interval just before the time interval found
tmp = 0;
);
);
if (tmp = 1,
dt_toShutdown(unit, t) = dt(t);
tmp=0;
);
);
);
loop(shutdownCounter(unit, 'c000'), // Loop over units with meaningful shutdowns
loop(t_active(t)${sum(f_solve, uft_shutdownTrajectory(unit, f_solve, t))},
dt_toShutdown(unit, tt(t_)) // tt still used as a clone of t_active (see above)
${ sum(f_solve, uft_startupTrajectory(unit, f_solve, t_))
and dtt(t_, t) > - p_u_shutdownTimeIntervalsCeil(unit)
and dtt(t_, t+dt(t)) <= -p_u_shutdownTimeIntervalsCeil(unit)
}
= dtt(t_, t+dt(t));
); // END loop(t_active)
); // END loop(runUpCounter)
* --- Historical Unit LP and MIP information ----------------------------------
......
......@@ -194,6 +194,7 @@ loop(ms(mSolve, s),
and p_gnu(grid, node, unit, 'maxRampUp')
and not unit_investLP(unit)
and not unit_investMIP(unit)
and not uft_startupTrajectory(unit, f, t) // Trajectories require occasional combinations with 'rampSpeedToMinLoad'
}
= ( p_gnu(grid, node, unit, 'maxGen') + p_gnu(grid, node, unit, 'maxCons') )
* p_gnu(grid, node, unit, 'maxRampUp')
......@@ -204,6 +205,7 @@ loop(ms(mSolve, s),
and p_gnu(grid, node, unit, 'maxRampDown')
and not unit_investLP(unit)
and not unit_investMIP(unit)
and not uft_startupTrajectory(unit, f, t) // Trajectories require occasional combinations with 'rampSpeedFromMinLoad'
}
= -( p_gnu(grid, node, unit, 'maxGen') + p_gnu(grid, node, unit, 'maxCons'))
* p_gnu(grid, node, unit, 'maxRampDown')
......@@ -432,6 +434,9 @@ loop((mft_start(mSolve, f, t), ms_initial(mSolve, s)),
v_gen.fx(grid, node, unit, s, f, t)${p_gnu(grid, node, unit, 'useInitialGeneration')}
= p_gnu(grid, node, unit, 'initialGeneration');
// Startup and shutdown variables are not applicable at the first time step
v_startup.fx(unitStarttype(unit, starttype), s, f, t) = 0;
v_shutdown.fx(unit, s, f, t) = 0;
else // For all other solves, fix the initial state values based on previous results.
......
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