spine-tools / SpineOpt.jl

A highly adaptable modelling framework for multi-energy systems
https://www.tools-for-energy-system-modelling.org/
GNU Lesser General Public License v3.0
49 stars 12 forks source link

Checking the replacement value for variables #1016

Open Mastomaki opened 1 month ago

Mastomaki commented 1 month ago

Description of the issue

I'm thinking of the following function, for example considering the variable units_out_of_service. It seems that if the replacement_value is a time series, which has been defined only for some time indices, then a NaN will be returned for other indices and the model will crash.

function _add_variable!(m, name, ind, replacement_value)
    if replacement_value !== nothing
        ind_ = (analysis_time=_analysis_time(m), ind...)
        value = replacement_value(ind_)
        if value !== nothing
            return value
        end
    end
    @variable(m, base_name=_base_name(name, ind))
end

Describe the solution you'd like In the case the replacement_value has not been defined for some time index, default value for the variable could be used.

clizbe commented 1 month ago

I agree this sounds like a desirable behavior. Until we're able to add it I think you'll have to work with filling the default value into your timeseries. Would that work?

Mastomaki commented 1 month ago

Yes. But actually there is the checking:

function Base.getindex(x::Union{TimeSeries,Map}, key)
    i = _searchsortedfirst(x.indexes, key)
    if get(x.indexes, i, nothing) == key
        x.values[i]
    else
        throw(BoundsError(x, key))
    end
end

For some reason this was not activated.

Mastomaki commented 1 month ago

Or then it was this function, which is the culprit:

function _get_time_series_value(pv, t::TimeSlice, upd)
    adjusted_t = pv.value.ignore_year ? t - Year(start(t)) : t
    t_start, t_end = start(adjusted_t), end_(adjusted_t)
    a, b = _search_overlap(pv.value, t_start, t_end)
    if upd !== nothing
        timeout = _timeout(pv.value, t_start, t_end, a, b)
        _add_update(t, timeout, upd)
    end
    t_end <= pv.value.indexes[1] && return NaN
    t_start > pv.value.indexes[end] && !pv.value.ignore_year && return NaN
    mean(Iterators.filter(!isnan, pv.value.values[a:b]))
end

So at least add Boundserror there too.

clizbe commented 1 month ago

Can you create a pull request for this update?

Mastomaki commented 1 month ago

I created a pull request in the SpineInterface repository.