### 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!