Commit 35d18b0b authored by Topi Rasku's avatar Topi Rasku
Browse files

Merge branch 'trtopi_performance' into dev

# Conflicts:
#	inc/3c_inputsLoop.gms
parents 3d26c2a9 99aecde1
......@@ -79,8 +79,10 @@ v_sos2
v_spill
v_online_LP
v_online_MIP
v_startup
v_shutdown
v_startup_LP
v_startup_MIP
v_shutdown_LP
v_shutdown_MIP
v_genRampUpDown
v_transferRightward
v_transferLeftward
......
......@@ -94,6 +94,7 @@ Sets
tt_block(counter, t) "Temporary time step subset for storing the time interval blocks"
tt_interval(t) "Temporary time steps when forming the ft structure, current sample"
tt_forecast(t) "Temporary subset for time steps used for forecast updating during solve loop"
tt_aggregate(t, t) "Time steps included in each active time step for time series aggregation"
mf(mType, f) "Forecasts present in the models"
ms(mType, s) "Samples present in the models"
mst_start(mType, s, t) "Start point of samples"
......
......@@ -110,7 +110,7 @@ Parameters
dt(t) "Displacement needed to reach the previous time interval (in time steps)"
dt_circular(t) "Circular t displacement if the time series data is not long enough to cover the model horizon"
dt_next(t) "Displacement needed to reach the next time interval (in time steps)"
dtt(t, t) "Displacement needed to reach any previous time interval (in time steps)"
dt_active(t) "Displacement needed to reach the corresponding active time interval from any time interval (in time steps)"
dt_toStartup(unit, t) "Displacement from the current time interval to the time interval where the unit was started up in case online variable changes from 0 to 1 (in time steps)"
dt_toShutdown(unit, t) "Displacement from the current time interval to the time interval where the shutdown phase began in case generation becomes 0 (in time steps)"
dt_starttypeUnitCounter(starttype, unit, counter) "Displacement needed to account for starttype constraints (in time steps)"
......
......@@ -23,6 +23,8 @@ Free variables
v_transfer(grid, node, node, s, f, t) "Average electricity transmission level from node to node during an interval (MW)"
;
Integer variables
v_startup_MIP(unit, starttype, s, f, t) "Sub-units started up after/during an interval (p.u.), (MIP variant)"
v_shutdown_MIP(unit, s, f, t) "Sub-units shut down after/during an interval (p.u.) (MIP variant)"
v_online_MIP(unit, s, f, t) "Number of sub-units online for units with unit commitment restrictions"
v_invest_MIP(unit, t) "Number of invested sub-units"
v_investTransfer_MIP(grid, node, node, t) "Number of invested transfer links"
......@@ -35,8 +37,8 @@ SOS2 variables
;
Positive variables
v_fuelUse(fuel, unit, s, f, t) "Fuel use of a unit during an interval (MWh_fuel)"
v_startup(unit, starttype, s, f, t) "Sub-units started up after/during an interval (p.u.)"
v_shutdown(unit, s, f, t) "Sub-units shut down after/during an interval (p.u.)"
v_startup_LP(unit, starttype, s, f, t) "Sub-units started up after/during an interval (p.u.), (LP variant)"
v_shutdown_LP(unit, s, f, t) "Sub-units shut down after/during an interval (p.u.) (LP variant)"
v_genRampUpDown(grid, node, unit, slack, s, f, t) "Change in energy generation or consumption over an interval, separated into different 'slacks' (MW/h)"
v_spill(grid, node, s, f, t) "Spill of energy from storage node during an interval (MWh)"
v_transferRightward(grid, node, node, s, f, t) "Average electricity transmission level from the first node to the second node during an interval (MW)"
......
......@@ -89,7 +89,10 @@ q_obj ..
// Start-up costs, initial startup free as units could have been online before model started
+ sum(uft_online(unit, f, t),
+ sum(unitStarttype(unit, starttype),
+ v_startup(unit, starttype, s, f, t) // Cost of starting up
+ [ // Unit startup variables
+ v_startup_LP(unit, starttype, s, f, t)${ uft_onlineLP(unit, f, t) }
+ v_startup_MIP(unit, starttype, s, f, t)${ uft_onlineMIP(unit, f, t) }
]
* [ // Startup variable costs
+ p_uStartup(unit, starttype, 'cost')
......@@ -111,7 +114,13 @@ q_obj ..
// Shut-down costs, initial shutdown free?
+ sum(uft_online(unit, f, t),
+ v_shutdown(unit, s, f, t) * p_uShutdown(unit, 'cost')
+ p_uShutdown(unit, 'cost')
* [
+ v_shutdown_LP(unit, s, f, t)
${ uft_onlineLP(unit, f, t) }
+ v_shutdown_MIP(unit, s, f, t)
${ uft_onlineMIP(unit, f, t) }
]
) // END sum(uft_online)
// Ramping costs
......
This diff is collapsed.
......@@ -36,8 +36,10 @@ Option clear = v_help_inc;
Option clear = v_sos2;
// Positive Variables
Option clear = v_fuelUse;
Option clear = v_startup;
Option clear = v_shutdown;
Option clear = v_startup_LP;
Option clear = v_startup_MIP;
Option clear = v_shutdown_LP;
Option clear = v_shutdown_MIP;
Option clear = v_genRampUpDown;
Option clear = v_spill;
Option clear = v_transferRightward;
......@@ -157,6 +159,7 @@ $endif
// Initialize the set of active t:s, counters and interval time steps
Option clear = t_active;
Option clear = dt_active;
Option clear = tt_block;
Option clear = cc;
tCounter = 1;
......@@ -213,14 +216,17 @@ loop(cc(counter),
// If stepsPerInterval equals one, simply use all the steps within the block
if(mInterval(mSolve, 'stepsPerInterval', counter) = 1,
tt_interval(tt(t)) = yes; // Include all time steps within the block
// Include all time steps within the block
tt_interval(tt(t)) = yes;
// If stepsPerInterval exceeds 1 (stepsPerInterval < 1 not defined)
elseif mInterval(mSolve, 'stepsPerInterval', counter) > 1,
tt_interval(tt(t)) // Select the active time steps within the block
${mod(ord(t) - tSolveFirst - tCounter,
mInterval(mSolve, 'stepsPerInterval', counter)) = 0
} = yes;
// Calculate the displacement required to reach the corresponding active time step from any time step
dt_active(tt(t)) = - (mod(ord(t) - tSolveFirst - tCounter, mInterval(mSolve, 'stepsPerInterval', counter)));
// Select the active time steps within the block
tt_interval(tt(t))${ not dt_active(t) } = yes;
); // END ELSEIF intervalLenght
......@@ -257,8 +263,6 @@ loop(cc(counter),
and ord(t) <= tSolveFirst + currentForecastLength
} = yes;
// Set of locked combinations of forecasts and intervals for the reserves?
// Update tActive
t_active(tt_interval) = yes;
......@@ -434,7 +438,9 @@ loop(ms(mSolve, s),
); // END loop(ms)
// Displacement from the first interval of a sample to the previous interval is always -1,
// except for stochastic samples
dt(t)${sum(ms(mSolve, s)$(not ms_central(mSolve, s)), mst_start(mSolve, s, t))} = -1;
dt(t_active(t))
${ sum(ms(mSolve, s)$(not ms_central(mSolve, s)), mst_start(mSolve, s, t)) }
= -1;
// Forecast index displacement between realized and forecasted intervals
// NOTE! This set cannot be reset without references to previously solved time steps in the stochastic tree becoming ill-defined!
......@@ -489,6 +495,14 @@ ft_reservesFixed(node, restype, f_solve(f), t_active(t))
}
= yes;
// Form a temporary clone of t_current
option clear = tt;
tt(t_current) = yes;
// Group each full time step under each active time step for time series aggregation.
option clear = tt_aggregate;
tt_aggregate(t_current(t+dt_active(t)), tt(t))
= yes;
* =============================================================================
* --- Defining unit aggregations and ramps ------------------------------------
* =============================================================================
......@@ -586,43 +600,29 @@ Option clear = uft_startupTrajectory;
Option clear = uft_shutdownTrajectory;
// Determine the intervals when units need to follow start-up and shutdown trajectories.
loop(uft_online(unit, f, t)${ p_u_runUpTimeIntervals(unit) },
uft_startupTrajectory(unit, f, t)${ord(t) <= tSolveFirst + mSettings(mSolve, 't_trajectoryHorizon')}
loop(runUpCounter(unit, 'c000'), // Loop over units with meaningful run-ups
uft_startupTrajectory(uft_online(unit, f, t))
${ ord(t) <= tSolveFirst + mSettings(mSolve, 't_trajectoryHorizon') }
= yes;
); // END loop(uf_online)
loop(uft_online(unit, f, t)${ p_u_shutdownTimeIntervals(unit) },
uft_shutdownTrajectory(unit, f, t)${ord(t) <= tSolveFirst + mSettings(mSolve, 't_trajectoryHorizon')}
); // END loop(runUpCounter)
loop(shutdownCounter(unit, 'c000'), // Loop over units with meaningful shutdowns
uft_shutdownTrajectory(uft_online(unit, f, t))
${ ord(t) <= tSolveFirst + mSettings(mSolve, 't_trajectoryHorizon') }
= yes;
); // END loop(uf_online)
); // END loop(shutdownCounter)
* -----------------------------------------------------------------------------
* --- Displacements for start-up and shutdown decisions -----------------------
* -----------------------------------------------------------------------------
// Form a temporary clone of the t_active set
Option clear = tt;
tt(t_active(t)) = yes;
// Calculate dtt: displacement needed to reach any previous time interval
// (needed to calculate dt_toStartup and dt_toShutdown)
Option clear = dtt;
dtt(t_active(t), tt(t_))
${ ord(t_) <= ord(t) }
= ord(t_) - ord(t);
* --- Start-up decisions ------------------------------------------------------
// 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(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)
dt_toStartup(unit, t_active(t))
= - p_u_runUpTimeIntervalsCeil(unit) + dt_active(t - p_u_runUpTimeIntervalsCeil(unit));
); // END loop(runUpCounter)
* --- Shutdown decisions ------------------------------------------------------
......@@ -632,13 +632,8 @@ loop(runUpCounter(unit, 'c000'), // Loop over units with meaningful run-ups
// the shutdown decisions was made
Option clear = dt_toShutdown;
loop(shutdownCounter(unit, 'c000'), // Loop over units with meaningful shutdowns
loop(t_active(t),
dt_toShutdown(unit, tt(t_)) // tt still used as a clone of t_active (see above)
${ 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)
dt_toShutdown(unit, t_active(t))
= - p_u_shutdownTimeIntervalsCeil(unit) + dt_active(t - p_u_shutdownTimeIntervalsCeil(unit))
); // END loop(runUpCounter)
* --- Historical Unit LP and MIP information ----------------------------------
......
......@@ -299,127 +299,87 @@ loop(cc(counter),
// Retrieve interval block time steps
option clear = tt_interval;
tt_interval(t) = tt_block(counter, t);
// Make a temporary clone of tt_interval(t)
option clear = tt_;
tt_(tt_interval) = yes;
// If stepsPerInterval equals one, simply use all the steps within the block
if(mInterval(mSolve, 'stepsPerInterval', counter) = 1,
* --- Select time series data matching the intervals, for stepsPerInterval = 1, this is trivial.
loop(ft(f_solve(f), tt_interval(t)),
ts_unit_(unit_timeseries(unit), param_unit, f, t) // Only if time series enabled for the unit
= ts_unit(unit, param_unit, f, t+dt_circular(t));
$ontext
* Should these be handled here at all? See above comment
ts_effUnit_(effGroupSelectorUnit(effSelector, unit_timeseries(unit), effSelector), param_eff, f_solve, t)
= ts_effUnit(effSelector, unit, effSelector, param_eff, f_solve, t+dt_circular(t));
ts_effGroupUnit_(effSelector, unit_timeseries(unit), param_eff, f_solve, t)
= ts_effGroupUnit(effSelector, unit, param_eff, f_solve, t+dt_circular(t));
$offtext
ts_cf_(flowNode(flow, node), fts(f, t, s))
= ts_cf(flow, node, f + (df_scenario(f, t)$gn_scenarios(flow, node, 'ts_cf')),
t + (dt_scenarioOffset(flow, node, 'ts_cf', s)
+ dt_circular(t)$(not gn_scenarios(flow, node, 'ts_cf'))));
ts_influx_(gn(grid, node), fts(f, t, s))
= ts_influx(grid, node, f + (df_scenario(f, t)$gn_scenarios(grid, node, 'ts_node')),
t + (dt_scenarioOffset(grid, node, 'ts_influx', s)
+ dt_circular(t)$(not gn_scenarios(grid, node, 'ts_influx'))));
// Reserve demand relevant only up until reserve_length
ts_reserveDemand_(restypeDirectionNode(restype, up_down, node), f, t)
${ord(t) <= tSolveFirst + p_nReserves(node, restype, 'reserve_length')}
= ts_reserveDemand(restype, up_down, node,
f + (df_scenario(f,t)$gn_scenarios(restype, node, 'ts_reserveDemand')),
t+dt_circular(t));
ts_node_(gn_state(grid, node), param_gnBoundaryTypes, fts(f, t, s))
$p_gnBoundaryPropertiesForStates(grid, node, param_gnBoundaryTypes, 'useTimeseries')
= ts_node(grid, node, param_gnBoundaryTypes,
f + (df_scenario(f, t)$gn_scenarios(grid, node, 'ts_node')),
t + (dt_scenarioOffset(grid, node, param_gnBoundaryTypes, s)
+ dt_circular(t)$(not gn_scenarios(grid, node, 'ts_node'))));
// Fuel price time series
ts_fuelPrice_(fuel, t)
${ p_fuelPrice(fuel, 'useTimeSeries') }
= ts_fuelPrice(fuel, t+dt_circular(t));
); // END loop(ft)
* --- If stepsPerInterval exceeds 1 (stepsPerInterval < 1 not defined) --------
elseif mInterval(mSolve, 'stepsPerInterval', counter) > 1,
// Select and average time series data matching the intervals, for stepsPerInterval > 1
// Loop over the t:s of the interval
loop(ft(f_solve(f), tt_interval(t)),
// Select t:s within the interval
Option clear = tt;
tt(tt_(t_))
${ ord(t_) >= ord(t)
and ord(t_) < ord(t) + mInterval(mSolve, 'stepsPerInterval', counter)
}
= yes;
ts_unit_(unit_timeseries(unit), param_unit, f, t)
= sum(tt(t_), ts_unit(unit, param_unit, f, t_+dt_circular(t_)))
/ mInterval(mSolve, 'stepsPerInterval', counter);
// Select and average time series data matching the intervals
ts_unit_(unit_timeseries(unit), param_unit, ft(f, tt_interval(t)))
= sum(tt_aggregate(t, t_),
ts_unit(unit, param_unit, f, t_+dt_circular(t_))
)
/ mInterval(mSolve, 'stepsPerInterval', counter);
$ontext
* Should these be handled here at all? See above comment
ts_effUnit_(effGroupSelectorUnit(effSelector, unit_timeseries(unit), effSelector), param_eff, f_solve, t)
= sum(tt(t_), ts_effUnit(effSelector, unit, effSelector, param_eff, f_solve, t_+dt_circular(t_))))
/ mInterval(mSolve, 'stepsPerInterval', counter);
ts_effGroupUnit_(effSelector, unit_timeseries(unit), param_eff, f_solve, t)
= sum(tt(t_), ts_effGroupUnit(effSelector, unit, param_eff, f_solve, t_+dt_circular(t_))))
/ mInterval(mSolve, 'stepsPerInterval', counter);
ts_effUnit_(effGroupSelectorUnit(effSelector, unit_timeseries(unit), effSelector), param_eff, ft(f, tt_interval(t)))
= sum(tt_aggregate(t, t_),
ts_effUnit(effSelector, unit, effSelector, param_eff, f, t_+dt_circular(t_))
)
/ mInterval(mSolve, 'stepsPerInterval', counter);
ts_effGroupUnit_(effSelector, unit_timeseries(unit), param_eff, ft(f, tt_interval(t)))
= sum(tt_aggregate(t, t_),
ts_effGroupUnit(effSelector, unit, param_eff, f, t_+dt_circular(t_))
)
/ mInterval(mSolve, 'stepsPerInterval', counter);
$offtext
ts_influx_(gn(grid, node), fts(f, t, s))
= sum(tt(t_), ts_influx(grid, node,
f + (df_scenario(f, t)$gn_scenarios(grid, node, 'ts_influx')),
t_ + (dt_scenarioOffset(grid, node, 'ts_influx', s)
+ dt_circular(t_)$(not gn_scenarios(grid, node, 'ts_influx')))))
/ mInterval(mSolve, 'stepsPerInterval', counter);
ts_cf_(flowNode(flow, node), fts(f, t, s))
= sum(tt(t_), ts_cf(flow, node,
f + (df_scenario(f, t)$gn_scenarios(flow, node, 'ts_cf')),
t_ + (dt_scenarioOffset(flow, node, 'ts_cf', s)
+ dt_circular(t_)$(not gn_scenarios(flow, node, 'ts_cf')))))
/ mInterval(mSolve, 'stepsPerInterval', counter);
// Reserves relevant only until reserve_length
ts_reserveDemand_(restypeDirectionNode(restype, up_down, node), f, t)
${ord(t) <= tSolveFirst + p_nReserves(node, restype, 'reserve_length') }
= sum(tt(t_), ts_reserveDemand(restype, up_down, node,
f + (df_scenario(f, t)$gn_scenarios(restype, node, 'ts_reserveDemand')),
t_+ dt_circular(t_)))
/ mInterval(mSolve, 'stepsPerInterval', counter);
ts_node_(gn_state(grid, node), param_gnBoundaryTypes, fts(f, t, s))
$p_gnBoundaryPropertiesForStates(grid, node, param_gnBoundaryTypes, 'useTimeseries')
// Take average if not a limit type
= (sum(tt(t_), ts_node(grid, node, param_gnBoundaryTypes,
f + (df_scenario(f, t)$gn_scenarios(grid, node, 'ts_node')),
t_ + (dt_scenarioOffset(grid, node, param_gnBoundaryTypes, s)
+ dt_circular(t_)$(not gn_scenarios(grid, node, 'ts_node')))))
/ mInterval(mSolve, 'stepsPerInterval', counter))$(not (sameas(param_gnBoundaryTypes, 'upwardLimit')
or sameas(param_gnBoundaryTypes, 'downwardLimit')
or slack(param_gnBoundaryTypes)))
// Maximum lower limit
+ smax(tt(t_), ts_node(grid, node, param_gnBoundaryTypes,
f + (df_scenario(f, t)$gn_scenarios(grid, node, 'ts_node')),
t_ + (dt_scenarioOffset(grid, node, param_gnBoundaryTypes, s)
+ dt_circular(t_)$(not gn_scenarios(grid, node, 'ts_node')))))
$(sameas(param_gnBoundaryTypes, 'downwardLimit') or downwardSlack(param_gnBoundaryTypes))
// Minimum upper limit
+ smin(tt(t_), ts_node(grid, node, param_gnBoundaryTypes,
f + (df_scenario(f, t)$gn_scenarios(grid, node, 'ts_node')),
t_ + (dt_scenarioOffset(grid, node, param_gnBoundaryTypes, s)
+ dt_circular(t_)$(not gn_scenarios(grid, node, 'ts_node')))))
$(sameas(param_gnBoundaryTypes, 'upwardLimit') or upwardSlack(param_gnBoundaryTypes));
// Fuel price time series
ts_fuelPrice_(fuel, t)
${ p_fuelPrice(fuel, 'useTimeSeries') }
= sum(tt(t_), ts_fuelPrice(fuel, t_+dt_circular(t_)))
/ mInterval(mSolve, 'stepsPerInterval', counter);
); // END loop(ft)
); // END if(stepsPerInterval)
ts_influx_(gn(grid, node), fts(f, tt_interval(t), s))
= sum(tt_aggregate(t, t_),
ts_influx(grid, node,
f + (df_scenario(f, t)$gn_scenarios(grid, node, 'ts_influx')),
t_+ ( + dt_scenarioOffset(grid, node, 'ts_influx', s)
+ dt_circular(t_)$(not gn_scenarios(grid, node, 'ts_influx'))))
)
/ mInterval(mSolve, 'stepsPerInterval', counter);
ts_cf_(flowNode(flow, node), fts(f, tt_interval(t), s))
= sum(tt_aggregate(t, t_),
ts_cf(flow, node,
f + (df_scenario(f, t)$gn_scenarios(flow, node, 'ts_cf')),
t_+ ( + dt_scenarioOffset(flow, node, 'ts_cf', s)
+ dt_circular(t_)$(not gn_scenarios(flow, node, 'ts_cf'))))
)
/ mInterval(mSolve, 'stepsPerInterval', counter);
// Reserves relevant only until reserve_length
ts_reserveDemand_(restypeDirectionNode(restype, up_down, node), ft(f, tt_interval(t)))
${ord(t) <= tSolveFirst + p_nReserves(node, restype, 'reserve_length') }
= sum(tt_aggregate(t, t_),
ts_reserveDemand(restype, up_down, node,
f + (df_scenario(f, t)$gn_scenarios(restype, node, 'ts_reserveDemand')),
t_+ dt_circular(t_))
)
/ mInterval(mSolve, 'stepsPerInterval', counter);
ts_node_(gn_state(grid, node), param_gnBoundaryTypes, fts(f, tt_interval(t), s))
$p_gnBoundaryPropertiesForStates(grid, node, param_gnBoundaryTypes, 'useTimeseries')
// Take average if not a limit type
= (sum(tt_aggregate(t, t_),
ts_node(grid, node, param_gnBoundaryTypes,
f + (df_scenario(f, t)$gn_scenarios(grid, node, 'ts_node')),
t_+ ( + dt_scenarioOffset(grid, node, param_gnBoundaryTypes, s)
+ dt_circular(t_)$(not gn_scenarios(grid, node, 'ts_node'))))
)
/ mInterval(mSolve, 'stepsPerInterval', counter))$( not (sameas(param_gnBoundaryTypes, 'upwardLimit')
or sameas(param_gnBoundaryTypes, 'downwardLimit')
or slack(param_gnBoundaryTypes)))
// Maximum lower limit
+ smax(tt_aggregate(t, t_),
ts_node(grid, node, param_gnBoundaryTypes,
f + (df_scenario(f, t)$gn_scenarios(grid, node, 'ts_node')),
t_+ ( + dt_scenarioOffset(grid, node, param_gnBoundaryTypes, s)
+ dt_circular(t_)$(not gn_scenarios(grid, node, 'ts_node'))))
)
$(sameas(param_gnBoundaryTypes, 'downwardLimit') or downwardSlack(param_gnBoundaryTypes))
// Minimum upper limit
+ smin(tt_aggregate(t, t_),
ts_node(grid, node, param_gnBoundaryTypes,
f + (df_scenario(f, t)$gn_scenarios(grid, node, 'ts_node')),
t_+ ( + dt_scenarioOffset(grid, node, param_gnBoundaryTypes, s)
+ dt_circular(t_)$(not gn_scenarios(grid, node, 'ts_node'))))
)
$(sameas(param_gnBoundaryTypes, 'upwardLimit') or upwardSlack(param_gnBoundaryTypes));
// Fuel price time series
ts_fuelPrice_(fuel, tt_interval(t))
${ p_fuelPrice(fuel, 'useTimeSeries') }
= sum(tt_aggregate(t, t_),
+ ts_fuelPrice(fuel, t_+dt_circular(t_))
)
/ mInterval(mSolve, 'stepsPerInterval', counter);
); // END loop(counter)
* --- Process unit time series data -------------------------------------------
......@@ -486,6 +446,7 @@ This avoids a discontinuity `jump' after the initial sample.
$offtext
// Do smoothing
<<<<<<< HEAD
if(mSettings(mSolve, 'scenarios'), // Only do smooting if using long-term scenarios
// Select the initial sample, first `t` not in it and `f` of the last `t` in it
loop((ms_initial(mSolve, s_), t_, ft(f_, t__))
......@@ -494,4 +455,4 @@ if(mSettings(mSolve, 'scenarios'), // Only do smooting if using long-term scena
$$batinclude 'inc/smoothing.gms' ts_influx
$$batinclude 'inc/smoothing.gms' ts_cf
);
);
\ No newline at end of file
); // END if('scenarios')
\ No newline at end of file
......@@ -187,28 +187,28 @@ v_gen.up(gnu_output(grid, node, unit), sft(s, f, t))${gnuft(grid, node, unit, f,
// Ramping capability of units not part of investment set
// NOTE: Apply the corresponding equations only to units with investment possibility,
// online variable, or reserve provision
loop(sft(s, f, t)$(ord(t) > msStart(mSolve, s) + 1),
v_genRamp.up(grid, node, unit, s, f, t)${gnuft_ramp(grid, node, unit, f, t)
and p_gnu(grid, node, unit, 'maxRampUp')
and not uft_online(unit, f, t)
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')
* 60; // Unit conversion from [p.u./min] to [p.u./h]
v_genRamp.lo(grid, node, unit, s, f, t)${gnuft_ramp(grid, node, unit, f, t)
and p_gnu(grid, node, unit, 'maxRampDown')
and not uft_online(unit, f, t)
and not unit_investLP(unit)
and not unit_investMIP(unit)
and not uft_shutdownTrajectory(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')
* 60; // Unit conversion from [p.u./min] to [p.u./h]
);
v_genRamp.up(gnu(grid, node, unit), sft(s, f, t))${ ord(t) > msStart(mSolve, s) + 1
and gnuft_ramp(grid, node, unit, f, t)
and p_gnu(grid, node, unit, 'maxRampUp')
and not uft_online(unit, f, t)
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')
* 60; // Unit conversion from [p.u./min] to [p.u./h]
v_genRamp.lo(gnu(grid, node, unit), sft(s, f, t))${ ord(t) > msStart(mSolve, s) + 1
and gnuft_ramp(grid, node, unit, f, t)
and p_gnu(grid, node, unit, 'maxRampDown')
and not uft_online(unit, f, t)
and not unit_investLP(unit)
and not unit_investMIP(unit)
and not uft_shutdownTrajectory(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')
* 60; // Unit conversion from [p.u./min] to [p.u./h]
// v_online cannot exceed unit count if investments disabled
// LP variant
......@@ -226,25 +226,49 @@ v_online_MIP.up(unit, sft(s, f, t))${uft_onlineMIP(unit, f, t) and not unit_inve
]
;
$ontext
// NOTE! These are unnecessary?
// Free the upper bound of start-up and shutdown variables (if previously bounded)
v_startup.up(unitStarttype(unit, starttype), sft(s, f, t)) = inf;
v_startup_LP.up(unitStarttype(unit, starttype), sft(s, f, t))
${ uft_onlineLP(unit, f, t) }
= inf;
v_startup_MIP.up(unitStarttype(unit, starttype), sft(s, f, t))
${ uft_onlineMIP(unit, f, t) }
= inf;
v_shutdown.up(unit, sft(s, f, t))$uft(unit, f, t) = inf;
$offtext
// v_startup cannot exceed unitCount
v_startup.up(unitStarttype(unit, starttype), sft(s, f, t))${ uft_online(unit, f, t)
and not unit_investLP(unit)
and not unit_investMIP(unit)
}
= p_unit(unit, 'unitCount')
;
v_startup_LP.up(unitStarttype(unit, starttype), sft(s, f, t))
${ uft_onlineLP(unit, f, t)
and not unit_investLP(unit)
and not unit_investMIP(unit)
}
= p_unit(unit, 'unitCount');
v_startup_MIP.up(unitStarttype(unit, starttype), sft(s, f, t))
${ uft_onlineMIP(unit, f, t)
and not unit_investLP(unit)
and not unit_investMIP(unit)
}
= p_unit(unit, 'unitCount');
// v_shutdown cannot exceed unitCount
v_shutdown.up(unit, sft(s, f, t))${uft_online(unit, f, t)
and not unit_investLP(unit)
and not unit_investMIP(unit)}
= p_unit(unit, 'unitCount')
;
v_shutdown_LP.up(unit, sft(s, f, t))
${ uft_onlineLP(unit, f, t)
and not unit_investLP(unit)
and not unit_investMIP(unit)}
= p_unit(unit, 'unitCount');
// v_shutdown cannot exceed unitCount
v_shutdown_MIP.up(unit, sft(s, f, t))
${ uft_onlineMIP(unit, f, t)
and not unit_investLP(unit)
and not unit_investMIP(unit)}
= p_unit(unit, 'unitCount');
// !!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The following limits are extremely slow, and shouldn't strictly be required.
// Commenting them out for now at least.
$ontext
// Cannot start a unit if the time when the unit would become online is outside
// the horizon when the unit has an online variable
v_startup.up(unitStarttype(unit, starttype), sft(s, f, t))${ uft_online(unit, f, t)
......@@ -259,7 +283,7 @@ v_shutdown.up(unit, sft(s, f, t))${uft_online(unit, f, t)
and not sum(t_active(t_)${ord(t) = ord(t_) + dt_toShutdown(unit,t_)}, uft_online(unit, f, t_))
}
= 0;
$offtext
//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;
......@@ -439,8 +463,10 @@ loop((mft_start(mSolve, f, t), ms_initial(mSolve, s)),
= 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;
v_startup_LP.fx(unitStarttype(unit_online_LP, starttype), s, f, t) = 0;
v_startup_MIP.fx(unitStarttype(unit_online_MIP, starttype), s, f, t) = 0;
v_shutdown_LP.fx(unit_online_LP, s, f, t) = 0;
v_shutdown_MIP.fx(unit_online_LP, s, f, t) = 0;
else // For all other solves, fix the initial state values based on previous results.
......@@ -463,16 +489,20 @@ loop((mft_start(mSolve, f, t), ms_initial(mSolve, s)),
// Needed for modelling hot and warm start-ups, minimum uptimes and downtimes, and run-up and shutdown phases.
if( tSolveFirst <> mSettings(mSolve, 't_start'), // Avoid rewriting the fixes on the first solve handled above
v_startup.fx(unitStarttype(unit, starttype), sft_realizedNoReset(s, f, t_active(t)))
${ ord(t) <= tSolveFirst // Only fix previously realized time steps
and unit_online(unit) // Check if the unit has an online variable on the first effLevel
}
v_startup_LP.fx(unitStarttype(unit_online_LP(unit), starttype), sft_realizedNoReset(s, f, t_active(t)))
${ ord(t) <= tSolveFirst } // Only fix previously realized time steps
= r_startup(unit, starttype, f, t);
v_shutdown.fx(unit, sft_realizedNoReset(s, f, t_active(t)))
${ ord(t) <= tSolveFirst // Only fix previously realized time steps
and unit_online(unit) // Check if the unit has an online variable on the first effLevel
}
v_startup_MIP.fx(unitStarttype(unit_online_MIP(unit), starttype), sft_realizedNoReset(s, f, t_active(t)))
${ ord(t) <= tSolveFirst } // Only fix previously realized time steps
= r_startup(unit, starttype, f, t);
v_shutdown_LP.fx(unit_online_LP(unit), sft_realizedNoReset(s, f, t_active(t)))
${ ord(t) <= tSolveFirst } // Only fix previously realized time steps
= r_shutdown(unit, f, t);
v_shutdown_MIP.fx(unit_online_MIP(unit), sft_realizedNoReset(s, f, t_active(t)))
${ ord(t) <= tSolveFirst } // Only fix previously realized time steps
= r_shutdown(unit, f, t);
v_online_MIP.fx(unit, sft_realizedNoReset(s, f, t_active(t)))
......
......@@ -49,10 +49,12 @@ loop(sft_realized(s, f, t),
;
// Unit startup and shutdown history
r_startup(unit, starttype, f, t)${ uft_online(unit, f, t) and [ord(t) > mSettings(mSolve, 't_start') + mSettings(mSolve, 't_initializationPeriod')] }
= v_startup.l(unit, starttype, s, f, t)
= v_startup_LP.l(unit, starttype, s, f, t)${ uft_onlineLP(unit, f, t) }
+ v_startup_MIP.l(unit, starttype, s, f, t)${ uft_onlineMIP(unit, f, t) }
;
r_shutdown(uft_online(unit, f, t))$[ord(t) > mSettings(mSolve, 't_start') + mSettings(mSolve, 't_initializationPeriod')]
= v_shutdown.l(unit, s, f, t)
= v_shutdown_LP.l(unit, s, f, t)${ uft_onlineLP(unit, f, t) }
+ v_shutdown_MIP.l(unit, s, f, t)${ uft_onlineMIP(unit, f, t) }
;
);
......
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