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

Various small fixes and clarifications.

parent 48dbc4b6
......@@ -410,11 +410,13 @@ loop(unit,
* --- Probabilities -----------------------------------------------------------
* -----------------------------------------------------------------------------
// Clear probabilities from previous solve
// Update probabilities
Option clear = p_sft_probability;
p_sft_probability(s, f, t)$(sInitial(s) and ft(f,t)) = p_fProbability(f) / sum(f_$ft(f_,t), p_fProbability(f_));
p_sft_probability(s, f, t)$(sInitial(s) and fCentral(f) and ord(t) = tSolveFirst + mSettings(mSolve, 't_horizon')) = p_fProbability(f) / sum(f_$(fCentral(f_) and ord(t) = tSolveFirst + mSettings(mSolve, 't_horizon')), p_fProbability(f_));
p_sft_probability(s, f, t)$(sInitial(s) and ord(f) > 1 and ord(t) = tSolveFirst + mSettings(mSolve, 't_horizon') and mSettings(mSolve, 't_forecastLength') >= mSettings(mSolve, 't_horizon')) = p_fProbability(f) / sum(f_$ft_dynamic(f_,t), p_fProbability(f_));
p_sft_probability(sInitial(s), ft(f,t)) = p_fProbability(f+cf_Central(f,t)) / sum(f_${ft(f_,t)}, p_fProbability(f_));
p_sft_probability(sInitial(s), ft_realized(f,t)) = p_fProbability(f);
p_sft_probability(sInitial(s), ft_full(f,t))${ mftLastSteps(mSolve, f, t)
and not cf_Central(f,t)
} = p_fProbability(f) / sum(f_${ft_full(f_,t)}, p_fProbability(f_));
......@@ -234,6 +234,7 @@ param_policy "Set of possible data parameters for grid, node, regulation" /
emissionTax "Emission tax (EUR/tonne)"
update_frequency "Frequency of updating reserve contributions"
gate_closure "Number of timesteps ahead of dispatch that reserves are fixed"
use_time_series "Flag for using time series data. !!! REDUNDANT WITH useTimeseries, PENDING REMOVAL !!!"
reserveContribution "Reliability parameter of reserve provisions"
/
......
......@@ -124,7 +124,9 @@ loop(gn2n_bidirectional(grid, node, node_)${p_gnn(grid, node, node_, 'transferCa
);
* Assume values for critical node related parameters, if not provided by input data
p_gnBoundaryPropertiesForStates(gn(grid, node), param_gnBoundaryTypes, 'multiplier')$(not p_gnBoundaryPropertiesForStates(grid, node, param_gnBoundaryTypes, 'multiplier')) = 1; // If multiplier has not been set, set it to 1 by default
p_gnBoundaryPropertiesForStates(gn(grid, node), param_gnBoundaryTypes, 'multiplier')${ not p_gnBoundaryPropertiesForStates(grid, node, param_gnBoundaryTypes, 'multiplier')
and sum(param_gnBoundaryProperties, p_gnBoundaryPropertiesForStates(grid, node, param_gnBoundaryTypes, param_gnBoundaryProperties))
} = 1; // If multiplier has not been set, set it to 1 by default
*p_gn(gn(grid, node), 'energyStoredPerUnitOfState')$(not p_gn(grid, node, 'energyStoredPerUnitOfState') and not p_gn(grid, node, 'boundAll')) = 1; // If unitConversion has not been set, default to 1; If the state is bound, there is no need for the term
* -----------------------------------------------------------------------------
......
......@@ -65,6 +65,7 @@ q_obj ..
$$ifi '%rampSched%' == 'yes' (p_stepLength(m, f, t) + p_stepLength(m, f, t+1))/2 *
v_gen(grid, node, unit, f, t)$nuft(node, unit, f, t)
)
// Fuel and emission costs
+ sum((uft(unit_fuel, f, t), fuel)$uFuel(unit_fuel, 'main', fuel),
+ p_stepLength(m, f, t)
......@@ -107,14 +108,27 @@ q_obj ..
)
)
// "Cost" of spilling energy
// "Cost" of spilling energy, !!! TEMPORARY MEASURES !!!
+ sum(gn(grid, node_spill(node)),
v_spill(grid, node, f, t) * p_stepLength(m, f, t)
+ v_spill(grid, node, f, t) * p_stepLength(m, f, t)
)
) // END * p_sft_probability(s,f,t)
) // END sum over msft(m, s, f, t)
*$ontext
// Node state slack variable penalties
+ sum(gn_stateSlack(grid, node),
+ sum(ms(m, s),
+ sum(ft_full(f, t)${ ft_dynamic(f,t) or mftStart(m, f, t) },
+ p_stepLength(m, f, t)
* p_sft_probability(s, f, t)
* sum(slack${p_gnBoundaryPropertiesForStates(grid, node, slack, 'slackCost')},
+ p_gnBoundaryPropertiesForStates(grid, node, slack, 'slackCost') * v_stateSlack(grid, node, slack, f, t)
)
)
)
)
// Value of energy storage change
- sum(mftLastSteps(m, f, t)$active('storageValue'),
sum(gn_state(grid, node),
......@@ -126,24 +140,24 @@ q_obj ..
sum(gn_state(grid, node),
p_storageValue(grid, node, t) *
sum(s$p_sft_probability(s,f,t), p_sft_probability(s, f, t) * v_state(grid, node, f, t))
)
) * mSettings(m, 'forecasts') // Correction for the smaller amount of starting points
)
// "Value" of online units
$ontext
// "Value" of online units, !!! TEMPORARY MEASURES !!!
- sum([s, m, uft_online(unit, ft_dynamic(f,t))]$mftStart(m, f, t),
+ p_sft_probability(s, f, t) * 0.5 * v_online(unit, f+cf(f,t), t)
* p_unit(unit, 'startCost')
* p_unit(unit, 'outputCapacityTotal')
/ p_unit(unit, 'unitCount')
) // minus value of avoiding startup costs before
) // minus value of avoiding startup costs before
- sum((s, uft_online_last(unit, ft_dynamic(f,t))),
+ p_sft_probability(s, f, t) * 0.5 * v_online(unit, f+cf(f,t), t)
* p_unit(unit, 'startCost')
* p_unit(unit, 'outputCapacityTotal')
/ p_unit(unit, 'unitCount')
) // or after the model solve
// Dummy variables
$offtext
// Dummy variable penalties
+ sum(msft(m, s, f, t), p_sft_probability(s, f, t) * (
sum(inc_dec,
sum( gn(grid, node), vq_gen(inc_dec, grid, node, f, t) * (p_stepLength(m, f, t) + p_stepLength(m, f+pf(f,t), t+pt(t))${not p_stepLength(m, f, t)}) * PENALTY_BALANCE(grid) )
......@@ -155,21 +169,12 @@ q_obj ..
)
)
)
// Node state slack variable penalties
+ sum(gn_stateSlack(grid, node),
+ sum(msft(m, s, f, t),
+ sum(upwardSlack$p_gnBoundaryPropertiesForStates(grid, node, upwardSlack, 'slackCost'),
+ p_sft_probability(s, f, t) * ( p_gnBoundaryPropertiesForStates(grid, node, upwardSlack, 'slackCost') * v_stateSlack(grid, node, upwardSlack, f, t) )
)
+ sum(downwardSlack$p_gnBoundaryPropertiesForStates(grid, node, downwardSlack, 'slackCost'),
+ p_sft_probability(s, f, t) * ( p_gnBoundaryPropertiesForStates(grid, node, downwardSlack, 'slackCost') * v_stateSlack(grid, node, downwardSlack, f, t) )
)
)
)
;
* -----------------------------------------------------------------------------
q_balance(gn(grid, node), m, ft_dynamic(f, t))${p_stepLength(m, f+pf(f,t), t+pt(t)) and not p_gn(grid, node, 'boundAll')} .. // Energy/power balance dynamics solved using implicit Euler discretization
q_balance(gn(grid, node), m, ft_dynamic(f, t))${ p_stepLength(m, f+pf(f,t), t+pt(t))
and not p_gn(grid, node, 'boundAll')
} .. // Energy/power balance dynamics solved using implicit Euler discretization
// The left side of the equation is the change in the state (will be zero if the node doesn't have a state)
+ p_gn(grid, node, 'energyStoredPerUnitOfState')$gn_state(grid, node) // Unit conversion between v_state of a particular node and energy variables (defaults to 1, but can have node based values if e.g. v_state is in Kelvins and each node has a different heat storage capacity)
* ( + v_state(grid, node, f+cf_Central(f,t), t) // The difference between current
......@@ -234,7 +239,7 @@ q_balance(gn(grid, node), m, ft_dynamic(f, t))${p_stepLength(m, f+pf(f,t), t+pt(
q_resDemand(restypeDirectionNode(restype, up_down, node), ft(f, t))${ ord(t) < tSolveFirst + sum[mf(m, f), mSettings(m, 't_reserveLength')]
} ..
+ sum(nuft(node, unit, f, t)${nuRescapable(restype, up_down, node, unit)}, // Reserve capable units on this node
v_reserve(restype, up_down, node, unit, f+cf_nReserves(node, restype, f, t), t) // * p_nuReserves(node, unit, restype, 'reserveContribution')
v_reserve(restype, up_down, node, unit, f+cf_nReserves(node, restype, f, t), t)
)
+ sum(gn2n(grid, from_node, node)${restypeDirectionNode(restype, up_down, from_node)},
(1 - p_gnn(grid, from_node, node, 'transferLoss')
......@@ -436,7 +441,9 @@ q_outputRatioConstrained(gngnu_constrainedOutputRatio(grid, node, grid_, node_,
/ p_gnu(grid_, node_, unit, 'cB')
;
* -----------------------------------------------------------------------------
q_stateSlack(gn_stateSlack(grid, node), slack, ft_dynamic(f, t))$p_gnBoundaryPropertiesForStates(grid, node, slack, 'slackCost') ..
q_stateSlack(gn_stateSlack(grid, node), slack, ft_full(f, t))${ p_gnBoundaryPropertiesForStates(grid, node, slack, 'slackCost')
and [ft_dynamic(f,t) or sum(m, mftStart(m, f, t))]
} ..
+ v_stateSlack(grid, node, slack, f, t)
=G=
+ p_slackDirection(slack) * (
......@@ -446,11 +453,11 @@ q_stateSlack(gn_stateSlack(grid, node), slack, ft_dynamic(f, t))$p_gnBoundaryPro
)
;
* -----------------------------------------------------------------------------
q_stateUpwardLimit(gn_state(grid, node), m, ft_dynamic(f, t))$( sum(gn2gnu(grid, node, grid_, node_output, unit)$(sum(restype, nuRescapable(restype, 'down', node_output, unit))), 1) // nodes that have units with endogenous output with possible reserve provision
or sum(gn2gnu(grid_, node_input, grid, node, unit) $(sum(restype, nuRescapable(restype, 'down', node_input , unit))), 1) // or nodes that have units with endogenous input with possible reserve provision
) ..
q_stateUpwardLimit(gn_state(grid, node), m, ft_dynamic(f, t))${ sum(gn2gnu(grid, node, grid_, node_output, unit)$(sum(restype, nuRescapable(restype, 'down', node_output, unit))), 1) // nodes that have units with endogenous output with possible reserve provision
or sum(gn2gnu(grid_, node_input, grid, node, unit)$(sum(restype, nuRescapable(restype, 'down', node_input , unit))), 1) // or nodes that have units with endogenous input with possible reserve provision
} ..
( // Utilizable headroom in the state variable
+ p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'useConstant') * p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'constant')
+ p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'useConstant') * p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'constant')
+ p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'useTimeSeries') * ts_nodeState(grid, node, 'upwardLimit', f, t)
- v_state(grid, node, f+cf_Central(f,t), t)
)
......@@ -483,9 +490,9 @@ q_stateUpwardLimit(gn_state(grid, node), m, ft_dynamic(f, t))$( sum(gn2gnu(gr
)
;
* -----------------------------------------------------------------------------
q_stateDownwardLimit(gn_state(grid, node), m, ft_dynamic(f, t))$( sum(gn2gnu(grid, node, grid_, node_output, unit)$(sum(restype, nuRescapable(restype, 'up', node_output, unit))), 1) // nodes that have units with endogenous output with possible reserve provision
or sum(gn2gnu(grid_, node_input, grid, node, unit) $(sum(restype, nuRescapable(restype, 'up', node_input , unit))), 1) // or nodes that have units with endogenous input with possible reserve provision
) ..
q_stateDownwardLimit(gn_state(grid, node), m, ft_dynamic(f, t))${ sum(gn2gnu(grid, node, grid_, node_output, unit)$(sum(restype, nuRescapable(restype, 'up', node_output, unit))), 1) // nodes that have units with endogenous output with possible reserve provision
or sum(gn2gnu(grid_, node_input, grid, node, unit) $(sum(restype, nuRescapable(restype, 'up', node_input , unit))), 1) // or nodes that have units with endogenous input with possible reserve provision
} ..
( // Utilizable headroom in the state variable
+ v_state(grid, node, f+cf_Central(f,t), t)
- p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'useConstant') * p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'constant')
......
......@@ -49,27 +49,34 @@ if (mSettings(mSolve, 'readForecastsInTheLoop') and ord(tSolve) >= tForecastNext
put_utility 'gdxin' / 'input\tertiary\' tSolve.tl:0 '.gdx';
execute_load ts_tertiary;
ts_reserveDemand('tertiary', up_down, node, f, tt(t))${ mf(mSolve, f)
and gn('elec', node)
and not fRealization(f)
} = min(500, ts_tertiary('wind', node, tSolve, up_down, t) * sum(flowUnit('wind', unit), p_gnu('elec', node, unit, 'maxGen')));
* } = min(500, ts_tertiary('wind', node, tSolve, up_down, t) * sum(flowUnit('wind', unit), p_gnu('elec', node, unit, 'maxGen')));
} = max(p_nReserves(node, 'primary', up_down), ts_tertiary('wind', node, tSolve, up_down, t) * sum(flowUnit('wind', unit), p_gnu('elec', node, unit, 'maxGen')));
); // END IF readForecastsInTheLoop
putclose log;
* --- Improve forecasts -------------------------------------------------------
// Define updated time window
Option clear = tt;
tt(t)${ ord(t) >= ord(tSolve)
and ord(t) <= ord(tSolve) + f_improve
} = yes;
// Improve capacity factors, linear improvement towards fRealization
loop(fRealization(f_),
ts_cf(flow, node, f, tt(t))${ not fRealization(f)
and fRealization(f_)
and mf(mSolve, f)
} = (
(ord(t) - ord(tSolve)) * ts_cf(flow, node, f, t)
+ (f_improve + ord(tSolve) - ord(t)) * ts_cf(flow, node, f_, t)
) / f_improve;
);
// !!! TEMPORARY MEASURES !!!
if(mSettings(mSolve, 'forecasts') > 0,
// Define updated time window
Option clear = tt;
tt(t)${ ord(t) >= ord(tSolve)
and ord(t) <= ord(tSolve) + f_improve
} = yes;
// Improve capacity factors, linear improvement towards fRealization
loop(fRealization(f_),
ts_cf(flow, node, f, tt(t))${ not fRealization(f)
and fRealization(f_)
and mf(mSolve, f)
} = (
(ord(t) - ord(tSolve)) * ts_cf(flow, node, f, t)
+ (f_improve + ord(tSolve) - ord(t)) * ts_cf(flow, node, f_, t)
) / f_improve;
);
); // END IF forecasts
......@@ -116,7 +116,7 @@ v_reserve.up(nuRescapable(restype, 'up', node, unit_elec), f+cf_nReserves(node,
v_reserve.up(nuRescapable(restype, 'down', node, unit_elec), f+cf_nReserves(node, restype, f, t), t)${ nuft(node, unit_elec, f, t)
and ord(t) < tSolveFirst + mSettings(mSolve, 't_reserveLength')
} = min { p_nuReserves(node, unit_elec, restype, 'down') * [ p_gnu('elec', node, unit_elec, 'maxGen') + p_gnu('elec', node, unit_elec, 'maxCons') ], // Generator + consuming unit res_range limit
v_gen.up('elec', node, unit_elec, f, t) - v_gen.lo('elec', node, unit_elec, f, t) // Generator + consuming unit available unit_elec. output delta
v_gen.up('elec', node, unit_elec, f, t) - v_gen.lo('elec', node, unit_elec, f, t) // Generator + consuming unit available unit_elec. output delta
}
* ( + 1${ft_nReserves(node, restype, f+cf_nReserves(node, restype, f, t), t)} // reserveContribution limits the reliability of reserves locked ahead of time.
+ p_nuReserves(node, unit_elec, restype, 'reserveContribution')${not ft_nReserves(node, restype, f+cf_nReserves(node, restype, f, t), 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