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

add time periods objects #16

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/PowerSystemsInvestments.jl
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ include("base/settings.jl")
include("base/solution_algorithms.jl")
include("base/technology_model.jl")
include("base/investment_model_template.jl")
include("base/time_mapping.jl")

include("base/objective_function.jl")
include("base/single_optimization_container.jl")
Expand Down
3 changes: 1 addition & 2 deletions src/base/multi_optimization_container.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ Base.@kwdef mutable struct MultiOptimizationContainer{T <: SolutionAlgorithm} <:
ISOPT.AbstractOptimizationContainer
main_problem::SingleOptimizationContainer
subproblems::Union{Nothing, Dict{String, SingleOptimizationContainer}}
time_steps::UnitRange{Int}
time_steps_operation::UnitRange{Int}
time_mapping::TimeMapping
resolution::Dates.TimePeriod
settings::Settings
settings_copy::Settings
Expand Down
3 changes: 1 addition & 2 deletions src/base/single_optimization_container.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
Base.@kwdef mutable struct SingleOptimizationContainer <:
ISOPT.AbstractOptimizationContainer
JuMPmodel::JuMP.Model
time_steps::UnitRange{Int}
time_steps_investments::UnitRange{Int}
time_mapping::TimeMapping
settings::Settings
settings_copy::Settings
variables::Dict{ISOPT.VariableKey, AbstractArray}
Expand Down
7 changes: 1 addition & 6 deletions src/base/technology_model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,5 @@ function TechnologyModel(
_check_technology_formulation(D, B, C)
#TODO: new is only defined for inner constructors, replace for now but we might want to reorganize this file later
#new{D, B, C}(use_slacks, duals, time_series_names, attributes_, nothing)
return TechnologyModel{D, B, C}(
use_slacks,
duals,
time_series_names,
attributes_,
)
return TechnologyModel{D, B, C}(use_slacks, duals, time_series_names, attributes_)
end
92 changes: 92 additions & 0 deletions src/base/time_mapping.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
struct InvestmentIntervals
time_stamps::Vector{NTuple{2, Dates.Date}}
map_to_operational_slices::Dict{Int, Vector{Int}}
map_to_feasibility_slices::Dict{Int, Vector{Int}}
end

struct OperationalPeriods
time_stamps::Vector{Dates.DateTime}
consecutive_slices::Vector{Vector{Int}}
inverse_invest_mapping::Vector{Int}
feasibility_indexes::Vector{Int}
operational_indexes::Vector{Int}
end

struct TimeMapping
investment::InvestmentIntervals
operation::OperationalPeriods

function TimeMapping(
investment_intervals::Vector{NTuple{2, Dates.Date}},
operational_periods::Vector{Vector{Dates.DateTime}},
feasibility_periods::Vector{Vector{Dates.DateTime}},
)
# TODO:
# Validation of the dates to avoid overlaps
# Validation of the dates to avoid gaps in the operational periods

op_index_last_slice = length(operational_periods)
all_operation_slices = union(operational_periods, feasibility_periods)
total_count = sum(length(x) for x in all_operation_slices)
total_slice_count = length(operational_periods) + length(feasibility_periods)
time_stamps = Vector{Dates.DateTime}(undef, total_count)
consecutive_slices = Vector{Vector{Int}}(undef, total_slice_count)
inverse_invest_mapping = Vector{Vector{Int}}(undef, total_slice_count)
map_to_operational_slices = Dict{Int, Vector{Int}}(
i => Vector{Int}() for i in 1:length(investment_intervals)
)
map_to_feasibility_slices = Dict{Int, Vector{Int}}(
i => Vector{Int}() for i in 1:length(investment_intervals)
)

ix = 1
slice_running_count = 0
for (sx, slice) in enumerate(all_operation_slices)
slice_length = length(slice)
slice_found_in_interval = false
for (ivx, investment_interval) in enumerate(investment_intervals)
if first(slice) >= investment_interval[1] &&
last(slice) <= investment_interval[2]
if sx <= op_index_last_slice
push!(map_to_operational_slices[ivx], sx)
else
push!(map_to_feasibility_slices[ivx], sx)
end
inverse_invest_mapping[sx] = ivx
slice_found_in_interval = true
break
end
end
if !slice_found_in_interval
error()
end
slice_length = length(slice)
slice_indeces = range(slice_running_count + 1, length=slice_length)
consecutive_slices[sx] = collect(slice_indeces)
slice_running_count = last(slice_indeces)
for time_stamp in slice
time_stamps[ix] = time_stamp
ix += 1
end
end

op_periods = OperationalPeriods(
time_stamps,
consecutive_slices,
inverse_invest_mapping,
collect(range(start=op_index_last_slice + 1, stop=total_slice_count)),
collect(range(1, op_index_last_slice)),
)

inv_periods = InvestmentIntervals(
investment_intervals,
map_to_operational_slices,
map_to_feasibility_slices,
)

new(inv_periods, op_periods)
end
end

get_total_operation_period_count(tm::TimeMapping) = length(tm.operation.time_stamps)
# TODO: use more accessors to get the problem times
20 changes: 10 additions & 10 deletions src/investment_model/investment_model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ is_built(model::InvestmentModel) =
isempty(model::InvestmentModel) =
IS.Optimization.get_status(get_internal(model)) == ModelBuildStatus.EMPTY


get_constraints(model::InvestmentModel) =
IS.Optimization.get_constraints(get_internal(model))
get_internal(model::InvestmentModel) = model.internal
Expand All @@ -139,30 +138,32 @@ function get_optimization_container(model::InvestmentModel)
return IS.Optimization.get_optimization_container(get_internal(model))
end


function get_timestamps(model::InvestmentModel)
optimization_container = get_optimization_container(model)
start_time = get_initial_time(optimization_container)
resolution = get_resolution(model)
horizon_count = get_time_steps(optimization_container)[end]
return range(start_time; length = horizon_count, step = resolution)
return range(start_time; length=horizon_count, step=resolution)
end

get_problem_base_power(model::InvestmentModel) = PSY.get_base_power(model.portfolio)
get_settings(model::InvestmentModel) = get_optimization_container(model).settings
get_optimizer_stats(model::InvestmentModel) = get_optimizer_stats(get_optimization_container(model))
get_optimizer_stats(model::InvestmentModel) =
get_optimizer_stats(get_optimization_container(model))

get_status(model::InvestmentModel) = IS.Optimization.get_status(get_internal(model))
get_portfolio(model::InvestmentModel) = model.portfolio
get_template(model::InvestmentModel) = model.template

get_store_params(model::InvestmentModel) = IS.Optimization.get_store_params(get_internal(model))
get_store_params(model::InvestmentModel) =
IS.Optimization.get_store_params(get_internal(model))
get_output_dir(model::InvestmentModel) = IS.Optimization.get_output_dir(get_internal(model))

get_variables(model::InvestmentModel) = get_variables(get_optimization_container(model))
get_parameters(model::InvestmentModel) = get_parameters(get_optimization_container(model))
get_duals(model::InvestmentModel) = get_duals(get_optimization_container(model))
get_initial_conditions(model::InvestmentModel) = get_initial_conditions(get_optimization_container(model))
get_initial_conditions(model::InvestmentModel) =
get_initial_conditions(get_optimization_container(model))

get_run_status(model::InvestmentModel) = get_run_status(get_simulation_info(model))
set_run_status!(model::InvestmentModel, status) =
Expand All @@ -188,13 +189,13 @@ function solve_impl!(model::InvestmentModel)
end
return
end

set_console_level!(model::InvestmentModel, val) =
IS.Optimization.set_console_level!(get_internal(model), val)
set_file_level!(model::InvestmentModel, val) =
IS.Optimization.set_file_level!(get_internal(model), val)

function set_status!(model::InvestmentModel, status::ModelBuildStatus)
function set_status!(model::InvestmentModel, status::ISOPT.ModelBuildStatus)
IS.Optimization.set_status!(get_internal(model), status)
return
end
Expand Down Expand Up @@ -235,7 +236,6 @@ end

read_optimizer_stats(model::InvestmentModel) = read_optimizer_stats(get_store(model))


list_aux_variable_keys(x::InvestmentModel) =
IS.Optimization.list_keys(get_store(x), STORE_CONTAINER_AUX_VARIABLES)
list_aux_variable_names(x::InvestmentModel) = _list_names(x, STORE_CONTAINER_AUX_VARIABLES)
Expand Down
2 changes: 1 addition & 1 deletion src/investment_model/investment_problem_results.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ function OptimizationProblemResults(model::InvestmentModel)
get_output_dir(model),
mkpath(joinpath(get_output_dir(model), "results")),
)
end
end
5 changes: 1 addition & 4 deletions src/technology_models/technologies/demand_tech.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,7 @@ function add_expression!(
time_steps_ix = mapping_ops[year]
multiplier = 1.0
for (ix, t) in enumerate(time_steps_ix)
_add_to_jump_expression!(
expression[t],
ts_data[ix] * multiplier,
)
_add_to_jump_expression!(expression[t], ts_data[ix] * multiplier)
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ function construct_technologies!(
technology_model::TechnologyModel{T, B, C},
# network_model::NetworkModel{<:PM.AbstractActivePowerModel},
) where {T <: PSIP.DemandRequirement, B <: StaticLoadInvestment, C <: BasicDispatch}

return
end

Expand Down Expand Up @@ -83,6 +82,5 @@ function construct_technologies!(
technology_model::TechnologyModel{T, B, C},
# network_model::NetworkModel{<:PM.AbstractActivePowerModel},
) where {T <: PSIP.DemandRequirement, B <: StaticLoadInvestment, C <: BasicDispatch}

return
end
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,3 @@ function construct_technologies!(

return
end

73 changes: 73 additions & 0 deletions test/test_base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,76 @@ end
@test length(c["cheap_thermal", :]) ==
length(PSIN.get_time_steps_investments(container))
end

@testset "Time Mappings" begin
investments = [
(Date(Month(1), Year(2025)), Date(Month(1), Year(2026))),
(Date(Month(1), Year(2026)), Date(Month(1), Year(2027))),
]

operations = [
[DateTime(Month(1), Day(25), Year(2025))],
collect(
range(
start=DateTime(Day(1), Month(3), Year(2025)),
stop=start = DateTime(Day(7), Month(3), Year(2025)),
step=Hour(1),
),
),
collect(
range(
start=DateTime(Day(1), Month(7), Year(2025)),
stop=start = DateTime(Day(13), Month(7), Year(2025)),
step=Hour(1),
),
),
collect(
range(
start=DateTime(Day(1), Month(9), Year(2025)),
stop=start = DateTime(Day(10), Month(9), Year(2025)),
step=Hour(1),
),
),
collect(
range(
start=DateTime(Day(1), Month(3), Year(2026)),
stop=start = DateTime(Day(8), Month(3), Year(2026)),
step=Hour(1),
),
),
collect(
range(
start=DateTime(Day(1), Month(7), Year(2026)),
stop=start = DateTime(Day(6), Month(7), Year(2026)),
step=Hour(1),
),
),
collect(
range(
start=DateTime(Day(1), Month(9), Year(2026)),
stop=start = DateTime(Day(10), Month(9), Year(2026)),
step=Hour(1),
),
),
]

feasibility = [
collect(
range(
start=DateTime(Day(1), Month(4), Year(2025)),
stop=start = DateTime(Day(15), Month(4), Year(2025)),
step=Hour(1),
),
),
collect(
range(
start=DateTime(Day(1), Month(6), Year(2026)),
stop=start = DateTime(Day(5), Month(6), Year(2026)),
step=Hour(1),
),
),
]

res = PSINV.TimeMapping(investments, operations, feasibility)
# TODO: add more tests
end
Loading