Skip to content

Commit cc9694c

Browse files
authored
Merge branch 'main' into safe-precompile
2 parents 689a723 + 09a43cc commit cc9694c

File tree

10 files changed

+153
-23
lines changed

10 files changed

+153
-23
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "DynamicQuantities"
22
uuid = "06fc5a27-2a28-4c7c-a15d-362465fb6821"
33
authors = ["MilesCranmer <[email protected]> and contributors"]
4-
version = "0.7.3"
4+
version = "0.7.5"
55

66
[deps]
77
Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,10 @@ julia> q^2
187187
```
188188

189189
You can convert to regular SI base units with
190-
`expand_units`:
190+
`uexpand`:
191191

192192
```julia
193-
julia> expand_units(q^2)
193+
julia> uexpand(q^2)
194194
1.0e6 kg² s⁻⁴
195195
```
196196

@@ -203,10 +203,16 @@ julia> x = us"Constants.c * Hz"
203203
julia> x^2
204204
1.0 Hz² c²
205205

206-
julia> expand_units(x^2)
206+
julia> uexpand(x^2)
207207
8.987551787368176e16 m² s⁻⁴
208208
```
209209

210+
You can also convert a quantity in regular base SI units to symbolic units with `uconvert`:
211+
```julia
212+
julia> uconvert(us"nm", 5e-9u"m") # can also write 5e-9u"m" |> uconvert(us"nm")
213+
5.0 nm
214+
```
215+
210216
### Arrays
211217

