Skip to content

Identifying the strategic period of a period. #74

@JulStraus

Description

@JulStraus

Problem statement

As outlined in #73, we currently allow for identifying whether a TimePeriod, AbstractOperationalScenario, or AbstractRepresentativePeriod is within an AbstractStrategicPeriod using the function _sp_period. We require it for the discounting approach to identify which strategic period has to be utilized when the input to discount or objective_weight is not a strategic period. The current system works but has a major issue as outlined in #73: It only checks that the field sp is the same (or sp and branch in the case of TwoLevelTree).
This implies that when working with multiple time structures, e.g., when using Plasmo, we can experience problems.

In addition, we only utilize the current system for strategic periods as we do not need it for a different purpose. It can be easily implemented as well for other types.

Solution

A new implementation for strategic periods is given by

_check_period(sp::AbstractStrategicPeriod, t::TimePeriod) = t in sp
_check_period(sp::AbstractStrategicPeriod, t::AbstractOperationalScenario) = t in opscenarios(sp)
_check_period(sp::AbstractStrategicPeriod, t::AbstractRepresentativePeriod) = t in repr_periods(sp)

_identify_sp(sp::AbstractStrategicPeriod, ts::TimeStructure) = sp
function _identify_sp(t::Union{TimePeriod, AbstractOperationalScenario, AbstractRepresentativePeriod}, ts::TimeStructure)
    sps = collect(strat_periods(ts))
    filter_fun(sp) = _check_period(sp, t)
    per = findfirst(filter_fun, sps)
    isnothing(per) && throw(ErrorException("Period not part of any strategic period"))
    return sps[per]
end

This implementation can be extended for both representative periods

_check_period(rp::AbstractRepresentativePeriod, t::TimePeriod) = t in rp
_check_period(rp::AbstractRepresentativePeriod, t::AbstractOperationalScenario) = t in opscenarios(rp)

_identify_rp(rp::AbstractRepresentativePeriod, ts::TimeStructure) = rp
function _identify_rp(t::Union{TimePeriod, AbstractOperationalScenario}, ts::TimeStructure)
    rps = collect(repr_periods(ts))
    filter_fun(sp) = _check_period(sp, t)
    per = findfirst(filter_fun, rps)
    isnothing(per) && throw(ErrorException("Period not part of any representative period"))
    return rps[per]
end

and operational scenarios

_check_period(osc::AbstractOperationalScenario, t::TimePeriod) = t in osc

_identify_osc(osc::AbstractOperationalScenario, ts::TimeStructure) = osc
function _identify_osc(t::TimePeriod, ts::TimeStructure)
    oscs = collect(opscenarios(ts))
    filter_fun(sp) = _check_period(sp, t)
    per = findfirst(filter_fun, oscs)
    isnothing(per) && throw(ErrorException("Period not part of any operational scenario"))
    return oscs[per]
end

Discussion

The new approach is in practice slower than the old approach as we do not only compare the field sp, but the complete OperationalPeriod. Due to the application of findfirst, its penalty is dependent on which period we are interested in (in which strategic period it is located) and how the time structure looks like. The penalty can be high if we have a lot of strategic periods and operational periods.

As an example, consider the following time structure:

# 15 strategic periods with 4 weeks each
ts = TwoLevel(15, 5, SimpleTimes(168*4, 1); op_per_strat=8760)

The required time through specifying the functions

function test_old(t, ts)
    for k  range(1,1e5)
        TimeStruct._sp_period(t, ts)
    end
end
function test_new(t, ts)
    for k  range(1,1e5)
        _identify_sp(t, ts)
    end
end

is dependent on the chosen time period (which strategic period it is in). If it is in the first strategic period, it requires on my PC 0.11 s compared to 0.08 s for the old method. If it is in the 15th, that changes to 0.52 s compared to 0.07 s.

This leaves the question whether we want to include it or not. Do we see any problems by just comparing a subset of parameters (_strat_per and comparable for the new methods) of a period? What are your thoughts @hellemo and @trulsf?

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions