From 34f459126a495b5411bf1d42694c27077308165c Mon Sep 17 00:00:00 2001 From: Cora Kingdon Date: Fri, 14 Dec 2018 14:59:43 -0500 Subject: [PATCH 1/4] Support `missing` backup data; disable missing error in connector components --- src/components/connector.jl | 8 ++++---- src/core/connections.jl | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/connector.jl b/src/components/connector.jl index ce723ce74..432fc1601 100644 --- a/src/components/connector.jl +++ b/src/components/connector.jl @@ -10,9 +10,9 @@ using Mimi function run_timestep(p, v, d, ts) if gettime(ts) >= p.first && gettime(ts) <= p.last - v.output[ts] = p.input1[ts] + v.output[ts.t] = p.input1[ts.t] else - v.output[ts] = p.input2[ts] + v.output[ts.t] = p.input2[ts.t] end end end @@ -29,9 +29,9 @@ end function run_timestep(p, v, d, ts) if gettime(ts) >= p.first && gettime(ts) <= p.last - v.output[ts, :] = p.input1[ts, :] + v.output[ts.t, :] = p.input1[ts.t, :] else - v.output[ts, :] = p.input2[ts, :] + v.output[ts.t, :] = p.input2[ts.t, :] end end end diff --git a/src/core/connections.jl b/src/core/connections.jl index d0ff960fe..e9fc5cc23 100644 --- a/src/core/connections.jl +++ b/src/core/connections.jl @@ -125,7 +125,7 @@ function connect_param!(md::ModelDef, dst_param = parameter(dst_comp_def, dst_par_name) dst_dims = dimensions(dst_param) - backup = convert(Array{number_type(md)}, backup) # converts number type and, if it's a NamedArray, it's converted to Array + backup = convert(Array{Union{Missing, number_type(md)}}, backup) # converts number type and, if it's a NamedArray, it's converted to Array first = first_period(md, dst_comp_def) T = eltype(backup) From a5aef1886e130e84431ae9fba38b279a9185daac Mon Sep 17 00:00:00 2001 From: Cora Kingdon Date: Mon, 17 Dec 2018 10:26:55 -0500 Subject: [PATCH 2/4] Use MissingException for missing data check; catch in connector comps --- src/components/connector.jl | 33 +++++++++++++++++++---- src/core/time.jl | 53 +++++++++++-------------------------- test/test_timesteparrays.jl | 2 +- 3 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/components/connector.jl b/src/components/connector.jl index 432fc1601..7bf45c25f 100644 --- a/src/components/connector.jl +++ b/src/components/connector.jl @@ -10,10 +10,20 @@ using Mimi function run_timestep(p, v, d, ts) if gettime(ts) >= p.first && gettime(ts) <= p.last - v.output[ts.t] = p.input1[ts.t] + input = p.input1 else - v.output[ts.t] = p.input2[ts.t] + input = p.input2 end + + try + v.output[ts] = input[ts] + catch e + if e isa MissingException + v.output[ts] = missing + else + rethrow([e]) + end + end end end @@ -28,10 +38,23 @@ end last = Parameter() # last year to use the shorter data function run_timestep(p, v, d, ts) - if gettime(ts) >= p.first && gettime(ts) <= p.last - v.output[ts.t, :] = p.input1[ts.t, :] + + if gettime(ts) >= p.first && gettime(ts) <= p.last + input = p.input1 else - v.output[ts.t, :] = p.input2[ts.t, :] + input = p.input2 + end + + for r in d.regions + try + v.output[ts, r] = input[ts, r] + catch e + if e isa MissingException + v.output[ts, r] = missing + else + rethrow([e]) + end + end end end end diff --git a/src/core/time.jl b/src/core/time.jl index 6144f324d..58b1dd960 100644 --- a/src/core/time.jl +++ b/src/core/time.jl @@ -184,42 +184,35 @@ const AnyIndex = Union{Int, Vector{Int}, Tuple, Colon, OrdinalRange} # 3b. TimestepVector # -function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP}, T}, ts::FixedTimestep{FIRST, STEP, LAST}) where {T, FIRST, STEP, LAST} - data = v.data[ts.t] +# Helper function for getindex; throws a MissingException if data is missing, otherwise returns data +function _missing_data_check(data) if data === missing - error("Cannot get index; data is missing. You may have tried to access a value that has not yet been computed.") + throw(MissingException("Cannot get index; data is missing. You may have tried to access a value that has not yet been computed.")) else return data end +end + +function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP}, T}, ts::FixedTimestep{FIRST, STEP, LAST}) where {T, FIRST, STEP, LAST} + data = v.data[ts.t] + _missing_data_check(data) end function Base.getindex(v::TimestepVector{VariableTimestep{TIMES}, T}, ts::VariableTimestep{TIMES}) where {T, TIMES} data = v.data[ts.t] - if data === missing - error("Cannot get index; data is missing. You may have tried to access a value that has not yet been computed.") - else - return data - end + _missing_data_check(data) end function Base.getindex(v::TimestepVector{FixedTimestep{D_FIRST, STEP}, T}, ts::FixedTimestep{T_FIRST, STEP, LAST}) where {T, D_FIRST, T_FIRST, STEP, LAST} t = Int(ts.t + (T_FIRST - D_FIRST) / STEP) data = v.data[t] - if data === missing - error("Cannot get index; data is missing. You may have tried to access a value that has not yet been computed.") - else - return data - end + _missing_data_check(data) end function Base.getindex(v::TimestepVector{VariableTimestep{D_FIRST}, T}, ts::VariableTimestep{T_FIRST}) where {T, D_FIRST, T_FIRST} t = ts.t + findfirst(isequal(T_FIRST[1]), D_FIRST) - 1 data = v.data[t] - if data === missing - error("Cannot get index; data is missing. You may have tried to access a value that has not yet been computed.") - else - return data - end + _missing_data_check(data) end # int indexing version supports old-style components and internal functions, not @@ -274,40 +267,24 @@ Base.lastindex(v::TimestepVector) = length(v) function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T}, ts::FixedTimestep{FIRST, STEP, LAST}, i::AnyIndex) where {T, FIRST, STEP, LAST} data = mat.data[ts.t, i] - if data === missing - error("Cannot get index; data is missing. You may have tried to access a value that has not yet been computed.") - else - return data - end + _missing_data_check(data) end function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T}, ts::VariableTimestep{TIMES}, i::AnyIndex) where {T, TIMES} data = mat.data[ts.t, i] - if data === missing - error("Cannot get index; data is missing. You may have tried to access a value that has not yet been computed.") - else - return data - end + _missing_data_check(data) end function Base.getindex(mat::TimestepMatrix{FixedTimestep{D_FIRST, STEP}, T}, ts::FixedTimestep{T_FIRST, STEP, LAST}, i::AnyIndex) where {T, D_FIRST, T_FIRST, STEP, LAST} t = Int(ts.t + (T_FIRST - D_FIRST) / STEP) data = mat.data[t, i] - if data === missing - error("Cannot get index; data is missing. You may have tried to access a value that has not yet been computed.") - else - return data - end + _missing_data_check(data) end function Base.getindex(mat::TimestepMatrix{VariableTimestep{D_FIRST}, T}, ts::VariableTimestep{T_FIRST}, i::AnyIndex) where {T, D_FIRST, T_FIRST} t = ts.t + findfirst(isequal(T_FIRST[1]), D_FIRST) - 1 data = mat.data[t, i] - if data === missing - error("Cannot get index; data is missing. You may have tried to access a value that has not yet been computed.") - else - return data - end + _missing_data_check(data) end # int indexing version supports old-style components and internal functions, not diff --git a/test/test_timesteparrays.jl b/test/test_timesteparrays.jl index 18b59e65e..94199af48 100644 --- a/test/test_timesteparrays.jl +++ b/test/test_timesteparrays.jl @@ -243,7 +243,7 @@ add_comp!(m, foo, :second) connect_param!(m, :second=>:par, :first=>:var) set_param!(m, :first, :par, 1:length(years)) -@test_throws ErrorException run(m) +@test_throws MissingException run(m) end #module From 547d87c00267d89f888c997384aaf4d37a229df9 Mon Sep 17 00:00:00 2001 From: Cora Kingdon Date: Mon, 17 Dec 2018 14:04:54 -0500 Subject: [PATCH 3/4] @allow_missing macro --- src/components/connector.jl | 21 +++------------------ src/core/time.jl | 26 ++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/components/connector.jl b/src/components/connector.jl index 7bf45c25f..10f3435b9 100644 --- a/src/components/connector.jl +++ b/src/components/connector.jl @@ -15,15 +15,8 @@ using Mimi input = p.input2 end - try - v.output[ts] = input[ts] - catch e - if e isa MissingException - v.output[ts] = missing - else - rethrow([e]) - end - end + v.output[ts] = @allow_missing(input[ts]) + end end @@ -46,15 +39,7 @@ end end for r in d.regions - try - v.output[ts, r] = input[ts, r] - catch e - if e isa MissingException - v.output[ts, r] = missing - else - rethrow([e]) - end - end + v.output[ts, r] = @allow_missing(input[ts, r]) end end end diff --git a/src/core/time.jl b/src/core/time.jl index 58b1dd960..8e45c3511 100644 --- a/src/core/time.jl +++ b/src/core/time.jl @@ -180,10 +180,6 @@ const AnyIndex = Union{Int, Vector{Int}, Tuple, Colon, OrdinalRange} # TBD: can it be reduced to this? # const AnyIndex = Union{Int, AbstractRange} -# -# 3b. TimestepVector -# - # Helper function for getindex; throws a MissingException if data is missing, otherwise returns data function _missing_data_check(data) if data === missing @@ -193,6 +189,28 @@ function _missing_data_check(data) end end +# Helper macro used by connector +macro allow_missing(expr) + let e = gensym("e") + retexpr = :( + try + return $expr + catch $e + if $e isa MissingException + return missing + else + rethrow($e) + end + end + ) + return esc(retexpr) + end +end + +# +# 3b. TimestepVector +# + function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP}, T}, ts::FixedTimestep{FIRST, STEP, LAST}) where {T, FIRST, STEP, LAST} data = v.data[ts.t] _missing_data_check(data) From 228a7368ad0929a15ffa55cf40012ab1b2e88d70 Mon Sep 17 00:00:00 2001 From: Richard Plevin Date: Mon, 17 Dec 2018 12:37:49 -0800 Subject: [PATCH 4/4] Fixed @allow_missing macro --- src/core/time.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/time.jl b/src/core/time.jl index 8e45c3511..3042ca393 100644 --- a/src/core/time.jl +++ b/src/core/time.jl @@ -192,17 +192,17 @@ end # Helper macro used by connector macro allow_missing(expr) let e = gensym("e") - retexpr = :( + retexpr = quote try - return $expr + $expr catch $e if $e isa MissingException - return missing + missing else rethrow($e) end end - ) + end return esc(retexpr) end end