Commit 56980570 authored by Juha Kiviluoma's avatar Juha Kiviluoma
Browse files

Enabled the inclusion of additional constraints from the input data, the...

Enabled the inclusion of additional constraints from the input data, the replacement of the objective function and the addition of new terms to the objective function. The basic file structure was also changed to better accommodate these.
parent 9883ba19
$title Backbone
$ontext
Backbone - chronological energy systems model
Copyright (C) 2016 - 2017 VTT Technical Research Centre of Finland
Copyright (C) 2016 - 2018 VTT Technical Research Centre of Finland
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
......@@ -91,8 +91,18 @@ $include 'inc\1d_results.gms' // Parameter definitions for model results
$include 'inc\1e_inputs.gms' // Load input data
* === Variables and equations =================================================
$include 'inc\2a_variables.gms' // Define variables for the models
$include 'inc\2b_equations.gms' // Define equations for the models
$include 'inc\2a_variables.gms' // Define variables for the models
$include 'inc\2b_eqDeclarations.gms' // Equation declarations
$ifthen exist 'input\2c_alternative_objective.gms' // Objective function - either the default or an alternative from input files
$$include 'input\2c_alternative_objective.gms';
$else
$$include 'inc\2c_objective.gms'
$endif
$include 'inc\2d_constraints.gms' // Define constraint equations for the models
$ifthen exist 'input/2e_additional_constraints.gms'
$$include 'input/2e_additional_constraints.gms' // Define additional constraints from the input data
$endif
* === Model definition files ==================================================
$include 'defModels\schedule.gms'
......@@ -109,7 +119,8 @@ loop(modelSolves(mSolve, tSolve),
$$include 'inc\3c_periodicLoop.gms' // Update modelling loop
$$include 'inc\3d_setVariableLimits.gms' // Set new variable limits (.lo and .up)
$$include 'inc\3e_solve.gms' // Solve model(s)
$$include 'inc\4a_outputVariant.gms' // Store results from the loop
$$include 'inc\3f_afterSolve.gms' // Post-processing variables after the solve
$$include 'inc\4a_outputVariant.gms' // Store results from the loop
$iftheni.debug '%debug%' == 'yes'
putclose gdx;
put_utility 'gdxout' / 'output\'mSolve.tl:0, '-', tSolve.tl:0, '.gdx';
......
$ontext
This file is part of Backbone.
Backbone is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Backbone is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
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
* =============================================================================
* --- Penalty Definitions -----------------------------------------------------
* =============================================================================
$setlocal def_penalty 1e4
Scalars
PENALTY "Default equation violation penalty" / %def_penalty% /
;
Parameters
PENALTY_BALANCE(grid) "Penalty on violating energy balance eq. (EUR/MWh)"
PENALTY_RES(restype, up_down) "Penalty on violating a reserve (EUR/MW)"
PENALTY_RES_MISSING(restype, up_down) "Penalty on violating a reserve (EUR/MW)"
;
PENALTY_BALANCE(grid) = %def_penalty%;
PENALTY_RES(restype, up_down) = 0.9*%def_penalty%;
PENALTY_RES_MISSING(restype, up_down) = 0.1*%def_penalty%;
* =============================================================================
* --- Equation Declarations ---------------------------------------------------
* =============================================================================
equations
// Objective Function, Energy Balance, and Reserve demand
q_obj "Objective function"
q_balance(grid, node, mType, f, t) "Energy demand must be satisfied at each node"
q_resDemand(restype, up_down, node, f, t) "Procurement for each reserve type is greater than demand"
// Unit Operation
q_maxDownward(mType, grid, node, unit, f, t) "Downward commitments will not undercut power plant minimum load constraints or maximum elec. consumption"
q_noReserveInRunUp(mType, grid, node, unit, f, t)
q_maxUpward(mType, grid, node, unit, f, t) "Upward commitments will not exceed maximum available capacity or consumed power"
q_startshut(mType, unit, f, t) "Online cap. now minus online cap in the previous time step is equal to started up minus shut down capacity"
q_startuptype(mType, starttype, unit, f, t) "Startup type depends on the time the unit has been non-operational"
q_onlineOnStartUp(unit, f, t) "Unit must be online after starting up"
q_offlineAfterShutdown(unit, f, t) "Unit must be offline after shutting down"
q_onlineLimit(mType, unit, f, t) "Number of online units limited for units with startup constraints and investment possibility"
q_onlineMinUptime(mType, unit, f, t) "Unit must stay operational if it has started up during the previous minOperationHours hours"
q_genRamp(mType, grid, node, s, unit, f, t) "Record the ramps of units with ramp restricitions or costs"
q_rampUpLimit(mType, grid, node, s, unit, f, t) "Up ramping limited for units"
q_rampDownLimit(grid, node, mType, s, unit, f, t) "Down ramping limited for units"
q_outputRatioFixed(grid, node, grid, node, unit, f, t) "Force fixed ratio between two energy outputs into different energy grids"
q_outputRatioConstrained(grid, node, grid, node, unit, f, t) "Constrained ratio between two grids of energy output; e.g. electricity generation is greater than cV times unit_heat generation in extraction plants"
q_conversionDirectInputOutput(effSelector, unit, f, t) "Direct conversion of inputs to outputs (no piece-wise linear part-load efficiencies)"
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"
// Energy Transfer
q_transfer(grid, node, node, f, t) "Rightward and leftward transfer must match the total transfer"
q_transferRightwardLimit(grid, node, node, f, t) "Transfer of energy and capacity reservations to the rightward direction are less than the transfer capacity"
q_transferLeftwardLimit(grid, node, node, f, t) "Transfer of energy and capacity reservations to the leftward direction are less than the transfer capacity"
q_resTransferLimitRightward(grid, node, node, f, t) "Transfer of energy and capacity reservations are less than the transfer capacity to the rightward direction"
q_resTransferLimitLeftward(grid, node, node, f, t) "Transfer of energy and capacity reservations are less than the transfer capacity to the leftward direction"
// State Variables
q_stateSlack(grid, node, slack, f, t) "Slack variable greater than the difference between v_state and the slack boundary"
q_stateUpwardLimit(grid, node, mType, f, t) "Limit the commitments of a node with a state variable to the available headrooms"
q_stateDownwardLimit(grid, node, mType, f, t) "Limit the commitments of a node with a state variable to the available headrooms"
q_boundStateMaxDiff(grid, node, node, mType, f, t) "Node state variables bounded by other nodes (maximum state difference)"
q_boundCyclic(grid, node, mType, s, s) "Cyclic bound for the first and the last states of samples"
// Policy
q_inertiaMin(group, f, t) "Minimum inertia in a group of nodes"
q_instantaneousShareMax(group, f, t) "Maximum instantaneous share of generation and controlled import from a group of units and links"
q_constrainedOnlineMultiUnit(group, f, t) "Constrained number of online units for a group of units"
q_capacityMargin(grid, node, f, t) "There needs to be enough capacity to cover energy demand plus a margin"
q_constrainedCapMultiUnit(group, t) "Constrained unit number ratios and sums for a group of units"
q_emissioncap(group, emission) "Limit for emissions"
q_energyShareMax(group) "Maximum energy share of generation and import from a group of units"
q_energyShareMin(group) "Minimum energy share of generation and import from a group of units"
;
$ontext
This file is part of Backbone.
Backbone is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Backbone is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
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
* --- Objective Function ------------------------------------------------------
q_obj ..
+ v_obj * 1e6
=E=
// Sum over all the samples, forecasts, and time steps in the current model
+ sum(msft(m, s, f, t),
// Probability (weight coefficient) of (s,f,t)
+ p_msft_probability(m, s, f, t)
* [
// Time step length dependent costs
+ p_stepLength(m, f, t)
* [
// Variable O&M costs
+ sum(gnuft(gnu_output(grid, node, unit), f, t), // Calculated only for output energy
+ v_gen(grid, node, unit, f, t)
* p_unit(unit, 'omCosts')
) // END sum(gnu_output)
// Fuel and emission costs
+ sum(uFuel(unit, 'main', fuel)${uft(unit, f, t)},
+ v_fuelUse(fuel, unit, f, t)
* [
+ ts_fuelPrice_(fuel ,t)
+ sum(emission, // Emission taxes
+ p_unitFuelEmissionCost(unit, fuel, emission)
)
] // END * v_fuelUse
) // END sum(uFuel)
// Node state slack variable costs
+ sum(gn_stateSlack(grid, node),
+ sum(slack${p_gnBoundaryPropertiesForStates(grid, node, slack, 'slackCost')},
+ v_stateSlack(grid, node, slack, f, t)
* p_gnBoundaryPropertiesForStates(grid, node, slack, 'slackCost')
) // END sum(slack)
) // END sum(gn_stateSlack)
// Dummy variable penalties
// Energy balance feasibility dummy varible penalties
+ sum(inc_dec,
+ sum(gn(grid, node),
+ vq_gen(inc_dec, grid, node, f, t)
* PENALTY_BALANCE(grid)
) // END sum(gn)
) // END sum(inc_dec)
// Reserve provision feasibility dummy variable penalties
+ sum(restypeDirectionNode(restype, up_down, node),
+ vq_resDemand(restype, up_down, node, f, t)
* PENALTY_RES(restype, up_down)
+ vq_resMissing(restype, up_down, node, f, t)$(ord(t) <= tSolveFirst + p_nReserves(node, restype, 'gate_closure') - mod(tSolveFirst - 1, p_nReserves(node, restype, 'update_frequency')))
* PENALTY_RES_MISSING(restype, up_down)
) // END sum(restypeDirectionNode)
] // END * p_stepLength
// 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, f+df_central(f,t), t) // Cost of starting up
* [ // Startup variable costs
+ p_uStartup(unit, starttype, 'cost', 'unit')
// Start-up fuel and emission costs
+ sum(uFuel(unit, 'startup', fuel),
+ p_uStartup(unit, starttype, 'consumption', 'unit') //${ not unit_investLP(unit) } WHY THIS CONDITIONAL WOULD BE NEEDED?
* [
+ ts_fuelPrice_(fuel, t)
+ sum(emission, // Emission taxes of startup fuel use
+ p_unitFuelEmissionCost(unit, fuel, emission)
) // END sum(emission)
] // END * p_uStartup
) // END sum(uFuel)
] // END * v_startup
) // END sum(starttype)
) // END sum(uft_online)
$ontext
// !!! PENDING CHANGES !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Ramping costs
+ sum(gnuft_ramp(grid, node, unit, f, t)${ p_gnu(grid, node, unit, 'rampUpCost')
or p_gnu(grid, node, unit, 'rampDownCost')
},
+ p_gnu(grid, node, unit, 'rampUpCost') * v_genRampChange(grid, node, unit, 'up', f, t)
+ p_gnu(grid, node, unit, 'rampDownCost') * v_genRampChange(grid, node, unit, 'down', f, t)
) // END sum(gnuft_ramp)
$offtext
] // END * p_sft_probability(s,f,t)
) // END sum over msft(m, s, f, t)
// Cost of energy storage change
+ sum(gn_state(grid, node),
+ sum(mft_start(m, f, t)${ p_storageValue(grid, node, t)
and active(m, 'storageValue')
},
+ v_state(grid, node, f, t)
* p_storageValue(grid, node, t)
* sum(ms(m, s)${ p_msft_probability(m, s, f, t) },
+ p_msft_probability(m, s, f, t)
) // END sum(s)
) // END sum(mftStart)
- sum(mft_lastSteps(m, f, t)${ p_storageValue(grid, node, t)
and active(m, 'storageValue')
},
+ v_state(grid, node, f, t)
* p_storageValue(grid, node, t)
* sum(ms(m, s)${p_msft_probability(m, s, f, t)},
+ p_msft_probability(m, s, f, t)
) // END sum(s)
) // END sum(mftLastSteps)
) // END sum(gn_state)
// Investment Costs
+ sum(t_invest(t),
// 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, '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, 'fomCosts')
]
) // END sum(gnu)
// Transfer link investment costs
+ sum(gn2n_directional(grid, from_node, to_node),
+ v_investTransfer_LP(grid, from_node, to_node, t)${ not p_gnn(grid, from_node, to_node, 'investMIP') }
* [
+ p_gnn(grid, from_node, to_node, 'invCost')
* p_gnn(grid, from_node, to_node, 'annuity')
+ p_gnn(grid, to_node, from_node, 'invCost')
* p_gnn(grid, to_node, from_node, 'annuity')
] // END * v_investTransfer_LP
+ v_investTransfer_MIP(grid, from_node, to_node, t)${ p_gnn(grid, from_node, to_node, 'investMIP') }
* [
+ p_gnn(grid, from_node, to_node, 'unitSize')
* p_gnn(grid, from_node, to_node, 'invCost')
* p_gnn(grid, from_node, to_node, 'annuity')
+ p_gnn(grid, to_node, from_node, 'unitSize')
* p_gnn(grid, to_node, from_node, 'invCost')
* p_gnn(grid, to_node, from_node, 'annuity')
] // END * v_investTransfer_MIP
) // END sum(gn2n_directional)
) // END sum(t_invest)
$ifthen exist 'input\2c_additional_objective_terms.gms'
$$include 'input\2c_additional_objective_terms.gms';
$endif
;
......@@ -15,240 +15,11 @@ 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
* =============================================================================
* --- Penalty Definitions -----------------------------------------------------
* =============================================================================
$setlocal def_penalty 1e4
Scalars
PENALTY "Default equation violation penalty" / %def_penalty% /
;
Parameters
PENALTY_BALANCE(grid) "Penalty on violating energy balance eq. (EUR/MWh)"
PENALTY_RES(restype, up_down) "Penalty on violating a reserve (EUR/MW)"
PENALTY_RES_MISSING(restype, up_down) "Penalty on violating a reserve (EUR/MW)"
;
PENALTY_BALANCE(grid) = %def_penalty%;
PENALTY_RES(restype, up_down) = 0.9*%def_penalty%;
PENALTY_RES_MISSING(restype, up_down) = 0.1*%def_penalty%;
* =============================================================================
* --- Equation Declarations ---------------------------------------------------
* =============================================================================
equations
// Objective Function, Energy Balance, and Reserve demand
q_obj "Objective function"
q_balance(grid, node, mType, f, t) "Energy demand must be satisfied at each node"
q_resDemand(restype, up_down, node, f, t) "Procurement for each reserve type is greater than demand"
// Unit Operation
q_maxDownward(mType, grid, node, unit, f, t) "Downward commitments will not undercut power plant minimum load constraints or maximum elec. consumption"
q_noReserveInRunUp(mType, grid, node, unit, f, t)
q_maxUpward(mType, grid, node, unit, f, t) "Upward commitments will not exceed maximum available capacity or consumed power"
q_startshut(mType, unit, f, t) "Online cap. now minus online cap in the previous time step is equal to started up minus shut down capacity"
q_startuptype(mType, starttype, unit, f, t) "Startup type depends on the time the unit has been non-operational"
q_onlineOnStartUp(unit, f, t) "Unit must be online after starting up"
q_offlineAfterShutdown(unit, f, t) "Unit must be offline after shutting down"
q_onlineLimit(mType, unit, f, t) "Number of online units limited for units with startup constraints and investment possibility"
q_onlineMinUptime(mType, unit, f, t) "Unit must stay operational if it has started up during the previous minOperationHours hours"
q_genRamp(mType, grid, node, s, unit, f, t) "Record the ramps of units with ramp restricitions or costs"
q_rampUpLimit(mType, grid, node, s, unit, f, t) "Up ramping limited for units"
q_rampDownLimit(grid, node, mType, s, unit, f, t) "Down ramping limited for units"
q_outputRatioFixed(grid, node, grid, node, unit, f, t) "Force fixed ratio between two energy outputs into different energy grids"
q_outputRatioConstrained(grid, node, grid, node, unit, f, t) "Constrained ratio between two grids of energy output; e.g. electricity generation is greater than cV times unit_heat generation in extraction plants"
q_conversionDirectInputOutput(effSelector, unit, f, t) "Direct conversion of inputs to outputs (no piece-wise linear part-load efficiencies)"
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"
// Energy Transfer
q_transfer(grid, node, node, f, t) "Rightward and leftward transfer must match the total transfer"
q_transferRightwardLimit(grid, node, node, f, t) "Transfer of energy and capacity reservations to the rightward direction are less than the transfer capacity"
q_transferLeftwardLimit(grid, node, node, f, t) "Transfer of energy and capacity reservations to the leftward direction are less than the transfer capacity"
q_resTransferLimitRightward(grid, node, node, f, t) "Transfer of energy and capacity reservations are less than the transfer capacity to the rightward direction"
q_resTransferLimitLeftward(grid, node, node, f, t) "Transfer of energy and capacity reservations are less than the transfer capacity to the leftward direction"
// State Variables
q_stateSlack(grid, node, slack, f, t) "Slack variable greater than the difference between v_state and the slack boundary"
q_stateUpwardLimit(grid, node, mType, f, t) "Limit the commitments of a node with a state variable to the available headrooms"
q_stateDownwardLimit(grid, node, mType, f, t) "Limit the commitments of a node with a state variable to the available headrooms"
q_boundStateMaxDiff(grid, node, node, mType, f, t) "Node state variables bounded by other nodes (maximum state difference)"
q_boundCyclic(grid, node, mType, s, s) "Cyclic bound for the first and the last states of samples"
// Policy
q_inertiaMin(group, f, t) "Minimum inertia in a group of nodes"
q_instantaneousShareMax(group, f, t) "Maximum instantaneous share of generation and controlled import from a group of units and links"
q_constrainedOnlineMultiUnit(group, f, t) "Constrained number of online units for a group of units"
q_capacityMargin(grid, node, f, t) "There needs to be enough capacity to cover energy demand plus a margin"
q_constrainedCapMultiUnit(group, t) "Constrained unit number ratios and sums for a group of units"
q_emissioncap(group, emission) "Limit for emissions"
q_energyShareMax(group) "Maximum energy share of generation and import from a group of units"
q_energyShareMin(group) "Minimum energy share of generation and import from a group of units"
;
* =============================================================================
* --- Equation Definitions ----------------------------------------------------
* =============================================================================
* --- Objective Function ------------------------------------------------------
q_obj ..
+ v_obj * 1e6
=E=
// Sum over all the samples, forecasts, and time steps in the current model
+ sum(msft(m, s, f, t),
// Probability (weight coefficient) of (s,f,t)
+ p_msft_probability(m, s, f, t)
* [
// Time step length dependent costs
+ p_stepLength(m, f, t)
* [
// Variable O&M costs
+ sum(gnuft(gnu_output(grid, node, unit), f, t), // Calculated only for output energy
+ v_gen(grid, node, unit, f, t)
* p_unit(unit, 'omCosts')
) // END sum(gnu_output)
// Fuel and emission costs
+ sum(uFuel(unit, 'main', fuel)${uft(unit, f, t)},
+ v_fuelUse(fuel, unit, f, t)
* [
+ ts_fuelPrice_(fuel ,t)
+ sum(emission, // Emission taxes
+ p_unitFuelEmissionCost(unit, fuel, emission)
)
] // END * v_fuelUse
) // END sum(uFuel)
// Node state slack variable costs
+ sum(gn_stateSlack(grid, node),
+ sum(slack${p_gnBoundaryPropertiesForStates(grid, node, slack, 'slackCost')},
+ v_stateSlack(grid, node, slack, f, t)
* p_gnBoundaryPropertiesForStates(grid, node, slack, 'slackCost')
) // END sum(slack)
) // END sum(gn_stateSlack)
// Dummy variable penalties
// Energy balance feasibility dummy varible penalties
+ sum(inc_dec,
+ sum(gn(grid, node),
+ vq_gen(inc_dec, grid, node, f, t)
* PENALTY_BALANCE(grid)
) // END sum(gn)
) // END sum(inc_dec)
// Reserve provision feasibility dummy variable penalties
+ sum(restypeDirectionNode(restype, up_down, node),
+ vq_resDemand(restype, up_down, node, f, t)
* PENALTY_RES(restype, up_down)
+ vq_resMissing(restype, up_down, node, f, t)$(ord(t) <= tSolveFirst + p_nReserves(node, restype, 'gate_closure') - mod(tSolveFirst - 1, p_nReserves(node, restype, 'update_frequency')))
* PENALTY_RES_MISSING(restype, up_down)
) // END sum(restypeDirectionNode)
] // END * p_stepLength
// 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, f+df_central(f,t), t) // Cost of starting up
* [ // Startup variable costs
+ p_uStartup(unit, starttype, 'cost', 'unit')
// Start-up fuel and emission costs
+ sum(uFuel(unit, 'startup', fuel),
+ p_uStartup(unit, starttype, 'consumption', 'unit') //${ not unit_investLP(unit) } WHY THIS CONDITIONAL WOULD BE NEEDED?
* [
+ ts_fuelPrice_(fuel, t)
+ sum(emission, // Emission taxes of startup fuel use
+ p_unitFuelEmissionCost(unit, fuel, emission)
) // END sum(emission)
] // END * p_uStartup
) // END sum(uFuel)
] // END * v_startup
) // END sum(starttype)
) // END sum(uft_online)
$ontext
// !!! PENDING CHANGES !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Ramping costs
+ sum(gnuft_ramp(grid, node, unit, f, t)${ p_gnu(grid, node, unit, 'rampUpCost')
or p_gnu(grid, node, unit, 'rampDownCost')
},
+ p_gnu(grid, node, unit, 'rampUpCost') * v_genRampChange(grid, node, unit, 'up', f, t)
+ p_gnu(grid, node, unit, 'rampDownCost') * v_genRampChange(grid, node, unit, 'down', f, t)
) // END sum(gnuft_ramp)
$offtext
] // END * p_sft_probability(s,f,t)
) // END sum over msft(m, s, f, t)
// Cost of energy storage change
+ sum(gn_state(grid, node),
+ sum(mft_start(m, f, t)${ p_storageValue(grid, node, t)
and active(m, 'storageValue')
},
+ v_state(grid, node, f, t)
* p_storageValue(grid, node, t)
* sum(ms(m, s)${ p_msft_probability(m, s, f, t) },
+ p_msft_probability(m, s, f, t)
) // END sum(s)
) // END sum(mftStart)
- sum(mft_lastSteps(m, f, t)${ p_storageValue(grid, node, t)
and active(m, 'storageValue')
},
+ v_state(grid, node, f, t)
* p_storageValue(grid, node, t)
* sum(ms(m, s)${p_msft_probability(m, s, f, t)},
+ p_msft_probability(m, s, f, t)
) // END sum(s)
) // END sum(mftLastSteps)
) // END sum(gn_state)
// Investment Costs
+ sum(t_invest(t),
// 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, '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, 'fomCosts')
]
) // END sum(gnu)
// Transfer link investment costs
+ sum(gn2n_directional(grid, from_node, to_node),
+ v_investTransfer_LP(grid, from_node, to_node, t)${ not p_gnn(grid, from_node, to_node, 'investMIP') }
* [
+ p_gnn(grid, from_node, to_node, 'invCost')
* p_gnn(grid, from_node, to_node, 'annuity')
+ p_gnn(grid, to_node, from_node, 'invCost')
* p_gnn(grid, to_node, from_node, 'annuity')
] // END * v_investTransfer_LP
+ v_investTransfer_MIP(grid, from_node, to_node, t)${ p_gnn(grid, from_node, to_node, 'investMIP') }
* [
+ p_gnn(grid, from_node, to_node, 'unitSize')
* p_gnn(grid, from_node, to_node, 'invCost')
* p_gnn(grid, from_node, to_node, 'annuity')
+ p_gnn(grid, to_node, from_node, 'unitSize')
* p_gnn(grid, to_node, from_node, 'invCost')
* p_gnn(grid, to_node, from_node, 'annuity')
] // END * v_investTransfer_MIP
) // END sum(gn2n_directional)
) // END sum(t_invest)
;
* --- Energy Balance ----------------------------------------------------------
q_balance(gn(grid, node), mft(m, f, t))${ not p_gn(grid, node, 'boundAll')
......@@ -1727,3 +1498,6 @@ q_energyShareMin(group)${ p_groupPolicy(group, 'energyShareMin')
;
$ifthen exist 'input/additional_constraints.inc'
$$include 'input/additional_constraints.inc'
$endif
......@@ -39,18 +39,3 @@ $offtext
* =============================================================================
* --- Fixing some variable values after solve ---------------------------------
* =============================================================================
// Fix non-flow unit reserves ahead of time
// Upper bound can be supplemented from the tertiary reserves when realized.
v_reserve.fx(nuRescapable(restype, up_down, node, unit), f_solve(f), t_active(t))${ mft_nReserves(node, restype, mSolve, f, t) // This set contains the combination of reserve types and time periods that should be fixed
and ord(t) > mSettings(mSolve, 't_start') + p_nReserves(node, restype, 'update_frequency') // Don't lock reserves before the first update
and not unit_flow(unit) // NOTE! Units using flows can change their reserve (they might not have as much available in real time as they had bid)
}
= v_reserve.l(restype, up_down, node, unit, f, t);
vq_resDemand.fx(restypeDirectionNode(restype, up_down, node), f_solve(f), t_active(t))${ mft_nReserves(node, restype, mSolve, f, t) // This set contains the combination of reserve types and time periods that should be fixed
and ord(t) > mSettings(mSolve, 't_start') + p_nReserves(node, restype, 'update_frequency') // Don't lock reserves before the first update
}
= vq_resDemand.l(restype, up_down, node, f, t);
$ontext
This file is part of Backbone.
Backbone is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Backbone is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
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
* =============================================================================
* --- Fixing some variable values after solve ---------------------------------
* =============================================================================
// Fix non-flow unit reserves ahead of time
// Upper bound can be supplemented from the tertiary reserves when realized.
v_reserve.fx(nuRescapable(restype, up_down, node, unit), f_solve(f), t_active(t))${ mft_nReserves(node, restype, mSolve, f, t) // This set contains the combination of reserve types and time periods that should be fixed
and ord(t) > mSettings(mSolve, 't_start') + p_nReserves(node, restype, 'update_frequency') // Don't lock reserves before the first update
and not unit_flow(unit) // NOTE! Units using flows can change their reserve (they might not have as much available in real time as they had bid)
}
= v_reserve.l(restype, up_down, node, unit, f, t);
vq_resDemand.fx(restypeDirectionNode(restype, up_down, node), f_solve(f), t_active(t))${ mft_nReserves(node, restype, mSolve, f, t) // This set contains the combination of reserve types and time periods that should be fixed
and ord(t) > mSettings(mSolve, 't_start') + p_nReserves(node, restype, 'update_frequency') // Don't lock reserves before the first update
}
= vq_resDemand.l(restype, up_down, node, f, t);
{
"name": "Backbone",
"description": "Backbone",
"tooltype": "gams",
"includes": [
"Backbone.gms",
"inc\\1a_definitions.gms",
"inc\\1b_sets.gms",
"inc\\1c_parameters.gms",
"inc\\1d_results.gms",
"inc\\1e_inputs.gms",
"inc\\2a_variables.gms",
"inc\\2b_equations.gms",
"inc\\3a_periodicInit.gms",
"inc\\3b_inputsLoop.gms",
"inc\\3c_periodicLoop.gms",
"inc\\3d_setVariableLimits.gms",
"inc\\3e_solve.gms",
"inc\\4a_outputVariant.gms",
"inc\\4b_outputInvariant.gms",
"inc\\4c_outputQuickFile.gms",
"defModels\\building.gms",
"defModels\\invest.gms",
"defModels\\schedule.gms",
"defOutput\\debugSymbols.inc",
"defOutput\\resultSymbols.inc",
"cplex.opt"
],
"inputfiles": [