|
| 1 | +""" |
| 2 | + struct ParameterTimeseriesCollection{T} |
| 3 | + function ParameterTimeseriesCollection(collection) |
| 4 | +
|
| 5 | +A utility struct that helps in storing multiple parameter timeseries. It expects a |
| 6 | +collection of timseries objects ([`is_timeseries`](@ref) returns [`Timeseries`](@ref)) |
| 7 | +for each. Each of the timeseries objects should implement [`state_values`](@ref) and |
| 8 | +[`current_time`](@ref). Effectively, the "states" of each contained timeseries object are |
| 9 | +the parameter values it stores the timeseries of. |
| 10 | +
|
| 11 | +The collection is expected to implement `Base.eachindex`, `Base.iterate` and |
| 12 | +`Base.getindex`. The indexes of the collection should agree with the timeseries indexes |
| 13 | +returned by calling [`timeseries_parameter_index`](@ref) on the corresponding index |
| 14 | +provider. |
| 15 | +
|
| 16 | +This type forwards `eachindex`, `iterate` and `length` to the contained `collection`. It |
| 17 | +implements `Base.parent` to allow access to the contained `collection`, and has the |
| 18 | +following `getindex` methods: |
| 19 | +
|
| 20 | +- `getindex(ptc::ParameterTimeseriesCollection, idx) = ptc.collection[idx]`. |
| 21 | +- `getindex(::ParameterTimeseriesCollection, idx::ParameterTimeseriesIndex)` returns the |
| 22 | + timeseries of the parameter referred to by `idx`. |
| 23 | +- `getindex(::ParameterTimeseriesCollection, idx::ParameterTimeseriesIndex, subidx)` |
| 24 | + returns the value of the parameter referred to by `idx` at the time index `subidx`. |
| 25 | +- Apart from these cases, if multiple indexes are provided the first is treated as a |
| 26 | + timeseries index, the second the time index in the timeseries, and the (optional) |
| 27 | + third the index of the parameter in an element of the timeseries. |
| 28 | +
|
| 29 | +The three-argument version of [`parameter_values`](@ref) is implemented for this type. |
| 30 | +The single-argument version of `parameter_values` returns the cached parameter object. |
| 31 | +This type does not implement any traits. |
| 32 | +""" |
| 33 | +struct ParameterTimeseriesCollection{T, P} |
| 34 | + collection::T |
| 35 | + paramcache::P |
| 36 | + |
| 37 | + function ParameterTimeseriesCollection(collection::T, paramcache::P) where {T, P} |
| 38 | + if any(x -> is_timeseries(x) == NotTimeseries(), collection) |
| 39 | + throw(ArgumentError(""" |
| 40 | + All objects in the collection `ParameterTimeseriesCollection` must be \ |
| 41 | + timeseries objects. |
| 42 | + """)) |
| 43 | + end |
| 44 | + new{T, P}(collection, paramcache) |
| 45 | + end |
| 46 | +end |
| 47 | + |
| 48 | +Base.eachindex(ptc::ParameterTimeseriesCollection) = eachindex(ptc.collection) |
| 49 | + |
| 50 | +Base.iterate(ptc::ParameterTimeseriesCollection, args...) = iterate(ptc.collection, args...) |
| 51 | + |
| 52 | +Base.length(ptc::ParameterTimeseriesCollection) = length(ptc.collection) |
| 53 | + |
| 54 | +Base.parent(ptc::ParameterTimeseriesCollection) = ptc.collection |
| 55 | + |
| 56 | +Base.getindex(ptc::ParameterTimeseriesCollection, idx) = ptc.collection[idx] |
| 57 | +function Base.getindex(ptc::ParameterTimeseriesCollection, idx::ParameterTimeseriesIndex) |
| 58 | + timeseries = ptc.collection[idx.timeseries_idx] |
| 59 | + return getindex.(state_values(timeseries), (idx.parameter_idx,)) |
| 60 | +end |
| 61 | +function Base.getindex( |
| 62 | + ptc::ParameterTimeseriesCollection, idx::ParameterTimeseriesIndex, subidx::Union{ |
| 63 | + Int, CartesianIndex}) |
| 64 | + timeseries = ptc.collection[idx.timeseries_idx] |
| 65 | + return state_values(timeseries, subidx)[idx.parameter_idx] |
| 66 | +end |
| 67 | +function Base.getindex( |
| 68 | + ptc::ParameterTimeseriesCollection, idx::ParameterTimeseriesIndex, ::Colon) |
| 69 | + return ptc[idx] |
| 70 | +end |
| 71 | +function Base.getindex( |
| 72 | + ptc::ParameterTimeseriesCollection, idx::ParameterTimeseriesIndex, subidx::AbstractArray{Bool}) |
| 73 | + timeseries = ptc.collection[idx.timeseries_idx] |
| 74 | + map(only(to_indices(current_time(timeseries), (subidx,)))) do i |
| 75 | + state_values(timeseries, i)[idx.parameter_idx] |
| 76 | + end |
| 77 | +end |
| 78 | +function Base.getindex( |
| 79 | + ptc::ParameterTimeseriesCollection, idx::ParameterTimeseriesIndex, subidx) |
| 80 | + timeseries = ptc.collection[idx.timeseries_idx] |
| 81 | + getindex.(state_values.((timeseries,), subidx), idx.parameter_idx) |
| 82 | +end |
| 83 | +function Base.getindex(ptc::ParameterTimeseriesCollection, ts_idx, subidx) |
| 84 | + return state_values(ptc.collection[ts_idx], subidx) |
| 85 | +end |
| 86 | +function Base.getindex(ptc::ParameterTimeseriesCollection, ts_idx, subidx, param_idx) |
| 87 | + return ptc[ParameterTimeseriesIndex(ts_idx, param_idx), subidx] |
| 88 | +end |
| 89 | + |
| 90 | +function parameter_values(ptc::ParameterTimeseriesCollection) |
| 91 | + return ptc.paramcache |
| 92 | +end |
| 93 | + |
| 94 | +function parameter_values( |
| 95 | + ptc::ParameterTimeseriesCollection, idx::ParameterTimeseriesIndex, subidx) |
| 96 | + return ptc[idx, subidx] |
| 97 | +end |
| 98 | +function parameter_values(prob, i::ParameterTimeseriesIndex, j) |
| 99 | + parameter_values(get_parameter_timeseries_collection(prob), i, j) |
| 100 | +end |
| 101 | +function parameter_timeseries(ptc::ParameterTimeseriesCollection, idx) |
| 102 | + return current_time(ptc[idx]) |
| 103 | +end |
| 104 | + |
| 105 | +function _timeseries_value(ptc::ParameterTimeseriesCollection, ts_idx, t) |
| 106 | + ts_obj = ptc[ts_idx] |
| 107 | + time_idx = searchsortedlast(current_time(ts_obj), t) |
| 108 | + value = state_values(ts_obj, time_idx) |
| 109 | + return value |
| 110 | +end |
| 111 | + |
| 112 | +""" |
| 113 | + parameter_values_at_time(valp, t) |
| 114 | +
|
| 115 | +Return an indexable collection containing the value of all parameters in `valp` at time |
| 116 | +`t`. Note that `t` here is a floating-point time, and not an index into a timeseries. |
| 117 | +
|
| 118 | +This has a default implementation relying on [`get_parameter_timeseries_collection`](@ref) |
| 119 | +and [`with_updated_parameter_timeseries_values`](@ref). |
| 120 | +""" |
| 121 | +function parameter_values_at_time(valp, t) |
| 122 | + ptc = get_parameter_timeseries_collection(valp) |
| 123 | + with_updated_parameter_timeseries_values(ptc.paramcache, |
| 124 | + (ts_idx => _timeseries_value(ptc, ts_idx, t) for ts_idx in eachindex(ptc))...) |
| 125 | +end |
| 126 | + |
| 127 | +""" |
| 128 | + parameter_values_at_state_time(valp, i) |
| 129 | + parameter_values_at_state_time(valp) |
| 130 | +
|
| 131 | +Return an indexable collection containing the value of all parameters in `valp` at time |
| 132 | +index `i` in the state timeseries. |
| 133 | +
|
| 134 | +By default, this function relies on [`parameter_values_at_time`](@ref) and |
| 135 | +[`current_time`](@ref) for a default implementation. |
| 136 | +
|
| 137 | +The single-argument version of this function is a shorthand to return parameter values |
| 138 | +at each point in the state timeseries. This also has a default implementation relying on |
| 139 | +[`parameter_values_at_time`](@ref) and [`current_time`](@ref). |
| 140 | +""" |
| 141 | +function parameter_values_at_state_time end |
| 142 | + |
| 143 | +function parameter_values_at_state_time(p, i) |
| 144 | + state_time = current_time(p, i) |
| 145 | + return parameter_values_at_time(p, state_time) |
| 146 | +end |
| 147 | +function parameter_values_at_state_time(p) |
| 148 | + return (parameter_values_at_time(p, t) for t in current_time(p)) |
| 149 | +end |
| 150 | + |
| 151 | +""" |
| 152 | + parameter_timeseries(valp, i) |
| 153 | +
|
| 154 | +Return a vector of the time steps at which the parameter values in the parameter |
| 155 | +timeseries at index `i` are saved. This is only required for objects where |
| 156 | +`is_parameter_timeseries(valp) === Timeseries()`. It will not be called otherwise. It is |
| 157 | +assumed that the timeseries is sorted in increasing order. |
| 158 | +
|
| 159 | +See also: [`is_parameter_timeseries`](@ref). |
| 160 | +""" |
| 161 | +function parameter_timeseries end |
| 162 | + |
| 163 | +function parameter_timeseries(valp, i) |
| 164 | + return parameter_timeseries(get_parameter_timeseries_collection(valp), i) |
| 165 | +end |
| 166 | + |
| 167 | +""" |
| 168 | + parameter_timeseries_at_state_time(valp, i, j) |
| 169 | + parameter_timeseries_at_state_time(valp, i) |
| 170 | +
|
| 171 | +Return the index of the timestep in the parameter timeseries at timeseries index `i` which |
| 172 | +occurs just before or at the same time as the state timestep with index `j`. The two- |
| 173 | +argument version of this function returns an iterable of indexes, one for each timestep in |
| 174 | +the state timeseries. If `j` is an object that refers to multiple values in the state |
| 175 | +timeseries (e.g. `Colon`), return an iterable of the indexes in the parameter timeseries |
| 176 | +at the appropriate points. |
| 177 | +
|
| 178 | +Both versions of this function have default implementations relying on |
| 179 | +[`current_time`](@ref) and [`parameter_timeseries`](@ref), for the cases where `j` is one |
| 180 | +of: `Int`, `CartesianIndex`, `AbstractArray{Bool}`, `Colon` or an iterable of the |
| 181 | +aforementioned. |
| 182 | +""" |
| 183 | +function parameter_timeseries_at_state_time end |
| 184 | + |
| 185 | +function parameter_timeseries_at_state_time(valp, i, j::Union{Int, CartesianIndex}) |
| 186 | + state_time = current_time(valp, j) |
| 187 | + timeseries = parameter_timeseries(valp, i) |
| 188 | + searchsortedlast(timeseries, state_time) |
| 189 | +end |
| 190 | + |
| 191 | +function parameter_timeseries_at_state_time(valp, i, ::Colon) |
| 192 | + parameter_timeseries_at_state_time(valp, i) |
| 193 | +end |
| 194 | + |
| 195 | +function parameter_timeseries_at_state_time(valp, i, j::AbstractArray{Bool}) |
| 196 | + parameter_timeseries_at_state_time(valp, i, only(to_indices(current_time(valp), (j,)))) |
| 197 | +end |
| 198 | + |
| 199 | +function parameter_timeseries_at_state_time(valp, i, j) |
| 200 | + (parameter_timeseries_at_state_time(valp, i, jj) for jj in j) |
| 201 | +end |
| 202 | + |
| 203 | +function parameter_timeseries_at_state_time(valp, i) |
| 204 | + parameter_timeseries_at_state_time(valp, i, eachindex(current_time(valp))) |
| 205 | +end |
0 commit comments