Commit 0b2de1ef authored by jussi ikäheimo's avatar jussi ikäheimo
Browse files

Added boundstart and boundend for superposed nodes. Added self-discharge loss.

parent 1f51eb63
......@@ -77,7 +77,8 @@ Model invest /
q_boundCyclic
// superpositioned state variables
q_superposBegin
q_superposSampleBegin
q_superposBoundEnd
q_superposInter
q_superposStateMax
q_superposStateMin
......
......@@ -54,6 +54,7 @@ Sets
onlyExistingForecasts "Use only existing forecast values when reading updated forecasts. Note: zero values need to be saved as Eps in the gdx file."
scenarios "Number of long-term scenarios used"
scenarioLength "Length of scenario in time steps for creating stochastic scenarios from time series data"
candidate_periods "Number of candidate periods which are mapped to typical periods"
// Features
t_trajectoryHorizon "Length of the horizon when start-up and shutdown trajectories are considered (in time steps)"
......
......@@ -110,7 +110,8 @@ equations
q_boundCyclic(grid, node, s, s, mType) "Cyclic node state bound for the first and the last states of samples"
// superpositioned state variables
q_superposBegin(grid, node, mType, s)
q_superposSampleBegin(grid, node, mType, s)
q_superposBoundEnd(grid, node, mType)
q_superposInter(grid, node, mType,z)
q_superposStateMax(grid, node, mType, s, f, t)
q_superposStateMin(grid, node, mType, s, f, t)
......
......@@ -2261,10 +2261,23 @@ q_stateSlack(gn_stateSlack(grid, node), slack, sft(s, f, t))
* --- Upwards Limit for State Variables ---------------------------------------
q_stateUpwardLimit(gn_state(grid, node), msft(m, s, f, t))
${ sum(gn2gnu(grid, node, grid_, node_output, unit)$(sum(restype, gnuRescapable(restype, 'down', grid_, 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, gnuRescapable(restype, 'down', grid_, node_input , unit))), 1) // or nodes that have units with endogenous input with possible reserve provision
or sum(gnu(grid, node, unit), p_gnu(grid, node, unit, 'upperLimitCapacityRatio')) // or nodes that have units whose invested capacity limits their state
} ..
${ not node_superpos(node)
and
{
sum(gn2gnu(grid, node, grid_, node_output, unit)
$(sum(restype, gnuRescapable(restype, 'down', grid_, 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, gnuRescapable(restype, 'down', grid_, node_input , unit))),
1) // or nodes that have units with endogenous input with possible reserve provision
or
sum(gnu(grid, node, unit),
p_gnu(grid, node, unit, 'upperLimitCapacityRatio')
) // or nodes that have units whose invested capacity limits their state
}
} ..
// Utilizable headroom in the state variable
+ [
......@@ -2340,9 +2353,17 @@ q_stateUpwardLimit(gn_state(grid, node), msft(m, s, f, t))
* --- Downwards Limit for State Variables -------------------------------------
q_stateDownwardLimit(gn_state(grid, node), msft(m, s, f, t))
${ sum(gn2gnu(grid, node, grid_, node_output, unit)$(sum(restype, gnuRescapable(restype, 'up', grid_, 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, gnuRescapable(restype, 'up', grid_, node_input , unit))), 1) // or nodes that have units with endogenous input with possible reserve provision
} ..
${ //ordinary nodes with no superpositioning of state
not node_superpos(node)
and
{
// nodes that have units with endogenous output with possible reserve provision
sum(gn2gnu(grid, node, grid_, node_output, unit)$(sum(restype, gnuRescapable(restype, 'up', grid_, node_output, unit))), 1)
or
// or nodes that have units with endogenous input with possible reserve provision
sum(gn2gnu(grid_, node_input, grid, node, unit) $(sum(restype, gnuRescapable(restype, 'up', grid_, node_input , unit))), 1)
}
}..
// Utilizable headroom in the state variable
+ [
......@@ -2545,7 +2566,10 @@ q_boundCyclic(gnss_bound(gn_state(grid, node), s_, s), m)
*--- Intra-period state for superpositioned states ----------------------------
q_superposBegin(gn_state(grid, node_superpos(node)), m, s)
* v_state for superpositioned states represents the intra-period state. It
* always starts from zero.
q_superposSampleBegin(gn_state(grid, node_superpos(node)), m, s)
${ ms(m, s)
}..
......@@ -2559,18 +2583,62 @@ q_superposBegin(gn_state(grid, node_superpos(node)), m, s)
=E= 0
;
q_superposBoundEnd(gn_state(grid, node_superpos(node)), m)
$(p_gn(grid, node, 'boundEnd') )..
// Value of the superposed state of the node at the end of the last candidate
// period
sum(mz(m,z)$(ord(z) eq mSettings('invest', 'candidate_periods') ),
//the inter-period state at the beginning of the last candidate period
v_state_z(grid, node, z)
+
//change of the intra-period state during the representative period
sum(zs(z, s_),
// State of the node at the end of the sample s_
+ sum(mst_end(m, s_, t),
+ sum(sft(s_, f, t),
+ v_state(grid, node, s_, f, t)
) // END sum(ft)
) // END sum(mst_end)
// State of the node at the start of the sample s_
- sum(mst_start(m, s_, t),
sum(sft(s_, f, t),
+ v_state(grid, node, s_, f+df(f,t+dt(t)), t+dt(t))
) // END sum(ft)
) // END sum(mst_start)
) // end sum(zs)
)
=E=
p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'multiplier')
;
*--- Inter-period state dynamic equation for superpositioned states -----------
q_superposInter(gn_state(grid, node_superpos(node)), mz(m,z))
${ ord(z) > 1
}..
// State of the node at the beginning of period z
v_state_z(grid, node, z)
=E=
v_state_z(grid, node, z-1)
+
sum(zs(z-1, s_),
// Inter-period state of the node at the beginning of period z
v_state_z(grid, node, z)
=E=
// State of the node at the beginning of previous period z-1
v_state_z(grid, node, z-1)
*
//multiplied by the self discharge loss over the period
sum(zs(z-1, s_),
power(1 - mSettings(m, 'stepLengthInHours')
* p_gn(grid, node, 'selfDischargeLoss'),
msEnd(m,s_) - msStart(m,s_) )
)
+
//change of the intra-period state during the representative period
sum(zs(z-1, s_),
// State of the node at the end of the sample s_
+ sum(mst_end(m, s_, t),
+ sum(sft(s_, f, t),
......
......@@ -19,107 +19,120 @@ $offtext
* --- Variable limits ---------------------------------------------------------
* =============================================================================
* =============================================================================
* --- Node State Boundaries ---------------------------------------------------
* =============================================================================
// When using constant values and to supplement time series with constant values (time series will override when data available)
// Upper bound
v_state.up(gn_state(grid, node), sft(s, f, t))${ p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'useConstant')
and not df_central(f,t)
and not node_superpos(node)
}
= p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'multiplier')
;
// Lower bound
v_state.lo(gn_state(grid, node), sft(s, f, t))${ p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'useConstant')
and not df_central(f,t)
and not node_superpos(node)
}
= p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'multiplier')
;
// Fixed value
v_state.fx(gn_state(grid, node), sft(s, f, t))${ p_gn(grid, node, 'boundAll')
and p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'useConstant')
and not df_central(f,t)
and not node_superpos(node)
}
= p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'multiplier')
;
// BoundEnd to a constant value
v_state.fx(gn_state(grid, node), sft(s, f,t))${ mft_lastSteps(mSolve, f, t)
and p_gn(grid, node, 'boundEnd')
and p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'useConstant')
and not node_superpos(node)
}
= p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'multiplier');
// When using time series
// Upper Bound
v_state.up(gn_state(grid, node), sft(s, f, t))${ p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'useTimeSeries')
and not df_central(f,t)
and not node_superpos(node)
}
= ts_node_(grid, node, 'upwardLimit', s, f, t)
* p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'multiplier')
;
// Lower bound
v_state.lo(gn_state(grid, node), sft(s, f, t))${ p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'useTimeSeries')
and not df_central(f,t)
and not node_superpos(node)
}
= ts_node_(grid, node, 'downwardLimit', s, f, t)
* p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'multiplier')
;
// Fixed value
v_state.fx(gn_state(grid, node), sft(s, f, t))${ p_gn(grid, node, 'boundAll')
and p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'useTimeSeries')
and not df_central(f,t)
and not node_superpos(node)
}
= ts_node_(grid, node, 'reference', s, f, t)
* p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'multiplier')
;
// BoundEnd to a timeseries value
v_state.fx(gn_state(grid, node), sft(s, f,t))${ mft_lastSteps(mSolve, f, t)
and p_gn(grid, node, 'boundEnd')
and p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'useTimeSeries')
and not node_superpos(node)
}
= ts_node_(grid, node, 'reference', s, f, t)
* p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'multiplier');
// BoundStartToEnd: bound the last interval in the horizon to the value just before the horizon
v_state.fx(gn_state(grid, node), sft(s, f, t))${ mft_lastSteps(mSolve, f, t)
and p_gn(grid, node, 'boundStartToEnd')
and not node_superpos(node)
}
= sum(mf_realization(mSolve, f_),
+ r_state(grid, node, f_, tSolve)
); // END sum(mf_realization)
loop(mst_start(mSolve, s, t)$(tSolveFirst = mSettings(mSolve, 't_start')),
// Bound also the intervals just before the start of each sample - currently just 'upwardLimit'&'useConstant' and 'downwardLimit'&'useConstant'
// state limits for normal (not superposed) nodes
loop(node$(not node_superpos(node)),
// When using constant values and to supplement time series with constant values (time series will override when data available)
// Upper bound
v_state.up(gn_state(grid, node), s, f_solve, t+dt(t))${ p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'useConstant')
and not df_central(f_solve,t)
and not node_superpos(node)
}
= p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'multiplier');
v_state.up(gn_state(grid, node), sft(s, f, t))${p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'useConstant')
and not df_central(f,t)
}
= p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'multiplier')
;
// Lower bound
v_state.lo(gn_state(grid, node), sft(s, f, t))${p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'useConstant')
and not df_central(f,t)
}
= p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'multiplier')
;
// Fixed value
v_state.fx(gn_state(grid, node), sft(s, f, t))${p_gn(grid, node, 'boundAll')
and p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'useConstant')
and not df_central(f,t)
}
= p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'multiplier')
;
// BoundEnd to a constant value
v_state.fx(gn_state(grid, node), sft(s, f,t))${ mft_lastSteps(mSolve, f, t)
and p_gn(grid, node, 'boundEnd')
and p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'useConstant')
}
= p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'multiplier');
// When using time series
// Upper Bound
v_state.up(gn_state(grid, node), sft(s, f, t))${p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'useTimeSeries')
and not df_central(f,t)
}
= ts_node_(grid, node, 'upwardLimit', s, f, t)
* p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'multiplier')
;
// Lower bound
v_state.lo(gn_state(grid, node), s, f_solve, t+dt(t))${ p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'useConstant')
and not df_central(f_solve,t)
and not node_superpos(node)
}
= p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'multiplier');
); // END loop(mst_start)
v_state.lo(gn_state(grid, node), sft(s, f, t))${p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'useTimeSeries')
and not df_central(f,t)
}
= ts_node_(grid, node, 'downwardLimit', s, f, t)
* p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'multiplier')
;
// Fixed value
v_state.fx(gn_state(grid, node), sft(s, f, t))${p_gn(grid, node, 'boundAll')
and p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'useTimeSeries')
and not df_central(f,t)
}
= ts_node_(grid, node, 'reference', s, f, t)
* p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'multiplier')
;
// BoundEnd to a timeseries value
v_state.fx(gn_state(grid, node), sft(s, f,t))${mft_lastSteps(mSolve, f, t)
and p_gn(grid, node, 'boundEnd')
and p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'useTimeSeries')
}
= ts_node_(grid, node, 'reference', s, f, t)
* p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'multiplier');
// BoundStartToEnd: bound the last interval in the horizon to the value just before the horizon
v_state.fx(gn_state(grid, node), sft(s, f, t))${mft_lastSteps(mSolve, f, t)
and p_gn(grid, node, 'boundStartToEnd')
}
= sum(mf_realization(mSolve, f_),
+ r_state(grid, node, f_, tSolve)
); // END sum(mf_realization)
// Bound also the intervals just before the start of each sample - currently just 'upwardLimit'&'useConstant' and 'downwardLimit'&'useConstant'
loop(mst_start(mSolve, s, t)$(tSolveFirst = mSettings(mSolve, 't_start')),
// Upper bound
v_state.up(gn_state(grid, node), s, f_solve, t+dt(t))${ p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'useConstant')
and not df_central(f_solve,t)
and not node_superpos(node)
}
= p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'multiplier');
// Lower bound
v_state.lo(gn_state(grid, node), s, f_solve, t+dt(t))${ p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'useConstant')
and not df_central(f_solve,t)
and not node_superpos(node)
}
= p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'multiplier');
); // END loop(mst_start)
); //end loop node
// Next deal with bounds for the superposed node states
// note that boundstart is handled further below
loop(node_superpos(node),
//add here the desired bounds for v_state_z
);
* =============================================================================
* --- Spilling of energy from the nodes----------------------------------------
* =============================================================================
// Spilling of energy from the nodes
// Max. & min. spilling, use constant value as base and overwrite with time series if desired
v_spill.lo(gn(grid, node_spill), sft(s, f, t))${ p_gnBoundaryPropertiesForStates(grid, node_spill, 'minSpill', 'constant') }
= p_gnBoundaryPropertiesForStates(grid, node_spill, 'minSpill', 'constant')
......@@ -469,34 +482,39 @@ v_investTransfer_MIP.up(gn2n_directional(grid, from_node, to_node), t_invest)${
// Loop over the start intervals
loop((mft_start(mSolve, f, t), ms_initial(mSolve, s)),
// If this is the very first solve, set boundStart
// If this is the very first solve, set various initial bounds
if(tSolveFirst = mSettings(mSolve, 't_start'),
// Upper bound
v_state.up(gn_state(grid, node), s, f, t)${ p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'useConstant')
and not df_central(f,t)
}
= p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'multiplier');
// state limits for normal (not superposed) nodes
loop(node$(not node_superpos(node)),
// Upper bound
v_state.up(gn_state(grid, node), s, f, t)${ p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'useConstant')
and not df_central(f,t)
}
= p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'upwardLimit', 'multiplier');
// Lower bound
v_state.lo(gn_state(grid, node), s, f, t)${ p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'useConstant')
and not df_central(f,t)
}
= p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'multiplier');
// First solve, state variables (only if boundStart flag is true)
v_state.fx(gn_state(grid, node), s, f, t)${ p_gn(grid, node, 'boundStart') }
= p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'multiplier');
// Time series form boundary
v_state.fx(gn_state(grid, node), s, f, t)${ p_gn(grid, node, 'boundStart')
and p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'useTimeSeries') // !!! NOTE !!! The check fails if value is zero
}
= ts_node(grid, node, 'reference', f, t) // NOTE!!! ts_node_ doesn't contain initial values so using raw data instead.
* p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'multiplier');
); //end loop of nodes
// Lower bound
v_state.lo(gn_state(grid, node), s, f, t)${ p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'useConstant')
and not df_central(f,t)
}
= p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'downwardLimit', 'multiplier');
// First solve, state variables (only if boundStart flag is true)
v_state.fx(gn_state(grid, node), s, f, t)${ p_gn(grid, node, 'boundStart') }
= p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'multiplier');
// Time series form boundary
v_state.fx(gn_state(grid, node), s, f, t)${ p_gn(grid, node, 'boundStart')
and p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'useTimeSeries') // !!! NOTE !!! The check fails if value is zero
}
= ts_node(grid, node, 'reference', f, t) // NOTE!!! ts_node_ doesn't contain initial values so using raw data instead.
* p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'multiplier');
// Initial online status for units
v_online_MIP.fx(unit, s, f, t)${p_unit(unit, 'useInitialOnlineStatus') and uft_onlineMIP(unit, f, t+1)} //sets online status for one time step before the first solve
......@@ -529,6 +547,16 @@ loop((mft_start(mSolve, f, t), ms_initial(mSolve, s)),
) // END loop(mft_start)
;
if(tSolveFirst = mSettings(mSolve, 't_start'),
// state limits for normal (not superposed) nodes
loop(node_superpos(node),
// First solve, state variables (only if boundStart flag is true)
v_state_z.fx(gn_state(grid, node), z)${ p_gn(grid, node, 'boundStart') }
= p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'constant')
* p_gnBoundaryPropertiesForStates(grid, node, 'reference', 'multiplier');
) //END loop node_superpos
); //END if(tSolveFirst)
* =============================================================================
* --- Fix previously realized start-ups, shutdowns, and online states ---------
......
Markdown is supported
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