Commit 818c3cff authored by Topi Rasku's avatar Topi Rasku
Browse files

#65: *v_startup* divided into *v_startup_LP* and *v_startup_MIP* variants to...

#65: *v_startup* divided into *v_startup_LP* and *v_startup_MIP* variants to avoid undesired behavior when using integer online variables.
parent 9230f447
......@@ -23,6 +23,7 @@ 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_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,7 +36,7 @@ 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_startup_LP(unit, starttype, s, f, t) "Sub-units started up after/during an interval (p.u.), (LP variant)"
v_shutdown(unit, s, f, t) "Sub-units shut down after/during an interval (p.u.)"
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)"
......
......@@ -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')
......
......@@ -259,7 +259,12 @@ q_maxDownward(gnu(grid, node, unit), msft(m, s, f, t))${gnuft(grid, node, unit,
+ p_gnu(grid, node, unit, 'unitSizeGen')
* sum(unitStarttype(unit, starttype)${uft_startupTrajectory(unit, f, t)},
sum(runUpCounter(unit, counter)${t_active(t+dt_trajectory(counter))}, // Sum over the run-up intervals
+ v_startup(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
+ [
+ v_startup_LP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
${ uft_onlineLP(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) }
+ v_startup_MIP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
${ uft_onlineMIP(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) }
]
* p_uCounter_runUpMin(unit, counter)
) // END sum(runUpCounter)
) // END sum(unitStarttype)
......@@ -380,7 +385,12 @@ q_maxUpward(gnu(grid, node, unit), msft(m, s, f, t))${gnuft(grid, node, unit, f,
+ p_gnu(grid, node, unit, 'unitSizeGen')
* sum(unitStarttype(unit, starttype)${uft_startupTrajectory(unit, f, t)},
sum(runUpCounter(unit, counter)${t_active(t+dt_trajectory(counter))}, // Sum over the run-up intervals
+ v_startup(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
+ [
+ v_startup_LP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
${ uft_onlineLP(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) }
+ v_startup_MIP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
${ uft_onlineMIP(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) }
]
* p_uCounter_runUpMax(unit, counter)
) // END sum(runUpCounter)
) // END sum(unitStarttype)
......@@ -451,7 +461,10 @@ q_startshut(m, s, uft_online(unit, f, t))$msft(m, s, f, t) ..
// Add startup of units dt_toStartup before the current t (no start-ups for aggregator units before they become active)
+ sum(unitStarttype(unit, starttype),
+ v_startup(unit, starttype, s, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t))
+ v_startup_LP(unit, starttype, s, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t))
${ uft_onlineLP(unit, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t)) }
+ v_startup_MIP(unit, starttype, s, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t))
${ uft_onlineMIP(unit, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t)) }
)${not [unit_aggregator(unit) and ord(t) + dt_toStartup(unit, t) <= tSolveFirst + p_unit(unit, 'lastStepNotAggregated')]} // END sum(starttype)
// NOTE! According to 3d_setVariableLimits,
......@@ -473,7 +486,8 @@ q_startuptype(m, s, starttypeConstrained(starttype), uft_online(unit, f, t))
${msft(m, s, f, t) and unitStarttype(unit, starttype)} ..
// Startup type
+ v_startup(unit, starttype, s, f, t)
+ 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) }
=L=
......@@ -539,7 +553,10 @@ q_onlineOnStartUp(s, uft_online(unit, f, t))
=G=
+ sum(unitStarttype(unit, starttype),
+ v_startup(unit, starttype, s, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t)) //dt_toStartup displaces the time step to the one where the unit would be started up in order to reach online at t
+ v_startup_LP(unit, starttype, s, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t)) //dt_toStartup displaces the time step to the one where the unit would be started up in order to reach online at t
${ uft_onlineLP(unit, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t)) }
+ v_startup_MIP(unit, starttype, s, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t)) //dt_toStartup displaces the time step to the one where the unit would be started up in order to reach online at t
${ uft_onlineMIP(unit, f+df(f,t+dt_toStartup(unit, t)), t+dt_toStartup(unit, t)) }
) // END sum(starttype)
;
......@@ -576,19 +593,27 @@ q_onlineMinUptime(m, s, uft_online(unit, f, t))
=G=
// Units that have minimum operation time requirements active
+ sum(unitCounter(unit, counter)${dt_uptimeUnitCounter(unit, counter)},
+ sum(unitCounter(unit, counter)${ dt_uptimeUnitCounter(unit, counter)
and t_active(t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)) // Don't sum over counters that don't point to an active time step
},
+ sum(unitStarttype(unit, starttype),
+ v_startup(unit, starttype, s, f+df(f,t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)), t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1))
${t_active(t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1))}
+ v_startup_LP(unit, starttype, s, f+df(f,t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)), t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1))
${ uft_onlineLP(unit, f+df(f,t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)), t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)) }
+ v_startup_MIP(unit, starttype, s, f+df(f,t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)), t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1))
${ uft_onlineMIP(unit, f+df(f,t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)), t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)) }
) // END sum(starttype)
) // END sum(counter)
// Units that have minimum operation time requirements active (aggregated units in the past horizon or if they have an online variable)
+ sum(unitAggregator_unit(unit, unit_),
+ sum(unitCounter(unit, counter)${dt_uptimeUnitCounter(unit, counter)},
+ sum(unitCounter(unit, counter)${ dt_uptimeUnitCounter(unit, counter)
and t_active(t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)) // Don't sum over counters that don't point to an active time step
},
+ sum(unitStarttype(unit, starttype),
+ v_startup(unit, starttype, s, f+df(f,t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)), t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1))
${t_active(t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1))}
+ v_startup_LP(unit, starttype, s, f+df(f,t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)), t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1))
${ uft_onlineLP(unit, f+df(f,t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)), t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)) }
+ v_startup_MIP(unit, starttype, s, f+df(f,t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)), t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1))
${ uft_onlineMIP(unit, f+df(f,t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)), t+(dt_uptimeUnitCounter(unit, counter)+dt_toStartup(unit, t) + 1)) }
) // END sum(starttype)
) // END sum(counter)
)${unit_aggregator(unit)} // END sum(unit_)
......@@ -696,7 +721,10 @@ q_rampUpLimit(m, s, gnuft_ramp(grid, node, unit, f, t))${ ord(t) > msStart(m, s
* 60 > 0
)
},
+ v_startup(unit, starttype, s, f, t)
+ 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) }
) // END sum(starttype)
* p_gnu(grid, node, unit, 'unitSizeTot')
* (
......@@ -713,7 +741,12 @@ q_rampUpLimit(m, s, gnuft_ramp(grid, node, unit, f, t))${ ord(t) > msStart(m, s
+ p_gnu(grid, node, unit, 'unitSizeTot')
* sum(unitStarttype(unit, starttype)${uft_startupTrajectory(unit, f, t)},
sum(runUpCounter(unit, counter)${t_active(t+dt_trajectory(counter))}, // Sum over the run-up intervals
+ v_startup(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
+ [
+ v_startup_LP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
${ uft_onlineLP(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) }
+ v_startup_MIP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
${ uft_onlineMIP(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) }
]
* [
+ p_unit(unit, 'rampSpeedToMinLoad')
+ ( p_gnu(grid, node, unit, 'maxRampUp') - p_unit(unit, 'rampSpeedToMinLoad') )${ not runUpCounter(unit, counter+1) } // Ramp speed adjusted for the last run-up interval
......@@ -854,7 +887,10 @@ q_rampDownLimit(m, s, gnuft_ramp(grid, node, unit, f, t))${ ord(t) > msStart(m,
* 60 > 0
)
},
+ v_startup(unit, starttype, s, f, t)
+ 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) }
) // END sum(starttype)
* p_gnu(grid, node, unit, 'unitSizeTot')
* (
......@@ -922,7 +958,12 @@ q_rampSlack(m, s, gnuft_rampCost(grid, node, unit, slack, f, t))${ ord(t) > msS
+ p_gnu(grid, node, unit, 'unitSizeTot')
* sum(unitStarttype(unit, starttype)${uft_startupTrajectory(unit, f, t)},
sum(runUpCounter(unit, counter)${t_active(t+dt_trajectory(counter))}, // Sum over the run-up intervals
+ v_startup(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
+ [
+ v_startup_LP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
${ uft_onlineLP(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) }
+ v_startup_MIP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
${ uft_onlineMIP(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) }
]
* [
+ p_unit(unit, 'rampSpeedToMinLoad')
+ ( p_gnuBoundaryProperties(grid, node, unit, slack, 'rampLimit') - p_unit(unit, 'rampSpeedToMinLoad') )${ not runUpCounter(unit, counter+1) } // Ramp speed adjusted for the last run-up interval
......@@ -1031,7 +1072,12 @@ q_conversionDirectInputOutput(s, suft(effDirect(effGroup), unit, f, t))$sft(s, f
// Run-up 'online state'
+ sum(unitStarttype(unit, starttype)${uft_startupTrajectory(unit, f, t)},
+ sum(runUpCounter(unit, counter)${t_active(t+dt_trajectory(counter))}, // Sum over the run-up intervals
+ v_startup(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
+ [
+ v_startup_LP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
${ uft_onlineLP(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) }
+ v_startup_MIP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
${ uft_onlineMIP(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) }
]
* p_uCounter_runUpMin(unit, counter)
/ p_unit(unit, 'op00') // Scaling the p_uCounter_runUp using minload
) // END sum(runUpCounter)
......@@ -1086,7 +1132,12 @@ q_conversionIncHR(s, suft(effIncHR(effGroup), unit, f, t))$sft(s, f, t) ..
// Run-up 'online state'
+ sum(unitStarttype(unit, starttype)${uft_startupTrajectory(unit, f, t)},
+ sum(runUpCounter(unit, counter)${t_active(t+dt_trajectory(counter))}, // Sum over the run-up intervals
+ v_startup(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
+ [
+ v_startup_LP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
${ uft_onlineLP(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) }
+ v_startup_MIP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
${ uft_onlineMIP(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) }
]
* p_uCounter_runUpMin(unit, counter)
/ p_unit(unit, 'hrop00') // Scaling the p_uCounter_runUp using minload
) // END sum(runUpCounter)
......@@ -1229,7 +1280,12 @@ q_conversionSOS2Constraint(s, suft(effLambda(effGroup), unit, f, t))$sft(s, f, t
// Run-up 'online state'
+ sum(unitStarttype(unit, starttype)${uft_startupTrajectory(unit, f, t)},
+ sum(runUpCounter(unit, counter)${t_active(t+dt_trajectory(counter))}, // Sum over the run-up intervals
+ v_startup(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
+ [
+ v_startup_LP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
${ uft_onlineLP(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) }
+ v_startup_MIP(unit, starttype, s, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter))
${ uft_onlineMIP(unit, f+df(f, t+dt_trajectory(counter)), t+dt_trajectory(counter)) }
]
* p_uCounter_runUpMin(unit, counter)
/ p_unit(unit, 'op00') // Scaling the p_uCounter_runUp using minload
) // END sum(runUpCounter)
......@@ -1973,7 +2029,12 @@ q_emissioncap(group, emission)${ p_groupPolicy3D(group, 'emissionCap', emission
// Start-up emissions
+ sum(uft_online(unit_fuel, f, t),
+ sum(unitStarttype(unit_fuel, starttype),
+ v_startup(unit_fuel, starttype, s, f, t)
+ [
+ v_startup_LP(unit_fuel, starttype, s, f, t)
${ uft_onlineLP(unit_fuel, f, t) }
+ v_startup_MIP(unit_fuel, starttype, s, f, t)
${ uft_onlineMIP(unit_fuel, f, t) }
]
* sum(uFuel(unit_fuel, 'startup', fuel),
+ p_uStartup(unit_fuel, starttype, 'consumption')
* p_uFuel(unit_fuel, 'startup', fuel, 'fixedFuelFraction')
......
......@@ -36,7 +36,8 @@ Option clear = v_help_inc;
Option clear = v_sos2;
// Positive Variables
Option clear = v_fuelUse;
Option clear = v_startup;
Option clear = v_startup_LP;
Option clear = v_startup_MIP;
Option clear = v_shutdown;
Option clear = v_genRampUpDown;
Option clear = v_spill;
......
......@@ -226,17 +226,31 @@ 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)
......@@ -443,7 +457,8 @@ 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_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.fx(unit, s, f, t) = 0;
else // For all other solves, fix the initial state values based on previous results.
......@@ -467,10 +482,12 @@ 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_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.fx(unit, sft_realizedNoReset(s, f, t_active(t)))
......
......@@ -49,7 +49,8 @@ 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)
......
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