I have a package that works fine. First all my types and function were hard-coded to Float64
. Then I evolved into parameterizing everything to {T <: AbstractFloat}
. Now I’m looking into allowing for Unitful units, but I’m stumped on how to best do this.
It would be great if there was some simple way of making everything unit-friendly while retaining the concreteness of the types/functions. How do you people do it?
As an example, here is how my Ray type looks like now:
using LinearAlgebra, StaticArrays
mutable struct Ray{T <: AbstractFloat}
origin::SVector{3, T}
direction::SVector{3, T}
intensity::T
Ray(o::SVector{3, T}, d::SVector{3, T}) where {T <: AbstractFloat} = new{T}(o, normalize(d), one(T))
end
While its origin can be unitful, its direction shouldn’t, and its intensity can remain unitless (though that too could get upgraded to a unitful representation).
julia> Ray(SVector(1.0, 2.0, 3.0), SVector(1.0, 2.0., 3.0))
Ray{Float64}([1.0, 2.0, 3.0], [0.267261, 0.534522, 0.801784], 1.0)
You can see how currently this won’t work with units:
julia> using Unitful
julia> import Unitful: μm
julia> Ray(SVector(1.0μm, 2.0μm, 3.0μm), SVector(1.0μm, 2.0μm, 3.0μm))
ERROR: MethodError: no method matching Ray(::SArray{Tuple{3},Quantity{Float64,Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)},Unitful.FreeUnits{(Unitful.Unit{:Meter,Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}}(-6, 1//1),),Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}}},1,3}, ::SArray{Tuple{3},Quantity{Float64,Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)},Unitful.FreeUnits{(Unitful.Unit{:Meter,Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}}(-6, 1//1),),Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}}},1,3})