Skip to content

Commit

Permalink
avoid broadcasting to improving performance
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexander-Barth committed Mar 19, 2020
1 parent fd9cdcb commit 317bc9a
Showing 1 changed file with 41 additions and 22 deletions.
63 changes: 41 additions & 22 deletions src/cfvariable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ time_factor(v::CFVariable) = v._storage_attrib.time_factor



# fillvaue can be NaN (unfortunately)
# fillvalue can be NaN (unfortunately)
@inline isfillvalue(data,fillvalue) = data == fillvalue
@inline isfillvalue(data,fillvalue::AbstractFloat) = (isnan(fillvalue) ? isnan(data) : data == fillvalue)

Expand Down Expand Up @@ -421,13 +421,20 @@ time_factor(v::CFVariable) = v._storage_attrib.time_factor
return asdate(CFtransform_offset(CFtransform_scale(CFtransform_missing(data,fv),scale_factor),add_offset),time_origin,time_factor,DTcast)
end

# round float to integers
_approximate(::Type{T},data) where T <: Integer = round(T,data)
_approximate(::Type,data) = data

@inline function CFinvtransform(data,fv,inv_scale_factor,minus_offset,time_origin,inv_time_factor,DTcast)
# return asdate(CFtransform_offset(CFtransform_scale(CFtransform_missing(data,fv),scale_factor),add_offset),time_origin,time_factor,DTcast)
return CFtransform_replace_missing(CFtransform_scale(CFtransform_offset(data,minus_offset),inv_scale_factor),fv)

@inline function CFinvtransform(data,fv,inv_scale_factor,minus_offset,time_origin,inv_time_factor,DT)
return _approximate(DT,CFtransform_replace_missing(
CFtransform_scale(CFtransform_offset(data,minus_offset),
inv_scale_factor),fv))
end


# this is really slow
# https://github.com/JuliaLang/julia/issues/28126
#@inline CFtransformdata(data,fv,scale_factor,add_offset,time_origin,time_factor,DTcast) =
# # in boardcasting we trust..., or not
# CFtransform.(data,fv,scale_factor,add_offset,time_origin,time_factor,DTcast)
Expand All @@ -448,19 +455,43 @@ end
# this function is necessary to avoid "iterating" over a single character in Julia 1.0 (fixed Julia 1.3)
# https://discourse.julialang.org/t/broadcasting-and-single-characters/16836
@inline CFtransformdata(data::Char,fv,scale_factor,add_offset,time_origin,time_factor,DTcast) = data
@inline CFinvtransformdata(data::Char,fv,scale_factor,add_offset,time_origin,time_factor,DTcast) = data
@inline CFinvtransformdata(data::Char,fv,scale_factor,add_offset,time_origin,time_factor,DT) = data


@inline _inv(x::Nothing) = nothing
@inline _inv(x) = 1/x
@inline _minus(x::Nothing) = nothing
@inline _minus(x) = -x

@inline function CFinvtransformdata(data,fv,scale_factor,add_offset,time_origin,time_factor,DTcast)

# # so slow
# @inline function CFinvtransformdata(data,fv,scale_factor,add_offset,time_origin,time_factor,DT)
# inv_scale_factor = _inv(scale_factor)
# minus_offset = _minus(add_offset)
# inv_time_factor = _inv(time_factor)
# return CFinvtransform.(data,fv,inv_scale_factor,minus_offset,time_origin,inv_time_factor,DT)
# end

# for arrays
@inline function CFinvtransformdata(data::AbstractArray{T,N},fv,scale_factor,add_offset,time_origin,time_factor,DT) where {T,N}
inv_scale_factor = _inv(scale_factor)
minus_offset = _minus(add_offset)
inv_time_factor = _inv(time_factor)

out = Array{DT,N}(undef,size(data))
@inbounds @simd for i in eachindex(data)
out[i] = CFinvtransform(data[i],fv,inv_scale_factor,minus_offset,time_origin,inv_time_factor,DT)
end
return out
end

# for scalar
@inline function CFinvtransformdata(data,fv,scale_factor,add_offset,time_origin,time_factor,DT)
inv_scale_factor = _inv(scale_factor)
minus_offset = _minus(add_offset)
inv_time_factor = _inv(time_factor)
return CFinvtransform.(data,fv,inv_scale_factor,minus_offset,time_origin,inv_time_factor,DTcast)

return CFinvtransform(data,fv,inv_scale_factor,minus_offset,time_origin,inv_time_factor,DT)
end

function Base.getindex(v::CFVariable,
Expand Down Expand Up @@ -492,32 +523,20 @@ function Base.setindex!(v::CFVariable,data::Union{T,Array{T,N}},indexes::Union{I
throw(NetCDFError(-1, "Time units and calendar must be defined during defVar and cannot change"))
end

# round float to integers
_approximate(::Type{T},data) where T <: Integer = round(T,data)
_approximate(::Type,data) = data

function Base.setindex!(v::CFVariable,data,indexes::Union{Int,Colon,UnitRange{Int},StepRange{Int,Int}}...)
tmp = CFinvtransformdata(
v.var[indexes...] = CFinvtransformdata(
data,fillvalue(v),scale_factor(v),add_offset(v),
time_origin(v),time_factor(v),eltype(v))

# https://discourse.julialang.org/t/broadcasting-and-single-characters/16836
@static if VERSION < v"1.1"
_approximatedata(T,x) = _approximate.(T,x)
_approximatedata(T,x::Char) = x
time_origin(v),time_factor(v),eltype(v.var))

v.var[indexes...] = _approximatedata(eltype(v.var),tmp)
else
v.var[indexes...] = _approximate.(eltype(v.var),tmp)
end
return data
end

############################################################
# Convertion to array
############################################################
Base.Array(v::Union{CFVariable{T,N},Variable{T,N}}) where {T,N} = v[ntuple(i -> :, Val(N))...]

Base.Array(v::Union{CFVariable{T,N},Variable{T,N}}) where {T,N} = v[ntuple(i -> :, Val(N))...]

Base.show(io::IO,v::CFVariable; indent="") = Base.show(io::IO,v.var; indent=indent)

Expand Down

0 comments on commit 317bc9a

Please sign in to comment.