-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathDynamicQuantitiesUnitfulExt.jl
74 lines (64 loc) · 3.08 KB
/
DynamicQuantitiesUnitfulExt.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
module DynamicQuantitiesUnitfulExt
using DynamicQuantities: DynamicQuantities, ABSTRACT_QUANTITY_TYPES
import Unitful
import Unitful: @u_str
function get_si_units()
return (length=u"m", mass=u"kg", time=u"s", current=u"A", temperature=u"K", luminosity=u"cd", amount=u"mol")
end
@generated function validate_upreferred()
si_units = get_si_units()
for k in keys(si_units)
if Unitful.upreferred(si_units[k]) !== si_units[k]
return :(error("Found custom `Unitful.preferunits`. This is not supported when interfacing Unitful and DynamicQuantities: you must leave the default `Unitful.upreferred`, which is the SI base units."))
end
end
return true
end
function unitful_equivalences()
si_units = get_si_units()
return NamedTuple((k => si_units[k] for k in keys(si_units)))
end
for (_, _, Q) in ABSTRACT_QUANTITY_TYPES
@eval begin
function Base.convert(::Type{Unitful.Quantity}, x::$Q)
validate_upreferred()
cumulator = DynamicQuantities.ustrip(x)
dims = DynamicQuantities.dimension(x)
if dims isa DynamicQuantities.AbstractSymbolicDimensions
throw(ArgumentError("Conversion of a `DynamicQuantities." * string($Q) * "` to a `Unitful.Quantity` is not defined with dimensions of type `SymbolicDimensions`. Instead, you can first use the `uexpand` function to convert the dimensions to their base SI form of type `Dimensions`, then convert this quantity to a `Unitful.Quantity`."))
end
equiv = unitful_equivalences()
for dim in keys(dims)
value = dims[dim]
iszero(value) && continue
cumulator *= equiv[dim]^value
end
cumulator
end
function Base.convert(::Type{$Q}, x::Unitful.Quantity{T}) where {T}
return convert($Q{T,DynamicQuantities.DEFAULT_DIM_TYPE}, x)
end
function Base.convert(::Type{$Q{T,D}}, x::Unitful.Quantity) where {T,R,D<:DynamicQuantities.AbstractDimensions{R}}
value = Unitful.ustrip(Unitful.upreferred(x))
dimension = convert(D, Unitful.dimension(x))
return $Q(convert(T, value), dimension)
end
end
end
Base.convert(::Type{DynamicQuantities.Dimensions}, d::Unitful.Dimensions) = convert(DynamicQuantities.DEFAULT_DIM_TYPE, d)
function Base.convert(::Type{DynamicQuantities.Dimensions{R}}, d::Unitful.Dimensions{D}) where {R,D}
validate_upreferred()
return prod(Base.Fix1(_dynamic_dimension, R), D; init=DynamicQuantities.Dimensions{R}())
end
function _dynamic_dimension(::Type{R}, dims::Unitful.Dimension{D}) where {R,D}
DimType = DynamicQuantities.Dimensions{R}
D == :Length && return DimType(length=dims.power)
D == :Mass && return DimType(mass=dims.power)
D == :Time && return DimType(time=dims.power)
D == :Current && return DimType(current=dims.power)
D == :Temperature && return DimType(temperature=dims.power)
D == :Luminosity && return DimType(luminosity=dims.power)
D == :Amount && return DimType(amount=dims.power)
error("Unknown dimension: $D")
end
end