diff --git a/defOutput/resultSymbols.inc b/defOutput/resultSymbols.inc index 465daae6dc4303998529040271f9b2ed64f72c81..90eb02335209ceb6e9e6c3937cb41b34d88db7dc 100644 --- a/defOutput/resultSymbols.inc +++ b/defOutput/resultSymbols.inc @@ -119,6 +119,9 @@ r_gnTotalConsumption r_gnTotalConsumptionShare r_gTotalConsumption +// Start-up consumption results +r_nuStartupConsumption + * --- Unit Online State Result Symbols ---------------------------------------- // Online results required for model structure !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -136,10 +139,13 @@ r_uTotalShutdown * --- Emissions Results ----------------------------------------------- -// Unit level emissions +// Unit level emissions from normal operation r_emissions -// Emission sums +// Unit level emissions from start-ups +r_emissionsStartup + +// Emission sums from normal operation r_nuTotalEmissions r_nTotalEmissions r_uTotalEmissions diff --git a/inc/1b_sets.gms b/inc/1b_sets.gms index d668ca45a556018b621a2ab51147bfe0345089e6..4ba8059b0a6161321fe13456a7bcc261c7b5dc91 100644 --- a/inc/1b_sets.gms +++ b/inc/1b_sets.gms @@ -71,6 +71,7 @@ Sets gnu_input(grid, node, unit) "Forms of energy the unit uses as endogenous inputs" gnu_output(grid, node, unit) "Forms of energy the unit uses as endogenous outputs" nu(node, unit) "Units attached to particular nodes" + nu_startup(node, unit) "Units consuming energy from particular nodes in start-up" gn_state(grid, node) "Nodes with a state variable" gn_stateSlack(grid, node) "Nodes with a state slack variable" gnn_state(grid, node, node) "Nodes with state variables interconnected via diffusion" @@ -219,7 +220,7 @@ alias(group, group_); -sets +sets tt_agg_circular(t, t, t) "Alternative aggregation ordering with embedded circulars" startp(t) "Temporary subset for time steps" s_realized(s) "All s among realized sft (redundant if always equivalent to s)" diff --git a/inc/1d_results.gms b/inc/1d_results.gms index dfe8cfa1b198552ee41eaf97f7b4d603deb63539..5312a2d1dd4b95e0e9653e195c48a691bec0847f 100644 --- a/inc/1d_results.gms +++ b/inc/1d_results.gms @@ -126,13 +126,19 @@ Parameters r_gnTotalConsumptionShare(grid, node) "Total consumption gn/g share" r_gTotalConsumption(grid) "Total consumption of energy in g over the simulation (MWh)" + // Start-up consumption results + r_nuStartupConsumption(node, unit, f, t) "Energy consumption during start-up (MWh)" + * --- Emissions Results ------------------------------------------------------- - // Unit level emissions + // Unit level emissions from normal operation r_emissions (node, emission, unit, f, t) "Emissions from units (tCO2)" - // Emission sums + // Unit level emissions from start-ups + r_emissionsStartup(node, emission, unit, f, t) "Emissions from units in start-ups (tCO2)" + + // Emission sums from normal operation r_nuTotalEmissions (node, unit, emission) "node unit total emissions (tCO2)" r_nTotalEmissions(node, emission) "node total emissions (tCO2)" r_uTotalEmissions(unit, emission) "unit total emissions (tCO2)" diff --git a/inc/1e_inputs.gms b/inc/1e_inputs.gms index 3a1513d51983e8d3d292ae08af1621820f187db8..ad3b7b3079b70de6155c6d926c9acffbbfa7a09c 100644 --- a/inc/1e_inputs.gms +++ b/inc/1e_inputs.gms @@ -205,6 +205,8 @@ unitStarttype(unit, starttypeConstrained)${ p_unit(unit, 'startWarmAfterXhours') or p_unit(unit, 'startColdAfterXhours') } = yes; +// Units consuming energy from particular nodes in start-up +nu_startup(node, unit)$p_uStartupfuel(unit, node, 'fixedFuelFraction') = yes; // Units with time series data enabled unit_timeseries(unit)${ p_unit(unit, 'useTimeseries') } @@ -273,6 +275,10 @@ p_uStartup(unit, 'cold', 'consumption') = p_unit(unit, 'startFuelConsCold') * sum(gnu_output(grid, node, unit), p_gnu(grid, node, unit, 'unitSize')); +// Start-up fuel consumption per fuel +p_unStartup(unit, node, starttype)$p_uStartupfuel(unit, node, 'fixedFuelFraction') + = p_uStartup(unit, starttype, 'consumption') + * p_uStartupfuel(unit, node, 'fixedFuelFraction'); //shutdown cost parameters p_uShutdown(unit, 'cost') @@ -599,8 +605,8 @@ loop( unit, * --- Check startupfuel fraction related data ---------------------------------------- -loop( unit${sum(commodity$p_uStartupfuel(unit, commodity, 'fixedFuelFraction'), 1)}, - if(sum(commodity, p_uStartupfuel(unit, commodity, 'fixedFuelFraction')) <> 1, +loop( unit${sum(starttype$p_uStartup(unit, starttype, 'consumption'), 1)}, + if(sum(node, p_uStartupfuel(unit, node, 'fixedFuelFraction')) <> 1, put log '!!! Error occurred on unit ' unit.tl:0 /; put log '!!! Abort: The sum of fixedFuelFraction over start-up fuels needs to be one for all units using start-up fuels!' /; abort "The sum of 'fixedFuelFraction' over start-up fuels needs to be one for all units using start-up fuels!" @@ -689,7 +695,7 @@ loop( unit_investMIP(unit), * --- Check consistency of inputs for superposed node states ------------------- * no checking yet because node_superpos is not given in the gdx input - + * ============================================================================= * --- Default values --------------------------------------------------------- diff --git a/inc/2d_constraints.gms b/inc/2d_constraints.gms index 3241c881b6bbff11803455f69a662fcfb550b97f..f9a5ab5d0f22a9e4a03dd0c88fed0bed1e89dc89 100644 --- a/inc/2d_constraints.gms +++ b/inc/2d_constraints.gms @@ -90,6 +90,18 @@ q_balance(gn(grid, node), msft(m, s, f, t)) // Energy/power balance dynamics sol + vq_gen('increase', grid, node, s, f, t) // Note! When stateSlack is permitted, have to take caution with the penalties so that it will be used first - vq_gen('decrease', grid, node, s, f, t) // Note! When stateSlack is permitted, have to take caution with the penalties so that it will be used first ) // END * p_stepLength + + // Unit start-up consumption + - sum(uft(unit, f, t)$nu_startup(node, unit), + + sum(unitStarttype(unit, starttype), + + p_unStartup(unit, node, starttype) // MWh/start-up + * [ // Startup type + + 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(unitStarttype) + ) // END sum(uft) + ; * --- Reserve Demand ---------------------------------------------------------- @@ -3209,7 +3221,7 @@ q_emissioncap(group, emission) + v_startup_MIP(unit, starttype, s, f, t) ${ uft_onlineMIP(unit, f, t) } ] - * sum(nu(node, unit)${sum(grid, gnGroup(grid, node, group)) and p_nEmission(node, emission)}, + * sum(nu_startup(node, unit)${sum(grid, gnGroup(grid, node, group)) and p_nEmission(node, emission)}, + p_unStartup(unit, node, starttype) // MWh/start-up * p_nEmission(node, emission) // kg/MWh / 1e3 // NOTE!!! Conversion to t/MWh from kg/MWh in data diff --git a/inc/3c_inputsLoop.gms b/inc/3c_inputsLoop.gms index b1dd7d92dd918820853fe462976517cb00661653..370f8c0b76de7fc0f43090bef25008ab6382769a 100644 --- a/inc/3c_inputsLoop.gms +++ b/inc/3c_inputsLoop.gms @@ -408,7 +408,7 @@ $offtext + dt_circular(t_)$(not gn_scenarios(grid, node, 'ts_node')))) ) $(sameas(param_gnBoundaryTypes, 'upwardLimit') or upwardSlack(param_gnBoundaryTypes)); - + ts_gnn_(gn2n_timeseries(grid, node, node_, param_gnn), ft(f, tt_interval(t))) = sum(tt_aggregate(t, t_), ts_gnn(grid, node, node_, param_gnn, f, t_+dt_circular(t_)) @@ -423,7 +423,7 @@ $offtext + p_price(node, 'price')$p_price(node, 'useConstant') + sum(tt_aggcircular(t, t_), ts_price(node, t_))$p_price(node, 'useTimeSeries') / mInterval(mSolve, 'stepsPerInterval', counter) - )$un_commodity_in(unit, node) + )$un_commodity_in(unit, node) // output node cost (if price > 0 --> ts_vomCost_ < 0, i.e. considered as revenue) - ( + p_price(node, 'price')$p_price(node, 'useConstant') @@ -435,30 +435,30 @@ $offtext + p_unitEmissionCost(unit, node, emission) ); // END sum(emission) - p_unStartup(unit, node, starttype)$p_uStartupfuel(unit, node, 'fixedFuelFraction') - = - + p_uStartup(unit, starttype, 'consumption') - * p_uStartupfuel(unit, node, 'fixedFuelFraction'); - // Calculating startup cost time series ts_startupCost_(unit, starttype, tt_interval(t)) = + p_uStartup(unit, starttype, 'cost') // CUR/start-up // Start-up fuel and emission costs - + sum(nu(node,unit)$p_unStartup(unit, node, starttype), + + sum(nu_startup(node, unit), + p_unStartup(unit, node, starttype) // MWh/start-up * [ + // Fuel costs + p_price(node, 'price')$p_price(node, 'useConstant') // CUR/MWh + sum(tt_aggcircular(t, t_), + ts_price(node, t_) // CUR/MWh )$p_price(node, 'useTimeseries') / mInterval(mSolve, 'stepsPerInterval', counter) - ] // END * p_uStartup - ) // END sum(node) - + sum((nu(node, unit), emission)$p_unitEmissionCost(unit, node, emission), - + p_unStartup(unit, node, starttype) // MWh/start-up - * p_unitEmissionCost(unit, node, emission) // CUR/MWh - ); // END sum(nu, emission) + // Emission costs + + sum(emission$p_nEmission(node, emission), + + p_nEmission(node, emission) // kg/MWh + / 1e3 // NOTE!!! Conversion to t/MWh from kg/MWh in data + * sum(gnGroup(grid, node, group), + + p_groupPolicyEmission(group, 'emissionTax', emission) // CUR/t + ) // END sum(gnGroup) + ) // END sum(emission) + ] // END * p_unStartup + ); // END sum(nu_startup) // `storageValue` ts_storageValue_(gn_state(grid, node), sft(s, f, tt_interval(t)))${ p_gn(grid, node, 'storageValueUseTimeSeries') } diff --git a/inc/4b_outputInvariant.gms b/inc/4b_outputInvariant.gms index 9da3b5f3ff8f82a599326acf1d28e7ef1cd91f83..f933884a99330b765e7d804fcd02a02417fa19f4 100644 --- a/inc/4b_outputInvariant.gms +++ b/inc/4b_outputInvariant.gms @@ -53,19 +53,24 @@ loop(m, * sum(unitStarttype(unit, starttype), + r_startup(unit, starttype, f, t) * [ + // Fuel costs + p_uStartup(unit, starttype, 'cost') // CUR/start-up // Start-up fuel and emission costs - + sum(nu(node,unit)$p_unStartup(unit, node, starttype), + + sum(nu_startup(node,unit), + p_unStartup(unit, node, starttype) // MWh/start-up * [ + p_price(node, 'price')$p_price(node, 'useConstant') // CUR/MWh + ts_price(node, t)$p_price(node, 'useTimeseries') // CUR/MWh - ] // END * p_uStartup - ) // END sum(node) - + sum((nu(node, unit), emission)$p_unitEmissionCost(unit, node, emission), - + p_unStartup(unit, node, starttype) // MWh/start-up - * p_unitEmissionCost(unit, node, emission) // CUR/MWh - ) // END sum(nu, emission) + // Emission costs + + sum(emission$p_nEmission(node, emission), + + p_nEmission(node, emission) // kg/MWh + / 1e3 // NOTE!!! Conversion to t/MWh from kg/MWh in data + * sum(gnGroup(grid, node, group), + + p_groupPolicyEmission(group, 'emissionTax', emission) // CUR/t + ) // END sum(gnGroup) + ) // END sum(emission) + ] // END * p_unStartup + ) // END sum(nu_startup) ] // END * r_startup ); // END sum(starttype) @@ -309,6 +314,14 @@ loop(m, * sum(msft_realizedNoReset(m, s, f, t), p_msProbability(m, s) * p_msWeight(m, s)) ); // END sum(ft_realizedNoReset) + // Unit start-up consumption + r_nuStartupConsumption(nu_startup(node, unit), ft_realizedNoReset(f,startp(t))) + ${sum(starttype, unitStarttype(unit, starttype))} + = sum(unitStarttype(unit, starttype), + + r_startup(unit, starttype, f, t) + * p_unStartup(unit, node, starttype) // MWh/start-up + ); // END sum(unitStarttype) + * --- Emission Results -------------------------------------------------------- // Emissions of units (only for commodities, not including startup fuels) @@ -319,8 +332,20 @@ loop(m, / 1e3 // NOTE!!! Conversion to t/MWh from kg/MWh in data ; + // Emissions from unit start-ups + r_emissionsStartup(node, emission, unit, ft_realizedNoReset(f,startp(t))) + ${sum(starttype, unitStarttype(unit, starttype)) + and sum(starttype, p_unStartup(unit, node, starttype)) + and p_nEmission(node, emission)} + = sum(unitStarttype(unit, starttype), + + r_startup(unit, starttype, f, t) + * p_unStartup(unit, node, starttype) // MWh/start-up + * p_nEmission(node, emission) // kg/MWh + / 1e3 // NOTE!!! Conversion to t/MWh from kg/MWh in data + ); // END sum(starttype) + - // Emission sums + // Emission sums (only for commodities, not including startup fuels) r_nuTotalEmissions (commodity, unit, emission) = sum(ft_realizedNoReset(f, startp(t)), + r_emissions(commodity, emission, unit, f, t)