Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix time indices for representative temporal blocks #1015

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
Draft
6 changes: 5 additions & 1 deletion src/constraints/constraint_unit_pw_heat_rate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,15 @@ function _build_constraint_unit_pw_heat_rate(m::Model, u, n_from, n_to, s_path,
* unit_idle_heat_rate(
m; unit=u, node1=n_from, node2=n_to, stochastic_scenario=s, analysis_time=t0, t=t
)
for (u, s, t1) in units_on_indices(m; unit=u, stochastic_scenario=s_path, t=t_overlaps_t(m; t=t));
init=0,
)
+ sum(
+ units_started_up[u, s, t1]
* unit_start_flow(
m; unit=u, node1=n_from, node2=n_to, stochastic_scenario=s, analysis_time=t0, t=t
)
for (u, s, t1) in units_on_indices(m; unit=u, stochastic_scenario=s_path, t=t_overlaps_t(m; t=t));
for (u, s, t1) in units_switched_indices(m; unit=u, stochastic_scenario=s_path, t=t_overlaps_t(m; t=t));
init=0,
)
)
Expand Down
9 changes: 8 additions & 1 deletion src/constraints/constraint_unit_state_transition.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,19 @@ function _build_constraint_unit_state_transition(m::Model, u, s_path, t_before,
# TODO: use :integer, :binary, :linear as parameter values -> reusable for other pruposes
@build_constraint(
sum(
+ units_on[u, s, t_after] - units_started_up[u, s, t_after] + units_shut_down[u, s, t_after]
+ units_on[u, s, t_after]
for (u, s, t_after) in units_on_indices(
m; unit=u, stochastic_scenario=s_path, t=t_after, temporal_block=anything,
);
init=0,
)
+ sum(
+ units_shut_down[u, s, t_after] - units_started_up[u, s, t_after]
for (u, s, t_after) in units_switched_indices(
m; unit=u, stochastic_scenario=s_path, t=t_after, temporal_block=anything,
);
init=0,
)
==
sum(
+ units_on[u, s, t_before]
Expand Down
2 changes: 1 addition & 1 deletion src/data_structure/temporal_structure.jl
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,7 @@ function unit_dynamic_time_indices(
(
(unit=u, t_before=tb, t_after=ta)
for (u, blk) in units_on__temporal_block(unit=unit, _compact=false)
for (tb, ta) in dynamic_time_indices(m, blk; t_before=t_before, t_after=t_after)
for (tb, ta) in dynamic_time_indices(m, blk; t_before=t_before, t_after=t_after)
)
end

Expand Down
13 changes: 11 additions & 2 deletions src/variables/variable_common.jl
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,12 @@ function add_variable!(
t = vcat(history_time_slices, time_slice(m))
first_ind = iterate(indices(m; t=t))
K = first_ind === nothing ? Any : typeof(first_ind[1])
# Some indices functions may use as default the temporal_blocks that exclude the history_time_slices.
# This could cause trouble for variables in some constraints (e.g. units_on in constraint_unit_state_transition)
# when using representiative temporal structure.
_iter_indices = Iterators.flatten((indices(m; t=t), indices(m; temporal_block=anything, t=history_time_slices)))
vars = m.ext[:spineopt].variables[name] = Dict{K,Union{VariableRef,AffExpr,Call}}(
ind => _add_variable!(m, name, ind, replacement_value) for ind in indices(m; t=t) if !haskey(ind_map, ind)
ind => _add_variable!(m, name, ind, replacement_value) for ind in Set(_iter_indices) if !haskey(ind_map, ind)
)
inverse_ind_map = Dict(ref_ind => (ind, 1 / coeff) for (ind, (ref_ind, coeff)) in ind_map)
Threads.@threads for ind in collect(keys(vars))
Expand All @@ -89,7 +93,10 @@ function add_variable!(
res_internal_fix_value = _resolve(internal_fix_value, m, ind, other_ind_and_factor...; reducer=_check_unique)
_finalize_variable!(vars[ind], res_bin, res_int, res_lb, res_ub, res_fix_value, res_internal_fix_value)
end
merge!(vars, Dict(ind => coeff * vars[ref_ind] for (ind, (ref_ind, coeff)) in ind_map))
# A ref_ind may not be covered by keys(vars) unless
# the ind_map is carefully designed in specific variable adding functions.
filtered_ind_map = Dict(ind => (ref_ind, coeff) for (ind, (ref_ind, coeff)) in ind_map if haskey(vars, ref_ind))
merge!(vars, Dict(ind => coeff * vars[ref_ind] for (ind, (ref_ind, coeff)) in filtered_ind_map))
# Apply initial value, but make sure it updates itself by using a TimeSeries Call
if initial_value !== nothing
last_history_t = last(history_time_slice(m))
Expand All @@ -104,6 +111,8 @@ function add_variable!(
end
end
isempty(SpineInterface.indices(representative_periods_mapping)) || merge!(
# When a representative termporal structure is used, the syntax will generate representative periods mapping
# only for the given indices, excluding the internally generated history_time_slice.
vars, _representative_periods_mapping(m, vars, indices)
)
vars
Expand Down
Loading