diff --git a/src/components/connector.jl b/src/components/connector.jl index ce723ce74..10f3435b9 100644 --- a/src/components/connector.jl +++ b/src/components/connector.jl @@ -10,10 +10,13 @@ using Mimi function run_timestep(p, v, d, ts) if gettime(ts) >= p.first && gettime(ts) <= p.last - v.output[ts] = p.input1[ts] + input = p.input1 else - v.output[ts] = p.input2[ts] + input = p.input2 end + + v.output[ts] = @allow_missing(input[ts]) + end end @@ -28,10 +31,15 @@ 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, :] = p.input1[ts, :] + + if gettime(ts) >= p.first && gettime(ts) <= p.last + input = p.input1 else - v.output[ts, :] = p.input2[ts, :] + input = p.input2 + end + + for r in d.regions + v.output[ts, r] = @allow_missing(input[ts, r]) 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) diff --git a/src/core/time.jl b/src/core/time.jl index 6144f324d..3042ca393 100644 --- a/src/core/time.jl +++ b/src/core/time.jl @@ -180,46 +180,57 @@ const AnyIndex = Union{Int, Vector{Int}, Tuple, Colon, OrdinalRange} # TBD: can it be reduced to this? # const AnyIndex = Union{Int, AbstractRange} +# Helper function for getindex; throws a MissingException if data is missing, otherwise returns data +function _missing_data_check(data) + if data === missing + 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 + +# Helper macro used by connector +macro allow_missing(expr) + let e = gensym("e") + retexpr = quote + try + $expr + catch $e + if $e isa MissingException + missing + else + rethrow($e) + end + 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] - 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{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 +285,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