diff --git a/src/TimeStruct.jl b/src/TimeStruct.jl index 1b3ed3b..e2b9195 100644 --- a/src/TimeStruct.jl +++ b/src/TimeStruct.jl @@ -23,9 +23,9 @@ include("op_scenarios/rep_periods.jl") include("op_scenarios/strat_periods.jl") include("op_scenarios/tree_periods.jl") -include("utils.jl") include("discount.jl") include("profiles.jl") +include("utils.jl") include("partitions/strat_periods.jl") include("partitions/rep_periods.jl") diff --git a/src/partitions/opscenarios.jl b/src/partitions/opscenarios.jl index 6381746..52cf338 100644 --- a/src/partitions/opscenarios.jl +++ b/src/partitions/opscenarios.jl @@ -11,7 +11,9 @@ struct OpScenPart{N,T} <: AbstractOpScenPart{T} chunk::NTuple{N,T} end PeriodPartition(itr::OperationalScenario, part, chunk) = OpScenPart(itr.scen, part, chunk) -eltype(::Type{PartitionDurationIterator{I}}) where {I<:OperationalScenario} = OpScenPart +function eltype(::Type{PartitionDurationIterator{I,T,D}}) where {I<:OperationalScenario,T,D} + return OpScenPart +end Base.show(io::IO, pd::OpScenPart) = print(io, "sc$(pd.scen)-part$(pd.part)") diff --git a/src/partitions/rep_periods.jl b/src/partitions/rep_periods.jl index 3293719..2736b78 100644 --- a/src/partitions/rep_periods.jl +++ b/src/partitions/rep_periods.jl @@ -11,7 +11,11 @@ struct ReprPart{N,T} <: AbstractReprPart{T} chunk::NTuple{N,T} end PeriodPartition(itr::RepresentativePeriod, part, chunk) = ReprPart(itr.rp, part, chunk) -eltype(::Type{PartitionDurationIterator{I}}) where {I<:RepresentativePeriod} = ReprPart +function eltype( + ::Type{PartitionDurationIterator{I,T,D}}, +) where {I<:RepresentativePeriod,T,D} + return ReprPart +end Base.show(io::IO, pd::ReprPart) = print(io, "rp$(pd.rp)-part$(pd.part)") @@ -26,7 +30,9 @@ end function PeriodPartition(itr::ReprOpScenario, part, chunk) return ReprOpScenPart(itr.rp, itr.scen, part, chunk) end -eltype(::Type{PartitionDurationIterator{I}}) where {I<:ReprOpScenario} = ReprOpScenPart +function eltype(::Type{PartitionDurationIterator{I,T,D}}) where {I<:ReprOpScenario,T,D} + return ReprOpScenPart +end Base.show(io::IO, pd::ReprOpScenPart) = print(io, "rp$(pd.rp)-sc$(pd.scen)-part$(pd.part)") ScenarioIndexable(::Type{<:ReprOpScenPart}) = HasScenarioIndex() diff --git a/src/partitions/strat_periods.jl b/src/partitions/strat_periods.jl index 79c6825..97c3780 100644 --- a/src/partitions/strat_periods.jl +++ b/src/partitions/strat_periods.jl @@ -11,7 +11,7 @@ struct StratPart{N,T} <: AbstractStratPart{T} chunk::NTuple{N,T} end PeriodPartition(itr::StrategicPeriod, part, chunk) = StratPart(itr.sp, part, chunk) -eltype(::Type{PartitionDurationIterator{I}}) where {I<:StrategicPeriod} = StratPart +eltype(::Type{PartitionDurationIterator{I,T,D}}) where {I<:StrategicPeriod,T,D} = StratPart Base.show(io::IO, pd::StratPart) = print(io, "sp$(pd.sp)-part$(pd.part)") @@ -26,7 +26,9 @@ end function PeriodPartition(itr::StratReprPeriod, part, chunk) return StratReprPart(itr.sp, itr.rp, part, chunk) end -eltype(::Type{PartitionDurationIterator{I}}) where {I<:StratReprPeriod} = StratReprPart +function eltype(::Type{PartitionDurationIterator{I,T,D}}) where {I<:StratReprPeriod,T,D} + return StratReprPart +end Base.show(io::IO, pd::StratReprPart) = print(io, "sp$(pd.sp)-rp$(pd.rp)-part$(pd.part)") RepresentativeIndexable(::Type{<:StratReprPart}) = HasReprIndex() @@ -43,7 +45,9 @@ end function PeriodPartition(itr::StratOpScenario, part, chunk) return StratOpScenPart(itr.sp, itr.scen, part, chunk) end -eltype(::Type{PartitionDurationIterator{I}}) where {I<:StratOpScenario} = StratOpScenPart +function eltype(::Type{PartitionDurationIterator{I,T,D}}) where {I<:StratOpScenario,T,D} + return StratOpScenPart +end function Base.show(io::IO, pd::StratOpScenPart) return print(io, "sp$(pd.sp)-sc$(pd.scen)-part$(pd.part)") @@ -63,7 +67,7 @@ end function PeriodPartition(itr::StratReprOpScenario, part, chunk) return StratReprOpScenPart(itr.sp, itr.rp, itr.scen, part, chunk) end -function eltype(::Type{PartitionDurationIterator{I}}) where {I<:StratReprOpScenario} +function eltype(::Type{PartitionDurationIterator{I,T,D}}) where {I<:StratReprOpScenario,T,D} return StratReprOpScenPart end diff --git a/src/structures.jl b/src/structures.jl index 449abb2..91bbfc9 100644 --- a/src/structures.jl +++ b/src/structures.jl @@ -114,3 +114,29 @@ _total_duration(tss::Vector) = sum(duration(ts) for ts in tss) _multiple_adj(ts::TimeStructure, per) = 1.0 stripunit(val) = val + +""" + abstract type PeriodPartition{T<:TimePeriod} + +Supertype for individual partitions for operational time periods. Subtypes must be created +for all potential time structures to be able to identify the respective +[`TimeStructurePeriod`](@ref). +""" + +abstract type PeriodPartition{T<:TimePeriod} end + +Base.iterate(pd::PeriodPartition) = iterate(pd.chunk) +Base.iterate(pd::PeriodPartition, state) = iterate(pd.chunk, state) +Base.length(pd::PeriodPartition) = length(pd.chunk) +Base.first(pd::PeriodPartition) = first(pd.chunk) +Base.last(pd::PeriodPartition) = last(pd.chunk) + +_part(pd::PeriodPartition) = pd.part + +abstract type PartitionIndexable end + +struct HasPartIndex <: PartitionIndexable end +struct NoPartIndex <: PartitionIndexable end + +PartitionIndexable(::Type) = NoPartIndex() +PartitionIndexable(::Type{<:PeriodPartition}) = HasPartIndex() diff --git a/src/utils.jl b/src/utils.jl index f32df0d..4620ef1 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -171,44 +171,15 @@ function chunk_duration(_::StratTreeNodes{S,T,OP}, _) where {S,T,OP} "`chunk_duration` can not be used when iterating nodes of a strategic tree structure.", ) end - -""" - abstract type PeriodPartition{T<:TimePeriod} - -Supertype for individual partitions based on durations for operational time periods. Subtypes -must be created for all potential time structures to be able to identify the respective -[`TimeStructurePeriod`](@ref). -""" - -abstract type PeriodPartition{T<:TimePeriod} end - -function PeriodPartition(itr, part, chunk) - return throw( - ArgumentError( - "The type` PeriodPartition` called through `period_duration` is not " * - "implemented for iterator type $(typeof(itr))", - ), - ) -end -Base.iterate(pd::PeriodPartition) = iterate(pd.chunk) -Base.iterate(pd::PeriodPartition, state) = iterate(pd.chunk, state) -Base.length(pd::PeriodPartition) = length(pd.chunk) -Base.first(pd::PeriodPartition) = first(pd.chunk) -Base.last(pd::PeriodPartition) = last(pd.chunk) - -_part(pd::PeriodPartition) = pd.part - -abstract type PartitionIndexable end - -struct HasPartIndex <: PartitionIndexable end -struct NoPartIndex <: PartitionIndexable end - -PartitionIndexable(::Type) = NoPartIndex() -PartitionIndexable(::Type{<:PeriodPartition}) = HasPartIndex() - -struct PartitionDurationIterator{I<:TimeStructure} +struct PartitionDurationIterator{I<:TimeStructure,T<:Duration,D<:TimeProfile{T}} itr::I - duration::TimeStruct.Duration + duration::D +end +function PartitionDurationIterator(itr::TimeStructure, dur::Duration) + return PartitionDurationIterator(itr, FixedProfile(dur)) +end +function PartitionDurationIterator(itr::TimeStructure, dur::Vector{<:Duration}) + return PartitionDurationIterator(itr, PartitionProfile(dur)) end """ @@ -228,19 +199,22 @@ over the following time periods until at least `dur` time is covered or the end partition_duration(itr, dur) = PartitionDurationIterator(itr, dur) IteratorSize(::Type{<:PartitionDurationIterator}) = Base.SizeUnknown() -IteratorEltype(::Type{PartitionDurationIterator{I}}) where {I} = Base.HasEltype() -function Base.iterate(w::PartitionDurationIterator, state = (nothing, 1)) +function Base.iterate( + w::PartitionDurationIterator{I,T,D}, + state = (nothing, 1), +) where {I,T,D} isa(state[1], Iterators.IterationCutShort) && return nothing y = iterate(w.itr, state[1]) isnothing(y) && return nothing part = state[2] + dur_part = w.duration[PeriodPartition(w.itr, part, (y[1],))] chunk = eltype(w.itr)[] - acc = zero(w.duration) + acc = zero(T) while !isnothing(y) push!(chunk, y[1]) acc += duration(y[1]) - acc >= w.duration && break + acc >= dur_part && break y = iterate(w.itr, y[2]) end pd = PeriodPartition(w.itr, part, Tuple(chunk)) diff --git a/test/runtests.jl b/test/runtests.jl index f12fd7d..f29855c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1906,223 +1906,373 @@ end @test (sum(duration(t) for t in s) >= 5) || (last(periods) in s) end - # Test of the duration partitions when using operational scenarios - ts_ops = SimpleTimes([1, 2, 3, 6, 1, 1, 1, 1, 1, 1]) - ts = OperationalScenarios(2, ts_ops) - ops = collect(ts) - - osc = first(opscenarios(ts)) - pds_osc = [pd for pd in partition_duration(osc, 6)] - idx = [1:3, 4:4, 5:10] - - @test typeof(pds_osc[1]) <: TimeStruct.OpScenPart{3,<:TimeStruct.ScenarioPeriod} - @test all(collect(pds_osc[k]) == ops[l] for (k, l) in enumerate(idx)) - @test first(pds_osc[1]) == first(ops) - @test last(pds_osc[1]) == ops[3] - @test length(pds_osc[1]) == 3 - @test repr(pds_osc[3]) == "sc1-part3" - - @test length(pds_osc) == 3 - @test typeof(partition_duration(osc, 6)) <: - TimeStruct.PartitionDurationIterator{<:TimeStruct.OperationalScenario} - @test eltype(partition_duration(osc, 6)) == TimeStruct.OpScenPart - @test all(sum(duration(t) for t in pd) >= 6 for pd in pds_osc) - - # Test of the iterator invariants - pds_tl = partition_duration(ts, 6) - @test length(pds_tl) == 6 - @test all(pds_osc[k] == pds_tl[k] for k in 1:3) - - # Test of the duration partitions when using representative periods - ts_ops = SimpleTimes([1, 2, 3, 6, 1, 1, 1, 1, 1, 1]) - ts = RepresentativePeriods(2, 1, ts_ops) - ops = collect(ts) - - rp = first(repr_periods(ts)) - pds_rp = [pd for pd in partition_duration(rp, 6)] - idx = [1:3, 4:4, 5:10] - - @test typeof(pds_rp[1]) <: TimeStruct.ReprPart{3,<:TimeStruct.ReprPeriod} - @test all(collect(pds_rp[k]) == ops[l] for (k, l) in enumerate(idx)) - @test first(pds_rp[1]) == first(ops) - @test last(pds_rp[1]) == ops[3] - @test length(pds_rp[1]) == 3 - @test repr(pds_rp[3]) == "rp1-part3" - - @test length(pds_rp) == 3 - @test typeof(partition_duration(rp, 6)) <: - TimeStruct.PartitionDurationIterator{<:TimeStruct.RepresentativePeriod} - @test eltype(partition_duration(rp, 6)) == TimeStruct.ReprPart - @test all(sum(duration(t) for t in pd) >= 6 for pd in pds_rp) - - # Test of the iterator invariants - pds_tl = partition_duration(ts, 6) - @test length(pds_tl) == 6 - @test all(pds_rp[k] == pds_tl[k] for k in 1:3) - - # Test of the duration partitions when using representative periods - # with operational scenarios - ts_ops = SimpleTimes([1, 2, 3, 6, 1, 1, 1, 1, 1, 1]) - oscs = OperationalScenarios(2, ts_ops) - ts = RepresentativePeriods(2, 1, oscs) - ops = collect(ts) - - rp = first(repr_periods(ts)) - osc = first(opscenarios(rp)) - pds_osc = [pd for pd in partition_duration(osc, 6)] - idx = [1:3, 4:4, 5:10] - - @test typeof(pds_osc[1]) <: TimeStruct.ReprOpScenPart{3,<:TimeStruct.ReprPeriod} - @test all(collect(pds_osc[k]) == ops[l] for (k, l) in enumerate(idx)) - @test first(pds_osc[1]) == first(ops) - @test last(pds_osc[1]) == ops[3] - @test length(pds_osc[1]) == 3 - @test repr(pds_osc[3]) == "rp1-sc1-part3" - - @test length(pds_osc) == 3 - @test typeof(partition_duration(osc, 6)) <: - TimeStruct.PartitionDurationIterator{<:TimeStruct.ReprOpScenario} - @test eltype(partition_duration(osc, 6)) == TimeStruct.ReprOpScenPart - @test all(sum(duration(t) for t in pd) >= 6 for pd in pds_osc) - - # Test of the iterator invariants - pds_tl = partition_duration(ts, 6) - pds_rp = [pd for pd in partition_duration(rp, 6)] - @test length(pds_tl) == 12 - @test all(pds_rp[k] == pds_tl[k] for k in 1:3) - @test all(pds_osc[k] == pds_tl[k] for k in 1:3) - - # Test of the duration partitions when using strategic periods - ts_ops = SimpleTimes([1, 2, 3, 6, 1, 1, 1, 1, 1, 1]) - ts = TwoLevel(2, 1, ts_ops) - ops = collect(ts) - - sp = first(strategic_periods(ts)) - pds_sp = [pd for pd in partition_duration(sp, 6)] - idx = [1:3, 4:4, 5:10] - - @test typeof(pds_sp[1]) <: TimeStruct.StratPart{3,<:TimeStruct.OperationalPeriod} - @test all(collect(pds_sp[k]) == ops[l] for (k, l) in enumerate(idx)) - @test first(pds_sp[1]) == first(ops) - @test last(pds_sp[1]) == ops[3] - @test length(pds_sp[1]) == 3 - @test repr(pds_sp[3]) == "sp1-part3" - - @test length(pds_sp) == 3 - @test typeof(partition_duration(sp, 6)) <: - TimeStruct.PartitionDurationIterator{<:TimeStruct.StrategicPeriod} - @test eltype(partition_duration(sp, 6)) == TimeStruct.StratPart - @test all(sum(duration(t) for t in pd) >= 6 for pd in pds_sp) - - # Test of the iterator invariants - pds_tl = partition_duration(ts, 6) - @test length(pds_tl) == 6 - @test all(pds_sp[k] == pds_tl[k] for k in 1:3) - - # Test of the duration partitions when using strategic periods with - # operational scenarios - ts_ops = SimpleTimes([1, 2, 3, 6, 1, 1, 1, 1, 1, 1]) - oscs = OperationalScenarios(2, ts_ops) - ts = TwoLevel(2, 1, oscs) - ops = collect(ts) - - sp = first(strategic_periods(ts)) - osc = first(opscenarios(sp)) - pds_osc = [pd for pd in partition_duration(osc, 6)] - idx = [1:3, 4:4, 5:10] - - @test typeof(pds_osc[1]) <: TimeStruct.StratOpScenPart{3,<:TimeStruct.OperationalPeriod} - @test all(collect(pds_osc[k]) == ops[l] for (k, l) in enumerate(idx)) - @test first(pds_osc[1]) == first(ops) - @test last(pds_osc[1]) == ops[3] - @test length(pds_osc[1]) == 3 - @test repr(pds_osc[3]) == "sp1-sc1-part3" - - @test length(pds_osc) == 3 - @test typeof(partition_duration(osc, 6)) <: - TimeStruct.PartitionDurationIterator{<:TimeStruct.StratOpScenario} - @test eltype(partition_duration(osc, 6)) == TimeStruct.StratOpScenPart - @test all(sum(duration(t) for t in pd) >= 6 for pd in pds_osc) - - # Test of the iterator invariants - pds_tl = partition_duration(ts, 6) - pds_sp = [pd for pd in partition_duration(sp, 6)] - @test length(pds_tl) == 12 - @test length(pds_sp) == 6 - @test all(pds_sp[k] == pds_tl[k] for k in 1:3) - @test all(pds_osc[k] == pds_tl[k] for k in 1:3) - - # Test of the duration partitions when using strategic periods with - # representative periods - ts_ops = SimpleTimes([1, 2, 3, 6, 1, 1, 1, 1, 1, 1]) - rps = RepresentativePeriods(2, 1, ts_ops) - ts = TwoLevel(2, 1, rps) - ops = collect(ts) - - sp = first(strategic_periods(ts)) - rp = first(repr_periods(sp)) - pds_rp = [pd for pd in partition_duration(rp, 6)] - idx = [1:3, 4:4, 5:10] - - @test typeof(pds_rp[1]) <: TimeStruct.StratReprPart{3,<:TimeStruct.OperationalPeriod} - @test all(collect(pds_rp[k]) == ops[l] for (k, l) in enumerate(idx)) - @test first(pds_rp[1]) == first(ops) - @test last(pds_rp[1]) == ops[3] - @test length(pds_rp[1]) == 3 - @test repr(pds_rp[3]) == "sp1-rp1-part3" - - @test length(pds_rp) == 3 - @test typeof(partition_duration(rp, 6)) <: - TimeStruct.PartitionDurationIterator{<:TimeStruct.StratReprPeriod} - @test eltype(partition_duration(rp, 6)) == TimeStruct.StratReprPart - @test all(sum(duration(t) for t in pd) >= 6 for pd in pds_rp) - - # Test of the iterator invariants - pds_tl = partition_duration(ts, 6) - pds_sp = [pd for pd in partition_duration(sp, 6)] - @test length(pds_tl) == 12 - @test length(pds_sp) == 6 - @test all(pds_sp[k] == pds_tl[k] for k in 1:3) - @test all(pds_rp[k] == pds_tl[k] for k in 1:3) - - # Test of the duration partitions when using strategic periods with - # operational scenarios and representative periods - ts_ops = SimpleTimes([1, 2, 3, 6, 1, 1, 1, 1, 1, 1]) - oscs = OperationalScenarios(2, ts_ops) - rps = RepresentativePeriods(2, 1, oscs) - ts = TwoLevel(2, 1, rps) - ops = collect(ts) - - sp = first(strategic_periods(ts)) - rp = first(repr_periods(sp)) - osc = first(opscenarios(rp)) - pds_osc = [pd for pd in partition_duration(osc, 6)] - idx = [1:3, 4:4, 5:10] - - @test typeof(pds_osc[1]) <: - TimeStruct.StratReprOpScenPart{3,<:TimeStruct.OperationalPeriod} - @test all(collect(pds_osc[k]) == ops[l] for (k, l) in enumerate(idx)) - @test first(pds_osc[1]) == first(ops) - @test last(pds_osc[1]) == ops[3] - @test length(pds_osc[1]) == 3 - @test repr(pds_osc[3]) == "sp1-rp1-sc1-part3" - - @test length(pds_osc) == 3 - @test typeof(partition_duration(osc, 6)) <: - TimeStruct.PartitionDurationIterator{<:TimeStruct.StratReprOpScenario} - @test eltype(partition_duration(osc, 6)) == TimeStruct.StratReprOpScenPart - @test all(sum(duration(t) for t in pd) >= 6 for pd in pds_osc) - - # Test of the iterator invariants - pds_tl = partition_duration(ts, 6) - pds_sp = [pd for pd in partition_duration(sp, 6)] - pds_rp = [pd for pd in partition_duration(rp, 6)] - @test length(pds_tl) == 24 - @test length(pds_sp) == 12 - @test length(pds_rp) == 6 - @test all(pds_sp[k] == pds_tl[k] for k in 1:3) - @test all(pds_rp[k] == pds_tl[k] for k in 1:3) - @test all(pds_osc[k] == pds_tl[k] for k in 1:3) + @testset "Partitions" begin + ts_ops = SimpleTimes([1, 2, 3, 6, 1, 1, 1, 1, 1, 1]) + + # Test of the duration partitions when using operational scenarios + @testset "Partitions - OperationalScenarios" begin + ts = OperationalScenarios(2, ts_ops) + ops = collect(ts) + + osc = first(opscenarios(ts)) + pds_osc = [pd for pd in partition_duration(osc, 6)] + idx = [1:3, 4:4, 5:10] + + @test typeof(pds_osc[1]) <: TimeStruct.OpScenPart{3,<:TimeStruct.ScenarioPeriod} + @test all(collect(pds_osc[k]) == ops[l] for (k, l) in enumerate(idx)) + @test first(pds_osc[1]) == first(ops) + @test last(pds_osc[1]) == ops[3] + @test length(pds_osc[1]) == 3 + @test repr(pds_osc[3]) == "sc1-part3" + + @test length(pds_osc) == 3 + @test isa( + partition_duration(osc, 6), + TimeStruct.PartitionDurationIterator{ + TimeStruct.OperationalScenario{Int64,SimpleTimes{Int64}}, + Int, + FixedProfile{Int}, + }, + ) + + @test eltype(partition_duration(osc, 6)) == TimeStruct.OpScenPart + @test all(sum(duration(t) for t in pd) >= 6 for pd in pds_osc) + + # Test of the iterator invariants + pds_tl = partition_duration(ts, 6) + @test length(pds_tl) == 6 + @test all(pds_osc[k] == pds_tl[k] for k in 1:3) + end + + # Test of the duration partitions when using representative periods + @testset "Partitions - RepresentativePeriods" begin + ts = RepresentativePeriods(2, 1, ts_ops) + ops = collect(ts) + + rp = first(repr_periods(ts)) + pds_rp = [pd for pd in partition_duration(rp, 6)] + idx = [1:3, 4:4, 5:10] + + @test typeof(pds_rp[1]) <: TimeStruct.ReprPart{3,<:TimeStruct.ReprPeriod} + @test all(collect(pds_rp[k]) == ops[l] for (k, l) in enumerate(idx)) + @test first(pds_rp[1]) == first(ops) + @test last(pds_rp[1]) == ops[3] + @test length(pds_rp[1]) == 3 + @test repr(pds_rp[3]) == "rp1-part3" + + @test length(pds_rp) == 3 + @test isa( + partition_duration(rp, 6), + TimeStruct.PartitionDurationIterator{ + TimeStruct.RepresentativePeriod{Int64,SimpleTimes{Int64}}, + Int, + FixedProfile{Int}, + }, + ) + @test eltype(partition_duration(rp, 6)) == TimeStruct.ReprPart + @test all(sum(duration(t) for t in pd) >= 6 for pd in pds_rp) + + # Test of the iterator invariants + pds_tl = partition_duration(ts, 6) + @test length(pds_tl) == 6 + @test all(pds_rp[k] == pds_tl[k] for k in 1:3) + end + + # Test of the duration partitions when using representative periods + # with operational scenarios + @testset "Partitions - RepresentativePeriods{OperationalScenarios}" begin + oscs = OperationalScenarios(2, ts_ops) + ts = RepresentativePeriods(2, 1, oscs) + ops = collect(ts) + + rp = first(repr_periods(ts)) + osc = first(opscenarios(rp)) + pds_osc = [pd for pd in partition_duration(osc, 6)] + idx = [1:3, 4:4, 5:10] + + @test typeof(pds_osc[1]) <: TimeStruct.ReprOpScenPart{3,<:TimeStruct.ReprPeriod} + @test all(collect(pds_osc[k]) == ops[l] for (k, l) in enumerate(idx)) + @test first(pds_osc[1]) == first(ops) + @test last(pds_osc[1]) == ops[3] + @test length(pds_osc[1]) == 3 + @test repr(pds_osc[3]) == "rp1-sc1-part3" + + @test length(pds_osc) == 3 + @test isa( + partition_duration(osc, 6), + TimeStruct.PartitionDurationIterator{ + TimeStruct.ReprOpScenario{ + Int64, + TimeStruct.OperationalScenario{Int64,SimpleTimes{Int64}}, + }, + Int, + FixedProfile{Int}, + }, + ) + @test eltype(partition_duration(osc, 6)) == TimeStruct.ReprOpScenPart + @test all(sum(duration(t) for t in pd) >= 6 for pd in pds_osc) + + # Test of the iterator invariants + pds_tl = partition_duration(ts, 6) + pds_rp = [pd for pd in partition_duration(rp, 6)] + @test length(pds_tl) == 12 + @test all(pds_rp[k] == pds_tl[k] for k in 1:3) + @test all(pds_osc[k] == pds_tl[k] for k in 1:3) + end + + # Test of the duration partitions when using strategic periods + @testset "Partitions - TwoLevel" begin + ts = TwoLevel(2, 1, ts_ops) + ops = collect(ts) + + sp = first(strategic_periods(ts)) + pds_sp = [pd for pd in partition_duration(sp, 6)] + idx = [1:3, 4:4, 5:10] + + @test typeof(pds_sp[1]) <: + TimeStruct.StratPart{3,<:TimeStruct.OperationalPeriod} + @test all(collect(pds_sp[k]) == ops[l] for (k, l) in enumerate(idx)) + @test first(pds_sp[1]) == first(ops) + @test last(pds_sp[1]) == ops[3] + @test length(pds_sp[1]) == 3 + @test repr(pds_sp[3]) == "sp1-part3" + + @test length(pds_sp) == 3 + @test isa( + partition_duration(sp, 6), + TimeStruct.PartitionDurationIterator{ + TimeStruct.StrategicPeriod{Int64,Int64,SimpleTimes{Int64}}, + Int, + FixedProfile{Int}, + }, + ) + @test eltype(partition_duration(sp, 6)) == TimeStruct.StratPart + @test all(sum(duration(t) for t in pd) >= 6 for pd in pds_sp) + + # Test of the iterator invariants + pds_tl = partition_duration(ts, 6) + @test length(pds_tl) == 6 + @test all(pds_sp[k] == pds_tl[k] for k in 1:3) + end + + # Test of the duration partitions when using strategic periods with + # operational scenarios + @testset "Partitions - TwoLevel{OperationalScenarios}" begin + oscs = OperationalScenarios(2, ts_ops) + ts = TwoLevel(2, 1, oscs) + ops = collect(ts) + + sp = first(strategic_periods(ts)) + osc = first(opscenarios(sp)) + pds_osc = [pd for pd in partition_duration(osc, 6)] + idx = [1:3, 4:4, 5:10] + + @test typeof(pds_osc[1]) <: + TimeStruct.StratOpScenPart{3,<:TimeStruct.OperationalPeriod} + @test all(collect(pds_osc[k]) == ops[l] for (k, l) in enumerate(idx)) + @test first(pds_osc[1]) == first(ops) + @test last(pds_osc[1]) == ops[3] + @test length(pds_osc[1]) == 3 + @test repr(pds_osc[3]) == "sp1-sc1-part3" + + @test length(pds_osc) == 3 + @test isa( + partition_duration(osc, 6), + TimeStruct.PartitionDurationIterator{ + TimeStruct.StratOpScenario{ + Int64, + TimeStruct.OperationalScenario{Int64,SimpleTimes{Int64}}, + }, + Int, + FixedProfile{Int}, + }, + ) + @test eltype(partition_duration(osc, 6)) == TimeStruct.StratOpScenPart + @test all(sum(duration(t) for t in pd) >= 6 for pd in pds_osc) + + # Test of the iterator invariants + pds_tl = partition_duration(ts, 6) + pds_sp = [pd for pd in partition_duration(sp, 6)] + @test length(pds_tl) == 12 + @test length(pds_sp) == 6 + @test all(pds_sp[k] == pds_tl[k] for k in 1:3) + @test all(pds_osc[k] == pds_tl[k] for k in 1:3) + end + + # Test of the duration partitions when using strategic periods with + # representative periods + @testset "Partitions - TwoLevel{RepresentativePeriods}" begin + rps = RepresentativePeriods(2, 1, ts_ops) + ts = TwoLevel(2, 1, rps) + ops = collect(ts) + + sp = first(strategic_periods(ts)) + rp = first(repr_periods(sp)) + pds_rp = [pd for pd in partition_duration(rp, 6)] + idx = [1:3, 4:4, 5:10] + + @test typeof(pds_rp[1]) <: + TimeStruct.StratReprPart{3,<:TimeStruct.OperationalPeriod} + @test all(collect(pds_rp[k]) == ops[l] for (k, l) in enumerate(idx)) + @test first(pds_rp[1]) == first(ops) + @test last(pds_rp[1]) == ops[3] + @test length(pds_rp[1]) == 3 + @test repr(pds_rp[3]) == "sp1-rp1-part3" + + @test length(pds_rp) == 3 + @test isa( + partition_duration(rp, 6), + TimeStruct.PartitionDurationIterator{ + TimeStruct.StratReprPeriod{ + Int64, + TimeStruct.RepresentativePeriod{Int64,SimpleTimes{Int64}}, + }, + Int, + FixedProfile{Int}, + }, + ) + @test eltype(partition_duration(rp, 6)) == TimeStruct.StratReprPart + @test all(sum(duration(t) for t in pd) >= 6 for pd in pds_rp) + + # Test of the iterator invariants + pds_tl = partition_duration(ts, 6) + pds_sp = [pd for pd in partition_duration(sp, 6)] + @test length(pds_tl) == 12 + @test length(pds_sp) == 6 + @test all(pds_sp[k] == pds_tl[k] for k in 1:3) + @test all(pds_rp[k] == pds_tl[k] for k in 1:3) + end + + # Test of the duration partitions when using strategic periods with + # operational scenarios and representative periods + @testset "Partitions - TwoLevel{RepresentativePeriods{OperationalScenarios}}" begin + oscs = OperationalScenarios(2, ts_ops) + rps = RepresentativePeriods(2, 1, oscs) + ts = TwoLevel(2, 1, rps) + ops = collect(ts) + + sp = first(strategic_periods(ts)) + rp = first(repr_periods(sp)) + osc = first(opscenarios(rp)) + pds_osc = [pd for pd in partition_duration(osc, 6)] + idx = [1:3, 4:4, 5:10] + + @test typeof(pds_osc[1]) <: + TimeStruct.StratReprOpScenPart{3,<:TimeStruct.OperationalPeriod} + @test all(collect(pds_osc[k]) == ops[l] for (k, l) in enumerate(idx)) + @test first(pds_osc[1]) == first(ops) + @test last(pds_osc[1]) == ops[3] + @test length(pds_osc[1]) == 3 + @test repr(pds_osc[3]) == "sp1-rp1-sc1-part3" + + @test length(pds_osc) == 3 + @test isa( + partition_duration(osc, 6), + TimeStruct.PartitionDurationIterator{ + TimeStruct.StratReprOpScenario{ + Int64, + TimeStruct.OperationalScenario{Int64,SimpleTimes{Int64}}, + }, + Int, + FixedProfile{Int}, + }, + ) + @test eltype(partition_duration(osc, 6)) == TimeStruct.StratReprOpScenPart + @test all(sum(duration(t) for t in pd) >= 6 for pd in pds_osc) + + # Test of the iterator invariants + pds_tl = partition_duration(ts, 6) + pds_sp = [pd for pd in partition_duration(sp, 6)] + pds_rp = [pd for pd in partition_duration(rp, 6)] + @test length(pds_tl) == 24 + @test length(pds_sp) == 12 + @test length(pds_rp) == 6 + @test all(pds_sp[k] == pds_tl[k] for k in 1:3) + @test all(pds_rp[k] == pds_tl[k] for k in 1:3) + @test all(pds_osc[k] == pds_tl[k] for k in 1:3) + end + + # Test of the duration partitions when using strategic periods and a vector of durations + @testset "Partitions - TwoLevel w Vector" begin + ts = TwoLevel(2, 1, ts_ops) + ops = collect(ts) + + sp = first(strategic_periods(ts)) + dur = [3, 9, 6] + pds_sp = [pd for pd in partition_duration(sp, dur)] + idx = [1:2, 3:4, 5:10] + + @test typeof(pds_sp[1]) <: + TimeStruct.StratPart{2,<:TimeStruct.OperationalPeriod} + @test all(collect(pds_sp[k]) == ops[l] for (k, l) in enumerate(idx)) + @test first(pds_sp[1]) == first(ops) + @test last(pds_sp[1]) == ops[2] + @test length(pds_sp[1]) == 2 + @test repr(pds_sp[3]) == "sp1-part3" + + @test length(pds_sp) == 3 + @test isa( + partition_duration(sp, dur), + TimeStruct.PartitionDurationIterator{ + TimeStruct.StrategicPeriod{Int64,Int64,SimpleTimes{Int64}}, + Int, + PartitionProfile{Int}, + }, + ) + @test eltype(partition_duration(sp, dur)) == TimeStruct.StratPart + @test all( + sum(duration(t) for t in pd) >= dur[k] for (k, pd) in enumerate(pds_sp) + ) + + # Test of the iterator invariants + pds_tl = partition_duration(ts, dur) + @test length(pds_tl) == 6 + @test all(pds_sp[k] == pds_tl[k] for k in 1:3) + end + + # Test of the duration partitions when using strategic periods and a time profile of + # durations + @testset "Partitions - TwoLevel w TimeProfile" begin + ts = TwoLevel(2, 1, ts_ops) + sp = first(strategic_periods(ts)) + ops = collect(ts) + + dur = StrategicProfile([FixedProfile(6), PartitionProfile([3, 9, 3, 3])]) + pds_ts = partition_duration(ts, dur) + idx = [1:3, 4:4, 5:10, 11:12, 13:14, 15:17, 18:20] + + @test typeof(pds_ts[1]) <: + TimeStruct.StratPart{3,<:TimeStruct.OperationalPeriod} + @test typeof(pds_ts[2]) <: + TimeStruct.StratPart{1,<:TimeStruct.OperationalPeriod} + @test typeof(pds_ts[4]) <: + TimeStruct.StratPart{2,<:TimeStruct.OperationalPeriod} + @test typeof(pds_ts[5]) <: + TimeStruct.StratPart{2,<:TimeStruct.OperationalPeriod} + @test all(collect(pds_ts[k]) == ops[l] for (k, l) in enumerate(idx)) + @test first(pds_ts[1]) == first(ops) + @test last(pds_ts[1]) == ops[3] + @test length(pds_ts[1]) == 3 + @test repr(pds_ts[3]) == "sp1-part3" + + @test length(pds_ts) == 7 + @test isa( + partition_duration(sp, dur), + TimeStruct.PartitionDurationIterator{ + TimeStruct.StrategicPeriod{Int64,Int64,SimpleTimes{Int64}}, + Int64, + StrategicProfile{Int64,TimeProfile{Int64}}, + }, + ) + @test eltype(partition_duration(sp, dur)) == TimeStruct.StratPart + @test all(sum(duration(t) for t in pd) >= dur[pd] for pd in pds_ts) + + # Test of the iterator invariants + pds_sp = [pd for pd in partition_duration(sp, dur)] + @test length(pds_sp) == 3 + @test all(pds_sp[k] == pds_ts[k] for k in 1:3) + end + end end @testitem "Indexing of operational structures" begin