Commit 6b70441c authored by Niina Helistö's avatar Niina Helistö
Browse files

Several fixes to make the investment model work:

Added fixed operation and maintenance costs for investment options
Adding a new parameter unitOutputCapacityTotal to avoid division by zero
Added unit investment result parameter
Removed equation q_fixedGenCap1U
Added default value calculation for reserves update frequency
Moved tCounter update outside ms loop in 3c_periodicLoop.gms
Updated the limits of v_invest_LP and v_invest_MIP (no more maxGenCap, minGenCap)
Updated investInit_temp.gms
And some smaller updates
parent 688d8cf3
......@@ -42,7 +42,6 @@ Model invest /
q_conversionSOS2InputIntermediate
q_conversionSOS2Constraint
q_conversionSOS2IntermediateOutput
q_fixedGenCap1U
q_fixedGenCap2U
// Energy Transfer
......@@ -60,10 +59,10 @@ Model invest /
q_boundCyclic
// Policy
q_inertiaMin
q_instantaneousShareMax
q_capacityMargin
q_emissioncap
q_instantaneousShareMax
q_energyShareMax
q_energyShareMin
q_inertiaMin
/;
......@@ -15,54 +15,104 @@ You should have received a copy of the GNU Lesser General Public License
along with Backbone. If not, see <http://www.gnu.org/licenses/>.
$offtext
* =============================================================================
* --- Model Definition - Schedule ---------------------------------------------
* =============================================================================
if (mType('invest'),
m('invest') = yes; // Definition, that the model exists by its name
// Define the temporal structure of the model in time indeces
mSettings('invest', 'intervalInHours') = 1; // Define the duration of a single time-step in hours
mInterval('invest', 'intervalLength', 'c000') = 1;
mInterval('invest', 'intervalEnd', 'c000') = 504;
* --- Define Key Execution Parameters in Time Indeces -------------------------
// Define the model execution parameters in time indeces
// Define simulation start and end time indeces
mSettings('invest', 't_start') = 1; // Ord of first solve (i.e. >0)
mSettings('invest', 't_end') = 8760;
// Define simulation horizon and moving horizon optimization "speed"
mSettings('invest', 't_horizon') = 8760;
mSettings('invest', 't_jump') = 2184;
mSettings('invest', 't_forecastStart') = 1; // Ord of first forecast available
mSettings('invest', 't_forecastLength') = 2184;
mSettings('invest', 't_forecastJump') = 2184;
mSettings('invest', 't_end') = 2180;
mSettings('invest', 't_reserveLength') = 36;
mSettings('invest', 't_jump') = 8760;
// Define unit aggregation and efficiency levels starting indeces
mSettings('invest', 't_aggregate') = 4392;
mSettingsEff('invest', 'level1') = 1;
mSettingsEff('invest', 'level2') = 1;
mSettingsEff('invest', 'level3') = 1;
mSettingsEff('invest', 'level4') = 4392;
* =============================================================================
* --- Model Time Structure ----------------------------------------------------
* =============================================================================
// Define active model features
active('invest', 'storageValue') = yes;
* --- Define Samples ----------------------------------------------------------
// Number of samples used by the model
mSettings('invest', 'samples') = 3;
// Define Initial and Central samples
ms_initial('invest', s) = no;
ms_initial('invest', 's000') = yes;
ms_central('invest', s) = no;
ms_central('invest', 's000') = yes;
// Define time span of samples
msStart('invest', 's000') = mSettings('invest', 't_start');
msEnd('invest', 's000') = msStart('invest', 's000') + 168;
msStart('invest', 's001') = mSettings('invest', 't_start') + 18*168;
msEnd('invest', 's001') = msStart('invest', 's001') + 168;
msStart('invest', 's002') = mSettings('invest', 't_start') + 35*168;
msEnd('invest', 's002') = msStart('invest', 's002') + 168;
// Define the probability (weight) of samples
p_msProbability('invest', s) = 0;
p_msProbability('invest', 's000') = 8760/504;
p_msProbability('invest', 's001') = 8760/504;
p_msProbability('invest', 's002') = 8760/504;
* --- Define Time Step Intervals ----------------------------------------------
// Define the duration of a single time-step in hours
mSettings('invest', 'intervalInHours') = 1;
// Define the time step intervals in time-steps
mInterval('invest', 'intervalLength', 'c000') = 1;
mInterval('invest', 'intervalEnd', 'c000') = 8760;
* =============================================================================
* --- Model Forecast Structure ------------------------------------------------
* =============================================================================
// Define model stochastic parameters
mSettings('invest', 'samples') = 1;
// Define the number of forecasts used by the model
mSettings('invest', 'forecasts') = 0;
// Define forecast properties and features
mSettings('invest', 't_forecastStart') = 0;
mSettings('invest', 't_forecastLength') = 0;
mSettings('invest', 't_forecastJump') = 0;
mSettings('invest', 'readForecastsInTheLoop') = 0;
mf('invest', f)$[ord(f)-1 <= mSettings('invest', 'forecasts')] = yes;
// Define Realized and Central forecasts
mf_realization('invest', f) = no;
mf_realization('invest', 'f00') = yes;
mf_central('invest', f) = no;
mf_central('invest', 'f00') = yes;
ms_initial('invest', s) = no;
ms_initial('invest', 's000') = yes;
ms_central('invest', s) = no;
ms_central('invest', 's000') = yes;
p_stepLength('invest', f, t)$(ord(f)=1 and ord(t)=1) = 0; // set one p_stepLength value, so that unassigned values will not cause an error later
p_msProbability('invest', s) = 0;
p_msProbability('invest', 's000') = 1;
// Define forecast probabilities (weights)
p_mfProbability('invest', f) = 0;
p_mfProbability(mf_realization('invest', f)) = 1;
msStart('invest', 's000') = 1;
msEnd('invest', 's000') = msStart('invest', 's000') + 48;
);
// Define active model features
active('invest', 'storageValue') = yes;
* =============================================================================
* --- Model Features ----------------------------------------------------------
* =============================================================================
* --- Define Reserve Properties -----------------------------------------------
// Lenght of reserve horizon
mSettings('invest', 't_reserveLength') = 36; // CHECK THIS
* --- Define Unit Efficiency Approximations -----------------------------------
// Define unit aggregation threshold
mSettings('invest', 't_aggregate') = 8761;
// Define unit aggregation and efficiency levels starting indeces
mSettingsEff('invest', 'level1') = 1;
); // END if(mType)
......@@ -122,6 +122,11 @@ r_nuTotalReserve
r_nuTotalReserveShare
r_nTotalReserve
* --- Investment Result Symbols -----------------------------------------------
// Interesting investment results
r_unitInvestment
* --- Dummy and Diagnostic Variable Result Symbols ----------------------------
// Results regarding solution feasibility
......
......@@ -273,14 +273,16 @@ param_gnu "Set of possible data parameters for grid, node, unit" /
unitSizeTot "Sum of output and loading capacity of one unit (MW)"
unitSizeGenNet "Output minus loading capacity of one unit (MW)"
invCosts "Investment costs (€/MW)"
annuity "Investment annuity"
inertia "Inertia of the unit (s)"
annuity "Investment annuity factor"
fomCosts "Fixed operation and maintenance costs (€/MW/a)"
inertia "Inertia of the unit (s)"
unitSizeMVA "Generator MVA rating (MVA)"
/
param_unit "Set of possible data parameters for units" /
unitCount "Number of subunits if aggregated"
outputCapacityTotal "Output capacity of the unit, calculated by summing all the outputs together by default, unless defined in data"
unitOutputCapacityTotal "Output capacity of the unit, calculated by summing all the unit output sizes together by default"
availability "Availability of given energy conversion technology (p.u.)"
omCosts "Variable operation and maintenance costs (€/MWh)"
startCostCold "Variable start-up costs for cold starts excluding fuel costs (€/MW)"
......
......@@ -124,6 +124,11 @@ Parameters
r_nuTotalReserveShare(restype, up_down, node, unit) "Total nu/n reserve provision share over the simulation"
r_nTotalReserve(restype, up_down, node) "Total reserve provisions in nodes over the simulation (MW*h)"
* --- Investment Results ------------------------------------------------------
// Interesting investment results
r_unitInvestment(unit) "Number/amount of invested units"
* --- Dummy Variable Results --------------------------------------------------
// Results regarding solution feasibility
......
......@@ -164,9 +164,7 @@ unitStarttype(unit, starttypeConstrained)${ p_unit(unit, 'startWarmAfterXhours')
// Units with investment variables
unit_investLP(unit)${ not p_unit(unit, 'investMIP')
and sum(gnu(grid, node, unit),
p_gnu(grid, node, unit, 'maxGenCap') + p_gnu(grid, node, unit, 'maxConsCap')
)
and p_unit(unit, 'maxUnitCount')
}
= yes;
unit_investMIP(unit)${ p_unit(unit, 'investMIP')
......@@ -181,15 +179,18 @@ unit_investMIP(unit)${ p_unit(unit, 'investMIP')
p_unit(unit, 'eff00')${ not p_unit(unit, 'eff00') }
= 1;
// In case number of units has not been defined it is 1 except for units with integer investments allowed.
// In case number of units has not been defined it is 1 except for units with investments allowed.
p_unit(unit, 'unitCount')${ not p_unit(unit, 'unitCount')
and not p_unit(unit, 'investMIP')
and not unit_investMIP(unit)
and not unit_investLP(unit)
}
= 1;
// By default add outputs in order to get the total capacity of the unit
p_unit(unit, 'outputCapacityTotal')${ not p_unit(unit, 'outputCapacityTotal') }
= sum(gnu_output(grid, node, unit), p_gnu(grid, node, unit, 'maxGen'));
p_unit(unit, 'unitOutputCapacityTotal')
= sum(gnu_output(grid, node, unit), p_gnu(grid, node, unit, 'unitSizeGen'));
// Assume unit sizes based on given maximum capacity parameters and unit counts if able
p_gnu(grid, node, unit, 'unitSizeGen')${ p_gnu(grid, node, unit, 'maxGen')
......
......@@ -59,7 +59,6 @@ equations
q_conversionSOS2InputIntermediate(effSelector, unit, f, t) "Intermediate output when using SOS2 variable based part-load piece-wise linearization"
q_conversionSOS2Constraint(effSelector, unit, f, t) "Sum of v_sos2 has to equal v_online"
q_conversionSOS2IntermediateOutput(effSelector, unit, f, t) "Output is forced equal with v_sos2 output"
q_fixedGenCap1U(grid, node, unit, t) "Fixed capacity ratio of a unit in one node versus all nodes it is connected to"
q_fixedGenCap2U(grid, node, unit, grid, node, unit, t) "Fixed capacity ratio of two (grid, node, unit) pairs"
// Energy Transfer
......@@ -208,14 +207,20 @@ $offtext
// Investment Costs
+ sum(t_invest(t),
// Unit investment costs
// Unit investment costs (including fixed operation and maintenance costs)
+ sum(gnu(grid, node, unit),
+ v_invest_LP(unit, t)${ unit_investLP(unit) }
* p_gnu(grid, node, unit, 'invCosts')
* p_gnu(grid, node, unit, 'annuity')
* p_gnu(grid, node, unit, 'unitSizeTot')
* [
+ p_gnu(grid, node, unit, 'invCosts') * p_gnu(grid, node, unit, 'annuity')
+ p_gnu(grid, node, unit, 'fomCosts')
]
+ v_invest_MIP(unit, t)${ unit_investMIP(unit) }
* p_gnu(grid, node, unit, 'unitSizeTot')
* p_gnu(grid, node, unit, 'invCosts') * p_gnu(grid, node, unit, 'annuity')
* [
+ p_gnu(grid, node, unit, 'invCosts') * p_gnu(grid, node, unit, 'annuity')
+ p_gnu(grid, node, unit, 'fomCosts')
]
) // END sum(gnu)
// Transfer link investment costs
......@@ -590,8 +595,8 @@ q_onlineLimit(m, uft_online(unit, f, t))${ p_unit(unit, 'minShutdownHours')
// Investments into units
+ sum(t_invest(t_)${ord(t_)<=ord(t)},
+ v_invest_LP(unit, t_)
+ v_invest_MIP(unit, t_)
+ v_invest_LP(unit, t_)${unit_investLP(unit)}
+ v_invest_MIP(unit, t_)${unit_investMIP(unit)}
) // END sum(t_invest)
;
......@@ -926,48 +931,22 @@ q_conversionSOS2IntermediateOutput(suft(effLambda(effGroup), unit, f, t)) ..
) // END sum(gnu_output)
;
*--- Fixed Investment Ratios --------------------------------------------------
// !!! PENDING FIX !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// v_invest(unit) instead of the old v_invest(grid, node, unit)
// Are these even necessary anymore, if investment is unitwise?
// Maybe for batteries etc?
q_fixedGenCap1U(gnu(grid, node, unit), t_invest(t))${ unit_investLP(unit)
} ..
// Investment
+ v_invest_LP(unit, t)
=E=
// Capacity Ratios?
+ sum(gn(grid_, node_),
+ v_invest_LP(unit, t)
) // END sum(gn)
* p_gnu(grid, node, unit, 'unitSizeTot')
/ sum(gn(grid_, node_),
+ p_gnu(grid_, node_, unit, 'unitSizeTot')
) // END sum(gn)
;
*--- Fixed Investment Ratios 2 ------------------------------------------------
// !!! PENDING FIX !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// See notes in the above equation
*--- Fixed Investment Ratios Between Two Units --------------------------------
q_fixedGenCap2U(grid, node, unit, grid_, node_, unit_, t_invest(t))${ p_gnugnu(grid, node, unit, grid_, node_, unit_, 'capacityRatio')
} ..
// Investment
+ v_invest_LP(unit, t)
+ v_invest_MIP(unit, t)
+ v_invest_LP(unit, t)${unit_investLP(unit)}
+ v_invest_MIP(unit, t)${unit_investMIP(unit)}
=E=
// Capacity Ratio?
// Capacity Ratio
+ p_gnugnu(grid, node, unit, grid_, node_, unit_, 'capacityRatio')
* [
+ v_invest_LP(unit_, t)
+ v_invest_MIP(unit_, t)
+ v_invest_LP(unit_, t)${unit_investLP(unit_)}
+ v_invest_MIP(unit_, t)${unit_investMIP(unit_)}
] // END * p_gngnu(capacityRatio)
;
......@@ -1384,11 +1363,15 @@ q_capacityMargin(gn(grid, node), ft(f, t))${ p_gn(grid, node, 'capacityMargin
// Availability of units, including capacity factors
+ sum(gnu_output(grid, node, unit),
+ p_unit(unit, 'availability')
* sum(flow${ flowUnit(flow, unit)
and nu(node, unit)
},
+ ts_cf_(flow, node, f, t)
) // END sum(flow)
* [
// Capacity factors for flow units
+ sum(flow${ flowUnit(flow, unit)
and nu(node, unit)
},
+ ts_cf_(flow, node, f, t)
) // END sum(flow)
+ 1${not unit_flow(unit)}
]
* [
// Output capacity before investments
+ p_gnu(grid, node, unit, 'maxGen')
......
......@@ -342,6 +342,11 @@ loop(fuel,
p_slackDirection(upwardSlack) = 1;
p_slackDirection(downwardSlack) = -1;
* --- Using default value for reserves update frequency -----------------------
loop(m,
p_nReserves(node, restype, 'update_frequency')${ not p_nReserves(node, restype, 'update_frequency') }
= mSettings(m, 't_jump');
);
......@@ -298,10 +298,11 @@ loop(cc(counter),
// Update tActive
t_active(tt_interval) = yes;
// Update tCounter for the next interval
tCounter = mInterval(mSolve, 'intervalEnd', counter);
); // END loop(ms)
// Update tCounter for the next interval
tCounter = mInterval(mSolve, 'intervalEnd', counter);
); // END loop(counter)
// Time step displacement to reach previous time step
......
......@@ -297,68 +297,20 @@ v_resTransferLeftward.fx(restypeDirectionNode('tertiary', up_down, node), node_,
* --- Investment Variable Boundaries ------------------------------------------
// Unit Investments, Generation
// Unit Investments
// LP variant
v_invest_LP.up(unit, t_invest)${ unit_investLP(unit) }
= min( smax(gnu_output(grid, node, unit), p_gnu(grid, node, unit, 'maxGenCap')) // Maximum permitted gnu_output capacity investment
/ p_unit(unit, 'unitSizeGen')
,
p_unit(unit, 'maxUnitCount')
) // END min
= p_unit(unit, 'maxUnitCount')
;
v_invest_LP.lo(unit, t_invest)${ unit_investLP(unit) }
= min( smax(gnu_output(grid, node, unit), p_gnu(grid, node, unit, 'minGenCap')) // Maximum defined gnu_output minimun capacity requirement
/ p_unit(unit, 'unitSizeGen')
,
p_unit(unit, 'minUnitCount')
) // END min
= p_unit(unit, 'minUnitCount')
;
// MIP variant
v_invest_MIP.up(unit, t_invest)${ unit_investMIP(unit) }
= min( smax(gnu_output(grid, node, unit), p_gnu(grid, node, unit, 'maxGenCap')) // Maximum permitted gnu_output capacity investment
/ p_unit(unit, 'unitSizeGen')
,
p_unit(unit, 'maxUnitCount')
) // END min
= p_unit(unit, 'maxUnitCount')
;
v_invest_MIP.lo(unit, t_invest)${ unit_investMIP(unit) }
= min( smax(gnu_output(grid, node, unit), p_gnu(grid, node, unit, 'minGenCap'))
/ p_unit(unit, 'unitSizeGen')
,
p_unit(unit, 'minUnitCount')
) // END min
;
// Unit Investments, Consumption
// LP variant
v_invest_LP.up(unit, t_invest)${ unit_investLP(unit) }
= min( smax(gnu_input(grid, node, unit), p_gnu(grid, node, unit, 'maxConsCap')) // Maximum permitted gnu_output capacity investment
/ p_unit(unit, 'unitSizeCons')
,
p_unit(unit, 'maxUnitCount')
) // END min
;
v_invest_LP.lo(unit, t_invest)${ unit_investLP(unit) }
= min( smax(gnu_input(grid, node, unit), p_gnu(grid, node, unit, 'minConsCap')) // Maximum defined gnu_output minimun capacity requirement
/ p_unit(unit, 'unitSizeCons')
,
p_unit(unit, 'minUnitCount')
) // END min
;
// MIP variant
v_invest_MIP.up(unit, t_invest)${ unit_investMIP(unit) }
= min( smax(gnu_input(grid, node, unit), p_gnu(grid, node, unit, 'maxConsCap')) // Maximum permitted gnu_output capacity investment
/ p_unit(unit, 'unitSizeCons')
,
p_unit(unit, 'maxUnitCount')
) // END min
;
v_invest_MIP.lo(unit, t_invest)${ unit_investMIP(unit) }
= min( smax(gnu_output(grid, node, unit), p_gnu(grid, node, unit, 'minConsCap'))
/ p_unit(unit, 'unitSizeCons')
,
p_unit(unit, 'minUnitCount')
) // END min
= p_unit(unit, 'minUnitCount')
;
// Transfer Capacity Investments
......
......@@ -108,6 +108,10 @@ r_resDemandMarginal(restypeDirectionNode(restype, up_down, node), ft_realized(f,
r_stateSlack(gn_stateSlack(grid, node), slack, ft_realized(f, t))
= v_stateSlack.l(grid, node, slack, f, t)
;
// Unit investments
r_unitInvestment(unit)${unit_investLP(unit) or unit_investMIP(unit)}
= sum(t_invest, v_invest_LP.l(unit, t_invest) + v_invest_MIP.l(unit, t_invest))
;
* --- Feasibility results -----------------------------------------------------
......
......@@ -123,12 +123,18 @@ loop(m,
+ r_gnuVOMCost(grid, node, unit, f, t)
// Divide fuel and startup costs based on output capacities
+ p_gnu(grid, node, unit, 'maxGen')
/ p_unit(unit, 'outputCapacityTotal')
* [
+ sum(uFuel(unit, 'main', fuel), r_uFuelEmissionCost(fuel, unit, f, t))
+ r_uStartupCost(unit, f, t)
] // END *
+ [
+ p_gnu(grid, node, unit, 'maxGen')${p_unit(unit, 'outputCapacityTotal')}
+ p_gnu(grid, node, unit, 'unitSizeGen')${not p_unit(unit, 'outputCapacityTotal')}
]
/ [
+ p_unit(unit, 'outputCapacityTotal')${p_unit(unit, 'outputCapacityTotal')}
+ p_unit(unit, 'unitOutputCapacityTotal')${not p_unit(unit, 'outputCapacityTotal')}
] // END /
* [
+ sum(uFuel(unit, 'main', fuel), r_uFuelEmissionCost(fuel, unit, f, t))
+ r_uStartupCost(unit, f, t)
] // END *
) // END sum(gnu_output)
// Node state slack costs
......@@ -185,10 +191,10 @@ loop(m,
); // END sum(ft_realizedNoReset)
// Approximate utilization rates for gnus over the simulation
r_gnuUtilizationRate(gnu_output(grid, node, unit))
r_gnuUtilizationRate(gnu_output(grid, node, unit))${r_gnuTotalGen(grid, node, unit)}
= r_gnuTotalGen(grid, node, unit)
/ [
+ p_gnu(grid, node, unit, 'maxGen')
+ (p_gnu(grid, node, unit, 'maxGen') + r_unitInvestment(unit)*p_gnu(grid, node, unit, 'unitSizeGen'))
* (mSettings(m, 't_end') - mSettings(m, 't_start') + 1)
* mSettings(m, 'intervalInHours')
]; // END division
......
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