Commit 7a856a42 authored by Niina Helistö's avatar Niina Helistö
Browse files

Various small changes, mostly to comments

parent c3e9b043
......@@ -65,13 +65,14 @@ v_transfer
v_state
v_fuelUse
v_sos2
v_startup
v_spill
v_online_LP
v_online_MIP
v_startup
v_shutdown
v_genRampUpDown
v_transferRightward
v_transferLeftward
v_resTransferRightward
v_resTransferLeftward
v_reserve
......@@ -120,7 +121,18 @@ v_invest_MIP
q_boundStateMaxDiff
q_boundCyclic
// Policy
q_inertiaMin
q_instantaneousShareMax
q_constrainedOnlineMultiUnit
q_capacityMargin
q_constrainedCapMultiUnit
q_emissioncap
q_energyShareMax
q_energyShareMin
* Dummy variables
vq_gen
vq_resDemand
vq_resMissing
v_stateSlack
......@@ -38,6 +38,12 @@ loop(m,
= yes;
* --- Samples and Forecasts ---------------------------------------------------
$ontext
// Check that forecast length is feasible
if(mSettings(m, 't_forecastLength') > mSettings(m, 't_horizon'),
abort "t_forecastLength should be less than or equal to t_horizon";
);
$offtext
// Set the time for the next available forecast.
tForecastNext(m) = mSettings(m, 't_forecastStart');
......@@ -283,7 +289,11 @@ loop(m,
);
);
* --- Unit Startup and Shutdown Counters --------------------------------------
* =============================================================================
* --- Initialize Unit Startup and Shutdown Counters ---------------------------
* =============================================================================
* --- Unit Start-up Generation Levels -----------------------------------------
loop(m,
loop(unit$(p_unit(unit, 'rampSpeedToMinLoad') and p_unit(unit,'op00')),
......@@ -327,6 +337,8 @@ loop(m,
) // END loop(unit)
); // END loop(m)
* --- Unit Shutdown Generation Levels -----------------------------------------
loop(m,
loop(unit$(p_unit(unit, 'rampSpeedFromMinLoad') and p_unit(unit,'op00')),
// Calculate time intervals needed for the shutdown phase
......@@ -360,12 +372,14 @@ loop(m,
) // END loop(unit)
); // END loop(m)
* --- Unit Startup and Shutdown Counters --------------------------------------
loop(m,
// Loop over units with online approximations in the model
loop(effLevelGroupUnit(effLevel, effOnline(effGroup), unit)${mSettingsEff(m, effLevel)},
// Loop over the constrained starttypes
// Loop over the constrained start types
loop(starttypeConstrained(starttype),
// Find the time step displacements needed to define the startup time frame
// Find the time step displacements needed to define the start-up time frame
Option clear = cc;
cc(counter)${ ord(counter) <= p_uNonoperational(unit, starttype, 'max') / mSettings(m, 'intervalInHours')
and ord(counter) > p_uNonoperational(unit, starttype, 'min') / mSettings(m, 'intervalInHours')
......@@ -374,9 +388,12 @@ loop(m,
dt_starttypeUnitCounter(starttype, unit, cc(counter)) = - ord(counter);
); // END loop(starttypeConstrained)
// Find the time step displacements needed to define the downtime requirements (include run-up phase)
// Find the time step displacements needed to define the downtime requirements (include run-up phase and shutdown phase)
Option clear = cc;
cc(counter)${ ord(counter) <= ceil(p_unit(unit, 'minShutdownHours') / mSettings(m, 'intervalInHours')) + ceil(p_u_runUpTimeIntervals(unit)) }
cc(counter)${ ord(counter) <= ceil(p_unit(unit, 'minShutdownHours') / mSettings(m, 'intervalInHours'))
+ ceil(p_u_runUpTimeIntervals(unit))
+ ceil(p_u_shutdownTimeIntervals(unit))
}
= yes;
dt_downtimeUnitCounter(unit, cc(counter)) = - ord(counter);
......@@ -402,17 +419,6 @@ loop(fuel,
ts_fuelPrice(fuel, t_full(t)) = sum(tt(t_)${ ord(t_) <= ord(t) }, ts_fuelPriceChange(fuel, t_));
); // END loop(fuel)
* --- Calculating fuel price time series --------------------------------------
loop(fuel,
// Determine the time steps where the prices change
Option clear = tt;
tt(t_full(t))${ ts_fuelPriceChange(fuel, t) }
= yes;
// Calculate the fuel price time series based on the input price changes
ts_fuelPrice(fuel, t_full(t)) = sum(tt(t_)${ ord(t_) <= ord(t) }, ts_fuelPriceChange(fuel, t_));
); // END loop(fuel)
* --- Slack Direction ---------------------------------------------------------
// Upwards slack is positive, downward slack negative
......
......@@ -99,6 +99,7 @@ $iftheni.debug NOT '%debug%' == 'yes'
// Policy
Option clear = q_inertiaMin;
Option clear = q_instantaneousShareMax;
Option clear = q_constrainedOnlineMultiUnit;
Option clear = q_capacityMargin;
Option clear = q_constrainedCapMultiUnit;
Option clear = q_emissioncap;
......@@ -121,11 +122,14 @@ $iftheni.debug NOT '%debug%' == 'yes'
$endif.debug
* =============================================================================
* --- Determine the forecast-time indeces included in the current solve -------
* --- Determine the forecast-intervals included in the current solve ----------
* =============================================================================
// Determine the timesteps of the current solve
// Determine the time steps of the current solve
tSolveFirst = ord(tSolve); // tSolveFirst: the start of the current solve, t0 used only for initial values
// Is there any case where t_forecastLength should be larger than t_horizon?
// If not, add a check for mSettings(mSolve, 't_forecastLength') <= mSettings(mSolve, 't_horizon')
// and change the line below to 'tSolveLast = ord(tSolve) + mSettings(mSolve, 't_horizon');'
tSolveLast = ord(tSolve) + max(mSettings(mSolve, 't_forecastLength'), mSettings(mSolve, 't_horizon')); // tSolveLast: the end of the current solve
Option clear = t_current;
t_current(t_full(t))${ ord(t) >= tSolveFirst
......@@ -142,16 +146,16 @@ Option clear = mft;
Option clear = ft;
Option clear = mft_nReserves;
// Initialize the set of active time steps and counters
// Initialize the set of active t:s and counters
Option clear = t_active;
Option clear = cc;
tCounter = 1;
// Determine the set of active interval counters
// Determine the set of active interval counters (or blocks of intervals)
cc(counter)${ mInterval(mSolve, 'intervalLength', counter) }
= yes;
// Loop over the defined intervals
// Loop over the defined blocks of intervals
loop(cc(counter),
// Loop over defined samples
loop(ms(mSolve, s),
......@@ -159,20 +163,20 @@ loop(cc(counter),
// Initialize tInterval
Option clear = tt_interval;
// If intervalLength equals one, simply use all the steps within the interval
// If intervalLength equals one, simply use all the steps within the block
if(mInterval(mSolve, 'intervalLength', counter) = 1,
tt_interval(t_current(t))${ ord(t) >= tSolveFirst + tCounter
and ord(t) < min(tSolveFirst + mInterval(mSolve, 'intervalEnd', counter), tSolveLast)
and ord(t) > msStart(mSolve, s) + tSolveFirst - 1 // Move the samples along with the dispatch
and ord(t) < msEnd(mSolve, s) + tSolveFirst // Move the samples along with the dispatch
}
= yes; // Include all time steps within the interval
= yes; // Include all time steps within the block
// Calculate the time step length in hours
// Calculate the interval length in hours
p_stepLength(mf(mSolve, f_solve), tt_interval(t)) = mSettings(mSolve, 'intervalInHours');
p_stepLengthNoReset(mf(mSolve, f_solve), tt_interval(t)) = mSettings(mSolve, 'intervalInHours');
// Determine the forecast-time steps
// Determine the combinations of forecasts and intervals
// Include the t_jump for the realization
msft(msf(mSolve, s, f_solve), tt_interval(t))${ ord(t) <= tSolveFirst + mSettings(mSolve, 't_jump')
and mf_realization(mSolve, f_solve)
......@@ -194,7 +198,7 @@ loop(cc(counter),
// Reduce the sample dimension
mft(mf(mSolve, f_solve), tt_interval(t)) = msft(mSolve, s, f_solve, t);
// Set of locked forecast-time steps for the reserves
// Set of locked combinations of forecasts and intervals for the reserves
mft_nReserves(node, restype, mf_realization(mSolve, f), tt_interval(t))${ p_nReserves(node, restype, 'update_frequency')
and p_nReserves(node, restype, 'gate_closure')
and ord(t) > tSolveFirst + p_nReserves(node, restype, 'gate_closure') - mod(tSolveFirst - 1, p_nReserves(node, restype, 'update_frequency'))
......@@ -229,11 +233,11 @@ loop(cc(counter),
}
= yes;
// Length of the time step in hours
// Calculate the interval length in hours
p_stepLength(mf(mSolve, f_solve), tt_interval(t)) = mInterval(mSolve, 'intervalLength', counter) * mSettings(mSolve, 'intervalInHours');
p_stepLengthNoReset(mf(mSolve, f_solve), tt_interval(t)) = mInterval(mSolve, 'intervalLength', counter) * mSettings(mSolve, 'intervalInHours');
// Determine the forecast-time steps
// Determine the combinations of forecasts and intervals
// Include the t_jump for the realization
msft(msf(mSolve, s, f_solve), tt_interval(t))${ ord(t) <= tSolveFirst + mSettings(mSolve, 't_jump')
and mf_realization(mSolve, f_solve)
......@@ -255,6 +259,8 @@ loop(cc(counter),
// Reduce the sample dimension
mft(mf(mSolve, f_solve), tt_interval(t)) = msft(mSolve, s, f_solve, t);
// Set of locked combinations of forecasts and intervals for the reserves?
// Reduce the model dimension
ft(f_solve, tt_interval(t)) = mft(mSolve, f_solve, t)
......@@ -292,14 +298,14 @@ loop(cc(counter),
// Abort if intervalLength is less than one
elseif mInterval(mSolve, 'intervalLength', counter) < 1, abort "intervalLength < 1 is not defined!"
); // END IF intervalLenght
); // END IF intervalLenght
// Update tActive
t_active(tt_interval) = yes;
); // END loop(ms)
// Update tCounter for the next interval
// Update tCounter for the next block of intervals
tCounter = mInterval(mSolve, 'intervalEnd', counter);
); // END loop(counter)
......@@ -323,8 +329,8 @@ loop(t_active(t),
option clear = dt_next;
loop(t_active(t),
dt_next(t)
= sum(f$mf(mSolve, f), p_stepLength(mSolve, f, t))
/ sum(f${mf(mSolve, f) and p_stepLength(mSolve, f, t)}, 1)
= sum(f_solve$mf(mSolve, f_solve), p_stepLength(mSolve, f_solve, t))
/ sum(f_solve${mf(mSolve, f_solve) and p_stepLength(mSolve, f_solve, t)}, 1)
/ mSettings(mSolve, 'intervalInHours');
); // END loop(t_active)
......@@ -370,7 +376,7 @@ df_nReserves(node, restype, ft(f, t))${ p_nReserves(node, restype, 'update_frequ
* --- Defining unit aggregations and ramps ------------------------------------
* =============================================================================
// Units active on each forecast-time step
// Units active on each ft
Option clear = uft;
uft(unit, ft(f, t))${ [
ord(t) <= tSolveFirst + mSettings(mSolve, 't_aggregate') - 1
......@@ -384,23 +390,23 @@ uft(unit, ft(f, t))${ [
// only units with capacities or investment option
= yes;
// Active units in nodes on each forecast-time step
// Active units in nodes on each ft
Option clear = nuft;
nuft(nu(node, unit), ft(f, t))${ uft(unit, f, t) }
= yes
;
// Active (grid, node, unit) on each forecast-time step
// Active (grid, node, unit) on each ft
Option clear = gnuft;
gnuft(gn(grid, node), uft(unit, f, t))${ nuft(node, unit, f, t) }
= yes
;
// Active (grid, node, unit, slack, up_down) on each forecast-time step with ramp restrictions
// Active (grid, node, unit, slack, up_down) on each ft step with ramp restrictions
Option clear = gnuft_rampCost;
gnuft_rampCost(gnu(grid, node, unit), slack, ft(f, t))${ gnuft(grid, node, unit, f, t)
and p_gnuBoundaryProperties(grid, node, unit, slack, 'rampCost')
}
= yes;
// Active (grid, node, unit) on each forecast-time step with ramp restrictions
// Active (grid, node, unit) on each ft step with ramp restrictions
Option clear = gnuft_ramp;
gnuft_ramp(gnuft(grid, node, unit, f, t))${ p_gnu(grid, node, unit, 'maxRampUp')
OR p_gnu(grid, node, unit, 'maxRampDown')
......@@ -427,12 +433,12 @@ sufts(suft(effGroup, unit, f, t), effSelector)${ effGroupSelector(effGroup, e
= yes
;
// Units with online variables on each forecast-time step
// Units with online variables on each ft
Option clear = uft_online;
Option clear = uft_onlineLP;
Option clear = uft_onlineMIP;
// Determine the time steps when units need to have online variables.
// Determine the intervals when units need to have online variables.
loop(effOnline(effSelector),
uft_online(uft(unit, f, t))${ suft(effOnline, unit, f, t) }
= yes;
......@@ -474,14 +480,17 @@ 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);
* -----------------------------------------------------------------------------
* --- Displacements for start-up decisions ------------------------------------
* --- Displacements for start-up and shutdown decisions -----------------------
* -----------------------------------------------------------------------------
// Calculate dtt: displacement needed to reach any previous time period (needed to calculate dt_toStartup)
// Calculate dtt: displacement needed to reach any previous time period
// (needed to calculate dt_toStartup and dt_toShutdown)
Option clear = dtt;
dtt(t_active(t),t_activeNoReset(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 period,
// displacement needed to reach the time period where the unit was started up
Option clear = dt_toStartup;
......@@ -504,9 +513,7 @@ loop(unit$(p_u_runUpTimeIntervals(unit)),
);
);
* -----------------------------------------------------------------------------
* --- Displacements for shutdown decisions ------------------------------------
* -----------------------------------------------------------------------------
* --- 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
......
......@@ -136,36 +136,29 @@ v_gen.lo(gnuft(gnu_output(grid, node, unit), f, t))${ p_gnu(grid, node, unit,
v_gen.up(gnuft(gnu_output(grid, node, unit), f, t))${ p_gnu(grid, node, unit, 'maxGen') < 0 }
= 0;
// Ramping capability of units without online variable and not part of investment set
// !!! PENDING CHANGES !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
$ontext
// 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(ms(mSolve, s),
v_genRamp.up(grid, node, unit, f, t+pt(t))${ ft(f, t)
and gnuft_ramp(grid, node, unit, f, t)
and msft(mSolve, s, f, t)
and ord(t) > msStart(mSolve, s)
and p_gnu(grid, node, unit, 'maxRampUp')
and not uft_online_incl_previous(unit, f+cpf(f,t), t+pt(t))
and not unit_investLP(unit)
and not unit_investMIP(unit)
} = ( p_gnu(grid, node, unit, 'maxGen') - p_gnu(grid, node, unit, 'maxCons') )
v_genRamp.up(gnuft_ramp(grid, node, unit, f, t))${ ord(t) > msStart(mSolve, s)
and msft(mSolve, s, f, t)
and p_gnu(grid, node, unit, 'maxRampUp')
and not unit_investLP(unit)
and not unit_investMIP(unit)
} = ( p_gnu(grid, node, unit, 'maxGen') + p_gnu(grid, node, unit, 'maxCons') )
* p_gnu(grid, node, unit, 'maxRampUp')
* 60 / 100; // Unit conversion from [p.u./min] to [MW/h]
v_genRamp.lo(grid, node, unit, f, t+pt(t))${ ft(f, t)
and gnuft_ramp(grid, node, unit, f, t)
and msft(mSolve, s, f, t)
and ord(t) > msStart(mSolve, s)
and p_gnu(grid, node, unit, 'maxRampDown')
and not uft_online_incl_previous(unit, f+cpf(f,t), t+pt(t))
and not unit_investLP(unit)
and not unit_investMIP(unit)
} = -( p_gnu(grid, node, unit, 'maxGen') - p_gnu(grid, node, unit, 'maxCons') )
* 60; // Unit conversion from [p.u./min] to [p.u./h]
v_genRamp.lo(gnuft_ramp(grid, node, unit, f, t))${ ord(t) > msStart(mSolve, s)
and msft(mSolve, s, f, t)
and p_gnu(grid, node, unit, 'maxRampDown')
and not unit_investLP(unit)
and not unit_investMIP(unit)
} = -( p_gnu(grid, node, unit, 'maxGen') + p_gnu(grid, node, unit, 'maxCons') )
* p_gnu(grid, node, unit, 'maxRampDown')
* 60 / 100; // Unit conversion from [p.u./min] to [MW/h]
* 60; // Unit conversion from [p.u./min] to [p.u./h]
);
$offtext
// v_online cannot exceed unit count if investments disabled
// LP variant
......@@ -178,6 +171,7 @@ v_online_MIP.up(uft_onlineMIP(unit, f, t))${ not unit_investMIP(unit) }
;
// Free the upper bound of start-up and shutdown variables (if previously bounded)
// This should not be needed if t_activeNoReset is used properly?
v_startup.up(unitStarttype(unit, starttype), ft(f, t)) = inf;
v_shutdown.up(uft(unit, f, t)) = inf;
......@@ -188,13 +182,29 @@ v_startup.up(unitStarttype(unit, starttype), ft(f, t))${ uft_online(unit, f,
}
= p_unit(unit, 'unitCount')
;
// v_shutdown cannot exceed unitCount
v_shutdown.up(uft_online(unit, f, t))${ not unit_investLP(unit) and not unit_investMIP(unit) }
= p_unit(unit, 'unitCount')
;
// 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), ft(f, t))${ uft_online(unit, f, t)
and p_u_runUpTimeIntervals(unit)
and not sum(t_active(t_)${ord(t) = ord(t_) + dt_toStartup(unit,t_)}, uft_online(unit, f, t_))
}
= 0;
// Cannot start up or shut down a unit if the time time step is not active in the current horizon
// Cannot shut down a unit if the time when the generation of the unit would become
// zero is outside the horizon when the unit has an online variable
v_shutdown.up(uft_online(unit, f, t))${ p_u_shutdownTimeIntervals(unit)
and not sum(t_active(t_)${ord(t) = ord(t_) + dt_toShutdown(unit,t_)}, uft_online(unit, f, t_))
}
= 0;
// Cannot start up or shut down a unit if the interval is not active in the current horizon
// This should not be needed if t_activeNoReset is used properly
$ontext
v_startup.up(unitStarttype(unit, starttype), ft(f, t))${ ord(t) > tSolveFirst
and ord(t) <= tSolveLast
and not t_active(t)
......@@ -205,16 +215,12 @@ v_shutdown.up(uft(unit, f, t))${ ord(t) > tSolveFirst
and not t_active(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;
*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 unitCount
v_shutdown.up(uft_online(unit, f, t))${ not unit_investLP(unit) and not unit_investMIP(unit) }
= p_unit(unit, 'unitCount')
;
* --- Energy Transfer Boundaries ----------------------------------------------
......@@ -264,7 +270,7 @@ v_reserve.up(nuRescapable(restype, 'down', node, unit), f_solve(f+df_nReserves(n
;
// Fix reserves between t_jump and gate_closure based on previous allocations
// Primary reserves can use tertiary reserves as backup.
// Primary reserves can use tertiary reserves as backup. NOTE! handled using vq_resMissing at the moment
if(tSolveFirst > mSettings(mSolve, 't_start'), // No previous solution to fix the reserves with on the first solve.
$ontext
......@@ -374,19 +380,12 @@ v_investTransfer_MIP.up(gn2n_directional(grid, from_node, to_node), t_invest)${
/ p_gnn(grid, from_node, to_node, 'unitSize')
;
// If offline hours after which the start-up will be a warm/cold start is not
// defined, fix hot/warm start-up to zero.
// !!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// These should not be necessary,as if the time window is not defined, warm and
// hot starts should be impossible according to q_startuptype
*v_startup.fx(unit, 'hot', ft_dynamic(f, t))${not p_unit(unit, 'startWarmAfterXhours')} = 0;
*v_startup.fx(unit, 'warm', ft_dynamic(f, t))${not p_unit(unit, 'startColdAfterXhours')} = 0;
* =============================================================================
* --- Bounds for the first timestep -------------------------------------------
* --- Bounds for the first (and last) interval --------------------------------
* =============================================================================
// Loop over the start steps
// Loop over the start intervals
loop(mft_start(mSolve, f, t),
// If this is the very first solve, set boundStart
......@@ -432,22 +431,21 @@ loop(mft_start(mSolve, f, t),
) // END loop(mftStart)
;
// Fix previously realized start-up and shutdown decisions.
// Needed for modelling hot and warm start-ups, minimum uptimes and downtimes, and run-up phases.
$ontext
v_startup.up(unitStarttype(unit, starttype), f, t)${ sum(ft(f_, t_), uft_online(unit, f_, t_))
and mf_realization(mSolve, f)
and ord(t) <= tSolveFirst
}
= 0
;
v_shutdown.up(unit, f, t)${ sum(ft(f_, t_), uft_online(unit, f_, t_))
and mf_realization(mSolve, f)
and ord(t) <= tSolveFirst
}
= 0
// BoundStartToEnd
v_state.fx(grid, node, ft(f,t))${ mft_lastSteps(mSolve, f, t)
and p_gn(grid, node, 'boundStartToEnd')
}
= sum(mf_realization(mSolve, f_),
+ r_state(grid, node, f_, tSolve)
) // END sum(fRealization)
;
$offtext
* =============================================================================
* --- Fix previously realized start-ups, shutdowns, and online states ---------
* =============================================================================
// Needed for modelling hot and warm start-ups, minimum uptimes and downtimes, and run-up and shutdown phases.
v_startup.fx(unitStarttype(unit, starttype), ft_realizedNoReset(f, t))${ ord(t) <= tSolveFirst
and sum[ft(f_,t_), uft_online(unit,f_,t_)]
}
......@@ -460,21 +458,14 @@ v_shutdown.fx(unit, ft_realizedNoReset(f, t))${ ord(t) <= tSolveFirst
= round(r_shutdown(unit, f, t), 4)
;
v_online_MIP.fx(unit, ft_realizedNoReset(f, t))${ ord(t) <= tSolveFirst
and sum[ft(f_,t_), uft_onlineMIP(unit,f_,t_)]
}
= r_online(unit, f, t);
v_online_LP.fx(unit, ft_realizedNoReset(f, t))${ ord(t) <= tSolveFirst
and sum[ft(f_,t_), uft_onlineLP(unit,f_,t_)]
}
= r_online(unit, f, t);
// BoundStartToEnd
v_state.fx(grid, node, ft(f,t))${ mft_lastSteps(mSolve, f, t)
and p_gn(grid, node, 'boundStartToEnd')
}
= sum(mf_realization(mSolve, f_),
+ r_state(grid, node, f_, tSolve)
) // END sum(fRealization)
;
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