212218
For working with an array of quantities that have the same dimensions,

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ makedocs(;
3939
),
4040
pages=[
4141
"Home" => "index.md",
42+
"Examples" => "examples.md",
4243
"Utilities" => "api.md",
4344
"Units" => "units.md",
4445
"Constants" => "constants.md",

docs/src/examples.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Toy Examples with Code
2+
3+
## 1. Solving a Chemistry Homework Problem
4+
5+
On your chemistry homework, you are faced with the following problem on the photoelectric effect[^1]:
6+
7+
[^1]: Attribution: [MIT OCW](https://ocw.mit.edu/courses/5-111sc-principles-of-chemical-science-fall-2014/resources/mit5_111f14_lec04soln/)
8+
9+
> In a photoelectric effect experiment, electrons are ejected from a titanium surface (work function ``\Phi = 4.33\mathrm{eV}``) following irradition with UV light.
10+
> The energy of the incident UV light is ``7.2 \cdot 10^{-19} \mathrm{J}`` per photon. Calculate the wavelength of the ejected electrons, in nanometers.
11+
12+
Let's solve this problem with `DynamicQuantities.jl`!
13+
```jldoctest examples
14+
julia> using DynamicQuantities
15+
16+
julia> using DynamicQuantities.Constants: h, m_e
17+
18+
julia> Φ = 4.33u"Constants.eV" # work function
19+
6.93742482522e-19 m² kg s⁻²
20+
21+
julia> E = 7.2e-19u"J" # incident energy
22+
7.2e-19 m² kg s⁻²
23+
24+
julia> p = sqrt(2 * m_e * (E - Φ)) # momentum of ejected electrons
25+
2.1871890716439906e-25 m kg s⁻¹
26+
27+
julia> λ = h / p # wavelength of ejected electrons
28+
3.029491247878056e-9 m
29+
30+
julia> uconvert(us"nm", λ) # return answer in nanometers
31+
3.0294912478780556 nm
32+
```
33+
Since units are automatically propagated, we can verify the dimension of our answer and all intermediates.
34+
Also, using `DynamicQuantities.Constants`, we were able to obtain the (dimensionful!) values of all necessary constants without typing them ourselves.
35+

docs/src/symbolic_units.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,14 @@ units are `sym_uparse` and `us_str`:
1414
sym_uparse
1515
```
1616

17-
To convert a quantity to its regular base SI units, use `expand_units`:
17+
To convert a quantity to its regular base SI units, use `uexpand`:
1818

1919
```@docs
20-
expand_units
20+
uexpand
21+
```
22+
23+
To convert a quantity in regular base SI units to corresponding symbolic units, use `uconvert`:
24+
25+
```@docs
26+
uconvert
2127
```

src/DynamicQuantities.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export AbstractQuantity, AbstractDimensions
55
export Quantity, Dimensions, SymbolicDimensions, QuantityArray, DimensionError
66
export ustrip, dimension
77
export ulength, umass, utime, ucurrent, utemperature, uluminosity, uamount
8-
export uparse, @u_str, sym_uparse, @us_str, expand_units
8+
export uparse, @u_str, sym_uparse, @us_str, uexpand, uconvert
99

1010
include("fixed_rational.jl")
1111
include("types.jl")
@@ -17,6 +17,9 @@ include("constants.jl")
1717
include("uparse.jl")
1818
include("symbolic_dimensions.jl")
1919

20+
include("deprecated.jl")
21+
export expand_units
22+
2023
import PackageExtensionCompat: @require_extensions
2124
import .Units
2225
import .Constants

src/deprecated.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Base.@deprecate expand_units(q) uexpand(q)

src/symbolic_dimensions.jl

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ are so many unit symbols).
3232
3333
You can convert a quantity using `SymbolicDimensions` as its dimensions
3434
to one which uses `Dimensions` as its dimensions (i.e., base SI units)
35-
`expand_units`.
35+
`uexpand`.
3636
"""
3737
struct SymbolicDimensions{R} <: AbstractDimensions{R}
3838
nzdims::Vector{INDEX_TYPE}
@@ -94,17 +94,51 @@ function Base.convert(::Type{Quantity{T,D}}, q::Quantity{<:Any,<:SymbolicDimensi
9494
end
9595

9696
"""
97-
expand_units(q::Quantity{<:Any,<:SymbolicDimensions})
97+
uexpand(q::Quantity{<:Any,<:SymbolicDimensions})
9898
9999
Expand the symbolic units in a quantity to their base SI form.
100100
In other words, this converts a `Quantity` with `SymbolicDimensions`
101-
to one with `Dimensions`.
101+
to one with `Dimensions`. The opposite of this function is `uconvert`,
102+
for converting to specific symbolic units, or `convert(Quantity{<:Any,<:SymbolicDimensions}, q)`,
103+
for assuming SI units as the output symbols.
102104
"""
103-
function expand_units(q::Q) where {T,R,D<:SymbolicDimensions{R},Q<:AbstractQuantity{T,D}}
105+
function uexpand(q::Q) where {T,R,D<:SymbolicDimensions{R},Q<:AbstractQuantity{T,D}}
104106
return convert(constructor_of(Q){T,Dimensions{R}}, q)
105107
end
106-
expand_units(q::QuantityArray) = expand_units.(q)
108+
uexpand(q::QuantityArray) = uexpand.(q)
109+
# TODO: Make the array-based one more efficient
107110

111+
"""
112+
uconvert(qout::AbstractQuantity{<:Any, <:SymbolicDimensions}, q::AbstractQuantity{<:Any, <:Dimensions})
113+
114+
Convert a quantity `q` with base SI units to the symbolic units of `qout`, for `q` and `qout` with compatible units.
115+
Mathematically, the result has value `q / uexpand(qout)` and units `dimension(qout)`.
116+
"""
117+
function uconvert(qout::AbstractQuantity{<:Any, <:SymbolicDimensions}, q::AbstractQuantity{<:Any, <:Dimensions})
118+
@assert isone(ustrip(qout)) "You passed a quantity with a non-unit value to uconvert."
119+
qout_expanded = uexpand(qout)
120+
dimension(q) == dimension(qout_expanded) || throw(DimensionError(q, qout_expanded))
121+
new_val = ustrip(q) / ustrip(qout_expanded)
122+
new_dim = dimension(qout)
123+
return new_quantity(typeof(q), new_val, new_dim)
124+
end
125+
function uconvert(qout::AbstractQuantity{<:Any,<:SymbolicDimensions}, q::QuantityArray{<:Any,<:Any,<:Dimensions})
126+
@assert isone(ustrip(qout)) "You passed a quantity with a non-unit value to uconvert."
127+
qout_expanded = uexpand(qout)
128+
dimension(q) == dimension(qout_expanded) || throw(DimensionError(q, qout_expanded))
129+
new_array = ustrip(q) ./ ustrip(qout_expanded)
130+
new_dim = dimension(qout)
131+
return QuantityArray(new_array, new_dim, quantity_type(q))
132+
end
133+
# TODO: Method for converting SymbolicDimensions -> SymbolicDimensions
134+
135+
"""
136+
uconvert(qout::AbstractQuantity{<:Any, <:SymbolicDimensions})
137+
138+
Create a function that converts an input quantity `q` with base SI units to the symbolic units of `qout`, i.e
139+
a function equivalent to `q -> uconvert(qout, q)`.
140+
"""
141+
uconvert(qout::AbstractQuantity{<:Any, <:SymbolicDimensions}) = Base.Fix1(uconvert, qout)
108142

109143
Base.copy(d::SymbolicDimensions) = SymbolicDimensions(copy(getfield(d, :nzdims)), copy(getfield(d, :nzvals)))
110144
function Base.:(==)(l::SymbolicDimensions, r::SymbolicDimensions)

src/units.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ end
5252
@register_unit mol DEFAULT_QUANTITY_TYPE(1.0, amount=1)
5353

5454
@add_prefixes m (f, p, n, μ, u, c, d, m, k, M, G)
55-
@add_prefixes g (μ, u, m, k)
55+
@add_prefixes g (p, n, μ, u, m, k)
5656
@add_prefixes s (f, p, n, μ, u, m)
5757
@add_prefixes A (n, μ, u, m, k)
5858
@add_prefixes K (m,)
@@ -64,7 +64,7 @@ end
6464
m,
6565
)
6666
@doc(
67-
"Mass in kilograms. Available variants: `μg` (/`ug`), `mg`, `g`.",
67+
"Mass in kilograms. Available variants: `pg`, `ng`, `μg` (/`ug`), `mg`, `g`.",
6868
kg,
6969
)
7070
@doc(

test/unittests.jl

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -545,19 +545,19 @@ end
545545
@test q == 1.5 * us"km" / us"s"
546546
@test typeof(q) <: Quantity{Float64,<:SymbolicDimensions}
547547
@test string(dimension(q)) == "s⁻¹ km"
548-
@test expand_units(q) == 1.5u"km/s"
548+
@test uexpand(q) == 1.5u"km/s"
549549
@test string(dimension(us"Constants.au^1.5")) == "au³ᐟ²"
550-
@test string(dimension(expand_units(us"Constants.au^1.5"))) == "m³ᐟ²"
551-
@test expand_units(2.3us"Constants.au^1.5") 2.3u"Constants.au^1.5"
550+
@test string(dimension(uexpand(us"Constants.au^1.5"))) == "m³ᐟ²"
551+
@test uexpand(2.3us"Constants.au^1.5") 2.3u"Constants.au^1.5"
552552
@test iszero(dimension(us"1.0")) == true
553-
@test expand_units(inv(us"Constants.au")) 1/u"Constants.au"
553+
@test uexpand(inv(us"Constants.au")) 1/u"Constants.au"
554554
@test dimension(inv(us"s") * us"km") == dimension(us"km/s")
555555
@test dimension(inv(us"s") * us"m") != dimension(us"km/s")
556-
@test dimension(expand_units(inv(us"s") * us"m")) == dimension(expand_units(us"km/s"))
556+
@test dimension(uexpand(inv(us"s") * us"m")) == dimension(uexpand(us"km/s"))
557557

558558
f2(i::Int) = us"s"^i
559559
@inferred f2(5)
560-
@test expand_units(f2(5)) == u"s"^5
560+
@test uexpand(f2(5)) == u"s"^5
561561

562562
@test_throws ErrorException sym_uparse("'c'")
563563

@@ -567,7 +567,7 @@ end
567567
@test dimension(us"h")[:h] == 1
568568

569569
@test us"Constants.h" != us"h"
570-
@test expand_units(us"Constants.h") == u"Constants.h"
570+
@test uexpand(us"Constants.h") == u"Constants.h"
571571

572572
# Actually expands to:
573573
@test dimension(us"Constants.h")[:m] == 2
@@ -597,6 +597,50 @@ end
597597
testing=Val(true)
598598
)
599599
)
600+
601+
# Test deprecated method
602+
q = 1.5us"km/s"
603+
@test expand_units(q) == uexpand(q)
604+
end
605+
606+
@testset "uconvert" begin
607+
@test uconvert(us"nm", 5e-9u"m") (5e-9u"m" |> uconvert(us"nm")) 5us"nm"
608+
@test_throws DimensionError uconvert(us"nm * J", 5e-9u"m")
609+
610+
q = 1.5u"Constants.M_sun"
611+
qs = uconvert(us"Constants.M_sun", 5.0 * q)
612+
@test qs 7.5us"Constants.M_sun"
613+
@test dimension(qs)[:kg] == 0
614+
@test dimension(qs)[:g] == 0
615+
@test dimension(qs)[:M_sun] == 1
616+
@test uexpand(qs) 5.0 * q
617+
618+
# Refuses to convert to non-unit quantities:
619+
@test_throws AssertionError uconvert(1.2us"m", 1.0u"m")
620+
VERSION >= v"1.8" &&
621+
@test_throws "You passed a quantity" uconvert(1.2us"m", 1.0u"m")
622+
623+
# Different types require converting both arguments:
624+
q = convert(Quantity{Float16}, 1.5u"g")
625+
qs = uconvert(convert(Quantity{Float16}, us"g"), 5 * q)
626+
@test typeof(qs) <: Quantity{Float16,<:SymbolicDimensions{<:Any}}
627+
@test qs 7.5us"g"
628+
629+
# Arrays
630+
x = [1.0, 2.0, 3.0] .* u"kg"
631+
xs = x .|> uconvert(us"g")
632+
@test typeof(xs) <: Vector{<:Quantity{Float64,<:SymbolicDimensions{<:Any}}}
633+
@test xs[2] 2000us"g"
634+
635+
x_qa = QuantityArray(x)
636+
xs_qa = x_qa .|> uconvert(us"g")
637+
@test typeof(xs_qa) <: QuantityArray{Float64,1,<:SymbolicDimensions{<:Any}}
638+
@test xs_qa[2] 2000us"g"
639+
640+
# Without vectorized call:
641+
xs_qa2 = x_qa |> uconvert(us"g")
642+
@test typeof(xs_qa2) <: QuantityArray{Float64,1,<:SymbolicDimensions{<:Any}}
643+
@test xs_qa2[2] 2000us"g"
600644
end
601645

602646
@testset "Test ambiguities" begin
@@ -854,8 +898,8 @@ end
854898
z_ar = randn(32)
855899
z = QuantityArray(z_ar, us"Constants.h * km/s")
856900
z_expanded = QuantityArray(z_ar .* u"Constants.h * km/s")
857-
@test typeof(expand_units(z)) == typeof(z_expanded)
858-
@test all(expand_units(z) .≈ z_expanded)
901+
@test typeof(uexpand(z)) == typeof(z_expanded)
902+
@test all(uexpand(z) .≈ z_expanded)
859903
io = IOBuffer()
860904
Base.showarg(io, z, true)
861905
msg = String(take!(io))

0 commit comments

Comments
 (0)