From ada02e374b9b6da9ceb1c17038fc3f4496a7dbc1 Mon Sep 17 00:00:00 2001 From: lrennels Date: Wed, 16 Oct 2019 10:19:24 -0700 Subject: [PATCH 01/31] Add types and arithmetic functions --- src/core/time.jl | 16 ++++++++++++++++ src/core/types/time.jl | 9 +++++++++ 2 files changed, 25 insertions(+) diff --git a/src/core/time.jl b/src/core/time.jl index 23eb70bf9..6ea172307 100644 --- a/src/core/time.jl +++ b/src/core/time.jl @@ -106,6 +106,14 @@ function Base.:-(ts::VariableTimestep{TIMES}, val::Int) where {TIMES} return VariableTimestep{TIMES}(ts.t - val) end +function Base.:-(ts::TimestepValue, val::Int) + return TimestepValue(ts.value, ts.offset - val) +end + +function Base.:-(ts::TimestepIndex, val::Int) + return TimestepIndex(ts.index - val) +end + function Base.:+(ts::FixedTimestep{FIRST, STEP, LAST}, val::Int) where {FIRST, STEP, LAST} if finished(ts) error("Cannot get next timestep, this is last timestep.") @@ -125,6 +133,14 @@ function Base.:+(ts::VariableTimestep{TIMES}, val::Int) where {TIMES} new_ts = VariableTimestep{TIMES}(ts.t + val) end +function Base.:+(ts::TimestepValue, val::Int) + return TimestepValue(ts.value, ts.offset + val) +end + +function Base.:+(ts::TimestepIndex, val::Int) + return TimestepIndex(ts.index + val) +end + # # CLOCK # diff --git a/src/core/types/time.jl b/src/core/types/time.jl index 7c1adcdbe..132168ff0 100644 --- a/src/core/types/time.jl +++ b/src/core/types/time.jl @@ -22,6 +22,15 @@ struct VariableTimestep{TIMES} <: AbstractTimestep end end +struct TimestepValue{T} + value::T + offset::Int +end + +struct TimestepIndex + index::Int +end + mutable struct Clock{T <: AbstractTimestep} <: MimiStruct ts::T From 362b769f0a43fe05b6115a922057331756e13cda Mon Sep 17 00:00:00 2001 From: lrennels Date: Wed, 16 Oct 2019 10:58:42 -0700 Subject: [PATCH 02/31] Add getindex methods --- src/core/time_arrays.jl | 85 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index eb09425bf..af9e479c4 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -81,6 +81,24 @@ function Base.getindex(v::TimestepVector{VariableTimestep{D_TIMES}, T}, ts::Vari _missing_data_check(data, t) end +function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP, LAST}, T}, ts::TimestepValue) where {T, FIRST, STEP, LAST} + t = _get_time_value_position_([FIRST:STEP:LAST...], ts) + data = v.data[t] + _missing_data_check(data) +end + +function Base.getindex(v::TimestepVector{VariableTimestep{TIMES}, T}, ts::TimestepValue) where {T, TIMES} + t = _get_time_value_position_(TIMES, ts) + data = v.data[t] + _missing_data_check(data) +end + +function Base.getindex(v::TimestepVector, ts::TimestepIndex) + t = ts.index + length(v.data) < t ? error("TimestepIndex index $t extends beyond end of TimestepArray") : data = v.data[t] + _missing_data_check(data) +end + # int indexing version supports old-style components and internal functions, not # part of the public API @@ -176,6 +194,41 @@ function Base.getindex(mat::TimestepMatrix{VariableTimestep{D_TIMES}, T, 2}, idx _missing_data_check(data, t) end +function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP, LAST}, T, 1}, ts::TimestepValue, idx::AnyIndex) where {T, FIRST, STEP, LAST} + t = _get_time_value_position_([FIRST:STEP:LAST...], ts) + data = mat.data[t, idx] + _missing_data_check(data) +end + +function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T, 1}, ts::TimestepValue, idx::AnyIndex) where {T, TIMES} + t = _get_time_value_position_(TIMES, ts) + data = mat.data[t, idx] + _missing_data_check(data) +end + +function Base.getindex(mat::TimestepMatrix, ts::TimestepIndex, idx::AnyIndex) + t = ts.index + size(mat.data, 1) < t ? error("TimestepIndex index $t extends beyond end of first dim of TimestepMatrix") : data = mat.data[t, idx] + _missing_data_check(data) +end + +function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP, LAST}, T, 2}, idx::AnyIndex, ts::TimestepValue) where {T, FIRST, STEP, LAST} + t = _get_time_value_position_([FIRST:STEP:LAST...], ts) + data = mat.data[idx, t] + _missing_data_check(data) +end + +function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T, 2}, idx::AnyIndex, ts::TimestepValue) where {T, TIMES} + t = _get_time_value_position_(TIMES, ts) + data = mat.data[idx, t] + _missing_data_check(data) +end + +function Base.getindex(mat::TimestepMatrix, idx::AnyIndex, ts::TimestepIndex) + t = ts.t + size(mat.data, 2) < t ? error("TimestepIndex index $t extends beyond end of second dim of TimestepMatrix") : data = mat.data[idx, t] + _missing_data_check(data) +end function Base.setindex!(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, 1}, val, ts::FixedTimestep{FIRST, STEP, LAST}, idx::AnyIndex) where {T, FIRST, STEP, LAST} setindex!(mat.data, val, ts.t, idx) @@ -292,6 +345,24 @@ function Base.getindex(arr::TimestepArray{VariableTimestep{D_TIMES}, T, N, ti}, return arr.data[idxs1..., t, idxs2...] end +function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP, LAST}, T, N, ti}, idxs::Union{TimestepValue, AnyIndex}...) where {T, N, ti, FIRST, STEP, LAST} + idxs1, ts, idxs2 = split_indices(idxs, ti) + t = _get_time_value_position_([FIRST:STEP:LAST...], ts) + return arr.data[idxs1..., t, idxs2...] +end + +function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idxs::Union{TimestepValue, AnyIndex}...) where {T, N, ti, TIMES} + idxs1, ts, idxs2 = split_indices(idxs, ti) + t = _get_time_value_position_(TIMES, ts) + return arr.data[idxs1..., t, idxs2...] +end + +function Base.getindex(arr::TimestepArray{AbstractTimestep, T, N, ti}, idxs::Union{TimestepIndex, AnyIndex}...) where {T, N, ti} + idxs1, ts, idxs2 = split_indices(idxs, ti) + t = ts.t + return arr.data[idxs1..., t, idxs2...] +end + function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, val, idxs::Union{FixedTimestep{FIRST, STEP, LAST}, AnyIndex}...) where {T, N, ti, FIRST, STEP, LAST} idxs1, ts, idxs2 = split_indices(idxs, ti) setindex!(arr.data, val, idxs1..., ts.t, idxs2...) @@ -383,3 +454,17 @@ function hasvalue(arr::TimestepArray{VariableTimestep{D_FIRST}, T, N, ti}, return D_FIRST[1] <= gettime(ts) <= last_period(arr) && all([1 <= idx <= size(arr, i) for (i, idx) in enumerate(idxs)]) end + +# Helper functions for TimestepValue type +function _get_time_value_position_(times::Array, ts::TimestepValue) + t = findfirst(isequal.(ts.value, times)) + if t === nothing + error("cannot use TimestepValue with value $(ts.value), value is not in the TimestepArray") + end + + t_offset = t + ts.offset + if t_offset > length(times) + error("cannot get TimestepValue offset of $(ts.offset) from value $(ts.value), offset is after the end of the TimestepArray") + end + return t_offset +end From 14e70452038c75a7f8d9d82f4cde132e7f0128d5 Mon Sep 17 00:00:00 2001 From: lrennels Date: Wed, 16 Oct 2019 19:08:59 -0700 Subject: [PATCH 03/31] Export types; Add deprecation warnings; Fix constructor; Add tests --- docs/src/reference.md | 4 +- docs/src/userguide.md | 4 +- src/Mimi.jl | 2 + src/core/time_arrays.jl | 117 ++++++++++++++++++++---------------- src/core/types/time.jl | 7 +++ test/test_timesteparrays.jl | 46 +++++++++++--- 6 files changed, 119 insertions(+), 61 deletions(-) diff --git a/docs/src/reference.md b/docs/src/reference.md index 01d357ca8..c40181d99 100644 --- a/docs/src/reference.md +++ b/docs/src/reference.md @@ -32,7 +32,9 @@ plot_comp_graph replace_comp! set_dimension! set_leftover_params! -set_param! +set_param! +TimestepIndex +TimestepValue variables variable_dimensions variable_names diff --git a/docs/src/userguide.md b/docs/src/userguide.md index d94e05cba..5f7052132 100644 --- a/docs/src/userguide.md +++ b/docs/src/userguide.md @@ -186,8 +186,8 @@ In the `run_timestep` functions which the user defines, it may be useful to use is_first(t) # returns true or false, true if t is the first timestep to be run is_last(t) # returns true or false, true if t is the last timestep to be run gettime(t) # returns the year represented by timestep t -is_time(t, s) # Return true or false, true if the current time (year) for t is y -is_timestep(t, y) # rReturn true or false, true if t timestep is step s. +is_time(t, y) # Return true or false, true if the current time (year) for t is y +is_timestep(t, s) # Return true or false, true if t timestep is step s. ``` The API details for AbstractTimestep object `t` are as follows: diff --git a/src/Mimi.jl b/src/Mimi.jl index bd00f545b..ff9b1bff6 100644 --- a/src/Mimi.jl +++ b/src/Mimi.jl @@ -43,6 +43,8 @@ export set_dimension!, set_leftover_params!, set_param!, + TimestepIndex, + TimestepValue, update_param!, update_params!, # variables, diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index af9e479c4..b37be0210 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -55,6 +55,26 @@ macro allow_missing(expr) end end + +# Helper functions for TimestepValue type +function _get_time_value_position(times::Array, ts::TimestepValue{T}) where T + t = findfirst(isequal.(ts.value, times)) + if t === nothing + error("cannot use TimestepValue with value $(ts.value), value is not in the TimestepArray") + end + + t_offset = t + ts.offset + if t_offset > length(times) + error("cannot get TimestepValue offset of $(ts.offset) from value $(ts.value), offset is after the end of the TimestepArray") + end + return t_offset +end + +# Helper function for throwing integer indexing warnings +function _throw_int_index_warning() + @warn("Indexing into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndex(2)]") +end + # # b. TimestepVector # @@ -81,33 +101,22 @@ function Base.getindex(v::TimestepVector{VariableTimestep{D_TIMES}, T}, ts::Vari _missing_data_check(data, t) end -function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP, LAST}, T}, ts::TimestepValue) where {T, FIRST, STEP, LAST} - t = _get_time_value_position_([FIRST:STEP:LAST...], ts) +function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP, LAST}, T}, ts::TimestepValue{T}) where {T, FIRST, STEP, LAST} + t = _get_time_value_position([FIRST:STEP:LAST...], ts) data = v.data[t] - _missing_data_check(data) + _missing_data_check(data, t) end -function Base.getindex(v::TimestepVector{VariableTimestep{TIMES}, T}, ts::TimestepValue) where {T, TIMES} - t = _get_time_value_position_(TIMES, ts) +function Base.getindex(v::TimestepVector{VariableTimestep{TIMES}, T}, ts::TimestepValue{T}) where {T, TIMES} + t = _get_time_value_position(TIMES, ts) data = v.data[t] - _missing_data_check(data) + _missing_data_check(data, t) end function Base.getindex(v::TimestepVector, ts::TimestepIndex) t = ts.index length(v.data) < t ? error("TimestepIndex index $t extends beyond end of TimestepArray") : data = v.data[t] - _missing_data_check(data) -end - -# int indexing version supports old-style components and internal functions, not -# part of the public API - -function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP}, T}, i::AnyIndex) where {T, FIRST, STEP} - return v.data[i] -end - -function Base.getindex(v::TimestepVector{VariableTimestep{TIMES}, T}, i::AnyIndex) where {T, TIMES} - return v.data[i] + _missing_data_check(data, t) end function Base.setindex!(v::TimestepVector{FixedTimestep{FIRST, STEP}, T}, val, ts::FixedTimestep{FIRST, STEP, LAST}) where {T, FIRST, STEP, LAST} @@ -131,6 +140,18 @@ end # int indexing version supports old-style components and internal functions, not # part of the public API +# deprecated +function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP}, T}, i::AnyIndex) where {T, FIRST, STEP} + _throw_int_index_warning() + return v.data[i] +end + +#deprecated +function Base.getindex(v::TimestepVector{VariableTimestep{TIMES}, T}, i::AnyIndex) where {T, TIMES} + _throw_int_index_warning() + return v.data[i] +end + function Base.setindex!(v::TimestepVector{FixedTimestep{Start, STEP}, T}, val, i::AnyIndex) where {T, Start, STEP} setindex!(v.data, val, i) end @@ -194,40 +215,40 @@ function Base.getindex(mat::TimestepMatrix{VariableTimestep{D_TIMES}, T, 2}, idx _missing_data_check(data, t) end -function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP, LAST}, T, 1}, ts::TimestepValue, idx::AnyIndex) where {T, FIRST, STEP, LAST} - t = _get_time_value_position_([FIRST:STEP:LAST...], ts) +function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP, LAST}, T, 1}, ts::TimestepValue{T}, idx::AnyIndex) where {T, FIRST, STEP, LAST} + t = _get_time_value_position([FIRST:STEP:LAST...], ts) data = mat.data[t, idx] - _missing_data_check(data) + _missing_data_check(data, t) end -function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T, 1}, ts::TimestepValue, idx::AnyIndex) where {T, TIMES} - t = _get_time_value_position_(TIMES, ts) +function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T, 1}, ts::TimestepValue{T}, idx::AnyIndex) where {T, TIMES} + t = _get_time_value_position(TIMES, ts) data = mat.data[t, idx] - _missing_data_check(data) + _missing_data_check(data, t) end function Base.getindex(mat::TimestepMatrix, ts::TimestepIndex, idx::AnyIndex) t = ts.index size(mat.data, 1) < t ? error("TimestepIndex index $t extends beyond end of first dim of TimestepMatrix") : data = mat.data[t, idx] - _missing_data_check(data) + _missing_data_check(data, t) end -function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP, LAST}, T, 2}, idx::AnyIndex, ts::TimestepValue) where {T, FIRST, STEP, LAST} - t = _get_time_value_position_([FIRST:STEP:LAST...], ts) +function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP, LAST}, T, 2}, idx::AnyIndex, ts::TimestepValue{T}) where {T, FIRST, STEP, LAST} + t = _get_time_value_position([FIRST:STEP:LAST...], ts) data = mat.data[idx, t] - _missing_data_check(data) + _missing_data_check(data, t) end -function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T, 2}, idx::AnyIndex, ts::TimestepValue) where {T, TIMES} - t = _get_time_value_position_(TIMES, ts) +function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T, 2}, idx::AnyIndex, ts::TimestepValue{T}) where {T, TIMES} + t = _get_time_value_position(TIMES, ts) data = mat.data[idx, t] - _missing_data_check(data) + _missing_data_check(data, t) end function Base.getindex(mat::TimestepMatrix, idx::AnyIndex, ts::TimestepIndex) t = ts.t size(mat.data, 2) < t ? error("TimestepIndex index $t extends beyond end of second dim of TimestepMatrix") : data = mat.data[idx, t] - _missing_data_check(data) + _missing_data_check(data, t) end function Base.setindex!(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, 1}, val, ts::FixedTimestep{FIRST, STEP, LAST}, idx::AnyIndex) where {T, FIRST, STEP, LAST} @@ -269,11 +290,15 @@ end # int indexing version supports old-style components and internal functions, not # part of the public API +# deprecated function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, idx1::AnyIndex, idx2::AnyIndex) where {T, FIRST, STEP, ti} + _throw_int_index_warning() return mat.data[idx1, idx2] end +# deprecated function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, idx1::AnyIndex, idx2::AnyIndex) where {T, TIMES, ti} + _throw_int_index_warning() return mat.data[idx1, idx2] end @@ -345,22 +370,22 @@ function Base.getindex(arr::TimestepArray{VariableTimestep{D_TIMES}, T, N, ti}, return arr.data[idxs1..., t, idxs2...] end -function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP, LAST}, T, N, ti}, idxs::Union{TimestepValue, AnyIndex}...) where {T, N, ti, FIRST, STEP, LAST} +function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP, LAST}, T, N, ti}, idxs::Union{TimestepValue{T}, AnyIndex}...) where {T, N, ti, FIRST, STEP, LAST} idxs1, ts, idxs2 = split_indices(idxs, ti) - t = _get_time_value_position_([FIRST:STEP:LAST...], ts) + t = _get_time_value_position([FIRST:STEP:LAST...], ts) return arr.data[idxs1..., t, idxs2...] end -function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idxs::Union{TimestepValue, AnyIndex}...) where {T, N, ti, TIMES} +function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idxs::Union{TimestepValue{T}, AnyIndex}...) where {T, N, ti, TIMES} idxs1, ts, idxs2 = split_indices(idxs, ti) - t = _get_time_value_position_(TIMES, ts) + t = _get_time_value_position(TIMES, ts) return arr.data[idxs1..., t, idxs2...] end function Base.getindex(arr::TimestepArray{AbstractTimestep, T, N, ti}, idxs::Union{TimestepIndex, AnyIndex}...) where {T, N, ti} idxs1, ts, idxs2 = split_indices(idxs, ti) t = ts.t - return arr.data[idxs1..., t, idxs2...] + size(arr.data, ti) < t ? error("TimestepIndex index $t extends beyond end of first dim of TimestepMatrix") : return arr.data[idxs1..., t, idxs2...] end function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, val, idxs::Union{FixedTimestep{FIRST, STEP, LAST}, AnyIndex}...) where {T, N, ti, FIRST, STEP, LAST} @@ -388,11 +413,15 @@ end # int indexing version supports old-style components and internal functions, not # part of the public API; first index is Int or Range, rather than a Timestep +# deprecated function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, idx1::AnyIndex, idx2::AnyIndex, idxs::AnyIndex...) where {T, N, ti, FIRST, STEP} + _throw_int_index_warning() return arr.data[idx1, idx2, idxs...] end +# deprecated function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idx1::AnyIndex, idx2::AnyIndex, idxs::AnyIndex...) where {T, N, ti, TIMES} + _throw_int_index_warning() return arr.data[idx1, idx2, idxs...] end @@ -454,17 +483,3 @@ function hasvalue(arr::TimestepArray{VariableTimestep{D_FIRST}, T, N, ti}, return D_FIRST[1] <= gettime(ts) <= last_period(arr) && all([1 <= idx <= size(arr, i) for (i, idx) in enumerate(idxs)]) end - -# Helper functions for TimestepValue type -function _get_time_value_position_(times::Array, ts::TimestepValue) - t = findfirst(isequal.(ts.value, times)) - if t === nothing - error("cannot use TimestepValue with value $(ts.value), value is not in the TimestepArray") - end - - t_offset = t + ts.offset - if t_offset > length(times) - error("cannot get TimestepValue offset of $(ts.offset) from value $(ts.value), offset is after the end of the TimestepArray") - end - return t_offset -end diff --git a/src/core/types/time.jl b/src/core/types/time.jl index 132168ff0..31a1230c7 100644 --- a/src/core/types/time.jl +++ b/src/core/types/time.jl @@ -25,6 +25,13 @@ end struct TimestepValue{T} value::T offset::Int + + function TimestepValue(v::T) where T + return new{T}(v, 0) + end + function TimestepValue(v::T, offset::Int) where T + return new{T}(v, offset) + end end struct TimestepIndex diff --git a/test/test_timesteparrays.jl b/test/test_timesteparrays.jl index 15748a314..f819cd3d8 100644 --- a/test/test_timesteparrays.jl +++ b/test/test_timesteparrays.jl @@ -34,6 +34,20 @@ x = TimestepVector{FixedTimestep{2000, 1}, Int}(a[:,3]) #1b. test hasvalue, getindex, and setindex! (with both matching years and # mismatched years) +# TimestepValue and TimestepIndex Indexing +@test x[TimestepIndex(1)] == 9 +@test x[TimestepIndex(1) + 1] == 10 +@test x[TimestepIndex(4)] == 12 +@test_throws ErrorException x[TimestepIndex(5)] + +# TODO_LFR - these all fail with no method found ... +@test x[TimestepValue(2000)] == 9 +@test x[TimestepValue(2000, 1)] == 10 +@test x[TimestepValue(2000) + 1] == 10 +@test_throws ErrorException x[TimestepValue(2005)] +@test_throws ErrorException x[TimestepValue(2004)+1] + +# AbstractTimestep Indexing t = FixedTimestep{2001, 1, 3000}(1) @test hasvalue(x, t) @@ -53,8 +67,9 @@ t3 = FixedTimestep{2000, 1, 2003}(1) x[t3] = 100 @test x[t3] == 100 +# Deprecated Int Indexing x[1] = 101 -@test x[1] == 101 +@test x[1] == 101 # TODO_LFR: test for warning #------------------------------------------------------------------------------ @@ -67,6 +82,22 @@ x = TimestepVector{VariableTimestep{years}, Int}(a[:,3]) #2a. test hasvalue, getindex, and setindex! (with both matching years and # mismatched years) +# TimestepValue and TimestepIndex Indexing +@test x[TimestepIndex(1)] == 9 +@test x[TimestepIndex(1) + 1] == 10 +@test x[TimestepIndex(4)] == 12 +@test_throws ErrorException x[TimestepIndex(5)] + +# TODO_LFR - these all fail with no method found ... +@test x[TimestepValue(2000)] == 9 +@test x[TimestepValue(2000, 1)] == 10 +@test x[TimestepValue(2015)] == 11 +@test x[TimestepValue(2015, 1)] == 12 +@test x[TimestepValue(2000) + 1] == 10 +@test_throws ErrorException x[TimestepValue(2014)] +@test_throws ErrorException x[TimestepValue(2025)+1] + +# AbstractTimestep Indexing y2 = Tuple([2005:5:2010; 2015:10:3000]) t = VariableTimestep{y2}() @@ -88,8 +119,9 @@ t3 = VariableTimestep{years}() x[t3] = 100 @test x[t3] == 100 +# Deprecated Int Indexing x[1] = 101 -@test x[1] == 101 +@test x[1] == 101 # TODO_LFR: test for warning #------------------------------------------------------------------------------ @@ -129,8 +161,8 @@ y[t3, 1] = 10 @test y[t3,1] == 10 y[:,:] = 11 -@test all([y[i,1] == 11 for i in 1:4]) -@test all([y[1,j] == 11 for j in 1:2]) +@test all([y[i,1] == 11 for i in 1:4]) # TODO_LFR: test for warning +@test all([y[1,j] == 11 for j in 1:2]) # TODO_LFR: test for warning #3c. interval wider than 1 z = TimestepMatrix{FixedTimestep{2000, 2}, Int, 1}(a[:,3:4]) @@ -178,8 +210,8 @@ y[t3, 1] = 10 @test y[t3,1] == 10 y[:,:] = 11 -@test all([y[i,1] == 11 for i in 1:4]) -@test all([y[1,j] == 11 for j in 1:2]) +@test all([y[i,1] == 11 for i in 1:4]) # TODO_LFR: test for warning +@test all([y[1,j] == 11 for j in 1:2]) # TODO_LFR: test for warning #------------------------------------------------------------------------------ @@ -300,4 +332,4 @@ close(w) @test all(!ismissing, m[:gdp, :pop]) @test all(!ismissing, m[:gdp, :mat2]) -end #module \ No newline at end of file +end #module From 57ffc0824a4db23d6ddcdfc39ef177f315fb878e Mon Sep 17 00:00:00 2001 From: lrennels Date: Wed, 16 Oct 2019 22:42:18 -0700 Subject: [PATCH 04/31] Fix TimstepValue constructor --- src/core/types/time.jl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/core/types/time.jl b/src/core/types/time.jl index 31a1230c7..0d42208e5 100644 --- a/src/core/types/time.jl +++ b/src/core/types/time.jl @@ -26,10 +26,7 @@ struct TimestepValue{T} value::T offset::Int - function TimestepValue(v::T) where T - return new{T}(v, 0) - end - function TimestepValue(v::T, offset::Int) where T + function TimestepValue(v::T; offset::Int = 0) return new{T}(v, offset) end end From 7219739b40e097e2ef33b4b60393b4e595db1de3 Mon Sep 17 00:00:00 2001 From: lrennels Date: Wed, 16 Oct 2019 22:42:51 -0700 Subject: [PATCH 05/31] Fix TimstepValue constructor --- src/core/types/time.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/types/time.jl b/src/core/types/time.jl index 0d42208e5..b03378bf4 100644 --- a/src/core/types/time.jl +++ b/src/core/types/time.jl @@ -26,7 +26,7 @@ struct TimestepValue{T} value::T offset::Int - function TimestepValue(v::T; offset::Int = 0) + function TimestepValue(v::T; offset::Int = 0) where T return new{T}(v, offset) end end From c3b6b870db2334bb8b5f25d66a8bacee125e3815 Mon Sep 17 00:00:00 2001 From: lrennels Date: Thu, 17 Oct 2019 11:42:26 -0700 Subject: [PATCH 06/31] Fix type parameterization of TimestepValue --- src/core/time_arrays.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index b37be0210..52f270c29 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -101,13 +101,13 @@ function Base.getindex(v::TimestepVector{VariableTimestep{D_TIMES}, T}, ts::Vari _missing_data_check(data, t) end -function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP, LAST}, T}, ts::TimestepValue{T}) where {T, FIRST, STEP, LAST} +function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP, LAST}, T_data}, ts::TimestepValue{T_time}) where {T_data, FIRST, STEP, LAST, T_time} t = _get_time_value_position([FIRST:STEP:LAST...], ts) data = v.data[t] _missing_data_check(data, t) end -function Base.getindex(v::TimestepVector{VariableTimestep{TIMES}, T}, ts::TimestepValue{T}) where {T, TIMES} +function Base.getindex(v::TimestepVector{VariableTimestep{TIMES}, T_data}, ts::TimestepValue{T_time}) where {T_data, TIMES, T_time} t = _get_time_value_position(TIMES, ts) data = v.data[t] _missing_data_check(data, t) @@ -215,13 +215,13 @@ function Base.getindex(mat::TimestepMatrix{VariableTimestep{D_TIMES}, T, 2}, idx _missing_data_check(data, t) end -function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP, LAST}, T, 1}, ts::TimestepValue{T}, idx::AnyIndex) where {T, FIRST, STEP, LAST} +function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP, LAST}, T_data, 1}, ts::TimestepValue{T_time}, idx::AnyIndex) where {T_data, FIRST, STEP, LAST, T_time} t = _get_time_value_position([FIRST:STEP:LAST...], ts) data = mat.data[t, idx] _missing_data_check(data, t) end -function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T, 1}, ts::TimestepValue{T}, idx::AnyIndex) where {T, TIMES} +function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T_data, 1}, ts::TimestepValue{T_time}, idx::AnyIndex) where {T_data, TIMES, T_time} t = _get_time_value_position(TIMES, ts) data = mat.data[t, idx] _missing_data_check(data, t) @@ -233,13 +233,13 @@ function Base.getindex(mat::TimestepMatrix, ts::TimestepIndex, idx::AnyIndex) _missing_data_check(data, t) end -function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP, LAST}, T, 2}, idx::AnyIndex, ts::TimestepValue{T}) where {T, FIRST, STEP, LAST} +function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP, LAST}, T_data, 2}, idx::AnyIndex, ts::TimestepValue{T_time}) where {T_data, FIRST, STEP, LAST, T_time} t = _get_time_value_position([FIRST:STEP:LAST...], ts) data = mat.data[idx, t] _missing_data_check(data, t) end -function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T, 2}, idx::AnyIndex, ts::TimestepValue{T}) where {T, TIMES} +function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T_data, 2}, idx::AnyIndex, ts::TimestepValue{T_time}) where {T_data, TIMES, T_time} t = _get_time_value_position(TIMES, ts) data = mat.data[idx, t] _missing_data_check(data, t) @@ -370,13 +370,13 @@ function Base.getindex(arr::TimestepArray{VariableTimestep{D_TIMES}, T, N, ti}, return arr.data[idxs1..., t, idxs2...] end -function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP, LAST}, T, N, ti}, idxs::Union{TimestepValue{T}, AnyIndex}...) where {T, N, ti, FIRST, STEP, LAST} +function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP, LAST}, T_data, N, ti}, idxs::Union{TimestepValue{T_time}, AnyIndex}...) where {T_data, N, ti, FIRST, STEP, LAST, T_time} idxs1, ts, idxs2 = split_indices(idxs, ti) t = _get_time_value_position([FIRST:STEP:LAST...], ts) return arr.data[idxs1..., t, idxs2...] end -function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idxs::Union{TimestepValue{T}, AnyIndex}...) where {T, N, ti, TIMES} +function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T_data, N, ti}, idxs::Union{TimestepValue{T_time}, AnyIndex}...) where {T_data, N, ti, TIMES, T_time} idxs1, ts, idxs2 = split_indices(idxs, ti) t = _get_time_value_position(TIMES, ts) return arr.data[idxs1..., t, idxs2...] From a59ed1823af126173069cef30beff696589d293a Mon Sep 17 00:00:00 2001 From: lrennels Date: Thu, 17 Oct 2019 12:00:09 -0700 Subject: [PATCH 07/31] Add index error check function --- src/core/time_arrays.jl | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index 52f270c29..2bacd0a35 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -37,6 +37,13 @@ function _missing_data_check(data, t) end end +# Helper function for getindex; throws an error if the TimestepIndex index is out of range of the TimestepArray +function _index_bounds_check(data, dim, t) + if size(data, dim) < t + error("TimestepIndex index $t extends beyond bounds of TimestepArray dimension $dim") + end +end + # Helper macro used by connector macro allow_missing(expr) let e = gensym("e") @@ -115,7 +122,8 @@ end function Base.getindex(v::TimestepVector, ts::TimestepIndex) t = ts.index - length(v.data) < t ? error("TimestepIndex index $t extends beyond end of TimestepArray") : data = v.data[t] + _index_bounds_check(v.data, 1, t) + data = v.data[t] _missing_data_check(data, t) end @@ -229,7 +237,8 @@ end function Base.getindex(mat::TimestepMatrix, ts::TimestepIndex, idx::AnyIndex) t = ts.index - size(mat.data, 1) < t ? error("TimestepIndex index $t extends beyond end of first dim of TimestepMatrix") : data = mat.data[t, idx] + _index_bounds_check(mat.data, 1, t) + data = mat.data[t, idx] _missing_data_check(data, t) end @@ -247,7 +256,8 @@ end function Base.getindex(mat::TimestepMatrix, idx::AnyIndex, ts::TimestepIndex) t = ts.t - size(mat.data, 2) < t ? error("TimestepIndex index $t extends beyond end of second dim of TimestepMatrix") : data = mat.data[idx, t] + _index_bounds_check(mat.data, 2, t) + data = mat.data[idx, t] _missing_data_check(data, t) end @@ -385,7 +395,8 @@ end function Base.getindex(arr::TimestepArray{AbstractTimestep, T, N, ti}, idxs::Union{TimestepIndex, AnyIndex}...) where {T, N, ti} idxs1, ts, idxs2 = split_indices(idxs, ti) t = ts.t - size(arr.data, ti) < t ? error("TimestepIndex index $t extends beyond end of first dim of TimestepMatrix") : return arr.data[idxs1..., t, idxs2...] + _index_bounds_check(arr.data, ti, t) + return arr.data[idxs1..., t, idxs2...] end function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, val, idxs::Union{FixedTimestep{FIRST, STEP, LAST}, AnyIndex}...) where {T, N, ti, FIRST, STEP, LAST} From 19b2b64ec7b15a505f1782fc25583dfc7f4d2430 Mon Sep 17 00:00:00 2001 From: lrennels Date: Thu, 17 Oct 2019 15:53:06 -0700 Subject: [PATCH 08/31] Add tests and corner case errors --- src/core/time.jl | 4 +-- src/core/time_arrays.jl | 52 +++++++++++++++++++++------- test/test_timesteparrays.jl | 69 ++++++++++++++++++++++++++++++++----- 3 files changed, 102 insertions(+), 23 deletions(-) diff --git a/src/core/time.jl b/src/core/time.jl index 6ea172307..db723a0ff 100644 --- a/src/core/time.jl +++ b/src/core/time.jl @@ -107,7 +107,7 @@ function Base.:-(ts::VariableTimestep{TIMES}, val::Int) where {TIMES} end function Base.:-(ts::TimestepValue, val::Int) - return TimestepValue(ts.value, ts.offset - val) + return TimestepValue(ts.value; offset = ts.offset - val) end function Base.:-(ts::TimestepIndex, val::Int) @@ -134,7 +134,7 @@ function Base.:+(ts::VariableTimestep{TIMES}, val::Int) where {TIMES} end function Base.:+(ts::TimestepValue, val::Int) - return TimestepValue(ts.value, ts.offset + val) + return TimestepValue(ts.value; offset = ts.offset + val) end function Base.:+(ts::TimestepIndex, val::Int) diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index 2bacd0a35..3c6244430 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -44,6 +44,22 @@ function _index_bounds_check(data, dim, t) end end +# Helper function for getindex; throws an error if you index into a N-dimensional TimestepArray with only one index +# if N > 1; Note that Julia does allow this and returns the column-major value, but this could produce unexpected +# behavior for users in this case so we do not allow it for now +function _single_index_check(data, idxs) + num_idxs = length(idxs) + num_dims = length(size(data)) + if num_idxs < num_dims + error("Not enough indices provided to index into TimestepArray, $num_idxs provided, $num_dims required") + end +end + +# Helper function for getindex and setindex; throws an error if one indexes into a TimestepArray with an integer +function _throw_int_index_warning() + @warn("Indexing into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndex(2)]") +end + # Helper macro used by connector macro allow_missing(expr) let e = gensym("e") @@ -64,7 +80,7 @@ end # Helper functions for TimestepValue type -function _get_time_value_position(times::Array, ts::TimestepValue{T}) where T +function _get_time_value_position(times::Union{Tuple, Array}, ts::TimestepValue{T}) where T t = findfirst(isequal.(ts.value, times)) if t === nothing error("cannot use TimestepValue with value $(ts.value), value is not in the TimestepArray") @@ -77,11 +93,6 @@ function _get_time_value_position(times::Array, ts::TimestepValue{T}) where T return t_offset end -# Helper function for throwing integer indexing warnings -function _throw_int_index_warning() - @warn("Indexing into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndex(2)]") -end - # # b. TimestepVector # @@ -108,7 +119,8 @@ function Base.getindex(v::TimestepVector{VariableTimestep{D_TIMES}, T}, ts::Vari _missing_data_check(data, t) end -function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP, LAST}, T_data}, ts::TimestepValue{T_time}) where {T_data, FIRST, STEP, LAST, T_time} +function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP}, T_data}, ts::TimestepValue{T_time}) where {T_data, FIRST, STEP, T_time} + LAST = FIRST + ((length(v.data)-1) * STEP) t = _get_time_value_position([FIRST:STEP:LAST...], ts) data = v.data[t] _missing_data_check(data, t) @@ -223,7 +235,8 @@ function Base.getindex(mat::TimestepMatrix{VariableTimestep{D_TIMES}, T, 2}, idx _missing_data_check(data, t) end -function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP, LAST}, T_data, 1}, ts::TimestepValue{T_time}, idx::AnyIndex) where {T_data, FIRST, STEP, LAST, T_time} +function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T_data, 1}, ts::TimestepValue{T_time}, idx::AnyIndex) where {T_data, FIRST, STEP, T_time} + LAST = FIRST + ((size(mat.data, 1) - 1) * STEP) t = _get_time_value_position([FIRST:STEP:LAST...], ts) data = mat.data[t, idx] _missing_data_check(data, t) @@ -242,7 +255,8 @@ function Base.getindex(mat::TimestepMatrix, ts::TimestepIndex, idx::AnyIndex) _missing_data_check(data, t) end -function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP, LAST}, T_data, 2}, idx::AnyIndex, ts::TimestepValue{T_time}) where {T_data, FIRST, STEP, LAST, T_time} +function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T_data, 2}, idx::AnyIndex, ts::TimestepValue{T_time}) where {T_data, FIRST, STEP, T_time} + LAST = FIRST + ((size(mat.data, 2) - 1) * STEP) t = _get_time_value_position([FIRST:STEP:LAST...], ts) data = mat.data[idx, t] _missing_data_check(data, t) @@ -255,7 +269,7 @@ function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T_data, 2}, end function Base.getindex(mat::TimestepMatrix, idx::AnyIndex, ts::TimestepIndex) - t = ts.t + t = ts.index _index_bounds_check(mat.data, 2, t) data = mat.data[idx, t] _missing_data_check(data, t) @@ -380,21 +394,33 @@ function Base.getindex(arr::TimestepArray{VariableTimestep{D_TIMES}, T, N, ti}, return arr.data[idxs1..., t, idxs2...] end -function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP, LAST}, T_data, N, ti}, idxs::Union{TimestepValue{T_time}, AnyIndex}...) where {T_data, N, ti, FIRST, STEP, LAST, T_time} +function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T_data, N, ti}, idxs::Union{TimestepValue{T_time}, AnyIndex}...) where {T_data, N, ti, FIRST, STEP, T_time} + _single_index_check(arr.data, idxs) idxs1, ts, idxs2 = split_indices(idxs, ti) + LAST = FIRST + ((size(arr.data, ti) - 1) * STEP) t = _get_time_value_position([FIRST:STEP:LAST...], ts) return arr.data[idxs1..., t, idxs2...] end function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T_data, N, ti}, idxs::Union{TimestepValue{T_time}, AnyIndex}...) where {T_data, N, ti, TIMES, T_time} + _single_index_check(arr.data, idxs) idxs1, ts, idxs2 = split_indices(idxs, ti) t = _get_time_value_position(TIMES, ts) return arr.data[idxs1..., t, idxs2...] end -function Base.getindex(arr::TimestepArray{AbstractTimestep, T, N, ti}, idxs::Union{TimestepIndex, AnyIndex}...) where {T, N, ti} +function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, idxs::Union{TimestepIndex, AnyIndex}...) where {T, N, ti, FIRST, STEP} + _single_index_check(arr.data, idxs) idxs1, ts, idxs2 = split_indices(idxs, ti) - t = ts.t + t = ts.index + _index_bounds_check(arr.data, ti, t) + return arr.data[idxs1..., t, idxs2...] +end + +function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idxs::Union{TimestepIndex, AnyIndex}...) where {T, N, ti, TIMES} + _single_index_check(arr.data, idxs) + idxs1, ts, idxs2 = split_indices(idxs, ti) + t = ts.index _index_bounds_check(arr.data, ti, t) return arr.data[idxs1..., t, idxs2...] end diff --git a/test/test_timesteparrays.jl b/test/test_timesteparrays.jl index f819cd3d8..b186e436d 100644 --- a/test/test_timesteparrays.jl +++ b/test/test_timesteparrays.jl @@ -4,7 +4,7 @@ using Mimi using Test import Mimi: - FixedTimestep, VariableTimestep, TimestepVector, TimestepMatrix, next_timestep, hasvalue, + FixedTimestep, VariableTimestep, TimestepVector, TimestepMatrix, TimestepArray, next_timestep, hasvalue, isuniform, first_period, last_period, first_and_step a = collect(reshape(1:16,4,4)) @@ -40,9 +40,8 @@ x = TimestepVector{FixedTimestep{2000, 1}, Int}(a[:,3]) @test x[TimestepIndex(4)] == 12 @test_throws ErrorException x[TimestepIndex(5)] -# TODO_LFR - these all fail with no method found ... @test x[TimestepValue(2000)] == 9 -@test x[TimestepValue(2000, 1)] == 10 +@test x[TimestepValue(2000; offset = 1)] == 10 @test x[TimestepValue(2000) + 1] == 10 @test_throws ErrorException x[TimestepValue(2005)] @test_throws ErrorException x[TimestepValue(2004)+1] @@ -88,11 +87,10 @@ x = TimestepVector{VariableTimestep{years}, Int}(a[:,3]) @test x[TimestepIndex(4)] == 12 @test_throws ErrorException x[TimestepIndex(5)] -# TODO_LFR - these all fail with no method found ... @test x[TimestepValue(2000)] == 9 -@test x[TimestepValue(2000, 1)] == 10 +@test x[TimestepValue(2000; offset = 1)] == 10 @test x[TimestepValue(2015)] == 11 -@test x[TimestepValue(2015, 1)] == 12 +@test x[TimestepValue(2015; offset = 1)] == 12 @test x[TimestepValue(2000) + 1] == 10 @test_throws ErrorException x[TimestepValue(2014)] @test_throws ErrorException x[TimestepValue(2025)+1] @@ -134,9 +132,25 @@ years = Tuple(2000:1:2003) y = TimestepMatrix{FixedTimestep{2000, 1}, Int, 1}(a[:,1:2]) +# TimestepValue and TimestepIndex Indexing +@test y[TimestepIndex(1), 1] == 1 +@test y[TimestepIndex(1), 2] == 5 +@test y[TimestepIndex(1) + 1, 1] == 2 +@test y[TimestepIndex(4), 2] == 8 +@test_throws ErrorException y[TimestepIndex(5), 2] + +@test y[TimestepValue(2000), 1] == 1 +@test y[TimestepValue(2000), 2] == 5 +@test y[TimestepValue(2001), :] == [2,6] +@test y[TimestepValue(2000; offset = 1), 1] == 2 +@test y[TimestepValue(2000) + 1, 1] == 2 +@test_throws ErrorException y[TimestepValue(2005), 1] +@test_throws ErrorException y[TimestepValue(2004)+1, 1] + #3b. test hasvalue, getindex, and setindex! (with both matching years and # mismatched years) +# AbstractTimestep Indexing t = FixedTimestep{2001, 1, 3000}(1) @test hasvalue(y, t, 1) @@ -160,6 +174,7 @@ t3 = FixedTimestep{2000, 1, 2005}(1) y[t3, 1] = 10 @test y[t3,1] == 10 +# Deprecated Int Indexing y[:,:] = 11 @test all([y[i,1] == 11 for i in 1:4]) # TODO_LFR: test for warning @test all([y[1,j] == 11 for j in 1:2]) # TODO_LFR: test for warning @@ -186,6 +201,23 @@ y = TimestepMatrix{VariableTimestep{years}, Int, 1}(a[:,1:2]) #4a. test hasvalue, getindex, setindex!, and lastindex (with both matching years and # mismatched years) +# TimestepValue and TimestepIndex Indexing +@test y[TimestepIndex(1), 1] == 1 +@test y[TimestepIndex(1), 2] == 5 +@test y[TimestepIndex(1) + 1, 1] == 2 +@test y[TimestepIndex(4), 2] == 8 +@test_throws ErrorException y[TimestepIndex(5), 2] + +@test y[TimestepValue(2000), 1] == 1 +@test y[TimestepValue(2000), 2] == 5 +@test y[TimestepValue(2000; offset = 1), 1] == 2 +@test y[TimestepValue(2000) + 1, 1] == 2 +@test y[TimestepValue(2015), 1] == 3 +@test y[TimestepValue(2015) + 1, 2] == 8 +@test_throws ErrorException y[TimestepValue(2006), 1] +@test_throws ErrorException y[TimestepValue(2025)+1, 1] + +# AbstractTimestep Indexing t = VariableTimestep{Tuple([2005:5:2010; 2015:10:3000])}() @test hasvalue(y, t, 1) @@ -209,15 +241,37 @@ t3 = VariableTimestep{years}() y[t3, 1] = 10 @test y[t3,1] == 10 +# Deprecated Integer Indexing y[:,:] = 11 @test all([y[i,1] == 11 for i in 1:4]) # TODO_LFR: test for warning @test all([y[1,j] == 11 for j in 1:2]) # TODO_LFR: test for warning - #------------------------------------------------------------------------------ # 5. Test TimestepArray methods #------------------------------------------------------------------------------ +# 3 dimensional array +years = Tuple([2000:5:2005; 2015:10:2025]) +data = collect(reshape(1:64, 4, 4, 4)) +arr_fixed = TimestepArray{FixedTimestep{2000, 5}, Int, 3, 1}(data) +arr_variable = TimestepArray{VariableTimestep{years}, Int, 3, 1}(data) + +@test arr_fixed[TimestepValue(2000), 1, 1] == 1 +@test arr_fixed[TimestepValue(2010), 3, 3] == 43 +@test arr_variable[TimestepValue(2000), 1, 1] == 1 +@test arr_variable[TimestepValue(2015), 3, 3] == 43 + +@test arr_fixed[TimestepIndex(1), 1, 1] == 1 +@test arr_fixed[TimestepIndex(3), 3, 3] == 43 +@test arr_variable[TimestepIndex(1), 1, 1] == 1 +@test arr_variable[TimestepIndex(3), 3, 3] == 43 + +@test_throws ErrorException arr_fixed[TimestepValue(2000)] +@test_throws ErrorException arr_variable[TimestepValue(2000)] +@test_throws ErrorException arr_fixed[TimestepIndex(1)] +@test_throws ErrorException arr_variable[TimestepIndex(1)] + +# other methods x_years = Tuple(2000:5:2015) #fixed y_years = Tuple([2000:5:2005; 2015:10:2025]) #variable @@ -246,7 +300,6 @@ fill!(y, 2) @test x.data == fill(2, (4)) @test y.data == fill(2, (4, 2)) - #------------------------------------------------------------------------------ # 6. Test that getindex for TimestepArrays doesn't allow access to `missing` # values during `run` that haven't been computed yet. From 39edfe018ccd755e60cf94c95d4be5c97ab896c7 Mon Sep 17 00:00:00 2001 From: lrennels Date: Thu, 17 Oct 2019 16:23:03 -0700 Subject: [PATCH 09/31] Deprecate setindex with an integer --- src/core/time_arrays.jl | 37 ++++++++++++++++++++++--------------- test/test_timesteparrays.jl | 37 ++++++++++++++++++++++++------------- 2 files changed, 46 insertions(+), 28 deletions(-) diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index 3c6244430..73be6cb35 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -55,9 +55,14 @@ function _single_index_check(data, idxs) end end -# Helper function for getindex and setindex; throws an error if one indexes into a TimestepArray with an integer -function _throw_int_index_warning() - @warn("Indexing into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndex(2)]") +# Helper function for getindex; throws an error if one indexes into a TimestepArray with an integer +function _throw_int_getindex_warning() + @warn("Indexing with getindex into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndex(2)]") +end + +# Helper function for setindex; throws an error if one indexes into a TimestepArray with an integer +function _throw_int_setindex_warning() + @warn("Indexing with setindex into a TimestepArray with Integer(s) is deprecated") end # Helper macro used by connector @@ -160,23 +165,23 @@ end # int indexing version supports old-style components and internal functions, not # part of the public API -# deprecated function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP}, T}, i::AnyIndex) where {T, FIRST, STEP} - _throw_int_index_warning() + _throw_int_getindex_warning() return v.data[i] end -#deprecated function Base.getindex(v::TimestepVector{VariableTimestep{TIMES}, T}, i::AnyIndex) where {T, TIMES} - _throw_int_index_warning() + _throw_int_getindex_warning() return v.data[i] end function Base.setindex!(v::TimestepVector{FixedTimestep{Start, STEP}, T}, val, i::AnyIndex) where {T, Start, STEP} + _throw_int_setindex_warning() setindex!(v.data, val, i) end function Base.setindex!(v::TimestepVector{VariableTimestep{TIMES}, T}, val, i::AnyIndex) where {T, TIMES} + _throw_int_setindex_warning() setindex!(v.data, val, i) end @@ -314,31 +319,33 @@ end # int indexing version supports old-style components and internal functions, not # part of the public API -# deprecated function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, idx1::AnyIndex, idx2::AnyIndex) where {T, FIRST, STEP, ti} - _throw_int_index_warning() + _throw_int_getindex_warning() return mat.data[idx1, idx2] end -# deprecated function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, idx1::AnyIndex, idx2::AnyIndex) where {T, TIMES, ti} - _throw_int_index_warning() + _throw_int_getindex_warning() return mat.data[idx1, idx2] end function Base.setindex!(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, val, idx1::Int, idx2::Int) where {T, FIRST, STEP, ti} + _throw_int_setindex_warning() setindex!(mat.data, val, idx1, idx2) end function Base.setindex!(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, val, idx1::AnyIndex, idx2::AnyIndex) where {T, FIRST, STEP, ti} + _throw_int_setindex_warning() mat.data[idx1, idx2] .= val end function Base.setindex!(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, val, idx1::Int, idx2::Int) where {T, TIMES, ti} + _throw_int_setindex_warning() setindex!(mat.data, val, idx1, idx2) end function Base.setindex!(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, val, idx1::AnyIndex, idx2::AnyIndex) where {T, TIMES, ti} + _throw_int_setindex_warning() mat.data[idx1, idx2] .= val end @@ -450,23 +457,23 @@ end # int indexing version supports old-style components and internal functions, not # part of the public API; first index is Int or Range, rather than a Timestep -# deprecated function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, idx1::AnyIndex, idx2::AnyIndex, idxs::AnyIndex...) where {T, N, ti, FIRST, STEP} - _throw_int_index_warning() + _throw_int_getindex_warning() return arr.data[idx1, idx2, idxs...] end -# deprecated function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idx1::AnyIndex, idx2::AnyIndex, idxs::AnyIndex...) where {T, N, ti, TIMES} - _throw_int_index_warning() + _throw_int_getindex_warning() return arr.data[idx1, idx2, idxs...] end function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, val, idx1::AnyIndex, idx2::AnyIndex, idxs::AnyIndex...) where {T, N, ti, FIRST, STEP} + _throw_int_setindex_warning() setindex!(arr.data, val, idx1, idx2, idxs...) end function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, val, idx1::AnyIndex, idx2::AnyIndex, idxs::AnyIndex...) where {T, N, ti, TIMES} + _throw_int_setindex_warning() setindex!(arr.data, val, idx1, idx2, idxs...) end diff --git a/test/test_timesteparrays.jl b/test/test_timesteparrays.jl index b186e436d..8d4b90278 100644 --- a/test/test_timesteparrays.jl +++ b/test/test_timesteparrays.jl @@ -7,6 +7,9 @@ import Mimi: FixedTimestep, VariableTimestep, TimestepVector, TimestepMatrix, TimestepArray, next_timestep, hasvalue, isuniform, first_period, last_period, first_and_step +# general variables +getindex_warn_msg = "Indexing with getindex into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndex(2)]" +setindex_warn_msg = "Indexing with setindex into a TimestepArray with Integer(s) is deprecated" a = collect(reshape(1:16,4,4)) ## quick check of isuniform @@ -66,9 +69,9 @@ t3 = FixedTimestep{2000, 1, 2003}(1) x[t3] = 100 @test x[t3] == 100 -# Deprecated Int Indexing -x[1] = 101 -@test x[1] == 101 # TODO_LFR: test for warning +# Deprecated setindex and getindex method +@test_logs (:warn, setindex_warn_msg) (x[1] = 101) +@test_logs (:warn, getindex_warn_msg) x[1] == 101 #------------------------------------------------------------------------------ @@ -118,9 +121,8 @@ x[t3] = 100 @test x[t3] == 100 # Deprecated Int Indexing -x[1] = 101 -@test x[1] == 101 # TODO_LFR: test for warning - +@test_logs (:warn, setindex_warn_msg) (x[1] = 101) +@test_logs (:warn, getindex_warn_msg) x[1] == 101 #------------------------------------------------------------------------------ # 3. Test TimestepMatrix - Fixed Timestep @@ -175,9 +177,14 @@ y[t3, 1] = 10 @test y[t3,1] == 10 # Deprecated Int Indexing -y[:,:] = 11 -@test all([y[i,1] == 11 for i in 1:4]) # TODO_LFR: test for warning -@test all([y[1,j] == 11 for j in 1:2]) # TODO_LFR: test for warning +@test_logs (:warn, setindex_warn_msg) y[:,:] = 11 +for i = 1:4 + @test_logs (:warn, getindex_warn_msg) y[i,1] == 11 +end +for j = 1:2 + @test_logs (:warn, getindex_warn_msg) y[1,j] == 11 +end + #3c. interval wider than 1 z = TimestepMatrix{FixedTimestep{2000, 2}, Int, 1}(a[:,3:4]) @@ -241,10 +248,14 @@ t3 = VariableTimestep{years}() y[t3, 1] = 10 @test y[t3,1] == 10 -# Deprecated Integer Indexing -y[:,:] = 11 -@test all([y[i,1] == 11 for i in 1:4]) # TODO_LFR: test for warning -@test all([y[1,j] == 11 for j in 1:2]) # TODO_LFR: test for warning +# Deprecated Int Indexing +@test_logs (:warn, setindex_warn_msg) y[:,:] = 11 +for i = 1:4 + @test_logs (:warn, getindex_warn_msg) y[i,1] == 11 +end +for j = 1:2 + @test_logs (:warn, getindex_warn_msg) y[1,j] == 11 +end #------------------------------------------------------------------------------ # 5. Test TimestepArray methods From e11d70026906718a19f3e1a804775cd808f01682 Mon Sep 17 00:00:00 2001 From: lrennels Date: Thu, 17 Oct 2019 17:40:30 -0700 Subject: [PATCH 10/31] Work on _param_indices and set_param! for TimeIndex --- src/core/time_arrays.jl | 24 ++++++++++++++++++++++++ src/mcs/montecarlo.jl | 5 +++-- test/test_timesteparrays.jl | 22 ++++++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index 73be6cb35..16db664df 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -162,6 +162,10 @@ function Base.setindex!(v::TimestepVector{VariableTimestep{D_TIMES}, T}, val, ts setindex!(v.data, val, t) end +function Base.setindex!(v::TimestepVector, val, ts::TimestepIndex) + setindex!(v.data, val, ts.index) +end + # int indexing version supports old-style components and internal functions, not # part of the public API @@ -316,6 +320,14 @@ function Base.setindex!(mat::TimestepMatrix{VariableTimestep{D_TIMES}, T, 2}, va setindex!(mat.data, val, idx, t) end +function Base.setindex!(mat::TimestepMatrix, val, idx::AnyIndex, ts::TimestepIndex) + setindex!(mat.data, val, idx, ts.index) +end + +function Base.setindex!(mat::TimestepMatrix, val, ts::TimestepIndex, idx::AnyIndex) + setindex!(mat.data, val, ts.index, idx) +end + # int indexing version supports old-style components and internal functions, not # part of the public API @@ -454,6 +466,18 @@ function Base.setindex!(arr::TimestepArray{VariableTimestep{D_TIMES}, T, N, ti}, setindex!(arr.data, val, idxs1..., t, idxs2...) end +function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, val, idxs::Union{TimestepIndex, AnyIndex}...) where {T, N, ti, FIRST, STEP} + idxs1, ts, idxs2 = split_indices(idxs, ti) + t = ts.index + setindex!(arr.data, val, idxs1..., t, idxs2...) +end + +function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, val, idxs::Union{TimestepIndex, AnyIndex}...) where {T, N, ti, TIMES} + idxs1, ts, idxs2 = split_indices(idxs, ti) + t = ts.index + setindex!(arr.data, val, idxs1..., t, idxs2...) +end + # int indexing version supports old-style components and internal functions, not # part of the public API; first index is Int or Range, rather than a Timestep diff --git a/src/mcs/montecarlo.jl b/src/mcs/montecarlo.jl index 56dedd269..0b9793b70 100644 --- a/src/mcs/montecarlo.jl +++ b/src/mcs/montecarlo.jl @@ -304,10 +304,11 @@ function _param_indices(param::ArrayModelParameter{T}, md::ModelDef, trans::Tran indices = Vector() for (dim_name, dim_values) in zip(pdims, tdims) dim = dimension(md, dim_name) - push!(indices, dim[dim_values]) + dim_indices = dim[dim_values] + dim_name == :time ? dim_indices = TimestepIndex.(dim_indices) : nothing + push!(indices, dim_indices) end - # println("indices: $indices") return indices end diff --git a/test/test_timesteparrays.jl b/test/test_timesteparrays.jl index 8d4b90278..4b17e81f9 100644 --- a/test/test_timesteparrays.jl +++ b/test/test_timesteparrays.jl @@ -49,6 +49,9 @@ x = TimestepVector{FixedTimestep{2000, 1}, Int}(a[:,3]) @test_throws ErrorException x[TimestepValue(2005)] @test_throws ErrorException x[TimestepValue(2004)+1] +x[TimestepIndex(1)] = 100 +@test x[TimestepIndex(1)] == 100 + # AbstractTimestep Indexing t = FixedTimestep{2001, 1, 3000}(1) @@ -90,6 +93,10 @@ x = TimestepVector{VariableTimestep{years}, Int}(a[:,3]) @test x[TimestepIndex(4)] == 12 @test_throws ErrorException x[TimestepIndex(5)] +x[TimestepIndex(1)] = 100 +@test x[TimestepIndex(1)] == 100 +x[TimestepIndex(1)] = 1 # reset + @test x[TimestepValue(2000)] == 9 @test x[TimestepValue(2000; offset = 1)] == 10 @test x[TimestepValue(2015)] == 11 @@ -141,6 +148,10 @@ y = TimestepMatrix{FixedTimestep{2000, 1}, Int, 1}(a[:,1:2]) @test y[TimestepIndex(4), 2] == 8 @test_throws ErrorException y[TimestepIndex(5), 2] +y[TimestepIndex(1), 1] = 100 +@test y[TimestepIndex(1), 1] == 100 +y[TimestepIndex(1), 1] = 1 # reset + @test y[TimestepValue(2000), 1] == 1 @test y[TimestepValue(2000), 2] == 5 @test y[TimestepValue(2001), :] == [2,6] @@ -215,6 +226,10 @@ y = TimestepMatrix{VariableTimestep{years}, Int, 1}(a[:,1:2]) @test y[TimestepIndex(4), 2] == 8 @test_throws ErrorException y[TimestepIndex(5), 2] +y[TimestepIndex(1), 1] = 101 +@test y[TimestepIndex(1), 1] == 101 +y[TimestepIndex(1), 1] == 101 # reset + @test y[TimestepValue(2000), 1] == 1 @test y[TimestepValue(2000), 2] == 5 @test y[TimestepValue(2000; offset = 1), 1] == 2 @@ -282,6 +297,13 @@ arr_variable = TimestepArray{VariableTimestep{years}, Int, 3, 1}(data) @test_throws ErrorException arr_fixed[TimestepIndex(1)] @test_throws ErrorException arr_variable[TimestepIndex(1)] +arr_fixed[TimestepIndex(1), 1, 1] = 101 +arr_variable[TimestepIndex(1), 1, 1] = 101 +@test arr_fixed[TimestepIndex(1), 1, 1] == 101 +@test arr_variable[TimestepIndex(1), 1, 1] == 101 +arr_fixed[TimestepIndex(1), 1, 1] == 101 # reset +arr_variable[TimestepIndex(1), 1, 1] == 101 # reset + # other methods x_years = Tuple(2000:5:2015) #fixed y_years = Tuple([2000:5:2005; 2015:10:2025]) #variable From 6daac9e767d9bd8128a543902b9b59e6f4e15336 Mon Sep 17 00:00:00 2001 From: lrennels Date: Fri, 18 Oct 2019 12:52:54 -0700 Subject: [PATCH 11/31] Enhance warning message --- src/core/time_arrays.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index 16db664df..4efa21fec 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -62,7 +62,7 @@ end # Helper function for setindex; throws an error if one indexes into a TimestepArray with an integer function _throw_int_setindex_warning() - @warn("Indexing with setindex into a TimestepArray with Integer(s) is deprecated") + @warn("Indexing with setindex into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndec(2)]") end # Helper macro used by connector From 6a508561846eb22d24d3252be7aa47907b708b63 Mon Sep 17 00:00:00 2001 From: lrennels Date: Mon, 28 Oct 2019 19:41:30 -0700 Subject: [PATCH 12/31] Fix tests --- test/test_timesteparrays.jl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/test_timesteparrays.jl b/test/test_timesteparrays.jl index 4b17e81f9..bd822b860 100644 --- a/test/test_timesteparrays.jl +++ b/test/test_timesteparrays.jl @@ -9,7 +9,7 @@ import Mimi: # general variables getindex_warn_msg = "Indexing with getindex into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndex(2)]" -setindex_warn_msg = "Indexing with setindex into a TimestepArray with Integer(s) is deprecated" +setindex_warn_msg = "Indexing with setindex into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndec(2)]" a = collect(reshape(1:16,4,4)) ## quick check of isuniform @@ -51,6 +51,7 @@ x = TimestepVector{FixedTimestep{2000, 1}, Int}(a[:,3]) x[TimestepIndex(1)] = 100 @test x[TimestepIndex(1)] == 100 +x[TimestepIndex(1)] = 9 # reset for later tests # AbstractTimestep Indexing t = FixedTimestep{2001, 1, 3000}(1) @@ -95,7 +96,7 @@ x = TimestepVector{VariableTimestep{years}, Int}(a[:,3]) x[TimestepIndex(1)] = 100 @test x[TimestepIndex(1)] == 100 -x[TimestepIndex(1)] = 1 # reset +x[TimestepIndex(1)] = 9 # reset @test x[TimestepValue(2000)] == 9 @test x[TimestepValue(2000; offset = 1)] == 10 @@ -228,7 +229,7 @@ y = TimestepMatrix{VariableTimestep{years}, Int, 1}(a[:,1:2]) y[TimestepIndex(1), 1] = 101 @test y[TimestepIndex(1), 1] == 101 -y[TimestepIndex(1), 1] == 101 # reset +y[TimestepIndex(1), 1] = 1 # reset @test y[TimestepValue(2000), 1] == 1 @test y[TimestepValue(2000), 2] == 5 @@ -301,8 +302,8 @@ arr_fixed[TimestepIndex(1), 1, 1] = 101 arr_variable[TimestepIndex(1), 1, 1] = 101 @test arr_fixed[TimestepIndex(1), 1, 1] == 101 @test arr_variable[TimestepIndex(1), 1, 1] == 101 -arr_fixed[TimestepIndex(1), 1, 1] == 101 # reset -arr_variable[TimestepIndex(1), 1, 1] == 101 # reset +arr_fixed[TimestepIndex(1), 1, 1] = 1 # reset +arr_variable[TimestepIndex(1), 1, 1] = 1 # reset # other methods x_years = Tuple(2000:5:2015) #fixed From 1a5d4c5f4393e15563e3965991d375c0a7a87e00 Mon Sep 17 00:00:00 2001 From: lrennels Date: Mon, 28 Oct 2019 21:55:22 -0700 Subject: [PATCH 13/31] Add setindex methods for TimestepValue --- src/core/time_arrays.jl | 48 ++++++++++++++++++++++++++++++++++ test/test_timesteparrays.jl | 51 +++++++++++++++++++++++++++---------- 2 files changed, 85 insertions(+), 14 deletions(-) diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index 4efa21fec..3cac0a197 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -162,6 +162,17 @@ function Base.setindex!(v::TimestepVector{VariableTimestep{D_TIMES}, T}, val, ts setindex!(v.data, val, t) end +function Base.setindex!(v::TimestepVector{FixedTimestep{FIRST, STEP}, T_data}, val, ts::TimestepValue{T_time}) where {T_data, FIRST, STEP, T_time} + LAST = FIRST + ((length(v.data)-1) * STEP) + t = _get_time_value_position([FIRST:STEP:LAST...], ts) + setindex!(v.data, val, t) +end + +function Base.setindex!(v::TimestepVector{VariableTimestep{TIMES}, T_data}, val, ts::TimestepValue{T_time}) where {T_data, TIMES, T_time} + t = _get_time_value_position(TIMES, ts) + setindex!(v.data, val, t) +end + function Base.setindex!(v::TimestepVector, val, ts::TimestepIndex) setindex!(v.data, val, ts.index) end @@ -320,6 +331,28 @@ function Base.setindex!(mat::TimestepMatrix{VariableTimestep{D_TIMES}, T, 2}, va setindex!(mat.data, val, idx, t) end +function Base.setindex!(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T_data, 1}, val, ts::TimestepValue{T_time}, idx::AnyIndex) where {T_data, FIRST, STEP, T_time} + LAST = FIRST + ((size(mat.data, 1) - 1) * STEP) + t = _get_time_value_position([FIRST:STEP:LAST...], ts) + setindex!(mat.data, val, t, idx) +end + +function Base.setindex!(mat::TimestepMatrix{VariableTimestep{TIMES}, T_data, 1}, val, ts::TimestepValue{T_time}, idx::AnyIndex) where {T_data, TIMES, T_time} + t = _get_time_value_position(TIMES, ts) + setindex!(mat.data, val, t, idx) +end + +function Base.setindex!(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T_data, 2}, val, idx::AnyIndex, ts::TimestepValue{T_time}) where {T_data, FIRST, STEP, T_time} + LAST = FIRST + ((size(mat.data, 1) - 1) * STEP) + t = _get_time_value_position([FIRST:STEP:LAST...], ts) + setindex!(mat.data, val, idx, t) +end + +function Base.setindex!(mat::TimestepMatrix{VariableTimestep{TIMES}, T_data, 2}, val, idx::AnyIndex, ts::TimestepValue{T_time}) where {T_data, TIMES, T_time} + t = _get_time_value_position(TIMES, ts) + setindex!(mat.data, val, idx, t) +end + function Base.setindex!(mat::TimestepMatrix, val, idx::AnyIndex, ts::TimestepIndex) setindex!(mat.data, val, idx, ts.index) end @@ -466,6 +499,21 @@ function Base.setindex!(arr::TimestepArray{VariableTimestep{D_TIMES}, T, N, ti}, setindex!(arr.data, val, idxs1..., t, idxs2...) end +function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T_data, N, ti}, val, idxs::Union{TimestepValue{T_time}, AnyIndex}...) where {T_data, N, ti, FIRST, STEP, T_time} + _single_index_check(arr.data, idxs) + idxs1, ts, idxs2 = split_indices(idxs, ti) + LAST = FIRST + ((size(arr.data, ti) - 1) * STEP) + t = _get_time_value_position([FIRST:STEP:LAST...], ts) + setindex!(arr.data, val, idxs1..., t, idxs2...) +end + +function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T_data, N, ti}, val, idxs::Union{TimestepValue{T_time}, AnyIndex}...) where {T_data, N, ti, TIMES, T_time} + _single_index_check(arr.data, idxs) + idxs1, ts, idxs2 = split_indices(idxs, ti) + t = _get_time_value_position(TIMES, ts) + setindex!(arr.data, val, idxs1..., t, idxs2...) +end + function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, val, idxs::Union{TimestepIndex, AnyIndex}...) where {T, N, ti, FIRST, STEP} idxs1, ts, idxs2 = split_indices(idxs, ti) t = ts.index diff --git a/test/test_timesteparrays.jl b/test/test_timesteparrays.jl index bd822b860..7707924b3 100644 --- a/test/test_timesteparrays.jl +++ b/test/test_timesteparrays.jl @@ -43,15 +43,19 @@ x = TimestepVector{FixedTimestep{2000, 1}, Int}(a[:,3]) @test x[TimestepIndex(4)] == 12 @test_throws ErrorException x[TimestepIndex(5)] +x[TimestepIndex(1)] = 100 +@test x[TimestepIndex(1)] == 100 +x[TimestepIndex(1)] = 9 # reset for later tests + @test x[TimestepValue(2000)] == 9 @test x[TimestepValue(2000; offset = 1)] == 10 @test x[TimestepValue(2000) + 1] == 10 @test_throws ErrorException x[TimestepValue(2005)] @test_throws ErrorException x[TimestepValue(2004)+1] -x[TimestepIndex(1)] = 100 -@test x[TimestepIndex(1)] == 100 -x[TimestepIndex(1)] = 9 # reset for later tests +x[TimestepValue(2000)] = 101 +@test x[TimestepValue(2000)] == 101 +x[TimestepValue(2000)] = 9 # reset for later tests # AbstractTimestep Indexing t = FixedTimestep{2001, 1, 3000}(1) @@ -77,7 +81,6 @@ x[t3] = 100 @test_logs (:warn, setindex_warn_msg) (x[1] = 101) @test_logs (:warn, getindex_warn_msg) x[1] == 101 - #------------------------------------------------------------------------------ # 2. Test TimestepVector - Variable Timestep #------------------------------------------------------------------------------ @@ -106,6 +109,10 @@ x[TimestepIndex(1)] = 9 # reset @test_throws ErrorException x[TimestepValue(2014)] @test_throws ErrorException x[TimestepValue(2025)+1] +x[TimestepValue(2015)] = 100 +@test x[TimestepValue(2015)] == 100 +x[TimestepValue(2015)] = 11 # reset + # AbstractTimestep Indexing y2 = Tuple([2005:5:2010; 2015:10:3000]) t = VariableTimestep{y2}() @@ -161,6 +168,10 @@ y[TimestepIndex(1), 1] = 1 # reset @test_throws ErrorException y[TimestepValue(2005), 1] @test_throws ErrorException y[TimestepValue(2004)+1, 1] +y[TimestepValue(2000), 1] = 101 +@test y[TimestepValue(2000), 1] == 101 +y[TimestepValue(2000), 1] = 1 # reset + #3b. test hasvalue, getindex, and setindex! (with both matching years and # mismatched years) @@ -240,6 +251,10 @@ y[TimestepIndex(1), 1] = 1 # reset @test_throws ErrorException y[TimestepValue(2006), 1] @test_throws ErrorException y[TimestepValue(2025)+1, 1] +y[TimestepValue(2015), 1] = 100 +@test y[TimestepValue(2015), 1] == 100 +y[TimestepValue(2015), 1] = 3 # reset + # AbstractTimestep Indexing t = VariableTimestep{Tuple([2005:5:2010; 2015:10:3000])}() @@ -283,21 +298,11 @@ data = collect(reshape(1:64, 4, 4, 4)) arr_fixed = TimestepArray{FixedTimestep{2000, 5}, Int, 3, 1}(data) arr_variable = TimestepArray{VariableTimestep{years}, Int, 3, 1}(data) -@test arr_fixed[TimestepValue(2000), 1, 1] == 1 -@test arr_fixed[TimestepValue(2010), 3, 3] == 43 -@test arr_variable[TimestepValue(2000), 1, 1] == 1 -@test arr_variable[TimestepValue(2015), 3, 3] == 43 - @test arr_fixed[TimestepIndex(1), 1, 1] == 1 @test arr_fixed[TimestepIndex(3), 3, 3] == 43 @test arr_variable[TimestepIndex(1), 1, 1] == 1 @test arr_variable[TimestepIndex(3), 3, 3] == 43 -@test_throws ErrorException arr_fixed[TimestepValue(2000)] -@test_throws ErrorException arr_variable[TimestepValue(2000)] -@test_throws ErrorException arr_fixed[TimestepIndex(1)] -@test_throws ErrorException arr_variable[TimestepIndex(1)] - arr_fixed[TimestepIndex(1), 1, 1] = 101 arr_variable[TimestepIndex(1), 1, 1] = 101 @test arr_fixed[TimestepIndex(1), 1, 1] == 101 @@ -305,6 +310,24 @@ arr_variable[TimestepIndex(1), 1, 1] = 101 arr_fixed[TimestepIndex(1), 1, 1] = 1 # reset arr_variable[TimestepIndex(1), 1, 1] = 1 # reset +@test_throws ErrorException arr_fixed[TimestepIndex(1)] +@test_throws ErrorException arr_variable[TimestepIndex(1)] + +@test arr_fixed[TimestepValue(2000), 1, 1] == 1 +@test arr_fixed[TimestepValue(2010), 3, 3] == 43 +@test arr_variable[TimestepValue(2000), 1, 1] == 1 +@test arr_variable[TimestepValue(2015), 3, 3] == 43 + +arr_fixed[TimestepValue(2000), 1, 1] = 101 +arr_variable[TimestepValue(2000), 1, 1] = 101 +@test arr_fixed[TimestepValue(2000), 1, 1] == 101 +@test arr_variable[TimestepValue(2000), 1, 1] == 101 +arr_fixed[TimestepValue(2000), 1, 1] = 1 # reset +arr_variable[TimestepValue(2000), 1, 1] = 1 # reset + +@test_throws ErrorException arr_fixed[TimestepValue(2000)] +@test_throws ErrorException arr_variable[TimestepValue(2000)] + # other methods x_years = Tuple(2000:5:2015) #fixed y_years = Tuple([2000:5:2005; 2015:10:2025]) #variable From e5752deb15bf193afa2fdded86e379329df22020 Mon Sep 17 00:00:00 2001 From: lrennels Date: Tue, 29 Oct 2019 01:13:51 -0700 Subject: [PATCH 14/31] Add getindex and setindex for indexing with arrays of timesteps --- src/core/time_arrays.jl | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index 3cac0a197..7bb3b9ed8 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -98,6 +98,16 @@ function _get_time_value_position(times::Union{Tuple, Array}, ts::TimestepValue{ return t_offset end +# Helper function to get the array of indices from an Array{TimestepIndex,1} +function _get_ts_indices(ts_array::Array{TimestepIndex, 1}) + len = length(ts_array) + ts_idxs = Array{Int,1}(undef, len) + for i = 1:len + ts_idxs[i] = ts_array[i].index + end + return ts_idxs +end + # # b. TimestepVector # @@ -526,6 +536,31 @@ function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, v setindex!(arr.data, val, idxs1..., t, idxs2...) end +# handling arrays of TimestepIndex +function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, idxs::Union{Array{TimestepIndex,1}, AnyIndex}...) where {T, N, ti, FIRST, STEP} + idxs1, ts_array, idxs2 = split_indices(idxs, ti) + ts_idxs = _get_ts_indices(ts_array) + return arr.data[idxs1..., ts_idxs, idxs2...] +end + +function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idxs::Union{Array{TimestepIndex,1}, AnyIndex}...) where {T, N, ti, TIMES} + idxs1, ts_array, idxs2 = split_indices(idxs, ti) + ts_idxs = _get_ts_indices(ts_array) + return arr.data[idxs1..., ts_idxs, idxs2...] +end + +function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, vals, idxs::Union{Array{TimestepIndex,1}, AnyIndex}...) where {T, N, ti, FIRST, STEP} + idxs1, ts_array, idxs2 = split_indices(idxs, ti) + ts_idxs = _get_ts_indices(ts_array) + setindex!(arr.data, vals, idxs1..., ts_idxs, idxs2...) +end + +function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, vals, idxs::Union{Array{TimestepIndex,1}, AnyIndex}...) where {T, N, ti, TIMES} + idxs1, ts_array, idxs2 = split_indices(idxs, ti) + ts_idxs = _get_ts_indices(ts_array) + setindex!(arr.data, vals, idxs1..., ts_idxs, idxs2...) +end + # int indexing version supports old-style components and internal functions, not # part of the public API; first index is Int or Range, rather than a Timestep From b8e57c3b128c382afa6e140da06e711035d09b5b Mon Sep 17 00:00:00 2001 From: lrennels Date: Tue, 29 Oct 2019 02:01:32 -0700 Subject: [PATCH 15/31] Add Colon support --- src/core/time_arrays.jl | 54 +++++++++++++++++++++++++++++++++++++ test/test_timesteparrays.jl | 13 ++++++--- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index 7bb3b9ed8..2cfdf91d3 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -187,6 +187,24 @@ function Base.setindex!(v::TimestepVector, val, ts::TimestepIndex) setindex!(v.data, val, ts.index) end +# Colon support + +function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP}, T}, i::Colon) where {T, FIRST, STEP} + return v.data[i] +end + +function Base.getindex(v::TimestepVector{VariableTimestep{TIMES}, T}, i::Colon) where {T, TIMES} + return v.data[i] +end + +function Base.setindex!(v::TimestepVector{FixedTimestep{Start, STEP}, T}, val, i::Colon) where {T, Start, STEP} + setindex!(v.data, val, i) +end + +function Base.setindex!(v::TimestepVector{VariableTimestep{TIMES}, T}, val, i::Colon) where {T, TIMES} + setindex!(v.data, val, i) +end + # int indexing version supports old-style components and internal functions, not # part of the public API @@ -371,6 +389,24 @@ function Base.setindex!(mat::TimestepMatrix, val, ts::TimestepIndex, idx::AnyInd setindex!(mat.data, val, ts.index, idx) end +# Colon support + +function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, idx1::Colon, idx2::Colon) where {T, FIRST, STEP, ti} + return mat.data[idx1, idx2] +end + +function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, idx1::Colon, idx2::Colon) where {T, TIMES, ti} + return mat.data[idx1, idx2] +end + +function Base.setindex!(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, val, idx1::Colon, idx2::Colon) where {T, FIRST, STEP, ti} + mat.data[idx1, idx2] .= val +end + +function Base.setindex!(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, val, idx1::Colon, idx2::Colon) where {T, TIMES, ti} + mat.data[idx1, idx2] .= val +end + # int indexing version supports old-style components and internal functions, not # part of the public API @@ -561,6 +597,24 @@ function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, v setindex!(arr.data, vals, idxs1..., ts_idxs, idxs2...) end +# Colon support + +function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, idx1::Colon, idx2::Colon, idxs::Colon...) where {T, N, ti, FIRST, STEP} + return arr.data[idx1, idx2, idxs...] +end + +function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idx1::Colon, idx2::Colon, idxs::Colon...) where {T, N, ti, TIMES} + return arr.data[idx1, idx2, idxs...] +end + +function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, val, idx1::Colon, idx2::Colon, idxs::Colon...) where {T, N, ti, FIRST, STEP} + setindex!(arr.data, val, idx1, idx2, idxs...) +end + +function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, val, idx1::Colon, idx2::Colon, idxs::Colon...) where {T, N, ti, TIMES} + setindex!(arr.data, val, idx1, idx2, idxs...) +end + # int indexing version supports old-style components and internal functions, not # part of the public API; first index is Int or Range, rather than a Timestep diff --git a/test/test_timesteparrays.jl b/test/test_timesteparrays.jl index 7707924b3..9655f3162 100644 --- a/test/test_timesteparrays.jl +++ b/test/test_timesteparrays.jl @@ -199,8 +199,11 @@ t3 = FixedTimestep{2000, 1, 2005}(1) y[t3, 1] = 10 @test y[t3,1] == 10 -# Deprecated Int Indexing -@test_logs (:warn, setindex_warn_msg) y[:,:] = 11 +# Colon indexing +y[:,:] = 11 +@test y[:,:] == fill(11,4,2) + +# Deprecated Int Indexing for i = 1:4 @test_logs (:warn, getindex_warn_msg) y[i,1] == 11 end @@ -208,7 +211,6 @@ for j = 1:2 @test_logs (:warn, getindex_warn_msg) y[1,j] == 11 end - #3c. interval wider than 1 z = TimestepMatrix{FixedTimestep{2000, 2}, Int, 1}(a[:,3:4]) t = FixedTimestep{1980, 2, 3000}(11) @@ -279,8 +281,11 @@ t3 = VariableTimestep{years}() y[t3, 1] = 10 @test y[t3,1] == 10 +# Colon indexing +y[:,:] = 11 +@test y[:,:] == fill(11,4,2) + # Deprecated Int Indexing -@test_logs (:warn, setindex_warn_msg) y[:,:] = 11 for i = 1:4 @test_logs (:warn, getindex_warn_msg) y[i,1] == 11 end From fd7b2caf3ef0c6c160435a5dfa6956112848c6de Mon Sep 17 00:00:00 2001 From: lrennels Date: Tue, 29 Oct 2019 13:34:44 -0700 Subject: [PATCH 16/31] Add some Colon support for TimestepIndex; clean up --- src/core/time.jl | 19 +++++++++++++++++++ src/core/time_arrays.jl | 10 +++------- test/test_timesteps.jl | 13 ++++++++++++- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/core/time.jl b/src/core/time.jl index db723a0ff..9b3287a77 100644 --- a/src/core/time.jl +++ b/src/core/time.jl @@ -114,6 +114,10 @@ function Base.:-(ts::TimestepIndex, val::Int) return TimestepIndex(ts.index - val) end +function Base.:-(ts::TimestepIndex, val::TimestepIndex) + return TimestepIndex(ts.index - val.index) +end + function Base.:+(ts::FixedTimestep{FIRST, STEP, LAST}, val::Int) where {FIRST, STEP, LAST} if finished(ts) error("Cannot get next timestep, this is last timestep.") @@ -141,6 +145,21 @@ function Base.:+(ts::TimestepIndex, val::Int) return TimestepIndex(ts.index + val) end +# Colon support +function Base.:(:)(start::T, step::T, stop::T) where {T<:TimestepIndex} + indices = [start.index:step.index:stop.index...] + return TimestepIndex.(indices) +end + +function Base.:(:)(start::T, step::Int, stop::T) where {T<:TimestepIndex} + indices = [start.index:step:stop.index...] + return TimestepIndex.(indices) +end + +function Base.:(:)(start::T, stop::T) where {T<:TimestepIndex} + return Base.:(:)(start, 1, stop) +end + # # CLOCK # diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index 2cfdf91d3..0e11595ec 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -100,12 +100,7 @@ end # Helper function to get the array of indices from an Array{TimestepIndex,1} function _get_ts_indices(ts_array::Array{TimestepIndex, 1}) - len = length(ts_array) - ts_idxs = Array{Int,1}(undef, len) - for i = 1:len - ts_idxs[i] = ts_array[i].index - end - return ts_idxs + return [ts.index for ts in ts_array] end # @@ -572,7 +567,8 @@ function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, v setindex!(arr.data, val, idxs1..., t, idxs2...) end -# handling arrays of TimestepIndex +# Indexing with arrays of TimestepIndexes or TimestepValues + function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, idxs::Union{Array{TimestepIndex,1}, AnyIndex}...) where {T, N, ti, FIRST, STEP} idxs1, ts_array, idxs2 = split_indices(idxs, ti) ts_idxs = _get_ts_indices(ts_array) diff --git a/test/test_timesteps.jl b/test/test_timesteps.jl index 81cc8bd25..f5032cb6a 100644 --- a/test/test_timesteps.jl +++ b/test/test_timesteps.jl @@ -73,7 +73,18 @@ t4 = next_timestep(t3) @test_throws ErrorException t_next = t4 + 1 @test_throws ErrorException next_timestep(t4) - +#------------------------------------------------------------------------------ +# Test some basic functions for TimestepIndex and TimestepValue +#------------------------------------------------------------------------------ +start = 1 +stop = 10 +step = 2 + +@test TimestepIndex(start):TimestepIndex(stop) == TimestepIndex.([start:stop...]) +@test TimestepIndex(start):TimestepIndex(stop) == TimestepIndex(start):1:TimestepIndex(stop) +@test TimestepIndex(start):TimestepIndex(stop) == TimestepIndex(start):TimestepIndex(1):TimestepIndex(stop) +@test TimestepIndex(start):step:TimestepIndex(stop) == TimestepIndex.([start:step:stop...]) +@test TimestepIndex(start):TimestepIndex(step):TimestepIndex(stop) == TimestepIndex.([start:step:stop...]) #------------------------------------------------------------------------------ # Test a model with components with different offsets #------------------------------------------------------------------------------ From 174a68a28f617d4be070df5bca154e5c33b960d4 Mon Sep 17 00:00:00 2001 From: lrennels Date: Tue, 29 Oct 2019 14:37:09 -0700 Subject: [PATCH 17/31] Improve warning message with stacktrace; mute logging for dependency tests --- src/core/time_arrays.jl | 12 ++++++++++-- test/dependencies/run_dependency_tests.jl | 6 ++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index 0e11595ec..78ceb1632 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -55,14 +55,22 @@ function _single_index_check(data, idxs) end end -# Helper function for getindex; throws an error if one indexes into a TimestepArray with an integer +# Helper functions for getindex and setindex; throws an error if one indexes into a TimestepArray with an integer function _throw_int_getindex_warning() @warn("Indexing with getindex into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndex(2)]") + _print_stacktrace() end -# Helper function for setindex; throws an error if one indexes into a TimestepArray with an integer function _throw_int_setindex_warning() @warn("Indexing with setindex into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndec(2)]") + _print_stacktrace() +end + +function _print_stacktrace() + println("Stacktrace for warning as follows:") + for line in stacktrace() + println(" $line") + end end # Helper macro used by connector diff --git a/test/dependencies/run_dependency_tests.jl b/test/dependencies/run_dependency_tests.jl index 79c6e2877..315144ede 100644 --- a/test/dependencies/run_dependency_tests.jl +++ b/test/dependencies/run_dependency_tests.jl @@ -5,13 +5,15 @@ packages_to_test = [ ("https://github.com/fund-model/MimiFUND.jl.git", "v3.11.8", "MimiFUND") ] +null = Base.CoreLogging.NullLogger() # need to supress warnings to prevent Travis log overflow from int indexing for (pkg_url, pkg_rev, pkg_name) in packages_to_test mktempdir() do folder Pkg.activate(folder) Pkg.develop(PackageSpec(path=joinpath(@__DIR__, "..", ".."))) - - Pkg.add(PackageSpec(url=pkg_url, rev=pkg_rev)) + Base.CoreLogging.with_logger(null) do + Pkg.add(PackageSpec(url=pkg_url, rev=pkg_rev)) + end Pkg.test(pkg_name) end From 7d56cd677adcc5057c69d938d467006faf1e6bcb Mon Sep 17 00:00:00 2001 From: lrennels Date: Tue, 29 Oct 2019 14:51:45 -0700 Subject: [PATCH 18/31] Remove tests for timestep array int indexing --- test/test_timesteparrays.jl | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/test/test_timesteparrays.jl b/test/test_timesteparrays.jl index 9655f3162..11a4f5dbd 100644 --- a/test/test_timesteparrays.jl +++ b/test/test_timesteparrays.jl @@ -8,8 +8,6 @@ import Mimi: isuniform, first_period, last_period, first_and_step # general variables -getindex_warn_msg = "Indexing with getindex into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndex(2)]" -setindex_warn_msg = "Indexing with setindex into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndec(2)]" a = collect(reshape(1:16,4,4)) ## quick check of isuniform @@ -77,10 +75,6 @@ t3 = FixedTimestep{2000, 1, 2003}(1) x[t3] = 100 @test x[t3] == 100 -# Deprecated setindex and getindex method -@test_logs (:warn, setindex_warn_msg) (x[1] = 101) -@test_logs (:warn, getindex_warn_msg) x[1] == 101 - #------------------------------------------------------------------------------ # 2. Test TimestepVector - Variable Timestep #------------------------------------------------------------------------------ @@ -135,10 +129,6 @@ t3 = VariableTimestep{years}() x[t3] = 100 @test x[t3] == 100 -# Deprecated Int Indexing -@test_logs (:warn, setindex_warn_msg) (x[1] = 101) -@test_logs (:warn, getindex_warn_msg) x[1] == 101 - #------------------------------------------------------------------------------ # 3. Test TimestepMatrix - Fixed Timestep #------------------------------------------------------------------------------ @@ -203,14 +193,6 @@ y[t3, 1] = 10 y[:,:] = 11 @test y[:,:] == fill(11,4,2) -# Deprecated Int Indexing -for i = 1:4 - @test_logs (:warn, getindex_warn_msg) y[i,1] == 11 -end -for j = 1:2 - @test_logs (:warn, getindex_warn_msg) y[1,j] == 11 -end - #3c. interval wider than 1 z = TimestepMatrix{FixedTimestep{2000, 2}, Int, 1}(a[:,3:4]) t = FixedTimestep{1980, 2, 3000}(11) @@ -285,14 +267,6 @@ y[t3, 1] = 10 y[:,:] = 11 @test y[:,:] == fill(11,4,2) -# Deprecated Int Indexing -for i = 1:4 - @test_logs (:warn, getindex_warn_msg) y[i,1] == 11 -end -for j = 1:2 - @test_logs (:warn, getindex_warn_msg) y[1,j] == 11 -end - #------------------------------------------------------------------------------ # 5. Test TimestepArray methods #------------------------------------------------------------------------------ From 5afe427799a0bbadfc29c92df8b0dfcac8b401b8 Mon Sep 17 00:00:00 2001 From: lrennels Date: Tue, 29 Oct 2019 15:26:05 -0700 Subject: [PATCH 19/31] Fix logging bug in dependency tests --- test/dependencies/run_dependency_tests.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/dependencies/run_dependency_tests.jl b/test/dependencies/run_dependency_tests.jl index 315144ede..914a1394f 100644 --- a/test/dependencies/run_dependency_tests.jl +++ b/test/dependencies/run_dependency_tests.jl @@ -11,10 +11,9 @@ for (pkg_url, pkg_rev, pkg_name) in packages_to_test Pkg.activate(folder) Pkg.develop(PackageSpec(path=joinpath(@__DIR__, "..", ".."))) + Pkg.add(PackageSpec(url=pkg_url, rev=pkg_rev)) Base.CoreLogging.with_logger(null) do - Pkg.add(PackageSpec(url=pkg_url, rev=pkg_rev)) + Pkg.test(pkg_name) end - - Pkg.test(pkg_name) end end From aaf9cb8c18c2f7c4cdd5d4f1ceb972365917e341 Mon Sep 17 00:00:00 2001 From: lrennels Date: Tue, 29 Oct 2019 15:54:56 -0700 Subject: [PATCH 20/31] Add docs --- docs/src/userguide.md | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/docs/src/userguide.md b/docs/src/userguide.md index c21b81d32..fff960bae 100644 --- a/docs/src/userguide.md +++ b/docs/src/userguide.md @@ -149,7 +149,7 @@ In order to invoke the explorer UI and explore all of the variables and paramete ```julia run(mymodel) - explore(mymodel, title = "run1 results") +explore(mymodel, title = "run1 results") ``` ![Explorer Model Example](figs/explorer_model_example.png) @@ -194,6 +194,44 @@ The API details for AbstractTimestep object `t` are as follows: - useful functions for commonly used conditionals are `is_first(t)`,`is_last(t)`, `is_time(t, s)`, and `is_timestep(t, y)` as listed above - to access the index value of `t` as a `Number` representing the position in the time array, use `t.t`. Users are encouraged to avoid this access, and instead use the options listed above or a separate counter variable. each time the function gets called. +Indexing into a variable or parameter's `time` dimension with an `Integer` is deprecated and will soon error. Instead, users should take advantage of the `TimestepIndex` and `TimestepValue` types. For examples we will refer back to our component definition above, and repeated below. +```julia +@defcomp MyComponentName begin + regions = Index() + + A = Variable(index = [time]) + B = Variable(index = [time, regions]) + + c = Parameter() + d = Parameter(index = [time]) + e = Parameter(index = [time, regions]) + f = Parameter(index = [regions]) + + function run_timestep(p, v, d, t) + v.A[t] = p.c + p.d[t] + for r in d.regions + v.B[t, r] = p.f[r] * p.e[t, r] + end + end + +end +``` +`TimestepIndex` has one field, `index`, which refers to the absolute index in the parameter or variable array's `time` dimension. Thus, constructing a `TimestepIndex` is done by simply writing `TimestepIndex(index::Int)`. Looking back at our original component example +one could modify the first line of `run_timestep` to always refer to the second first timestep of `p.d` with the following. +```julia +v.A[t] = p.c + p.d[TimestepIndex(1)] +``` +`TimestepValue` has two fields, `value` and `offset`, referring to the value within the `time` dimension and an optional `offset` from that `value`. Thus, constructing a `TimestepValue` is done either by writing `TimestepValue(value)`, with an implied offset of 0, or `TimestepValue(value, offset = i::Int)`, with an explicit offset of i. This may be especially helpful when working with components that do not have matching `time` dimensions. For example, you can use a `TimestepValue` to keep track of a baseline year across different components. +```julia +v.A[t] = p.c + p.d[TimestepValue(2000)] +``` +Both `TimestepIndex` and `TimestepArray` have methods to support addition and subtraction of integers. Note that the addition or subtraction is relative to the definition of the `time` dimension, so while `TimestepIndex(1) + 1 == TimestepIndex(2)`, `TimestepValue(2000) + 1` could be equivalent to `TimestepValue(2001)` **if** 2001 is the next year in the time dimension, or `TimestepValue(2005)` if the array has a step size of 5. Hence additing or subtracting is relative to the definition of the `time` dimension. You may also use shorthand to create arrays of `TimestepIndex` using Colon syntax to return an array of `TimestepIndex`s. +```julia +TimestepIndex(1):TimestepIndex(10) # implicit step size of 1 +TimestepIndex(1):2:TimestepIndex(10) # step of type Int +TimestepIndex(1):TimestepIndex(2):TimestepIndex(10) # step of type TimestepIndex +``` + ### Parameter connections between different length components As mentioned earlier, it is possible for some components to start later or end sooner than the full length of the model. This presents potential complications for connecting their parameters. If you are setting the parameters to external values, then the provided values just need to be the right size for that component's parameter. If you are making an internal connection, this can happen in one of two ways: From f997e93c2cb451a59168f8774faee17d8c2bf049 Mon Sep 17 00:00:00 2001 From: lrennels Date: Tue, 29 Oct 2019 17:20:45 -0700 Subject: [PATCH 21/31] Use depwarn to reduce logging output --- src/core/time_arrays.jl | 47 ++++++++++------------- test/dependencies/run_dependency_tests.jl | 6 +-- 2 files changed, 21 insertions(+), 32 deletions(-) diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index 78ceb1632..6b3d71d02 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -56,21 +56,14 @@ function _single_index_check(data, idxs) end # Helper functions for getindex and setindex; throws an error if one indexes into a TimestepArray with an integer -function _throw_int_getindex_warning() - @warn("Indexing with getindex into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndex(2)]") - _print_stacktrace() +function _throw_int_getindex_depwarning() + msg = "Indexing with getindex into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndex(2)]" + Base.depwarn("$msg, $(stacktrace())", :getindex) end -function _throw_int_setindex_warning() - @warn("Indexing with setindex into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndec(2)]") - _print_stacktrace() -end - -function _print_stacktrace() - println("Stacktrace for warning as follows:") - for line in stacktrace() - println(" $line") - end +function _throw_int_setindex_depwarning() + msg = "Indexing with setindex into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndec(2)]" + Base.depwarn("$msg, $(stacktrace())", :setindex) end # Helper macro used by connector @@ -212,22 +205,22 @@ end # part of the public API function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP}, T}, i::AnyIndex) where {T, FIRST, STEP} - _throw_int_getindex_warning() + _throw_int_getindex_depwarning() return v.data[i] end function Base.getindex(v::TimestepVector{VariableTimestep{TIMES}, T}, i::AnyIndex) where {T, TIMES} - _throw_int_getindex_warning() + _throw_int_getindex_depwarning() return v.data[i] end function Base.setindex!(v::TimestepVector{FixedTimestep{Start, STEP}, T}, val, i::AnyIndex) where {T, Start, STEP} - _throw_int_setindex_warning() + _throw_int_setindex_depwarning() setindex!(v.data, val, i) end function Base.setindex!(v::TimestepVector{VariableTimestep{TIMES}, T}, val, i::AnyIndex) where {T, TIMES} - _throw_int_setindex_warning() + _throw_int_setindex_depwarning() setindex!(v.data, val, i) end @@ -414,32 +407,32 @@ end # part of the public API function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, idx1::AnyIndex, idx2::AnyIndex) where {T, FIRST, STEP, ti} - _throw_int_getindex_warning() + _throw_int_getindex_depwarning() return mat.data[idx1, idx2] end function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, idx1::AnyIndex, idx2::AnyIndex) where {T, TIMES, ti} - _throw_int_getindex_warning() + _throw_int_getindex_depwarning() return mat.data[idx1, idx2] end function Base.setindex!(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, val, idx1::Int, idx2::Int) where {T, FIRST, STEP, ti} - _throw_int_setindex_warning() + _throw_int_setindex_depwarning() setindex!(mat.data, val, idx1, idx2) end function Base.setindex!(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, val, idx1::AnyIndex, idx2::AnyIndex) where {T, FIRST, STEP, ti} - _throw_int_setindex_warning() + _throw_int_setindex_depwarning() mat.data[idx1, idx2] .= val end function Base.setindex!(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, val, idx1::Int, idx2::Int) where {T, TIMES, ti} - _throw_int_setindex_warning() + _throw_int_setindex_depwarning() setindex!(mat.data, val, idx1, idx2) end function Base.setindex!(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, val, idx1::AnyIndex, idx2::AnyIndex) where {T, TIMES, ti} - _throw_int_setindex_warning() + _throw_int_setindex_depwarning() mat.data[idx1, idx2] .= val end @@ -623,22 +616,22 @@ end # part of the public API; first index is Int or Range, rather than a Timestep function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, idx1::AnyIndex, idx2::AnyIndex, idxs::AnyIndex...) where {T, N, ti, FIRST, STEP} - _throw_int_getindex_warning() + _throw_int_getindex_depwarning() return arr.data[idx1, idx2, idxs...] end function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idx1::AnyIndex, idx2::AnyIndex, idxs::AnyIndex...) where {T, N, ti, TIMES} - _throw_int_getindex_warning() + _throw_int_getindex_depwarning() return arr.data[idx1, idx2, idxs...] end function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, val, idx1::AnyIndex, idx2::AnyIndex, idxs::AnyIndex...) where {T, N, ti, FIRST, STEP} - _throw_int_setindex_warning() + _throw_int_setindex_depwarning() setindex!(arr.data, val, idx1, idx2, idxs...) end function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, val, idx1::AnyIndex, idx2::AnyIndex, idxs::AnyIndex...) where {T, N, ti, TIMES} - _throw_int_setindex_warning() + _throw_int_setindex_depwarning() setindex!(arr.data, val, idx1, idx2, idxs...) end diff --git a/test/dependencies/run_dependency_tests.jl b/test/dependencies/run_dependency_tests.jl index 914a1394f..a114b1d8b 100644 --- a/test/dependencies/run_dependency_tests.jl +++ b/test/dependencies/run_dependency_tests.jl @@ -5,15 +5,11 @@ packages_to_test = [ ("https://github.com/fund-model/MimiFUND.jl.git", "v3.11.8", "MimiFUND") ] -null = Base.CoreLogging.NullLogger() # need to supress warnings to prevent Travis log overflow from int indexing for (pkg_url, pkg_rev, pkg_name) in packages_to_test mktempdir() do folder Pkg.activate(folder) - Pkg.develop(PackageSpec(path=joinpath(@__DIR__, "..", ".."))) Pkg.add(PackageSpec(url=pkg_url, rev=pkg_rev)) - Base.CoreLogging.with_logger(null) do - Pkg.test(pkg_name) - end + Pkg.test(pkg_name) end end From 1e387d1023e24bbcdff4c11ce31897e12006b9c8 Mon Sep 17 00:00:00 2001 From: lrennels Date: Tue, 29 Oct 2019 17:45:33 -0700 Subject: [PATCH 22/31] Change colon indexing methods --- docs/src/userguide.md | 5 ++--- test/test_timesteps.jl | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/src/userguide.md b/docs/src/userguide.md index fff960bae..0713ecbef 100644 --- a/docs/src/userguide.md +++ b/docs/src/userguide.md @@ -225,11 +225,10 @@ v.A[t] = p.c + p.d[TimestepIndex(1)] ```julia v.A[t] = p.c + p.d[TimestepValue(2000)] ``` -Both `TimestepIndex` and `TimestepArray` have methods to support addition and subtraction of integers. Note that the addition or subtraction is relative to the definition of the `time` dimension, so while `TimestepIndex(1) + 1 == TimestepIndex(2)`, `TimestepValue(2000) + 1` could be equivalent to `TimestepValue(2001)` **if** 2001 is the next year in the time dimension, or `TimestepValue(2005)` if the array has a step size of 5. Hence additing or subtracting is relative to the definition of the `time` dimension. You may also use shorthand to create arrays of `TimestepIndex` using Colon syntax to return an array of `TimestepIndex`s. +Both `TimestepIndex` and `TimestepArray` have methods to support addition and subtraction of integers. Note that the addition or subtraction is relative to the definition of the `time` dimension, so while `TimestepIndex(1) + 1 == TimestepIndex(2)`, `TimestepValue(2000) + 1` could be equivalent to `TimestepValue(2001)` **if** 2001 is the next year in the time dimension, or `TimestepValue(2005)` if the array has a step size of 5. Hence additing or subtracting is relative to the definition of the `time` dimension. You may also use shorthand to create arrays of `TimestepIndex` or `TimestepArray` using Colon syntax. ```julia TimestepIndex(1):TimestepIndex(10) # implicit step size of 1 -TimestepIndex(1):2:TimestepIndex(10) # step of type Int -TimestepIndex(1):TimestepIndex(2):TimestepIndex(10) # step of type TimestepIndex +TimestepIndex(1):2:TimestepIndex(10) # explicit step of type Int ``` ### Parameter connections between different length components diff --git a/test/test_timesteps.jl b/test/test_timesteps.jl index f5032cb6a..fe5a762ad 100644 --- a/test/test_timesteps.jl +++ b/test/test_timesteps.jl @@ -82,9 +82,7 @@ step = 2 @test TimestepIndex(start):TimestepIndex(stop) == TimestepIndex.([start:stop...]) @test TimestepIndex(start):TimestepIndex(stop) == TimestepIndex(start):1:TimestepIndex(stop) -@test TimestepIndex(start):TimestepIndex(stop) == TimestepIndex(start):TimestepIndex(1):TimestepIndex(stop) @test TimestepIndex(start):step:TimestepIndex(stop) == TimestepIndex.([start:step:stop...]) -@test TimestepIndex(start):TimestepIndex(step):TimestepIndex(stop) == TimestepIndex.([start:step:stop...]) #------------------------------------------------------------------------------ # Test a model with components with different offsets #------------------------------------------------------------------------------ From bb11eceeb1e55b8eb55a6b21cf0560b5ed16c873 Mon Sep 17 00:00:00 2001 From: lrennels Date: Tue, 29 Oct 2019 19:03:15 -0700 Subject: [PATCH 23/31] Add TimestepValue array indexing and tests --- docs/src/userguide.md | 9 ++++++--- src/core/time_arrays.jl | 35 +++++++++++++++++++++++++++++++++++ test/test_timesteparrays.jl | 14 ++++++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/docs/src/userguide.md b/docs/src/userguide.md index 0713ecbef..8c8165b19 100644 --- a/docs/src/userguide.md +++ b/docs/src/userguide.md @@ -217,19 +217,22 @@ Indexing into a variable or parameter's `time` dimension with an `Integer` is de end ``` `TimestepIndex` has one field, `index`, which refers to the absolute index in the parameter or variable array's `time` dimension. Thus, constructing a `TimestepIndex` is done by simply writing `TimestepIndex(index::Int)`. Looking back at our original component example -one could modify the first line of `run_timestep` to always refer to the second first timestep of `p.d` with the following. +one could modify the first line of `run_timestep` to always refer to the second first timestep of `p.d` with the following. One may index into the `time` dimension with a single `TimestepIndex`, or an `Array` of them. ```julia v.A[t] = p.c + p.d[TimestepIndex(1)] ``` -`TimestepValue` has two fields, `value` and `offset`, referring to the value within the `time` dimension and an optional `offset` from that `value`. Thus, constructing a `TimestepValue` is done either by writing `TimestepValue(value)`, with an implied offset of 0, or `TimestepValue(value, offset = i::Int)`, with an explicit offset of i. This may be especially helpful when working with components that do not have matching `time` dimensions. For example, you can use a `TimestepValue` to keep track of a baseline year across different components. +`TimestepValue` has two fields, `value` and `offset`, referring to the value within the `time` dimension and an optional `offset` from that `value`. Thus, constructing a `TimestepValue` is done either by writing `TimestepValue(value)`, with an implied offset of 0, or `TimestepValue(value, offset = i::Int)`, with an explicit offset of i. One may index into the `time` dimension with a single `TimestepValue`, or an `Array` of them. This may be especially helpful when working with components that do not have matching `time` dimensions. For example, you can use a `TimestepValue` to keep track of a baseline year across different components. ```julia v.A[t] = p.c + p.d[TimestepValue(2000)] ``` -Both `TimestepIndex` and `TimestepArray` have methods to support addition and subtraction of integers. Note that the addition or subtraction is relative to the definition of the `time` dimension, so while `TimestepIndex(1) + 1 == TimestepIndex(2)`, `TimestepValue(2000) + 1` could be equivalent to `TimestepValue(2001)` **if** 2001 is the next year in the time dimension, or `TimestepValue(2005)` if the array has a step size of 5. Hence additing or subtracting is relative to the definition of the `time` dimension. You may also use shorthand to create arrays of `TimestepIndex` or `TimestepArray` using Colon syntax. +You may also use shorthand to create arrays of `TimestepIndex` using Colon syntax. ```julia TimestepIndex(1):TimestepIndex(10) # implicit step size of 1 TimestepIndex(1):2:TimestepIndex(10) # explicit step of type Int ``` +Both `TimestepIndex` and `TimestepArray` have methods to support addition and subtraction of integers. Note that the addition or subtraction is relative to the definition of the `time` dimension, so while `TimestepIndex(1) + 1 == TimestepIndex(2)`, `TimestepValue(2000) + 1` could be equivalent to `TimestepValue(2001)` **if** 2001 is the next year in the time dimension, or `TimestepValue(2005)` if the array has a step size of 5. Hence additing or subtracting is relative to the definition of the `time` dimension. + + ### Parameter connections between different length components diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index 6b3d71d02..d572b4494 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -104,6 +104,15 @@ function _get_ts_indices(ts_array::Array{TimestepIndex, 1}) return [ts.index for ts in ts_array] end +function _get_ts_indices(ts_array::Array{TimestepValue{T}, 1}, times::Union{Tuple, Array}) where T + len = length(ts_array) + ts_idxs = Array{Int,1}(undef, len) + for i = 1:len + ts_idxs[i] = _get_time_value_position(times, ts_array[i]) + end + return ts_idxs +end + # # b. TimestepVector # @@ -582,6 +591,19 @@ function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, id return arr.data[idxs1..., ts_idxs, idxs2...] end +function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T_time, N, ti}, idxs::Union{Array{TimestepValue{T_data},1}, AnyIndex}...) where {T_time, N, ti, FIRST, STEP, T_data} + idxs1, ts_array, idxs2 = split_indices(idxs, ti) + LAST = FIRST + ((length(arr.data)-1) * STEP) + ts_idxs = _get_ts_indices(ts_array, [FIRST:STEP:LAST...]) + return arr.data[idxs1..., ts_idxs, idxs2...] +end + +function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T_data, N, ti}, idxs::Union{Array{TimestepValue{T_times},1}, AnyIndex}...) where {T_data, N, ti, TIMES, T_times} + idxs1, ts_array, idxs2 = split_indices(idxs, ti) + ts_idxs = _get_ts_indices(ts_array, TIMES) + return arr.data[idxs1..., ts_idxs, idxs2...] +end + function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, vals, idxs::Union{Array{TimestepIndex,1}, AnyIndex}...) where {T, N, ti, FIRST, STEP} idxs1, ts_array, idxs2 = split_indices(idxs, ti) ts_idxs = _get_ts_indices(ts_array) @@ -594,6 +616,19 @@ function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, v setindex!(arr.data, vals, idxs1..., ts_idxs, idxs2...) end +function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T_data, N, ti}, vals, idxs::Union{Array{TimestepValue{T_times},1}, AnyIndex}...) where {T_data, N, ti, FIRST, STEP, T_times} + idxs1, ts_array, idxs2 = split_indices(idxs, ti) + LAST = FIRST + ((length(arr.data)-1) * STEP) + ts_idxs = _get_ts_indices(ts_array, [FIRST:STEP:LAST...]) + setindex!(arr.data, vals, idxs1..., ts_idxs, idxs2...) +end + +function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T_data, N, ti}, vals, idxs::Union{Array{TimestepValue{T_times},1}, AnyIndex}...) where {T_data, N, ti, TIMES, T_times} + idxs1, ts_array, idxs2 = split_indices(idxs, ti) + ts_idxs = _get_ts_indices(ts_array, TIMES) + setindex!(arr.data, vals, idxs1..., ts_idxs, idxs2...) +end + # Colon support function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, idx1::Colon, idx2::Colon, idxs::Colon...) where {T, N, ti, FIRST, STEP} diff --git a/test/test_timesteparrays.jl b/test/test_timesteparrays.jl index 11a4f5dbd..13af2deb4 100644 --- a/test/test_timesteparrays.jl +++ b/test/test_timesteparrays.jl @@ -277,6 +277,8 @@ data = collect(reshape(1:64, 4, 4, 4)) arr_fixed = TimestepArray{FixedTimestep{2000, 5}, Int, 3, 1}(data) arr_variable = TimestepArray{VariableTimestep{years}, Int, 3, 1}(data) +# Indexing with TimestepIndex + @test arr_fixed[TimestepIndex(1), 1, 1] == 1 @test arr_fixed[TimestepIndex(3), 3, 3] == 43 @test arr_variable[TimestepIndex(1), 1, 1] == 1 @@ -292,6 +294,13 @@ arr_variable[TimestepIndex(1), 1, 1] = 1 # reset @test_throws ErrorException arr_fixed[TimestepIndex(1)] @test_throws ErrorException arr_variable[TimestepIndex(1)] +# Indexing with Array{TimestepIndex, N} (TODO_LFR) + +@test arr_fixed[TimestepIndex.([1,3]), 1, 1] == [1, 3] +@test arr_variable[TimestepIndex.([2,4]), 1, 1] == [2,4] + +# Indexing with TimestepValue + @test arr_fixed[TimestepValue(2000), 1, 1] == 1 @test arr_fixed[TimestepValue(2010), 3, 3] == 43 @test arr_variable[TimestepValue(2000), 1, 1] == 1 @@ -307,6 +316,11 @@ arr_variable[TimestepValue(2000), 1, 1] = 1 # reset @test_throws ErrorException arr_fixed[TimestepValue(2000)] @test_throws ErrorException arr_variable[TimestepValue(2000)] +# Indexing with Array{TimestepValue, N} (TODO_LFR) + +@test arr_fixed[TimestepValue.([2000, 2010]), 1, 1] == [1, 3] +@test arr_variable[TimestepValue.([2000, 2005, 2025]), 1, 1] == [1, 2,4] + # other methods x_years = Tuple(2000:5:2015) #fixed y_years = Tuple([2000:5:2005; 2015:10:2025]) #variable From 69d8e76f9c62db17923626754d0e3f0c12133289 Mon Sep 17 00:00:00 2001 From: lrennels Date: Wed, 30 Oct 2019 11:26:05 -0700 Subject: [PATCH 24/31] Fix typos; simplify functions --- docs/src/userguide.md | 6 +++--- src/core/time.jl | 5 ----- src/core/time_arrays.jl | 40 +++++++--------------------------------- 3 files changed, 10 insertions(+), 41 deletions(-) diff --git a/docs/src/userguide.md b/docs/src/userguide.md index 8c8165b19..ac6a73cb8 100644 --- a/docs/src/userguide.md +++ b/docs/src/userguide.md @@ -217,11 +217,11 @@ Indexing into a variable or parameter's `time` dimension with an `Integer` is de end ``` `TimestepIndex` has one field, `index`, which refers to the absolute index in the parameter or variable array's `time` dimension. Thus, constructing a `TimestepIndex` is done by simply writing `TimestepIndex(index::Int)`. Looking back at our original component example -one could modify the first line of `run_timestep` to always refer to the second first timestep of `p.d` with the following. One may index into the `time` dimension with a single `TimestepIndex`, or an `Array` of them. +one could modify the first line of `run_timestep` to always refer to the first timestep of `p.d` with the following. One may index into the `time` dimension with a single `TimestepIndex`, or an `Array` of them. ```julia v.A[t] = p.c + p.d[TimestepIndex(1)] ``` -`TimestepValue` has two fields, `value` and `offset`, referring to the value within the `time` dimension and an optional `offset` from that `value`. Thus, constructing a `TimestepValue` is done either by writing `TimestepValue(value)`, with an implied offset of 0, or `TimestepValue(value, offset = i::Int)`, with an explicit offset of i. One may index into the `time` dimension with a single `TimestepValue`, or an `Array` of them. This may be especially helpful when working with components that do not have matching `time` dimensions. For example, you can use a `TimestepValue` to keep track of a baseline year across different components. +`TimestepValue` has two fields, `value` and `offset`, referring to the value within the `time` dimension and an optional `offset` from that `value`. Thus, constructing a `TimestepValue` is done either by writing `TimestepValue(value)`, with an implied offset of 0, or `TimestepValue(value, offset = i::Int)`, with an explicit offset of i. One may index into the `time` dimension with a single `TimestepValue`, or an `Array` of them. For example, you can use a `TimestepValue` to keep track of a baseline year. ```julia v.A[t] = p.c + p.d[TimestepValue(2000)] ``` @@ -230,7 +230,7 @@ You may also use shorthand to create arrays of `TimestepIndex` using Colon synta TimestepIndex(1):TimestepIndex(10) # implicit step size of 1 TimestepIndex(1):2:TimestepIndex(10) # explicit step of type Int ``` -Both `TimestepIndex` and `TimestepArray` have methods to support addition and subtraction of integers. Note that the addition or subtraction is relative to the definition of the `time` dimension, so while `TimestepIndex(1) + 1 == TimestepIndex(2)`, `TimestepValue(2000) + 1` could be equivalent to `TimestepValue(2001)` **if** 2001 is the next year in the time dimension, or `TimestepValue(2005)` if the array has a step size of 5. Hence additing or subtracting is relative to the definition of the `time` dimension. +Both `TimestepIndex` and `TimestepArray` have methods to support addition and subtraction of integers. Note that the addition or subtraction is relative to the definition of the `time` dimension, so while `TimestepIndex(1) + 1 == TimestepIndex(2)`, `TimestepValue(2000) + 1` could be equivalent to `TimestepValue(2001)` **if** 2001 is the next year in the time dimension, or `TimestepValue(2005)` if the array has a step size of 5. Hence adding or subtracting is relative to the definition of the `time` dimension. diff --git a/src/core/time.jl b/src/core/time.jl index 9b3287a77..3e59dc9d1 100644 --- a/src/core/time.jl +++ b/src/core/time.jl @@ -114,10 +114,6 @@ function Base.:-(ts::TimestepIndex, val::Int) return TimestepIndex(ts.index - val) end -function Base.:-(ts::TimestepIndex, val::TimestepIndex) - return TimestepIndex(ts.index - val.index) -end - function Base.:+(ts::FixedTimestep{FIRST, STEP, LAST}, val::Int) where {FIRST, STEP, LAST} if finished(ts) error("Cannot get next timestep, this is last timestep.") @@ -125,7 +121,6 @@ function Base.:+(ts::FixedTimestep{FIRST, STEP, LAST}, val::Int) where {FIRST, S error("Cannot get requested timestep, exceeds last timestep.") end new_ts = FixedTimestep{FIRST, STEP, LAST}(ts.t + val) - end function Base.:+(ts::VariableTimestep{TIMES}, val::Int) where {TIMES} diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index d572b4494..bd9f41821 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -55,12 +55,13 @@ function _single_index_check(data, idxs) end end -# Helper functions for getindex and setindex; throws an error if one indexes into a TimestepArray with an integer +# Helper functionfor getindex; throws an error if one indexes into a TimestepArray with an integer function _throw_int_getindex_depwarning() msg = "Indexing with getindex into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndex(2)]" Base.depwarn("$msg, $(stacktrace())", :getindex) end +# Helper function for setindex; throws an deprecation warning if one indexes into a TimestepArray with an integer function _throw_int_setindex_depwarning() msg = "Indexing with setindex into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndec(2)]" Base.depwarn("$msg, $(stacktrace())", :setindex) @@ -105,12 +106,7 @@ function _get_ts_indices(ts_array::Array{TimestepIndex, 1}) end function _get_ts_indices(ts_array::Array{TimestepValue{T}, 1}, times::Union{Tuple, Array}) where T - len = length(ts_array) - ts_idxs = Array{Int,1}(undef, len) - for i = 1:len - ts_idxs[i] = _get_time_value_position(times, ts_array[i]) - end - return ts_idxs + return [_get_time_value_position(times, ts) for ts in ts_array] end # @@ -579,13 +575,7 @@ end # Indexing with arrays of TimestepIndexes or TimestepValues -function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, idxs::Union{Array{TimestepIndex,1}, AnyIndex}...) where {T, N, ti, FIRST, STEP} - idxs1, ts_array, idxs2 = split_indices(idxs, ti) - ts_idxs = _get_ts_indices(ts_array) - return arr.data[idxs1..., ts_idxs, idxs2...] -end - -function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idxs::Union{Array{TimestepIndex,1}, AnyIndex}...) where {T, N, ti, TIMES} +function Base.getindex(arr::TimestepArray{TS, T, N, ti}, idxs::Union{Array{TimestepIndex,1}, AnyIndex}...) where {TS, T, N, ti} idxs1, ts_array, idxs2 = split_indices(idxs, ti) ts_idxs = _get_ts_indices(ts_array) return arr.data[idxs1..., ts_idxs, idxs2...] @@ -604,13 +594,7 @@ function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T_data, N, ti return arr.data[idxs1..., ts_idxs, idxs2...] end -function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, vals, idxs::Union{Array{TimestepIndex,1}, AnyIndex}...) where {T, N, ti, FIRST, STEP} - idxs1, ts_array, idxs2 = split_indices(idxs, ti) - ts_idxs = _get_ts_indices(ts_array) - setindex!(arr.data, vals, idxs1..., ts_idxs, idxs2...) -end - -function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, vals, idxs::Union{Array{TimestepIndex,1}, AnyIndex}...) where {T, N, ti, TIMES} +function Base.setindex!(arr::TimestepArray{TS, T, N, ti}, vals, idxs::Union{Array{TimestepIndex,1}, AnyIndex}...) where {TS, T, N, ti} idxs1, ts_array, idxs2 = split_indices(idxs, ti) ts_idxs = _get_ts_indices(ts_array) setindex!(arr.data, vals, idxs1..., ts_idxs, idxs2...) @@ -650,22 +634,12 @@ end # int indexing version supports old-style components and internal functions, not # part of the public API; first index is Int or Range, rather than a Timestep -function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, idx1::AnyIndex, idx2::AnyIndex, idxs::AnyIndex...) where {T, N, ti, FIRST, STEP} - _throw_int_getindex_depwarning() - return arr.data[idx1, idx2, idxs...] -end - -function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idx1::AnyIndex, idx2::AnyIndex, idxs::AnyIndex...) where {T, N, ti, TIMES} +function Base.getindex(arr::TimestepArray{TS, T, N, ti}, idx1::AnyIndex, idx2::AnyIndex, idxs::AnyIndex...) where {TS, T, N, ti} _throw_int_getindex_depwarning() return arr.data[idx1, idx2, idxs...] end -function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, val, idx1::AnyIndex, idx2::AnyIndex, idxs::AnyIndex...) where {T, N, ti, FIRST, STEP} - _throw_int_setindex_depwarning() - setindex!(arr.data, val, idx1, idx2, idxs...) -end - -function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, val, idx1::AnyIndex, idx2::AnyIndex, idxs::AnyIndex...) where {T, N, ti, TIMES} +function Base.setindex!(arr::TimestepArray{TS, T, N, ti}, val, idx1::AnyIndex, idx2::AnyIndex, idxs::AnyIndex...) where {TS, T, N, ti} _throw_int_setindex_depwarning() setindex!(arr.data, val, idx1, idx2, idxs...) end From c19ac9228e96eabcbcd2962c344f2253f855aef0 Mon Sep 17 00:00:00 2001 From: lrennels Date: Wed, 30 Oct 2019 11:38:33 -0700 Subject: [PATCH 25/31] Fix typo --- src/core/time.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/time.jl b/src/core/time.jl index 3e59dc9d1..08c81e103 100644 --- a/src/core/time.jl +++ b/src/core/time.jl @@ -120,7 +120,7 @@ function Base.:+(ts::FixedTimestep{FIRST, STEP, LAST}, val::Int) where {FIRST, S elseif gettime(ts) + val > LAST + 1 error("Cannot get requested timestep, exceeds last timestep.") end - new_ts = FixedTimestep{FIRST, STEP, LAST}(ts.t + val) + return FixedTimestep{FIRST, STEP, LAST}(ts.t + val) end function Base.:+(ts::VariableTimestep{TIMES}, val::Int) where {TIMES} From 24d9535ea501b775e2e3f131d714d887546ec2b9 Mon Sep 17 00:00:00 2001 From: lrennels Date: Wed, 30 Oct 2019 20:23:56 -0700 Subject: [PATCH 26/31] Add tests; fix bugs in array colon methods --- src/core/time.jl | 5 - src/core/time_arrays.jl | 192 +++++++++++++++++++++--------------- test/test_timesteparrays.jl | 37 ++++++- test/test_timesteps.jl | 10 ++ 4 files changed, 154 insertions(+), 90 deletions(-) diff --git a/src/core/time.jl b/src/core/time.jl index 08c81e103..aef80fe72 100644 --- a/src/core/time.jl +++ b/src/core/time.jl @@ -141,11 +141,6 @@ function Base.:+(ts::TimestepIndex, val::Int) end # Colon support -function Base.:(:)(start::T, step::T, stop::T) where {T<:TimestepIndex} - indices = [start.index:step.index:stop.index...] - return TimestepIndex.(indices) -end - function Base.:(:)(start::T, step::Int, stop::T) where {T<:TimestepIndex} indices = [start.index:step:stop.index...] return TimestepIndex.(indices) diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index bd9f41821..f0e3e2420 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -27,6 +27,7 @@ function get_time_index_position(obj::AbstractCompositeComponentDef, comp_name:: end const AnyIndex = Union{Int, Vector{Int}, Tuple, Colon, OrdinalRange} +const AnyIndex_NonColon = Union{Int, Vector{Int}, Tuple, OrdinalRange} # Helper function for getindex; throws a MissingException if data is missing, otherwise returns data function _missing_data_check(data, t) @@ -190,41 +191,33 @@ end # Colon support -function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP}, T}, i::Colon) where {T, FIRST, STEP} +function Base.getindex(v::TimestepVector{TS, T}, i::Colon) where {TS<:AbstractTimestep, T} return v.data[i] end -function Base.getindex(v::TimestepVector{VariableTimestep{TIMES}, T}, i::Colon) where {T, TIMES} - return v.data[i] -end - -function Base.setindex!(v::TimestepVector{FixedTimestep{Start, STEP}, T}, val, i::Colon) where {T, Start, STEP} +function Base.setindex!(v::TimestepVector{TS, T}, val, i::Colon) where {TS<:AbstractTimestep, T} setindex!(v.data, val, i) end - -function Base.setindex!(v::TimestepVector{VariableTimestep{TIMES}, T}, val, i::Colon) where {T, TIMES} - setindex!(v.data, val, i) -end - + # int indexing version supports old-style components and internal functions, not # part of the public API -function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP}, T}, i::AnyIndex) where {T, FIRST, STEP} +function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP}, T}, i::AnyIndex_NonColon) where {T, FIRST, STEP} _throw_int_getindex_depwarning() return v.data[i] end -function Base.getindex(v::TimestepVector{VariableTimestep{TIMES}, T}, i::AnyIndex) where {T, TIMES} +function Base.getindex(v::TimestepVector{VariableTimestep{TIMES}, T}, i::AnyIndex_NonColon) where {T, TIMES} _throw_int_getindex_depwarning() return v.data[i] end -function Base.setindex!(v::TimestepVector{FixedTimestep{Start, STEP}, T}, val, i::AnyIndex) where {T, Start, STEP} +function Base.setindex!(v::TimestepVector{FixedTimestep{Start, STEP}, T}, val, i::AnyIndex_NonColon) where {T, Start, STEP} _throw_int_setindex_depwarning() setindex!(v.data, val, i) end -function Base.setindex!(v::TimestepVector{VariableTimestep{TIMES}, T}, val, i::AnyIndex) where {T, TIMES} +function Base.setindex!(v::TimestepVector{VariableTimestep{TIMES}, T}, val, i::AnyIndex_NonColon) where {T, TIMES} _throw_int_setindex_depwarning() setindex!(v.data, val, i) end @@ -392,31 +385,24 @@ end # Colon support -function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, idx1::Colon, idx2::Colon) where {T, FIRST, STEP, ti} +function Base.getindex(mat::TimestepMatrix{TS, T, ti}, idx1::Colon, idx2::Colon) where {TS<:AbstractTimestep, T, ti} return mat.data[idx1, idx2] end -function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, idx1::Colon, idx2::Colon) where {T, TIMES, ti} - return mat.data[idx1, idx2] -end - -function Base.setindex!(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, val, idx1::Colon, idx2::Colon) where {T, FIRST, STEP, ti} +function Base.setindex!(mat::TimestepMatrix{TS, T, ti}, val, idx1::Colon, idx2::Colon) where {TS<:AbstractTimestep, T, ti} mat.data[idx1, idx2] .= val end -function Base.setindex!(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, val, idx1::Colon, idx2::Colon) where {T, TIMES, ti} - mat.data[idx1, idx2] .= val -end # int indexing version supports old-style components and internal functions, not # part of the public API -function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, idx1::AnyIndex, idx2::AnyIndex) where {T, FIRST, STEP, ti} +function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, idx1::AnyIndex_NonColon, idx2::AnyIndex_NonColon) where {T, FIRST, STEP, ti} _throw_int_getindex_depwarning() return mat.data[idx1, idx2] end -function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, idx1::AnyIndex, idx2::AnyIndex) where {T, TIMES, ti} +function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, idx1::AnyIndex_NonColon, idx2::AnyIndex_NonColon) where {T, TIMES, ti} _throw_int_getindex_depwarning() return mat.data[idx1, idx2] end @@ -426,7 +412,7 @@ function Base.setindex!(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, setindex!(mat.data, val, idx1, idx2) end -function Base.setindex!(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, val, idx1::AnyIndex, idx2::AnyIndex) where {T, FIRST, STEP, ti} +function Base.setindex!(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, val, idx1::AnyIndex_NonColon, idx2::AnyIndex_NonColon) where {T, FIRST, STEP, ti} _throw_int_setindex_depwarning() mat.data[idx1, idx2] .= val end @@ -436,7 +422,7 @@ function Base.setindex!(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, val setindex!(mat.data, val, idx1, idx2) end -function Base.setindex!(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, val, idx1::AnyIndex, idx2::AnyIndex) where {T, TIMES, ti} +function Base.setindex!(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, val, idx1::AnyIndex_NonColon, idx2::AnyIndex_NonColon) where {T, TIMES, ti} _throw_int_setindex_depwarning() mat.data[idx1, idx2] .= val end @@ -473,104 +459,168 @@ split_indices(idxs, ti) = idxs[1:ti - 1], idxs[ti], idxs[ti + 1:end] function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, idxs::Union{FixedTimestep{FIRST, STEP, LAST}, AnyIndex}...) where {T, N, ti, FIRST, STEP, LAST} idxs1, ts, idxs2 = split_indices(idxs, ti) - return arr.data[idxs1..., ts.t, idxs2...] + if isa(ts, Colon) + return arr.data[idxs1..., :, idxs2...] + else + return arr.data[idxs1..., ts.t, idxs2...] + end end function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idxs::Union{VariableTimestep{TIMES}, AnyIndex}...) where {T, N, ti, TIMES} idxs1, ts, idxs2 = split_indices(idxs, ti) - return arr.data[idxs1..., ts.t, idxs2...] + if isa(ts, Colon) + return arr.data[idxs1..., :, idxs2...] + else + return arr.data[idxs1..., ts.t, idxs2...] + end end function Base.getindex(arr::TimestepArray{FixedTimestep{D_FIRST, STEP}, T, N, ti}, idxs::Union{FixedTimestep{T_FIRST, STEP, LAST}, AnyIndex}...) where {T, N, ti, D_FIRST, T_FIRST, STEP, LAST} idxs1, ts, idxs2 = split_indices(idxs, ti) - t = Int(ts.t + (FIRST - TIMES[1]) / STEP) - return arr.data[idxs1..., t, idxs2...] + if isa(ts, Colon) + return arr.data[idxs1..., :, idxs2...] + else + t = Int(ts.t + (FIRST - TIMES[1]) / STEP) + return arr.data[idxs1..., t, idxs2...] + end end function Base.getindex(arr::TimestepArray{VariableTimestep{D_TIMES}, T, N, ti}, idxs::Union{VariableTimestep{T_TIMES}, AnyIndex}...) where {T, N, ti, D_TIMES, T_TIMES} idxs1, ts, idxs2 = split_indices(idxs, ti) - t = ts.t + findfirst(isequal(T_TIMES[1]), D_TIMES) - 1 - return arr.data[idxs1..., t, idxs2...] + if isa(ts, Colon) + return arr.data[idxs1..., :, idxs2...] + else + t = ts.t + findfirst(isequal(T_TIMES[1]), D_TIMES) - 1 + return arr.data[idxs1..., t, idxs2...] + end end function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T_data, N, ti}, idxs::Union{TimestepValue{T_time}, AnyIndex}...) where {T_data, N, ti, FIRST, STEP, T_time} _single_index_check(arr.data, idxs) idxs1, ts, idxs2 = split_indices(idxs, ti) - LAST = FIRST + ((size(arr.data, ti) - 1) * STEP) - t = _get_time_value_position([FIRST:STEP:LAST...], ts) - return arr.data[idxs1..., t, idxs2...] + if isa(ts, Colon) + return arr.data[idxs1..., :, idxs2...] + else + LAST = FIRST + ((size(arr.data, ti) - 1) * STEP) + t = _get_time_value_position([FIRST:STEP:LAST...], ts) + return arr.data[idxs1..., t, idxs2...] + end end function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T_data, N, ti}, idxs::Union{TimestepValue{T_time}, AnyIndex}...) where {T_data, N, ti, TIMES, T_time} _single_index_check(arr.data, idxs) idxs1, ts, idxs2 = split_indices(idxs, ti) - t = _get_time_value_position(TIMES, ts) - return arr.data[idxs1..., t, idxs2...] + if isa(ts, Colon) + return arr.data[idxs1..., :, idxs2...] + else + t = _get_time_value_position(TIMES, ts) + return arr.data[idxs1..., t, idxs2...] + end end function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, idxs::Union{TimestepIndex, AnyIndex}...) where {T, N, ti, FIRST, STEP} _single_index_check(arr.data, idxs) idxs1, ts, idxs2 = split_indices(idxs, ti) - t = ts.index - _index_bounds_check(arr.data, ti, t) - return arr.data[idxs1..., t, idxs2...] + if isa(ts, Colon) + return arr.data[idxs1..., :, idxs2...] + else + t = ts.index + _index_bounds_check(arr.data, ti, t) + return arr.data[idxs1..., t, idxs2...] + end end function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idxs::Union{TimestepIndex, AnyIndex}...) where {T, N, ti, TIMES} _single_index_check(arr.data, idxs) idxs1, ts, idxs2 = split_indices(idxs, ti) - t = ts.index - _index_bounds_check(arr.data, ti, t) - return arr.data[idxs1..., t, idxs2...] + if isa(ts, Colon) + return arr.data[idxs1..., :, idxs2...] + else + t = ts.index + _index_bounds_check(arr.data, ti, t) + return arr.data[idxs1..., t, idxs2...] + end end function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, val, idxs::Union{FixedTimestep{FIRST, STEP, LAST}, AnyIndex}...) where {T, N, ti, FIRST, STEP, LAST} idxs1, ts, idxs2 = split_indices(idxs, ti) - setindex!(arr.data, val, idxs1..., ts.t, idxs2...) + if isa(ts, Colon) + setindex!(arr.data, val, idxs1..., :, idxs2...) + else + setindex!(arr.data, val, idxs1..., ts.t, idxs2...) + end end function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, val, idxs::Union{VariableTimestep{TIMES}, AnyIndex}...) where {T, N, ti, TIMES} idxs1, ts, idxs2 = split_indices(idxs, ti) - setindex!(arr.data, val, idxs1..., ts.t, idxs2...) + if isa(ts, Colon) + setindex!(arr.data, val, idxs1..., :, idxs2...) + else + setindex!(arr.data, val, idxs1..., ts.t, idxs2...) + end end function Base.setindex!(arr::TimestepArray{FixedTimestep{D_FIRST, STEP}, T, N, ti}, val, idxs::Union{FixedTimestep{T_FIRST, STEP, LAST}, AnyIndex}...) where {T, N, ti, D_FIRST, T_FIRST, STEP, LAST} idxs1, ts, idxs2 = split_indices(idxs, ti) - t = ts.t + findfirst(isequal(T_FIRST[1]), D_FIRST) - 1 - setindex!(arr.data, val, idxs1..., t, idxs2...) + if isa(ts, Colon) + setindex!(arr.data, val, idxs1..., :, idxs2...) + else + t = ts.t + findfirst(isequal(T_FIRST[1]), D_FIRST) - 1 + setindex!(arr.data, val, idxs1..., t, idxs2...) + end end function Base.setindex!(arr::TimestepArray{VariableTimestep{D_TIMES}, T, N, ti}, val, idxs::Union{VariableTimestep{T_TIMES}, AnyIndex}...) where {T, N, ti, D_TIMES, T_TIMES} idxs1, ts, idxs2 = split_indices(idxs, ti) - t = ts.t + findfirst(isequal(T_FIRST[1]), T_TIMES) - 1 - setindex!(arr.data, val, idxs1..., t, idxs2...) + if isa(ts, Colon) + setindex!(arr.data, val, idxs1..., :, idxs2...) + else + t = ts.t + findfirst(isequal(T_FIRST[1]), T_TIMES) - 1 + setindex!(arr.data, val, idxs1..., t, idxs2...) + end end function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T_data, N, ti}, val, idxs::Union{TimestepValue{T_time}, AnyIndex}...) where {T_data, N, ti, FIRST, STEP, T_time} _single_index_check(arr.data, idxs) idxs1, ts, idxs2 = split_indices(idxs, ti) - LAST = FIRST + ((size(arr.data, ti) - 1) * STEP) - t = _get_time_value_position([FIRST:STEP:LAST...], ts) - setindex!(arr.data, val, idxs1..., t, idxs2...) + if isa(ts, Colon) + setindex!(arr.data, val, idxs1..., :, idxs2...) + else + LAST = FIRST + ((size(arr.data, ti) - 1) * STEP) + t = _get_time_value_position([FIRST:STEP:LAST...], ts) + setindex!(arr.data, val, idxs1..., t, idxs2...) + end end function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T_data, N, ti}, val, idxs::Union{TimestepValue{T_time}, AnyIndex}...) where {T_data, N, ti, TIMES, T_time} _single_index_check(arr.data, idxs) idxs1, ts, idxs2 = split_indices(idxs, ti) - t = _get_time_value_position(TIMES, ts) - setindex!(arr.data, val, idxs1..., t, idxs2...) + if isa(ts, Colon) + setindex!(arr.data, val, idxs1..., :, idxs2...) + else + t = _get_time_value_position(TIMES, ts) + setindex!(arr.data, val, idxs1..., t, idxs2...) + end end function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, val, idxs::Union{TimestepIndex, AnyIndex}...) where {T, N, ti, FIRST, STEP} idxs1, ts, idxs2 = split_indices(idxs, ti) - t = ts.index - setindex!(arr.data, val, idxs1..., t, idxs2...) + if isa(ts, Colon) + setindex!(arr.data, val, idxs1..., :, idxs2...) + else + t = ts.index + setindex!(arr.data, val, idxs1..., t, idxs2...) + end end function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, val, idxs::Union{TimestepIndex, AnyIndex}...) where {T, N, ti, TIMES} idxs1, ts, idxs2 = split_indices(idxs, ti) - t = ts.index - setindex!(arr.data, val, idxs1..., t, idxs2...) + if isa(ts, Colon) + setindex!(arr.data, val, idxs1..., :, idxs2...) + else + t = ts.index + setindex!(arr.data, val, idxs1..., t, idxs2...) + end end # Indexing with arrays of TimestepIndexes or TimestepValues @@ -613,33 +663,15 @@ function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T_data, N, t setindex!(arr.data, vals, idxs1..., ts_idxs, idxs2...) end -# Colon support - -function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, idx1::Colon, idx2::Colon, idxs::Colon...) where {T, N, ti, FIRST, STEP} - return arr.data[idx1, idx2, idxs...] -end - -function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idx1::Colon, idx2::Colon, idxs::Colon...) where {T, N, ti, TIMES} - return arr.data[idx1, idx2, idxs...] -end - -function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, val, idx1::Colon, idx2::Colon, idxs::Colon...) where {T, N, ti, FIRST, STEP} - setindex!(arr.data, val, idx1, idx2, idxs...) -end - -function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, val, idx1::Colon, idx2::Colon, idxs::Colon...) where {T, N, ti, TIMES} - setindex!(arr.data, val, idx1, idx2, idxs...) -end - # int indexing version supports old-style components and internal functions, not # part of the public API; first index is Int or Range, rather than a Timestep -function Base.getindex(arr::TimestepArray{TS, T, N, ti}, idx1::AnyIndex, idx2::AnyIndex, idxs::AnyIndex...) where {TS, T, N, ti} +function Base.getindex(arr::TimestepArray{TS, T, N, ti}, idx1::AnyIndex_NonColon, idx2::AnyIndex_NonColon, idxs::AnyIndex_NonColon...) where {TS, T, N, ti} _throw_int_getindex_depwarning() return arr.data[idx1, idx2, idxs...] end -function Base.setindex!(arr::TimestepArray{TS, T, N, ti}, val, idx1::AnyIndex, idx2::AnyIndex, idxs::AnyIndex...) where {TS, T, N, ti} +function Base.setindex!(arr::TimestepArray{TS, T, N, ti}, val, idx1::AnyIndex_NonColon, idx2::AnyIndex_NonColon, idxs::AnyIndex_NonColon...) where {TS, T, N, ti} _throw_int_setindex_depwarning() setindex!(arr.data, val, idx1, idx2, idxs...) end diff --git a/test/test_timesteparrays.jl b/test/test_timesteparrays.jl index 13af2deb4..a85ee5935 100644 --- a/test/test_timesteparrays.jl +++ b/test/test_timesteparrays.jl @@ -35,6 +35,12 @@ x = TimestepVector{FixedTimestep{2000, 1}, Int}(a[:,3]) #1b. test hasvalue, getindex, and setindex! (with both matching years and # mismatched years) +# Colon +@test x[:] == a[:, 3] +x[:] = [100, 101, 102, 103] +@test x[:] == [100, 101, 102, 103] +x[:] = a[:, 3] #reset + # TimestepValue and TimestepIndex Indexing @test x[TimestepIndex(1)] == 9 @test x[TimestepIndex(1) + 1] == 10 @@ -85,6 +91,12 @@ x = TimestepVector{VariableTimestep{years}, Int}(a[:,3]) #2a. test hasvalue, getindex, and setindex! (with both matching years and # mismatched years) +# Colon +@test x[:] == a[:, 3] +x[:] = [100, 101, 102, 103] +@test x[:] == [100, 101, 102, 103] +x[:] = a[:, 3] #reset + # TimestepValue and TimestepIndex Indexing @test x[TimestepIndex(1)] == 9 @test x[TimestepIndex(1) + 1] == 10 @@ -165,6 +177,12 @@ y[TimestepValue(2000), 1] = 1 # reset #3b. test hasvalue, getindex, and setindex! (with both matching years and # mismatched years) +# Colon Support +@test y[:,1] == a[:, 1] +y[:, 1] = [100, 101, 102, 103] +@test y[:, 1] == [100, 101, 102, 103] +y[:, 1] = a[:, 1] #reset + # AbstractTimestep Indexing t = FixedTimestep{2001, 1, 3000}(1) @@ -215,6 +233,12 @@ y = TimestepMatrix{VariableTimestep{years}, Int, 1}(a[:,1:2]) #4a. test hasvalue, getindex, setindex!, and lastindex (with both matching years and # mismatched years) +# Colon Support +@test y[:,1] == a[:, 1] +y[:, 1] = [100, 101, 102, 103] +@test y[:, 1] == [100, 101, 102, 103] +y[:, 1] = a[:, 1] #reset + # TimestepValue and TimestepIndex Indexing @test y[TimestepIndex(1), 1] == 1 @test y[TimestepIndex(1), 2] == 5 @@ -277,8 +301,9 @@ data = collect(reshape(1:64, 4, 4, 4)) arr_fixed = TimestepArray{FixedTimestep{2000, 5}, Int, 3, 1}(data) arr_variable = TimestepArray{VariableTimestep{years}, Int, 3, 1}(data) -# Indexing with TimestepIndex +# Colon Support - TODO_LFR +# Indexing with single TimestepIndex @test arr_fixed[TimestepIndex(1), 1, 1] == 1 @test arr_fixed[TimestepIndex(3), 3, 3] == 43 @test arr_variable[TimestepIndex(1), 1, 1] == 1 @@ -294,13 +319,15 @@ arr_variable[TimestepIndex(1), 1, 1] = 1 # reset @test_throws ErrorException arr_fixed[TimestepIndex(1)] @test_throws ErrorException arr_variable[TimestepIndex(1)] -# Indexing with Array{TimestepIndex, N} (TODO_LFR) - +# Indexing with Array{TimestepIndex, N} @test arr_fixed[TimestepIndex.([1,3]), 1, 1] == [1, 3] @test arr_variable[TimestepIndex.([2,4]), 1, 1] == [2,4] -# Indexing with TimestepValue +# Indexing with Array{TimestepIndex, N} created by Colon syntax +@test arr_fixed[TimestepIndex(1):TimestepIndex(3), 1, 1] == [1,2,3] +@test arr_fixed[TimestepIndex(1):2:TimestepIndex(3), 1, 1] == [1,3] +# Indexing with single TimestepValue @test arr_fixed[TimestepValue(2000), 1, 1] == 1 @test arr_fixed[TimestepValue(2010), 3, 3] == 43 @test arr_variable[TimestepValue(2000), 1, 1] == 1 @@ -316,7 +343,7 @@ arr_variable[TimestepValue(2000), 1, 1] = 1 # reset @test_throws ErrorException arr_fixed[TimestepValue(2000)] @test_throws ErrorException arr_variable[TimestepValue(2000)] -# Indexing with Array{TimestepValue, N} (TODO_LFR) +# Indexing with Array{TimestepValue, N} @test arr_fixed[TimestepValue.([2000, 2010]), 1, 1] == [1, 3] @test arr_variable[TimestepValue.([2000, 2005, 2025]), 1, 1] == [1, 2,4] diff --git a/test/test_timesteps.jl b/test/test_timesteps.jl index fe5a762ad..5d56b5a2f 100644 --- a/test/test_timesteps.jl +++ b/test/test_timesteps.jl @@ -80,9 +80,19 @@ start = 1 stop = 10 step = 2 +# TimestepValue +@test TimestepValue(2000, offset = 1) + 1 == TimestepValue(2000, offset = 2) +@test TimestepValue(2000) + 1 == TimestepValue(2000, offset = 1) +@test TimestepValue(2000, offset = 1) - 1 == TimestepValue(2000) + +# TimestepIndex @test TimestepIndex(start):TimestepIndex(stop) == TimestepIndex.([start:stop...]) @test TimestepIndex(start):TimestepIndex(stop) == TimestepIndex(start):1:TimestepIndex(stop) @test TimestepIndex(start):step:TimestepIndex(stop) == TimestepIndex.([start:step:stop...]) + +@test TimestepIndex(1) + 1 == TimestepIndex(2) +@test TimestepIndex(2) - 1 == TimestepIndex(1) + #------------------------------------------------------------------------------ # Test a model with components with different offsets #------------------------------------------------------------------------------ From 4b67102b62979977868c18457927f619fcdf28db Mon Sep 17 00:00:00 2001 From: lrennels Date: Wed, 30 Oct 2019 23:30:17 -0700 Subject: [PATCH 27/31] Add more tests --- test/test_timesteparrays.jl | 71 +++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 22 deletions(-) diff --git a/test/test_timesteparrays.jl b/test/test_timesteparrays.jl index a85ee5935..968116a1e 100644 --- a/test/test_timesteparrays.jl +++ b/test/test_timesteparrays.jl @@ -35,10 +35,11 @@ x = TimestepVector{FixedTimestep{2000, 1}, Int}(a[:,3]) #1b. test hasvalue, getindex, and setindex! (with both matching years and # mismatched years) -# Colon +# Using a colon in the time dimension +vals = [100:103...] @test x[:] == a[:, 3] -x[:] = [100, 101, 102, 103] -@test x[:] == [100, 101, 102, 103] +x[:] = vals +@test x[:] == vals x[:] = a[:, 3] #reset # TimestepValue and TimestepIndex Indexing @@ -81,6 +82,9 @@ t3 = FixedTimestep{2000, 1, 2003}(1) x[t3] = 100 @test x[t3] == 100 +# Deprecated int indexing should still run +@test x[3] == 11 + #------------------------------------------------------------------------------ # 2. Test TimestepVector - Variable Timestep #------------------------------------------------------------------------------ @@ -91,10 +95,12 @@ x = TimestepVector{VariableTimestep{years}, Int}(a[:,3]) #2a. test hasvalue, getindex, and setindex! (with both matching years and # mismatched years) -# Colon +# Using a colon in the time dimension +vals = [100:103...] @test x[:] == a[:, 3] -x[:] = [100, 101, 102, 103] -@test x[:] == [100, 101, 102, 103] +x[:] = vals +@test x[:] == vals + x[:] = a[:, 3] #reset # TimestepValue and TimestepIndex Indexing @@ -141,6 +147,9 @@ t3 = VariableTimestep{years}() x[t3] = 100 @test x[t3] == 100 +# Deprecated int indexing should still run +@test x[3] == 11 + #------------------------------------------------------------------------------ # 3. Test TimestepMatrix - Fixed Timestep #------------------------------------------------------------------------------ @@ -177,11 +186,17 @@ y[TimestepValue(2000), 1] = 1 # reset #3b. test hasvalue, getindex, and setindex! (with both matching years and # mismatched years) -# Colon Support +# Using a colon in the time dimension +vals_arr = [100:103...] +vals_mat = fill(11,4,2) @test y[:,1] == a[:, 1] -y[:, 1] = [100, 101, 102, 103] -@test y[:, 1] == [100, 101, 102, 103] -y[:, 1] = a[:, 1] #reset +y[:, 1] = vals_arr +@test y[:, 1] == vals_arr +y[:,:] = 11 +@test y[:,:] == vals_mat +y[:,:] = vals_mat +@test y[:,:] == vals_mat +y = TimestepMatrix{FixedTimestep{2000, 1}, Int, 1}(a[:,1:2]) # reset # AbstractTimestep Indexing t = FixedTimestep{2001, 1, 3000}(1) @@ -207,10 +222,6 @@ t3 = FixedTimestep{2000, 1, 2005}(1) y[t3, 1] = 10 @test y[t3,1] == 10 -# Colon indexing -y[:,:] = 11 -@test y[:,:] == fill(11,4,2) - #3c. interval wider than 1 z = TimestepMatrix{FixedTimestep{2000, 2}, Int, 1}(a[:,3:4]) t = FixedTimestep{1980, 2, 3000}(11) @@ -222,6 +233,9 @@ t2 = next_timestep(t) @test z[t2,1] == 10 @test z[t2,2] == 14 +# Deprecated int indexing should still run +@test y[1,2] == a[:,1:2][1,2] +@test z[1,2] == a[:,3:4][1,2] #------------------------------------------------------------------------------ # 4. Test TimestepMatrix - Variable Timestep @@ -233,10 +247,11 @@ y = TimestepMatrix{VariableTimestep{years}, Int, 1}(a[:,1:2]) #4a. test hasvalue, getindex, setindex!, and lastindex (with both matching years and # mismatched years) -# Colon Support +# Using a colon in the time dimension +vals = [100:103...] @test y[:,1] == a[:, 1] -y[:, 1] = [100, 101, 102, 103] -@test y[:, 1] == [100, 101, 102, 103] +y[:, 1] = vals +@test y[:, 1] == vals y[:, 1] = a[:, 1] #reset # TimestepValue and TimestepIndex Indexing @@ -287,9 +302,8 @@ t3 = VariableTimestep{years}() y[t3, 1] = 10 @test y[t3,1] == 10 -# Colon indexing -y[:,:] = 11 -@test y[:,:] == fill(11,4,2) +# Deprecated int indexing should still run +@test y[1,2] == a[:,1:2][1,2] #------------------------------------------------------------------------------ # 5. Test TimestepArray methods @@ -301,7 +315,21 @@ data = collect(reshape(1:64, 4, 4, 4)) arr_fixed = TimestepArray{FixedTimestep{2000, 5}, Int, 3, 1}(data) arr_variable = TimestepArray{VariableTimestep{years}, Int, 3, 1}(data) -# Colon Support - TODO_LFR +# Using a colon in the time dimension +vals2d = fill(100,4) +vals3d = fill(200,4,4) +@test arr_fixed[:,1,1] == arr_variable[:,1,1] == data[:,1,1] +@test arr_fixed[:,2,3] == arr_variable[:,2,3] == data[:,2,3] +arr_fixed[:,1,1] = vals2d +arr_variable[:,1,1] = vals2d +@test arr_fixed[:,1,1] == arr_variable[:,1,1] == vals2d +arr_fixed[:,:,2] = vals3d +arr_variable[:,:,2] = vals3d +@test arr_fixed[:,:,2] == arr_variable[:,:,2] == vals3d + +data = collect(reshape(1:64, 4, 4, 4)) +arr_fixed[:,:,:] = data # reset +arr_variable[:,:,:] = data # reset # Indexing with single TimestepIndex @test arr_fixed[TimestepIndex(1), 1, 1] == 1 @@ -344,7 +372,6 @@ arr_variable[TimestepValue(2000), 1, 1] = 1 # reset @test_throws ErrorException arr_variable[TimestepValue(2000)] # Indexing with Array{TimestepValue, N} - @test arr_fixed[TimestepValue.([2000, 2010]), 1, 1] == [1, 3] @test arr_variable[TimestepValue.([2000, 2005, 2025]), 1, 1] == [1, 2,4] From 031f79b2a555d518b85f22147c4c727414f79f06 Mon Sep 17 00:00:00 2001 From: lrennels Date: Wed, 30 Oct 2019 23:41:03 -0700 Subject: [PATCH 28/31] Add more tests of deprecated functions --- test/test_timesteparrays.jl | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/test/test_timesteparrays.jl b/test/test_timesteparrays.jl index 968116a1e..2eb9b28ea 100644 --- a/test/test_timesteparrays.jl +++ b/test/test_timesteparrays.jl @@ -70,20 +70,21 @@ t = FixedTimestep{2001, 1, 3000}(1) @test x[t] == 10 t2 = next_timestep(t) - @test x[t2] == 11 - x[t2] = 99 @test x[t2] == 99 +x[t2] = 11 # reset t3 = FixedTimestep{2000, 1, 2003}(1) @test x[t3] == 9 - x[t3] = 100 @test x[t3] == 100 +x[t3] = 9 # reset # Deprecated int indexing should still run @test x[3] == 11 +x[3] = 100 +@test x[3] == 100 #------------------------------------------------------------------------------ # 2. Test TimestepVector - Variable Timestep @@ -134,21 +135,21 @@ t = VariableTimestep{y2}() @test x[t] == 10 t2 = next_timestep(t) - @test x[t2] == 11 -#@test indices(x) == (2000:2003,) #may remove this function - x[t2] = 99 @test x[t2] == 99 +x[t2] = 11 # reset t3 = VariableTimestep{years}() @test x[t3] == 9 - x[t3] = 100 @test x[t3] == 100 +x[t3] = 9 # reset # Deprecated int indexing should still run @test x[3] == 11 +x[3] = 100 +@test x[3] == 100 #------------------------------------------------------------------------------ # 3. Test TimestepMatrix - Fixed Timestep @@ -236,6 +237,10 @@ t2 = next_timestep(t) # Deprecated int indexing should still run @test y[1,2] == a[:,1:2][1,2] @test z[1,2] == a[:,3:4][1,2] +val = 100 +y[1,2] = val +z[1,2] = val +@test y[1,2] == z[1,2] == val #------------------------------------------------------------------------------ # 4. Test TimestepMatrix - Variable Timestep From 539b1a7359a58301383c19eea45b7cdf6122e0f3 Mon Sep 17 00:00:00 2001 From: lrennels Date: Thu, 31 Oct 2019 09:33:23 -0700 Subject: [PATCH 29/31] Clean up colon support in get and set index methods --- src/core/time_arrays.jl | 173 +++++++--------------- test/dependencies/run_dependency_tests.jl | 3 + test/test_timesteparrays.jl | 2 +- 3 files changed, 59 insertions(+), 119 deletions(-) diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index f0e3e2420..55615d3a1 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -188,16 +188,6 @@ end function Base.setindex!(v::TimestepVector, val, ts::TimestepIndex) setindex!(v.data, val, ts.index) end - -# Colon support - -function Base.getindex(v::TimestepVector{TS, T}, i::Colon) where {TS<:AbstractTimestep, T} - return v.data[i] -end - -function Base.setindex!(v::TimestepVector{TS, T}, val, i::Colon) where {TS<:AbstractTimestep, T} - setindex!(v.data, val, i) -end # int indexing version supports old-style components and internal functions, not # part of the public API @@ -383,17 +373,6 @@ function Base.setindex!(mat::TimestepMatrix, val, ts::TimestepIndex, idx::AnyInd setindex!(mat.data, val, ts.index, idx) end -# Colon support - -function Base.getindex(mat::TimestepMatrix{TS, T, ti}, idx1::Colon, idx2::Colon) where {TS<:AbstractTimestep, T, ti} - return mat.data[idx1, idx2] -end - -function Base.setindex!(mat::TimestepMatrix{TS, T, ti}, val, idx1::Colon, idx2::Colon) where {TS<:AbstractTimestep, T, ti} - mat.data[idx1, idx2] .= val -end - - # int indexing version supports old-style components and internal functions, not # part of the public API @@ -459,172 +438,130 @@ split_indices(idxs, ti) = idxs[1:ti - 1], idxs[ti], idxs[ti + 1:end] function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, idxs::Union{FixedTimestep{FIRST, STEP, LAST}, AnyIndex}...) where {T, N, ti, FIRST, STEP, LAST} idxs1, ts, idxs2 = split_indices(idxs, ti) - if isa(ts, Colon) - return arr.data[idxs1..., :, idxs2...] - else - return arr.data[idxs1..., ts.t, idxs2...] - end + return arr.data[idxs1..., ts.t, idxs2...] end function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idxs::Union{VariableTimestep{TIMES}, AnyIndex}...) where {T, N, ti, TIMES} idxs1, ts, idxs2 = split_indices(idxs, ti) - if isa(ts, Colon) - return arr.data[idxs1..., :, idxs2...] - else - return arr.data[idxs1..., ts.t, idxs2...] - end + return arr.data[idxs1..., ts.t, idxs2...] end function Base.getindex(arr::TimestepArray{FixedTimestep{D_FIRST, STEP}, T, N, ti}, idxs::Union{FixedTimestep{T_FIRST, STEP, LAST}, AnyIndex}...) where {T, N, ti, D_FIRST, T_FIRST, STEP, LAST} idxs1, ts, idxs2 = split_indices(idxs, ti) - if isa(ts, Colon) - return arr.data[idxs1..., :, idxs2...] - else - t = Int(ts.t + (FIRST - TIMES[1]) / STEP) - return arr.data[idxs1..., t, idxs2...] - end + t = Int(ts.t + (FIRST - TIMES[1]) / STEP) + return arr.data[idxs1..., t, idxs2...] end function Base.getindex(arr::TimestepArray{VariableTimestep{D_TIMES}, T, N, ti}, idxs::Union{VariableTimestep{T_TIMES}, AnyIndex}...) where {T, N, ti, D_TIMES, T_TIMES} idxs1, ts, idxs2 = split_indices(idxs, ti) - if isa(ts, Colon) - return arr.data[idxs1..., :, idxs2...] - else - t = ts.t + findfirst(isequal(T_TIMES[1]), D_TIMES) - 1 - return arr.data[idxs1..., t, idxs2...] - end + t = ts.t + findfirst(isequal(T_TIMES[1]), D_TIMES) - 1 + return arr.data[idxs1..., t, idxs2...] end function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T_data, N, ti}, idxs::Union{TimestepValue{T_time}, AnyIndex}...) where {T_data, N, ti, FIRST, STEP, T_time} _single_index_check(arr.data, idxs) idxs1, ts, idxs2 = split_indices(idxs, ti) - if isa(ts, Colon) - return arr.data[idxs1..., :, idxs2...] - else - LAST = FIRST + ((size(arr.data, ti) - 1) * STEP) - t = _get_time_value_position([FIRST:STEP:LAST...], ts) - return arr.data[idxs1..., t, idxs2...] - end + LAST = FIRST + ((size(arr.data, ti) - 1) * STEP) + t = _get_time_value_position([FIRST:STEP:LAST...], ts) + return arr.data[idxs1..., t, idxs2...] end function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T_data, N, ti}, idxs::Union{TimestepValue{T_time}, AnyIndex}...) where {T_data, N, ti, TIMES, T_time} _single_index_check(arr.data, idxs) idxs1, ts, idxs2 = split_indices(idxs, ti) - if isa(ts, Colon) - return arr.data[idxs1..., :, idxs2...] - else - t = _get_time_value_position(TIMES, ts) - return arr.data[idxs1..., t, idxs2...] - end + t = _get_time_value_position(TIMES, ts) + return arr.data[idxs1..., t, idxs2...] end function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, idxs::Union{TimestepIndex, AnyIndex}...) where {T, N, ti, FIRST, STEP} _single_index_check(arr.data, idxs) idxs1, ts, idxs2 = split_indices(idxs, ti) - if isa(ts, Colon) - return arr.data[idxs1..., :, idxs2...] - else - t = ts.index - _index_bounds_check(arr.data, ti, t) - return arr.data[idxs1..., t, idxs2...] - end + t = ts.index + _index_bounds_check(arr.data, ti, t) + return arr.data[idxs1..., t, idxs2...] end function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idxs::Union{TimestepIndex, AnyIndex}...) where {T, N, ti, TIMES} _single_index_check(arr.data, idxs) idxs1, ts, idxs2 = split_indices(idxs, ti) - if isa(ts, Colon) - return arr.data[idxs1..., :, idxs2...] - else - t = ts.index - _index_bounds_check(arr.data, ti, t) - return arr.data[idxs1..., t, idxs2...] - end + t = ts.index + _index_bounds_check(arr.data, ti, t) + return arr.data[idxs1..., t, idxs2...] end function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, val, idxs::Union{FixedTimestep{FIRST, STEP, LAST}, AnyIndex}...) where {T, N, ti, FIRST, STEP, LAST} idxs1, ts, idxs2 = split_indices(idxs, ti) - if isa(ts, Colon) - setindex!(arr.data, val, idxs1..., :, idxs2...) - else - setindex!(arr.data, val, idxs1..., ts.t, idxs2...) - end + setindex!(arr.data, val, idxs1..., ts.t, idxs2...) end function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, val, idxs::Union{VariableTimestep{TIMES}, AnyIndex}...) where {T, N, ti, TIMES} idxs1, ts, idxs2 = split_indices(idxs, ti) - if isa(ts, Colon) - setindex!(arr.data, val, idxs1..., :, idxs2...) - else - setindex!(arr.data, val, idxs1..., ts.t, idxs2...) - end + setindex!(arr.data, val, idxs1..., ts.t, idxs2...) end function Base.setindex!(arr::TimestepArray{FixedTimestep{D_FIRST, STEP}, T, N, ti}, val, idxs::Union{FixedTimestep{T_FIRST, STEP, LAST}, AnyIndex}...) where {T, N, ti, D_FIRST, T_FIRST, STEP, LAST} idxs1, ts, idxs2 = split_indices(idxs, ti) - if isa(ts, Colon) - setindex!(arr.data, val, idxs1..., :, idxs2...) - else - t = ts.t + findfirst(isequal(T_FIRST[1]), D_FIRST) - 1 - setindex!(arr.data, val, idxs1..., t, idxs2...) - end + t = ts.t + findfirst(isequal(T_FIRST[1]), D_FIRST) - 1 + setindex!(arr.data, val, idxs1..., t, idxs2...) end function Base.setindex!(arr::TimestepArray{VariableTimestep{D_TIMES}, T, N, ti}, val, idxs::Union{VariableTimestep{T_TIMES}, AnyIndex}...) where {T, N, ti, D_TIMES, T_TIMES} idxs1, ts, idxs2 = split_indices(idxs, ti) - if isa(ts, Colon) - setindex!(arr.data, val, idxs1..., :, idxs2...) - else - t = ts.t + findfirst(isequal(T_FIRST[1]), T_TIMES) - 1 - setindex!(arr.data, val, idxs1..., t, idxs2...) - end + t = ts.t + findfirst(isequal(T_FIRST[1]), T_TIMES) - 1 + setindex!(arr.data, val, idxs1..., t, idxs2...) end function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T_data, N, ti}, val, idxs::Union{TimestepValue{T_time}, AnyIndex}...) where {T_data, N, ti, FIRST, STEP, T_time} _single_index_check(arr.data, idxs) idxs1, ts, idxs2 = split_indices(idxs, ti) - if isa(ts, Colon) - setindex!(arr.data, val, idxs1..., :, idxs2...) - else - LAST = FIRST + ((size(arr.data, ti) - 1) * STEP) - t = _get_time_value_position([FIRST:STEP:LAST...], ts) - setindex!(arr.data, val, idxs1..., t, idxs2...) - end + LAST = FIRST + ((size(arr.data, ti) - 1) * STEP) + t = _get_time_value_position([FIRST:STEP:LAST...], ts) + setindex!(arr.data, val, idxs1..., t, idxs2...) end function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T_data, N, ti}, val, idxs::Union{TimestepValue{T_time}, AnyIndex}...) where {T_data, N, ti, TIMES, T_time} _single_index_check(arr.data, idxs) idxs1, ts, idxs2 = split_indices(idxs, ti) - if isa(ts, Colon) - setindex!(arr.data, val, idxs1..., :, idxs2...) - else - t = _get_time_value_position(TIMES, ts) - setindex!(arr.data, val, idxs1..., t, idxs2...) - end + t = _get_time_value_position(TIMES, ts) + setindex!(arr.data, val, idxs1..., t, idxs2...) end function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, val, idxs::Union{TimestepIndex, AnyIndex}...) where {T, N, ti, FIRST, STEP} idxs1, ts, idxs2 = split_indices(idxs, ti) - if isa(ts, Colon) - setindex!(arr.data, val, idxs1..., :, idxs2...) - else - t = ts.index - setindex!(arr.data, val, idxs1..., t, idxs2...) - end + t = ts.index + setindex!(arr.data, val, idxs1..., t, idxs2...) end function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, val, idxs::Union{TimestepIndex, AnyIndex}...) where {T, N, ti, TIMES} idxs1, ts, idxs2 = split_indices(idxs, ti) - if isa(ts, Colon) - setindex!(arr.data, val, idxs1..., :, idxs2...) - else - t = ts.index - setindex!(arr.data, val, idxs1..., t, idxs2...) - end + t = ts.index + setindex!(arr.data, val, idxs1..., t, idxs2...) end -# Indexing with arrays of TimestepIndexes or TimestepValues +# Colon support - this allows the time dimension to be indexed with a colon, and +# the deprecation warning will become an error when integer indexing is fully deprecated + +function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, idxs::AnyIndex...) where {FIRST, STEP, T, N, ti} + isa(idxs[ti], AnyIndex_NonColon) ? _throw_int_getindex_depwarning() : nothing + return arr.data[idxs...] +end + +function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idxs::AnyIndex...) where {TIMES, T, N, ti} + isa(idxs[ti], AnyIndex_NonColon) ? _throw_int_getindex_depwarning() : nothing + return arr.data[idxs...] +end + +function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, val, idxs::AnyIndex...) where {FIRST, STEP, T, N, ti} + isa(idxs[ti], AnyIndex_NonColon) ? _throw_int_getindex_depwarning() : nothing + setindex!(arr.data, val, idxs...) +end + +function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, val, idxs::AnyIndex...) where {TIMES, T, N, ti} + isa(idxs[ti], AnyIndex_NonColon) ? _throw_int_getindex_depwarning() : nothing + setindex!(arr.data, val, idxs...) +end +# Indexing with arrays of TimestepIndexes or TimestepValues function Base.getindex(arr::TimestepArray{TS, T, N, ti}, idxs::Union{Array{TimestepIndex,1}, AnyIndex}...) where {TS, T, N, ti} idxs1, ts_array, idxs2 = split_indices(idxs, ti) ts_idxs = _get_ts_indices(ts_array) diff --git a/test/dependencies/run_dependency_tests.jl b/test/dependencies/run_dependency_tests.jl index a114b1d8b..dd7bb8a66 100644 --- a/test/dependencies/run_dependency_tests.jl +++ b/test/dependencies/run_dependency_tests.jl @@ -8,8 +8,11 @@ packages_to_test = [ for (pkg_url, pkg_rev, pkg_name) in packages_to_test mktempdir() do folder Pkg.activate(folder) + Pkg.develop(PackageSpec(path=joinpath(@__DIR__, "..", ".."))) + Pkg.add(PackageSpec(url=pkg_url, rev=pkg_rev)) + Pkg.test(pkg_name) end end diff --git a/test/test_timesteparrays.jl b/test/test_timesteparrays.jl index 2eb9b28ea..b304fb19b 100644 --- a/test/test_timesteparrays.jl +++ b/test/test_timesteparrays.jl @@ -193,7 +193,7 @@ vals_mat = fill(11,4,2) @test y[:,1] == a[:, 1] y[:, 1] = vals_arr @test y[:, 1] == vals_arr -y[:,:] = 11 +y[:,:] .= vals_mat @test y[:,:] == vals_mat y[:,:] = vals_mat @test y[:,:] == vals_mat From 753d99c706f818ae3d68690ec308b019faacc82e Mon Sep 17 00:00:00 2001 From: lrennels Date: Thu, 31 Oct 2019 15:29:51 -0700 Subject: [PATCH 30/31] Clean up and add tests to test_timesteparrays --- test/test_timesteparrays.jl | 727 ++++++++++++++++++++++-------------- 1 file changed, 442 insertions(+), 285 deletions(-) diff --git a/test/test_timesteparrays.jl b/test/test_timesteparrays.jl index b304fb19b..c93a06cd8 100644 --- a/test/test_timesteparrays.jl +++ b/test/test_timesteparrays.jl @@ -7,8 +7,17 @@ import Mimi: FixedTimestep, VariableTimestep, TimestepVector, TimestepMatrix, TimestepArray, next_timestep, hasvalue, isuniform, first_period, last_period, first_and_step -# general variables -a = collect(reshape(1:16,4,4)) +function reset_time_val(arr, vals::Array{T, 1}) where T + arr[:] = vals +end + +function reset_time_val(arr, vals::Array{T, 2}) where T + arr[:,:] = vals +end + +function reset_time_val(arr, vals::Array{T, 3}) where T + arr[:,:,:] = vals +end ## quick check of isuniform @test isuniform([]) == false @@ -23,44 +32,45 @@ a = collect(reshape(1:16,4,4)) #------------------------------------------------------------------------------ # 1. Test TimestepVector - Fixed Timestep #------------------------------------------------------------------------------ -years = collect(2000:1:2003) #1a. test constructor, lastindex, and length (with both # matching years and mismatched years) -x = TimestepVector{FixedTimestep{2000, 1}, Int}(a[:,3]) +x = TimestepVector{FixedTimestep{2000, 1}, Int}([9, 10, 11, 12]) @test length(x) == 4 @test lastindex(x) == 4 +time_dim_val = [9, 10, 11, 12] +temp_dim_val = [100, 101, 102, 103] + #1b. test hasvalue, getindex, and setindex! (with both matching years and # mismatched years) # Using a colon in the time dimension -vals = [100:103...] -@test x[:] == a[:, 3] -x[:] = vals -@test x[:] == vals -x[:] = a[:, 3] #reset +@test x[:] == time_dim_val +x[:] = temp_dim_val +@test x[:] == temp_dim_val +reset_time_val(x, time_dim_val) # TimestepValue and TimestepIndex Indexing -@test x[TimestepIndex(1)] == 9 -@test x[TimestepIndex(1) + 1] == 10 -@test x[TimestepIndex(4)] == 12 +@test x[TimestepIndex(1)] == time_dim_val[1] +@test x[TimestepIndex(1) + 1] == time_dim_val[2] +@test x[TimestepIndex(4)] == time_dim_val[4] @test_throws ErrorException x[TimestepIndex(5)] -x[TimestepIndex(1)] = 100 -@test x[TimestepIndex(1)] == 100 -x[TimestepIndex(1)] = 9 # reset for later tests +x[TimestepIndex(1)] = temp_dim_val[1] +@test x[TimestepIndex(1)] == temp_dim_val[1] +reset_time_val(x, time_dim_val) -@test x[TimestepValue(2000)] == 9 -@test x[TimestepValue(2000; offset = 1)] == 10 -@test x[TimestepValue(2000) + 1] == 10 +@test x[TimestepValue(2000)] == time_dim_val[1] +@test x[TimestepValue(2000; offset = 1)] == time_dim_val[2] +@test x[TimestepValue(2000) + 1] == time_dim_val[2] @test_throws ErrorException x[TimestepValue(2005)] @test_throws ErrorException x[TimestepValue(2004)+1] -x[TimestepValue(2000)] = 101 -@test x[TimestepValue(2000)] == 101 -x[TimestepValue(2000)] = 9 # reset for later tests +x[TimestepValue(2000)] = temp_dim_val[1] +@test x[TimestepValue(2000)] == temp_dim_val[1] +reset_time_val(x, time_dim_val) # AbstractTimestep Indexing t = FixedTimestep{2001, 1, 3000}(1) @@ -70,344 +80,491 @@ t = FixedTimestep{2001, 1, 3000}(1) @test x[t] == 10 t2 = next_timestep(t) -@test x[t2] == 11 -x[t2] = 99 -@test x[t2] == 99 -x[t2] = 11 # reset +@test x[t2] == time_dim_val[3] +x[t2] = temp_dim_val[3] +@test x[t2] == temp_dim_val[3] +reset_time_val(x, time_dim_val) t3 = FixedTimestep{2000, 1, 2003}(1) -@test x[t3] == 9 -x[t3] = 100 -@test x[t3] == 100 -x[t3] = 9 # reset +@test x[t3] == time_dim_val[1] +x[t3] = temp_dim_val[1] +@test x[t3] == temp_dim_val[1] +reset_time_val(x, time_dim_val) # Deprecated int indexing should still run -@test x[3] == 11 -x[3] = 100 -@test x[3] == 100 +@test x[3] == time_dim_val[3] +x[3] = temp_dim_val[3] +@test x[3] == temp_dim_val[3] +reset_time_val(x, time_dim_val) #------------------------------------------------------------------------------ # 2. Test TimestepVector - Variable Timestep #------------------------------------------------------------------------------ years = (2000, 2005, 2015, 2025) -x = TimestepVector{VariableTimestep{years}, Int}(a[:,3]) +x = TimestepVector{VariableTimestep{years}, Int}([9, 10, 11, 12]) + +time_dim_val = [9, 10, 11, 12] +temp_dim_val = [100, 101, 102, 103] #2a. test hasvalue, getindex, and setindex! (with both matching years and # mismatched years) # Using a colon in the time dimension -vals = [100:103...] -@test x[:] == a[:, 3] -x[:] = vals -@test x[:] == vals - -x[:] = a[:, 3] #reset +@test x[:] == time_dim_val +x[:] = temp_dim_val +@test x[:] == temp_dim_val +reset_time_val(x, time_dim_val) # TimestepValue and TimestepIndex Indexing -@test x[TimestepIndex(1)] == 9 -@test x[TimestepIndex(1) + 1] == 10 -@test x[TimestepIndex(4)] == 12 +@test x[TimestepIndex(1)] == time_dim_val[1] +@test x[TimestepIndex(1) + 1] == time_dim_val[2] +@test x[TimestepIndex(4)] == time_dim_val[4] @test_throws ErrorException x[TimestepIndex(5)] -x[TimestepIndex(1)] = 100 -@test x[TimestepIndex(1)] == 100 -x[TimestepIndex(1)] = 9 # reset +x[TimestepIndex(1)] = temp_dim_val[1] +@test x[TimestepIndex(1)] == temp_dim_val[1] +reset_time_val(x, time_dim_val) -@test x[TimestepValue(2000)] == 9 -@test x[TimestepValue(2000; offset = 1)] == 10 -@test x[TimestepValue(2015)] == 11 -@test x[TimestepValue(2015; offset = 1)] == 12 -@test x[TimestepValue(2000) + 1] == 10 +@test x[TimestepValue(2000)] == time_dim_val[1] +@test x[TimestepValue(2000; offset = 1)] == time_dim_val[2] +@test x[TimestepValue(2015)] == time_dim_val[3] +@test x[TimestepValue(2015; offset = 1)] == time_dim_val[4] +@test x[TimestepValue(2000) + 1] == time_dim_val[2] @test_throws ErrorException x[TimestepValue(2014)] @test_throws ErrorException x[TimestepValue(2025)+1] -x[TimestepValue(2015)] = 100 -@test x[TimestepValue(2015)] == 100 -x[TimestepValue(2015)] = 11 # reset +x[TimestepValue(2015)] = temp_dim_val[3] +@test x[TimestepValue(2015)] == temp_dim_val[3] +reset_time_val(x, time_dim_val) # AbstractTimestep Indexing y2 = Tuple([2005:5:2010; 2015:10:3000]) t = VariableTimestep{y2}() @test hasvalue(x, t) -@test !hasvalue(x, VariableTimestep{years}(10)) -@test x[t] == 10 +@test !hasvalue(x, VariableTimestep{years}(time_dim_val[2])) +@test x[t] == time_dim_val[2] t2 = next_timestep(t) -@test x[t2] == 11 -x[t2] = 99 -@test x[t2] == 99 -x[t2] = 11 # reset +@test x[t2] == time_dim_val[3] +x[t2] = temp_dim_val[3] +@test x[t2] == temp_dim_val[3] +reset_time_val(x, time_dim_val) t3 = VariableTimestep{years}() -@test x[t3] == 9 -x[t3] = 100 -@test x[t3] == 100 -x[t3] = 9 # reset +@test x[t3] == time_dim_val[1] +x[t3] = temp_dim_val[1] +@test x[t3] == temp_dim_val[1] +reset_time_val(x, time_dim_val) # Deprecated int indexing should still run -@test x[3] == 11 -x[3] = 100 -@test x[3] == 100 +@test x[3] == time_dim_val[3] +x[3] = temp_dim_val[3] +@test x[3] == temp_dim_val[3] +reset_time_val(x, time_dim_val) #------------------------------------------------------------------------------ # 3. Test TimestepMatrix - Fixed Timestep #------------------------------------------------------------------------------ -years = Tuple(2000:1:2003) - -#3a. test constructor (with both matching years -# and mismatched years) - -y = TimestepMatrix{FixedTimestep{2000, 1}, Int, 1}(a[:,1:2]) - -# TimestepValue and TimestepIndex Indexing -@test y[TimestepIndex(1), 1] == 1 -@test y[TimestepIndex(1), 2] == 5 -@test y[TimestepIndex(1) + 1, 1] == 2 -@test y[TimestepIndex(4), 2] == 8 -@test_throws ErrorException y[TimestepIndex(5), 2] - -y[TimestepIndex(1), 1] = 100 -@test y[TimestepIndex(1), 1] == 100 -y[TimestepIndex(1), 1] = 1 # reset - -@test y[TimestepValue(2000), 1] == 1 -@test y[TimestepValue(2000), 2] == 5 -@test y[TimestepValue(2001), :] == [2,6] -@test y[TimestepValue(2000; offset = 1), 1] == 2 -@test y[TimestepValue(2000) + 1, 1] == 2 -@test_throws ErrorException y[TimestepValue(2005), 1] -@test_throws ErrorException y[TimestepValue(2004)+1, 1] - -y[TimestepValue(2000), 1] = 101 -@test y[TimestepValue(2000), 1] == 101 -y[TimestepValue(2000), 1] = 1 # reset - -#3b. test hasvalue, getindex, and setindex! (with both matching years and -# mismatched years) -# Using a colon in the time dimension -vals_arr = [100:103...] -vals_mat = fill(11,4,2) -@test y[:,1] == a[:, 1] -y[:, 1] = vals_arr -@test y[:, 1] == vals_arr -y[:,:] .= vals_mat -@test y[:,:] == vals_mat -y[:,:] = vals_mat -@test y[:,:] == vals_mat -y = TimestepMatrix{FixedTimestep{2000, 1}, Int, 1}(a[:,1:2]) # reset +for ti = 1:2 -# AbstractTimestep Indexing -t = FixedTimestep{2001, 1, 3000}(1) - -@test hasvalue(y, t, 1) -@test !hasvalue(y, FixedTimestep{2000, 1, 3000}(10), 1) -@test y[t,1] == 2 -@test y[t,2] == 6 - -t2 = next_timestep(t) + #3a. test constructor (with both matching years + # and mismatched years) -@test y[t2,1] == 3 -@test y[t2,2] == 7 - -y[t2, 1] = 5 -@test y[t2, 1] == 5 + y = TimestepMatrix{FixedTimestep{2000, 1}, Int, ti}(collect(reshape(1:8, 4, 2))) + z = TimestepMatrix{FixedTimestep{2000, 2}, Int, ti}(collect(reshape(1:8, 4, 2))) -t3 = FixedTimestep{2000, 1, 2005}(1) + time_dim_val = collect(reshape(1:8, 4, 2)) + temp_dim_val = collect(reshape(100:107, 4, 2)) -@test y[t3, 1] == 1 -@test y[t3, 2] == 5 + #3b. test hasvalue, getindex, and setindex! (with both matching years and + # mismatched years) -y[t3, 1] = 10 -@test y[t3,1] == 10 - -#3c. interval wider than 1 -z = TimestepMatrix{FixedTimestep{2000, 2}, Int, 1}(a[:,3:4]) -t = FixedTimestep{1980, 2, 3000}(11) + # Using a colon in the time dimension + y[:,:] = temp_dim_val + @test y[:,:] == temp_dim_val + y[:,:] = time_dim_val # reset + if ti == 1 + @test y[:,1] == time_dim_val[:,1] + y[:, 1] = temp_dim_val[:,1] + @test y[:, 1] == temp_dim_val[:,1] + else + @test y[1,:] == time_dim_val[1,:] + y[1,:] = temp_dim_val[1,:] + @test y[1,:] == temp_dim_val[1,:] + end + reset_time_val(y, time_dim_val) + + # TimestepValue and TimestepIndex Indexing + if ti == 1 + @test y[TimestepIndex(1), 1] == time_dim_val[1,1] + @test y[TimestepIndex(1), 2] == time_dim_val[1,2] + @test y[TimestepIndex(1) + 1, 1] == time_dim_val[2,1] + @test y[TimestepIndex(4), 2] == time_dim_val[4,2] + @test_throws ErrorException y[TimestepIndex(5), 2] + + y[TimestepIndex(1), 1] = temp_dim_val[1] + @test y[TimestepIndex(1), 1] == temp_dim_val[1] + reset_time_val(y, time_dim_val) + + @test y[TimestepValue(2000), 1] == time_dim_val[1, 1] + @test y[TimestepValue(2000), 2] == time_dim_val[1, 2] + @test y[TimestepValue(2001), :] == time_dim_val[2, :] + @test y[TimestepValue(2000; offset = 1), 1] == time_dim_val[2,1] + @test y[TimestepValue(2000) + 1, 1] == time_dim_val[2,1] + @test_throws ErrorException y[TimestepValue(2005), 1] + @test_throws ErrorException y[TimestepValue(2004)+1, 1] + + y[TimestepValue(2000), 1] = temp_dim_val[1] + @test y[TimestepValue(2000), 1] == temp_dim_val[1] + reset_time_val(y, time_dim_val) + else + @test y[1, TimestepIndex(1)] == time_dim_val[1,1] + @test y[2, TimestepIndex(1)] == time_dim_val[2, 1] + @test y[1, TimestepIndex(1) + 1] == time_dim_val[1, 2] + @test y[2, TimestepIndex(2)] == time_dim_val[2,2] + @test_throws ErrorException y[2, TimestepIndex(3)] + + y[1, TimestepIndex(1)] = temp_dim_val[1] + @test y[1, TimestepIndex(1)] == temp_dim_val[1] + reset_time_val(y, time_dim_val) + + @test y[1, TimestepValue(2000)] == time_dim_val[1,1] + @test y[2, TimestepValue(2000)] == time_dim_val[2,1] + @test y[:, TimestepValue(2001)] == time_dim_val[:,2] + @test y[1, TimestepValue(2000; offset = 1)] == time_dim_val[1,2] + @test y[1, TimestepValue(2000) + 1] == time_dim_val[1,2] + @test_throws ErrorException y[1, TimestepValue(2003)] + @test_throws ErrorException y[1, TimestepValue(2002)+1] + + y[1, TimestepValue(2000)] = temp_dim_val[1] + @test y[1, TimestepValue(2000)] == temp_dim_val[1] + reset_time_val(y, time_dim_val) + end -@test z[t,1] == 9 -@test z[t,2] == 13 + # AbstractTimestep Indexing + t = FixedTimestep{2001, 1, 3000}(1) + @test hasvalue(y, t, 1) + @test !hasvalue(y, FixedTimestep{2000, 1, 3000}(10), 1) + + if ti == 1 + @test y[t,1] == time_dim_val[2,1] + @test y[t,2] == time_dim_val[2,2] + + t2 = next_timestep(t) + @test y[t2,1] == time_dim_val[3,1] + @test y[t2,2] == time_dim_val[3,2] + y[t2, 1] = temp_dim_val[3,1] + @test y[t2, 1] == temp_dim_val[3,1] + reset_time_val(y, time_dim_val) + + t3 = FixedTimestep{2000, 1, 2005}(1) + @test y[t3, 1] == time_dim_val[1,1] + @test y[t3, 2] == time_dim_val[1,2] + y[t3, 1] = temp_dim_val[1,1] + @test y[t3,1] == temp_dim_val[1,1] + reset_time_val(y, time_dim_val) + + #3c. interval wider than 1 using z from above + t = FixedTimestep{1980, 2, 3000}(11) + + @test z[t,1] == time_dim_val[1,1] + @test z[t,2] == time_dim_val[1,2] + + t2 = next_timestep(t) + @test z[t2,1] == time_dim_val[2,1] + @test z[t2,2] == time_dim_val[2,2] + + else + @test y[1, t] == time_dim_val[1,2] + @test y[2, t] == time_dim_val[2,2] + + t2 = FixedTimestep{2000, 1, 2005}(1) + @test y[1, t2] == time_dim_val[1,1] + @test y[2, t2] == time_dim_val[2,1] + y[1, t2] = temp_dim_val[1,1] + @test y[1, t2] == temp_dim_val[1,1] + reset_time_val(y, time_dim_val) + + #3c. interval wider than 1 using z from above + t = FixedTimestep{1980, 2, 3000}(11) + + @test z[1, t] == time_dim_val[1,1] + @test z[2, t] == time_dim_val[2,1] + + t2 = next_timestep(t) + @test z[1, t2] == time_dim_val[1,2] + @test z[2, t2] == time_dim_val[2,2] + end -t2 = next_timestep(t) -@test z[t2,1] == 10 -@test z[t2,2] == 14 + # Deprecated int indexing should still run + @test y[1,2] == time_dim_val[1,2] + @test z[1,2] == time_dim_val[1,2] + y[1,2] = temp_dim_val[1] + z[1,2] = temp_dim_val[1] + @test y[1,2] == z[1,2] == temp_dim_val[1] -# Deprecated int indexing should still run -@test y[1,2] == a[:,1:2][1,2] -@test z[1,2] == a[:,3:4][1,2] -val = 100 -y[1,2] = val -z[1,2] = val -@test y[1,2] == z[1,2] == val + reset_time_val(y, time_dim_val) + reset_time_val(z, time_dim_val) +end #------------------------------------------------------------------------------ # 4. Test TimestepMatrix - Variable Timestep #------------------------------------------------------------------------------ -years = Tuple([2000:5:2005; 2015:10:2025]) -y = TimestepMatrix{VariableTimestep{years}, Int, 1}(a[:,1:2]) - -#4a. test hasvalue, getindex, setindex!, and lastindex (with both matching years and -# mismatched years) - -# Using a colon in the time dimension -vals = [100:103...] -@test y[:,1] == a[:, 1] -y[:, 1] = vals -@test y[:, 1] == vals -y[:, 1] = a[:, 1] #reset - -# TimestepValue and TimestepIndex Indexing -@test y[TimestepIndex(1), 1] == 1 -@test y[TimestepIndex(1), 2] == 5 -@test y[TimestepIndex(1) + 1, 1] == 2 -@test y[TimestepIndex(4), 2] == 8 -@test_throws ErrorException y[TimestepIndex(5), 2] - -y[TimestepIndex(1), 1] = 101 -@test y[TimestepIndex(1), 1] == 101 -y[TimestepIndex(1), 1] = 1 # reset - -@test y[TimestepValue(2000), 1] == 1 -@test y[TimestepValue(2000), 2] == 5 -@test y[TimestepValue(2000; offset = 1), 1] == 2 -@test y[TimestepValue(2000) + 1, 1] == 2 -@test y[TimestepValue(2015), 1] == 3 -@test y[TimestepValue(2015) + 1, 2] == 8 -@test_throws ErrorException y[TimestepValue(2006), 1] -@test_throws ErrorException y[TimestepValue(2025)+1, 1] - -y[TimestepValue(2015), 1] = 100 -@test y[TimestepValue(2015), 1] == 100 -y[TimestepValue(2015), 1] = 3 # reset - -# AbstractTimestep Indexing -t = VariableTimestep{Tuple([2005:5:2010; 2015:10:3000])}() - -@test hasvalue(y, t, 1) -@test !hasvalue(y, VariableTimestep{years}(10)) -@test y[t,1] == 2 -@test y[t,2] == 6 - -t2 = next_timestep(t) - -@test y[t2,1] == 3 -@test y[t2,2] == 7 - -y[t2, 1] = 5 -@test y[t2, 1] == 5 +for ti = 1:2 -t3 = VariableTimestep{years}() + #4a. test constructor (with both matching years + # and mismatched years) -@test y[t3, 1] == 1 -@test y[t3, 2] == 5 + if ti == 1 + years = Tuple([2000:5:2005; 2015:10:2025]) + else + years = (2000, 2005) + end + y = TimestepMatrix{VariableTimestep{years}, Int, ti}(collect(reshape(1:8, 4, 2))) + y = TimestepMatrix{VariableTimestep{years}, Int, ti}(collect(reshape(1:8, 4, 2))) + + time_dim_val = collect(reshape(1:8, 4, 2)) + temp_dim_val = collect(reshape(100:107, 4, 2)) + + #4b. test hasvalue, getindex, setindex!, and lastindex (with both matching years and + # mismatched years) + + # Using a colon in the time dimension + y[:,:] = temp_dim_val + @test y[:,:] == temp_dim_val + y[:,:] = time_dim_val # reset + if ti == 1 + @test y[:,1] == time_dim_val[:,1] + y[:, 1] = temp_dim_val[:,1] + @test y[:, 1] == temp_dim_val[:,1] + else + @test y[1,:] == time_dim_val[1,:] + y[1,:] = temp_dim_val[1,:] + @test y[1,:] == temp_dim_val[1,:] + end + reset_time_val(y, time_dim_val) + + # TimestepValue and TimestepIndex Indexing + if ti == 1 + @test y[TimestepIndex(1), 1] == time_dim_val[1,1] + @test y[TimestepIndex(1), 2] == time_dim_val[1,2] + @test y[TimestepIndex(1) + 1, 1] == time_dim_val[2,1] + @test y[TimestepIndex(4), 2] == time_dim_val[4,2] + @test_throws ErrorException y[TimestepIndex(5),2] + + y[TimestepIndex(1), 1] = temp_dim_val[1,1] + @test y[TimestepIndex(1), 1] == temp_dim_val[1,1] + reset_time_val(y, time_dim_val) + + @test y[TimestepValue(2000), 1] == time_dim_val[1,1] + @test y[TimestepValue(2000), 2] == time_dim_val[1,2] + @test y[TimestepValue(2000; offset = 1), 1] == time_dim_val[2,1] + @test y[TimestepValue(2000) + 1, 1] == time_dim_val[2,1] + @test y[TimestepValue(2015), 1] == time_dim_val[3,1] + @test y[TimestepValue(2015) + 1, 2] == time_dim_val[4,2] + @test_throws ErrorException y[TimestepValue(2006), 1] + @test_throws ErrorException y[TimestepValue(2025)+1, 1] + + y[TimestepValue(2015), 1] = temp_dim_val[3,1] + @test y[TimestepValue(2015), 1] == temp_dim_val[3,1] + reset_time_val(y, time_dim_val) + else + @test y[1, TimestepIndex(1)] == time_dim_val[1,1] + @test y[2, TimestepIndex(1)] == time_dim_val[2,1] + @test y[1, TimestepIndex(1) + 1] == time_dim_val[1,2] + @test y[2, TimestepIndex(2)] == time_dim_val[2,2] + @test_throws ErrorException y[2, TimestepIndex(3)] + + y[1, TimestepIndex(1)] = temp_dim_val[1,1] + @test y[1, TimestepIndex(1)] == temp_dim_val[1,1] + reset_time_val(y, time_dim_val) + + @test y[1, TimestepValue(2000)] == time_dim_val[1,1] + @test y[2, TimestepValue(2000)] == time_dim_val[2,1] + @test y[1, TimestepValue(2000; offset = 1)] == time_dim_val[1,2] + @test y[1, TimestepValue(2000) + 1] == time_dim_val[1,2] + @test y[1, TimestepValue(2005)] == time_dim_val[1,2] + @test_throws ErrorException y[1, TimestepValue(2006)] + @test_throws ErrorException y[1, TimestepValue(2005)+1] + + y[1, TimestepValue(2005)] = temp_dim_val[1,2] + @test y[1, TimestepValue(2005)] == temp_dim_val[1,2] + reset_time_val(y, time_dim_val) + end -y[t3, 1] = 10 -@test y[t3,1] == 10 + # AbstractTimestep Indexing + t = VariableTimestep{Tuple([2005:5:2010; 2015:10:3000])}() + if ti == 1 + @test hasvalue(y, t, time_dim_val[1]) + @test !hasvalue(y, VariableTimestep{years}(10)) + @test y[t,1] == time_dim_val[2,1] + @test y[t,2] == time_dim_val[2,2] + + t2 = next_timestep(t) + @test y[t2,1] == time_dim_val[3,1] + @test y[t2,2] == time_dim_val[3,2] + y[t2, 1] = temp_dim_val[3,1] + @test y[t2, 1] == temp_dim_val[3,1] + reset_time_val(y, time_dim_val) + + t3 = VariableTimestep{years}() + @test y[t3, 1] == time_dim_val[1,1] + @test y[t3, 2] == time_dim_val[1,2] + y[t3, 1] = temp_dim_val[1,1] + @test y[t3,1] == temp_dim_val[1,1] + reset_time_val(y, time_dim_val) + + else + @test hasvalue(y, t, time_dim_val[1]) + @test !hasvalue(y, VariableTimestep{years}(10)) + @test y[1,t] == time_dim_val[1,2] + @test y[2,t] == time_dim_val[2,2] + + t3 = VariableTimestep{years}() + @test y[1, t3] == time_dim_val[1,1] + @test y[2, t3] == time_dim_val[2,1] + y[1,t3] = temp_dim_val[1,1] + @test y[1,t3] == temp_dim_val[1,1] + reset_time_val(y, time_dim_val) + end -# Deprecated int indexing should still run -@test y[1,2] == a[:,1:2][1,2] + # Deprecated int indexing should still run + @test y[1,2] == time_dim_val[1,2] + y[1,2] = temp_dim_val[1,2] + @test y[1,2] == temp_dim_val[1,2] + reset_time_val(y, time_dim_val) +end #------------------------------------------------------------------------------ -# 5. Test TimestepArray methods +# 5. Test TimestepArray methods (3 dimensional) #------------------------------------------------------------------------------ -# 3 dimensional array -years = Tuple([2000:5:2005; 2015:10:2025]) -data = collect(reshape(1:64, 4, 4, 4)) -arr_fixed = TimestepArray{FixedTimestep{2000, 5}, Int, 3, 1}(data) -arr_variable = TimestepArray{VariableTimestep{years}, Int, 3, 1}(data) - -# Using a colon in the time dimension -vals2d = fill(100,4) -vals3d = fill(200,4,4) -@test arr_fixed[:,1,1] == arr_variable[:,1,1] == data[:,1,1] -@test arr_fixed[:,2,3] == arr_variable[:,2,3] == data[:,2,3] -arr_fixed[:,1,1] = vals2d -arr_variable[:,1,1] = vals2d -@test arr_fixed[:,1,1] == arr_variable[:,1,1] == vals2d -arr_fixed[:,:,2] = vals3d -arr_variable[:,:,2] = vals3d -@test arr_fixed[:,:,2] == arr_variable[:,:,2] == vals3d - -data = collect(reshape(1:64, 4, 4, 4)) -arr_fixed[:,:,:] = data # reset -arr_variable[:,:,:] = data # reset - -# Indexing with single TimestepIndex -@test arr_fixed[TimestepIndex(1), 1, 1] == 1 -@test arr_fixed[TimestepIndex(3), 3, 3] == 43 -@test arr_variable[TimestepIndex(1), 1, 1] == 1 -@test arr_variable[TimestepIndex(3), 3, 3] == 43 - -arr_fixed[TimestepIndex(1), 1, 1] = 101 -arr_variable[TimestepIndex(1), 1, 1] = 101 -@test arr_fixed[TimestepIndex(1), 1, 1] == 101 -@test arr_variable[TimestepIndex(1), 1, 1] == 101 -arr_fixed[TimestepIndex(1), 1, 1] = 1 # reset -arr_variable[TimestepIndex(1), 1, 1] = 1 # reset - -@test_throws ErrorException arr_fixed[TimestepIndex(1)] -@test_throws ErrorException arr_variable[TimestepIndex(1)] - -# Indexing with Array{TimestepIndex, N} -@test arr_fixed[TimestepIndex.([1,3]), 1, 1] == [1, 3] -@test arr_variable[TimestepIndex.([2,4]), 1, 1] == [2,4] - -# Indexing with Array{TimestepIndex, N} created by Colon syntax -@test arr_fixed[TimestepIndex(1):TimestepIndex(3), 1, 1] == [1,2,3] -@test arr_fixed[TimestepIndex(1):2:TimestepIndex(3), 1, 1] == [1,3] - -# Indexing with single TimestepValue -@test arr_fixed[TimestepValue(2000), 1, 1] == 1 -@test arr_fixed[TimestepValue(2010), 3, 3] == 43 -@test arr_variable[TimestepValue(2000), 1, 1] == 1 -@test arr_variable[TimestepValue(2015), 3, 3] == 43 - -arr_fixed[TimestepValue(2000), 1, 1] = 101 -arr_variable[TimestepValue(2000), 1, 1] = 101 -@test arr_fixed[TimestepValue(2000), 1, 1] == 101 -@test arr_variable[TimestepValue(2000), 1, 1] == 101 -arr_fixed[TimestepValue(2000), 1, 1] = 1 # reset -arr_variable[TimestepValue(2000), 1, 1] = 1 # reset - -@test_throws ErrorException arr_fixed[TimestepValue(2000)] -@test_throws ErrorException arr_variable[TimestepValue(2000)] - -# Indexing with Array{TimestepValue, N} -@test arr_fixed[TimestepValue.([2000, 2010]), 1, 1] == [1, 3] -@test arr_variable[TimestepValue.([2000, 2005, 2025]), 1, 1] == [1, 2,4] +for ti = 1:2 + + years = Tuple([2000:5:2005; 2015:10:2025]) + arr_fixed = TimestepArray{FixedTimestep{2000, 5}, Int, 3, ti}(collect(reshape(1:64, 4, 4, 4))) + arr_variable = TimestepArray{VariableTimestep{years}, Int, 3, ti}(collect(reshape(1:64, 4, 4, 4))) + + time_dim_val = collect(reshape(1:64, 4, 4, 4)) + temp_dim_val = collect(reshape(100:163, 4, 4, 4)) + + # Using a colon in the time dimension + @test arr_fixed[:,1,1] == arr_variable[:,1,1] == time_dim_val[:,1,1] + @test arr_fixed[:,2,3] == arr_variable[:,2,3] == time_dim_val[:,2,3] + arr_fixed[:,1,1] = temp_dim_val[:,1,1] + arr_variable[:,1,1] = temp_dim_val[:,1,1] + @test arr_fixed[:,1,1] == arr_variable[:,1,1] == temp_dim_val[:,1,1] + arr_fixed[:,:,2] = temp_dim_val[:,:,2] + arr_variable[:,:,2] = temp_dim_val[:,:,2] + @test arr_fixed[:,:,2] == arr_variable[:,:,2] == temp_dim_val[:,:,2] + arr_fixed[:,:,:] = temp_dim_val + arr_variable[:,:,:] = temp_dim_val + @test arr_fixed[:,:,:] == arr_variable[:,:,:] == temp_dim_val[:,:,:] + + reset_time_val(arr_fixed, time_dim_val) + reset_time_val(arr_variable, time_dim_val) + + @test_throws ErrorException arr_fixed[TimestepValue(2000)] + @test_throws ErrorException arr_variable[TimestepValue(2000)] + + # Indexing with single TimestepIndex + if ti == 1 + @test arr_fixed[TimestepIndex(1), 1, 1] == arr_variable[TimestepIndex(1), 1, 1] == time_dim_val[1,1,1] + @test arr_fixed[TimestepIndex(3), 3, 3] == arr_variable[TimestepIndex(3), 3, 3] == time_dim_val[3,3,3] + + arr_fixed[TimestepIndex(1), 1, 1] = temp_dim_val[1,1,1] + arr_variable[TimestepIndex(1), 1, 1] = temp_dim_val[1,1,1] + @test arr_fixed[TimestepIndex(1), 1, 1] == arr_variable[TimestepIndex(1), 1, 1] == temp_dim_val[1,1,1] + reset_time_val(arr_fixed, time_dim_val) + reset_time_val(arr_variable, time_dim_val) + + @test_throws ErrorException arr_fixed[TimestepIndex(1)] + @test_throws ErrorException arr_variable[TimestepIndex(1)] + + # Indexing with Array{TimestepIndex, N} + @test arr_fixed[TimestepIndex.([1,3]), 1, 1] == time_dim_val[[1,3], 1, 1] + @test arr_variable[TimestepIndex.([2,4]), 1, 1] == time_dim_val[[2,4], 1, 1] + + # Indexing with Array{TimestepIndex, N} created by Colon syntax + @test arr_fixed[TimestepIndex(1):TimestepIndex(3), 1, 1] == time_dim_val[[1:3...], 1, 1] + @test arr_fixed[TimestepIndex(1):2:TimestepIndex(3), 1, 1] == time_dim_val[[1:2:3...], 1, 1] + + # Indexing with single TimestepValue + @test arr_fixed[TimestepValue(2000), 1, 1] == arr_variable[TimestepValue(2000), 1, 1] == time_dim_val[1,1,1] + @test arr_fixed[TimestepValue(2010), 3, 3] == arr_variable[TimestepValue(2015), 3, 3] == time_dim_val[3,3,3] + + arr_fixed[TimestepValue(2000), 1, 1] = time_dim_val[1,1,1] + arr_variable[TimestepValue(2000), 1, 1] = time_dim_val[1,1,1] + @test arr_fixed[TimestepValue(2000), 1, 1] == arr_variable[TimestepValue(2000), 1, 1] == time_dim_val[1,1,1] + reset_time_val(arr_fixed, time_dim_val) + reset_time_val(arr_variable, time_dim_val) + + # Indexing with Array{TimestepValue, N} + @test arr_fixed[TimestepValue.([2000, 2010]), 1, 1] == time_dim_val[[1,3],1,1] + @test arr_variable[TimestepValue.([2000, 2005, 2025]), 1, 1] == time_dim_val[[1,2,4],1,1] + + else + + @test arr_fixed[1, TimestepIndex(1), 1] == arr_variable[1, TimestepIndex(1), 1] == time_dim_val[1,1,1] + @test arr_fixed[3, TimestepIndex(3), 3] == arr_variable[3, TimestepIndex(3), 3] == time_dim_val[3,3,3] + + arr_fixed[1, TimestepIndex(1), 1] = temp_dim_val[1,1,1] + arr_variable[1, TimestepIndex(1), 1] = temp_dim_val[1,1,1] + @test arr_fixed[1, TimestepIndex(1), 1] == arr_variable[1, TimestepIndex(1), 1] == temp_dim_val[1,1,1] + reset_time_val(arr_fixed, time_dim_val) + reset_time_val(arr_variable, time_dim_val) + + # Indexing with Array{TimestepIndex, N} + @test arr_fixed[1, TimestepIndex.([1,3]), 1] == time_dim_val[1, [1,3], 1] + @test arr_variable[1, TimestepIndex.([2,4]), 1] == time_dim_val[1, [2,4], 1] + + # Indexing with Array{TimestepIndex, N} created by Colon syntax + @test arr_fixed[1, TimestepIndex(1):TimestepIndex(3), 1] == time_dim_val[1, [1:3...], 1] + @test arr_fixed[1, TimestepIndex(1):2:TimestepIndex(3), 1] == time_dim_val[1, [1:2:3...], 1] + + # Indexing with single TimestepValue + @test arr_fixed[1, TimestepValue(2000), 1] == arr_variable[1, TimestepValue(2000), 1] == time_dim_val[1,1,1] + @test arr_fixed[3, TimestepValue(2010), 3] == arr_variable[3, TimestepValue(2015), 3] == time_dim_val[3,3,3] + + arr_fixed[1, TimestepValue(2000), 1] = temp_dim_val[1,1,1] + arr_variable[1, TimestepValue(2000), 1] = temp_dim_val[1,1,1] + @test arr_fixed[1, TimestepValue(2000), 1] == arr_variable[1, TimestepValue(2000), 1] == temp_dim_val[1,1,1] + reset_time_val(arr_fixed, time_dim_val) + reset_time_val(arr_variable, time_dim_val) + + # Indexing with Array{TimestepValue, N} + @test arr_fixed[1, TimestepValue.([2000, 2010]), 1] == time_dim_val[1, [1,3],1] + @test arr_variable[1, TimestepValue.([2000, 2005, 2025]), 1] == time_dim_val[1,[1,2,4],1] + end +end # other methods +time_dim_val = collect(reshape(1:64, 4, 4, 4)) + x_years = Tuple(2000:5:2015) #fixed y_years = Tuple([2000:5:2005; 2015:10:2025]) #variable -x_vec = TimestepVector{FixedTimestep{2000, 5}, Int}(a[:,3]) -x_mat = TimestepMatrix{FixedTimestep{2000, 5}, Int, 1}(a[:,1:2]) -y_vec = TimestepVector{VariableTimestep{y_years}, Int}(a[:,3]) -y_mat = TimestepMatrix{VariableTimestep{y_years}, Int, 1}(a[:,1:2]) +x_vec = TimestepVector{FixedTimestep{2000, 5}, Int}(time_dim_val[:,1,1]) +x_mat = TimestepMatrix{FixedTimestep{2000, 5}, Int, 1}(time_dim_val[:,:,1]) +y_vec = TimestepVector{VariableTimestep{y_years}, Int}(time_dim_val[:,2,2]) +y_mat = TimestepMatrix{VariableTimestep{y_years}, Int, 1}(time_dim_val[:,:,2]) @test first_period(x_vec) == first_period(x_mat) == x_years[1] @test first_period(y_vec) == first_period(y_mat) == y_years[1] @test last_period(x_vec) == last_period(x_mat) == x_years[end] @test last_period(y_vec) == last_period(y_mat) == y_years[end] -@test size(x) == size(a[:,3]) -@test size(y) == size(a[:,1:2]) -@test size(y,2) == size(a[:,1:2],2) - -@test ndims(x) == 1 -@test ndims(y) == 2 +@test size(x_vec) == size(y_vec) == (4,) +@test size(x_mat) == size(y_mat) == (4,4) -@test eltype(x) == eltype(a) -@test eltype(y) == eltype(a) +@test ndims(x_vec) == ndims(y_vec) == 1 +@test ndims(x_mat) == ndims(y_mat) == 2 -fill!(x, 2) -fill!(y, 2) -@test x.data == fill(2, (4)) -@test y.data == fill(2, (4, 2)) +@test eltype(x_vec) == eltype(y_vec) == eltype(y_vec) == eltype(y_mat) == eltype(time_dim_val) #------------------------------------------------------------------------------ # 6. Test that getindex for TimestepArrays doesn't allow access to `missing` From 417869d7d2471f0263240b408b562f9b16d8dbb2 Mon Sep 17 00:00:00 2001 From: lrennels Date: Thu, 31 Oct 2019 23:28:02 -0700 Subject: [PATCH 31/31] Add tests to improve coverage --- src/core/time_arrays.jl | 15 +-------------- test/test_timesteparrays.jl | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index 55615d3a1..9b91c10af 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -568,7 +568,7 @@ function Base.getindex(arr::TimestepArray{TS, T, N, ti}, idxs::Union{Array{Times return arr.data[idxs1..., ts_idxs, idxs2...] end -function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T_time, N, ti}, idxs::Union{Array{TimestepValue{T_data},1}, AnyIndex}...) where {T_time, N, ti, FIRST, STEP, T_data} +function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T_data, N, ti}, idxs::Union{Array{TimestepValue{T_time},1}, AnyIndex}...) where {T_data, N, ti, FIRST, STEP, T_time} idxs1, ts_array, idxs2 = split_indices(idxs, ti) LAST = FIRST + ((length(arr.data)-1) * STEP) ts_idxs = _get_ts_indices(ts_array, [FIRST:STEP:LAST...]) @@ -600,19 +600,6 @@ function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T_data, N, t setindex!(arr.data, vals, idxs1..., ts_idxs, idxs2...) end -# int indexing version supports old-style components and internal functions, not -# part of the public API; first index is Int or Range, rather than a Timestep - -function Base.getindex(arr::TimestepArray{TS, T, N, ti}, idx1::AnyIndex_NonColon, idx2::AnyIndex_NonColon, idxs::AnyIndex_NonColon...) where {TS, T, N, ti} - _throw_int_getindex_depwarning() - return arr.data[idx1, idx2, idxs...] -end - -function Base.setindex!(arr::TimestepArray{TS, T, N, ti}, val, idx1::AnyIndex_NonColon, idx2::AnyIndex_NonColon, idxs::AnyIndex_NonColon...) where {TS, T, N, ti} - _throw_int_setindex_depwarning() - setindex!(arr.data, val, idx1, idx2, idxs...) -end - """ hasvalue(arr::TimestepArray, ts::FixedTimestep) diff --git a/test/test_timesteparrays.jl b/test/test_timesteparrays.jl index c93a06cd8..2f3f437f2 100644 --- a/test/test_timesteparrays.jl +++ b/test/test_timesteparrays.jl @@ -507,6 +507,14 @@ for ti = 1:2 @test arr_fixed[TimestepValue.([2000, 2010]), 1, 1] == time_dim_val[[1,3],1,1] @test arr_variable[TimestepValue.([2000, 2005, 2025]), 1, 1] == time_dim_val[[1,2,4],1,1] + arr_fixed[TimestepValue.([2000, 2010]), 1, 1] = temp_dim_val[[1,3],1,1] + arr_variable[TimestepValue.([2000, 2005, 2025]), 1, 1] = temp_dim_val[[1,2,4],1,1] + @test arr_fixed[TimestepValue.([2000, 2010]), 1, 1] == temp_dim_val[[1,3],1,1] + @test arr_variable[TimestepValue.([2000, 2005, 2025]), 1, 1] == temp_dim_val[[1,2,4],1,1] + + reset_time_val(arr_fixed, time_dim_val) + reset_time_val(arr_variable, time_dim_val) + else @test arr_fixed[1, TimestepIndex(1), 1] == arr_variable[1, TimestepIndex(1), 1] == time_dim_val[1,1,1] @@ -539,7 +547,24 @@ for ti = 1:2 # Indexing with Array{TimestepValue, N} @test arr_fixed[1, TimestepValue.([2000, 2010]), 1] == time_dim_val[1, [1,3],1] @test arr_variable[1, TimestepValue.([2000, 2005, 2025]), 1] == time_dim_val[1,[1,2,4],1] + arr_fixed[1, TimestepValue.([2000, 2010]), 1] = temp_dim_val[1, [1,3],1] + arr_variable[1, TimestepValue.([2000, 2005, 2025]), 1] = temp_dim_val[1,[1,2,4],1] + @test arr_fixed[1, TimestepValue.([2000, 2010]), 1] == temp_dim_val[1, [1,3],1] + @test arr_variable[1, TimestepValue.([2000, 2005, 2025]), 1] == temp_dim_val[1,[1,2,4],1] + + reset_time_val(arr_fixed, time_dim_val) + reset_time_val(arr_variable, time_dim_val) end + + # Deprecated int indexing should still run + @test arr_fixed[1,2,3] == time_dim_val[1,2,3] + @test arr_variable[1,2,3] == time_dim_val[1,2,3] + arr_fixed[1,2,3] = temp_dim_val[1,2,3] + arr_variable[1,2,3] = temp_dim_val[1,2,3] + @test arr_fixed[1,2,3] == arr_variable[1,2,3] == temp_dim_val[1,2,3] + + reset_time_val(arr_fixed, time_dim_val) + reset_time_val(arr_variable, time_dim_val) end # other methods