Commit 347b2489 authored by Juha Kiviluoma's avatar Juha Kiviluoma
Browse files

Ramp, run-up and start-up constraints seem to work now

parent c6956581
......@@ -26,14 +26,15 @@ Model invest /
// Unit Equations
q_maxDownward
* q_noReserveInRunUp
q_maxUpward
q_startup
q_startuptype
q_onlineLimit
q_onlineMinUptime
* q_minDown
* q_startshut
* q_startuptype
* q_onlineOnStartUp
* q_offlineAfterShutDown
* q_onlineLimit
* q_onlineMinUptime
* q_genRamp
* q_genRampChange
* q_rampUpLimit
* q_rampDownLimit
q_outputRatioFixed
......
......@@ -26,18 +26,17 @@ Model schedule /
// Unit Equations
q_maxDownward
q_noReserveInRunUp
q_maxUpward
q_startup
q_startshut
q_startuptype
q_onlineLimit
q_onlineOnStartUp
q_offlineAfterShutDown
q_onlineMinUptime
* q_minDown
q_genRamp
* q_genRampChange
q_rampUpLimit
q_runUp
q_runUpLastInterval
* q_rampDownLimit
q_rampDownLimit
q_outputRatioFixed
q_outputRatioConstrained
q_conversionDirectInputOutput
......
......@@ -59,8 +59,10 @@ Parameters
p_gnugnu(grid, node, unit, grid, node, unit, param_gnugnu) "Data connecting units in nodes and grids"
p_uNonoperational(unit, starttype, min_max) "Non-operational time after being shut down before start up"
p_uStartup(unit, starttype, cost_consumption, unit_capacity) "Startup cost and fuel consumption"
p_uMaxRampInLastRunUpInterval(unit) "Ramp speed in the last interval for the run-up to min. load"
p_uRunUpTimeIntervals(unit) "Time intervals required for the run-up phase"
p_u_maxRampInLastRunUpInterval(unit) "Ramp speed in the last interval for the run-up to min. load"
p_u_runUpTimeIntervals(unit) "Time intervals required for the run-up phase"
p_ut_startup(unit, t)
p_ut_runUp(unit, t)
// 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"
......@@ -87,6 +89,7 @@ Parameters
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"
dtt(t, t) "Displacement needed to reach any previous time period (in time periods)"
// Forecast displacement arrays
df(f, t) "Displacement needed to reach the realized forecast on the current time step"
......
......@@ -148,7 +148,11 @@ unit_fuel(unit)${ sum(fuel, uFuel(unit, 'main', fuel)) }
// Units with special startup properties
// All units can cold start (default start category)
unitStarttype(unit, starttype('cold')) = yes;
unitStarttype(unit, starttype('cold'))${ p_unit(unit, 'startCostCold')
or p_unit(unit, 'startFuelConsCold')
or p_unit(unit, 'rampSpeedToMinLoad')
}
= yes;
// Units with parameters regarding hot/warm starts
unitStarttype(unit, starttypeConstrained)${ p_unit(unit, 'startWarmAfterXhours')
or p_unit(unit, 'startCostHot')
......
......@@ -32,7 +32,7 @@ SOS2 variables
;
Positive variables
v_fuelUse(fuel, unit, f, t) "Fuel use of a unit during time period (MWh_fuel)"
v_startup(unit, starttype, f, t) "Capacity started up after/during the time period/slice (MW)"
v_startup(unit, starttype, f, t) "Unit started up after/during the time period/slice (p.u.)"
v_shutdown(unit, f, t) "Capacity shut down after/during the time period/slice (MW)"
// v_genRampChange(grid, node, unit, up_down, f, t) "Rate of change in energy generation between time steps (MW/h)"
v_spill(grid, node, f, t) "Spill of energy from storage node during time period (MWh)"
......
This diff is collapsed.
......@@ -313,11 +313,22 @@ loop(m,
loop(m,
loop(unit$(p_unit(unit, 'rampSpeedToMinLoad') and p_unit(unit,'op00')),
p_unit(unit, 'rampSpeedToMinLoad') = p_unit(unit, 'rampSpeedToMinLoad');
tmp = [ p_unit(unit,'op00') / (p_unit(unit, 'rampSpeedToMinLoad') * 60) ] / mSettings(m, 'intervalInHours'); // rampToMinLoadInTimeIntervals
p_uRunUpTimeIntervals(unit) = tmp;
p_uMaxRampInLastRunUpInterval(unit) =
p_u_runUpTimeIntervals(unit) = tmp;
loop(t${ord(t)<=ceil(p_u_runUpTimeIntervals(unit))},
p_ut_runUp(unit, t)=p_unit(unit, 'rampSpeedToMinLoad') * (ceil(p_u_runUpTimeIntervals(unit) - ord(t) + 1));
);
p_u_maxRampInLastRunUpInterval(unit) =
+ p_unit(unit, 'rampSpeedToMinLoad') * (tmp-floor(tmp)) / mSettings(m, 'intervalInHours')
+ smin(gnu(grid, node, unit), p_gnu(grid, node, unit, 'maxRampUp')) * (ceil(tmp)-tmp) / mSettings(m, 'intervalInHours');
unitStarttype(unit, 'cold') = no;
unitStarttype(unit, 'cold')${ p_unit(unit, 'startCostCold')
or p_unit(unit, 'startFuelConsCold')
or p_u_runUpTimeIntervals(unit) > 1
or (p_u_runUpTimeIntervals(unit) <= 1 and p_u_maxRampInLastRunUpInterval(unit) < 1)
}
= yes;
) // END loop(unit)
); // END loop(m)
......
......@@ -64,7 +64,6 @@ $$iftheni.debug NOT '%debug%' == 'yes'
// Unit Operation
Option clear = q_maxDownward;
Option clear = q_maxUpward;
Option clear = q_startup;
Option clear = q_startuptype;
Option clear = q_onlineLimit;
Option clear = q_onlineMinUptime;
......@@ -451,3 +450,23 @@ loop(effLevelGroupUnit(effLevel, effGroup, unit)${ mSettingsEff(mSolve, effLeve
Option clear = p_msft_probability;
p_msft_probability(msft(mSolve, s, f, t))
= p_mfProbability(mSolve, f) / sum(f_${ft(f_, t)}, p_mfProbability(mSolve, f_)) * p_msProbability(mSolve, s);
Option clear = dtt;
dtt(t,t_)$(t_active(t) and (t_active(t_) or ord(t_) = tSolveFirst) and ord(t_)<=ord(t)) = sum(t__$(ord(t__)>ord(t_) and ord(t__) <= ord(t)), dt(t__));
Option clear = p_ut_startUp;
loop(unit$(p_u_runUpTimeIntervals(unit)),
loop(t$t_active(t),
tmp = 1;
loop(t_${t_active(t_) and ord(t_) <= ord(t) and tmp = 1},
if (-dtt(t,t_) < p_u_runUpTimeIntervals(unit),
p_ut_startup(unit, t) = dtt(t,t_+dt(t));
tmp = 0;
);
);
if (tmp = 1,
p_ut_startup(unit, t) = dt(t);
tmp=0;
);
);
);
......@@ -176,6 +176,21 @@ v_online_LP.up(uft_onlineLP(unit, f, t))${ not unit_investLP(unit) }
v_online_MIP.up(uft_onlineMIP(unit, f, t))${ not unit_investMIP(unit) }
= p_unit(unit, 'unitCount')
;
// v_startup cannot exceed untCount
v_startup.up(unitStarttype(unit, starttype), f, t)${uft_online(unit, f, t) and not unit_investLP(unit) }
= p_unit(unit, 'unitCount')
;
v_startup.up(unitStarttype(unit, starttype), f, t)${uft_online(unit, f, t) and not t_active(t-p_ut_startup(unit,t))} = 0;
//These might speed up, but they should be applied only to the new part of the horizon (should be explored)
*v_startup.l(unitStarttype(unit, starttype), f, t)${uft_online(unit, f, t) and not unit_investLP(unit) } = 0;
*v_shutdown.l(unit, f, t)${sum(starttype, unitStarttype(unit, starttype)) and uft_online(unit, f, t) and not unit_investLP(unit) } = 0;
// v_shutdown cannot exceed untCount
v_shutdown.up(uft_online(unit, f, t))${ not unit_investLP(unit) }
= p_unit(unit, 'unitCount')
;
* --- Energy Transfer Boundaries ----------------------------------------------
......@@ -411,9 +426,11 @@ loop(mft_start(mSolve, f, t),
// State and online variable initial values for the subsequent solves
v_state.fx(gn_state(grid, node), f, t)
= r_state(grid, node, f, t);
v_startup.fx(unitStarttype(unit, starttype), f, t)
= r_startup(unit, starttype, f, t);
); // END if(tSolveFirst)
) // END loop(mftStart)
); // END if(tSolveFirst)
) // END loop(mftStart)
;
// BoundStartToEnd
......
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