Skip to content

Commit 1a6ff33

Browse files
committed
Add documentation on symbolic units
1 parent a9f4625 commit 1a6ff33

File tree

4 files changed

+64
-4
lines changed

4 files changed

+64
-4
lines changed

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ makedocs(;
4242
"Utilities" => "api.md",
4343
"Units" => "units.md",
4444
"Constants" => "constants.md",
45+
"Symbolic Units" => "symbolic_units.md",
4546
"Types" => "types.md",
4647
]
4748
)

docs/src/types.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,10 @@ AbstractQuantity
1515
```
1616

1717
Note also that the `Quantity` object can take a custom `AbstractDimensions`
18-
as input, so there is often no need to subtype `AbstractQuantity` separately.
18+
as input, so there is often no need to subtype `AbstractQuantity` separately.
19+
20+
Another type which subtypes `AbstractDimensions` is `SymbolicDimensions`:
21+
22+
```@docs
23+
SymbolicDimensions
24+
```

src/symbolic_dimensions.jl

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ This is to allow for lazily reducing to SI base units, whereas
2929
`Dimensions` is always in SI base units. Furthermore, `SymbolicDimensions`
3030
stores dimensions using a sparse vector for efficiency (since there
3131
are so many unit symbols).
32+
33+
You can convert a quantity using `SymbolicDimensions` as its dimensions
34+
to one which uses `Dimensions` as its dimensions (i.e., base SI units)
35+
`expand_units`.
3236
"""
3337
struct SymbolicDimensions{R} <: AbstractDimensions{R}
3438
_data::SA.SparseVector{R}
@@ -37,7 +41,10 @@ struct SymbolicDimensions{R} <: AbstractDimensions{R}
3741
SymbolicDimensions{_R}(data::SA.SparseVector) where {_R} = new{_R}(data)
3842
end
3943

44+
static_fieldnames(::Type{<:SymbolicDimensions}) = ALL_SYMBOLS
4045
data(d::SymbolicDimensions) = getfield(d, :_data)
46+
Base.getproperty(d::SymbolicDimensions{R}, s::Symbol) where {R} = data(d)[ALL_MAPPING[s]]
47+
Base.getindex(d::SymbolicDimensions{R}, k::Symbol) where {R} = getproperty(d, k)
4148
constructor_of(::Type{<:SymbolicDimensions}) = SymbolicDimensions
4249

4350
SymbolicDimensions{R}(d::SymbolicDimensions) where {R} = SymbolicDimensions{R}(data(d))
@@ -59,14 +66,19 @@ function Base.convert(::Type{Q}, q::Quantity{<:Any,<:SymbolicDimensions}) where
5966
end
6067
return result
6168
end
69+
70+
"""
71+
expand_units(q::Quantity{<:Any,<:SymbolicDimensions})
72+
73+
Expand the symbolic units in a quantity to their base SI form.
74+
In other words, this converts a `Quantity` with `SymbolicDimensions`
75+
to one with `Dimensions`.
76+
"""
6277
function expand_units(q::Q) where {T,R,D<:SymbolicDimensions{R},Q<:Quantity{T,D}}
6378
return convert(Quantity{T,Dimensions{R}}, q)
6479
end
6580

6681

67-
static_fieldnames(::Type{<:SymbolicDimensions}) = ALL_SYMBOLS
68-
Base.getproperty(d::SymbolicDimensions{R}, s::Symbol) where {R} = data(d)[ALL_MAPPING[s]]
69-
Base.getindex(d::SymbolicDimensions{R}, k::Symbol) where {R} = getproperty(d, k)
7082
Base.copy(d::SymbolicDimensions) = SymbolicDimensions(copy(data(d)))
7183
Base.:(==)(l::SymbolicDimensions, r::SymbolicDimensions) = data(l) == data(r)
7284
Base.iszero(d::SymbolicDimensions) = iszero(data(d))
@@ -131,6 +143,22 @@ module SymbolicUnitsParse
131143
return nothing
132144
end
133145

146+
"""
147+
sym_uparse(raw_string::AbstractString)
148+
149+
Parse a string containing an expression of units and return the
150+
corresponding `Quantity` object with `Float64` value.
151+
However, that unlike the regular `u"..."` macro, this macro uses
152+
`SymbolicDimensions` for the dimension type, which means that all units and
153+
constants are stored symbolically and will not automatically expand to SI
154+
units. For example, `sym_uparse("km/s^2")` would be parsed to
155+
`Quantity(1.0, SymbolicDimensions, km=1, s=-2)`.
156+
157+
Note that inside this expression, you also have access to the `Constants`
158+
module. So, for example, `sym_uparse("Constants.c^2 * Hz^2")` would evaluate to
159+
`Quantity(1.0, SymbolicDimensions, c=2, Hz=2)`. However, note that due to
160+
namespace collisions, a few physical constants are not available.
161+
"""
134162
function sym_uparse(raw_string::AbstractString)
135163
_generate_unit_symbols()
136164
Constants._generate_unit_symbols()
@@ -145,6 +173,21 @@ end
145173

146174
import .SymbolicUnitsParse: sym_uparse
147175

176+
"""
177+
us"[unit expression]"
178+
179+
Parse a string containing an expression of units and return the
180+
corresponding `Quantity` object with `Float64` value. However,
181+
unlike the regular `u"..."` macro, this macro uses `SymbolicDimensions`
182+
for the dimension type, which means that all units and constants
183+
are stored symbolically and will not automatically expand to SI units.
184+
For example, `us"km/s^2"` would be parsed to `Quantity(1.0, SymbolicDimensions, km=1, s=-2)`.
185+
186+
Note that inside this expression, you also have access to the `Constants`
187+
module. So, for example, `us"Constants.c^2 * Hz^2"` would evaluate to
188+
`Quantity(1.0, SymbolicDimensions, c=2, Hz=2)`. However, note that due to
189+
namespace collisions, a few physical constants are not available.
190+
"""
148191
macro us_str(s)
149192
return esc(SymbolicUnitsParse.sym_uparse(s))
150193
end

src/uparse.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ eval(_generate_units_import())
2323
Parse a string containing an expression of units and return the
2424
corresponding `Quantity` object with `Float64` value. For example,
2525
`uparse("m/s")` would be parsed to `Quantity(1.0, length=1, time=-1)`.
26+
27+
Note that inside this expression, you also have access to the `Constants`
28+
module. So, for example, `uparse("Constants.c^2 * Hz^2")` would evaluate to
29+
the quantity corresponding to the speed of light multiplied by Hertz,
30+
squared.
2631
"""
2732
function uparse(s::AbstractString)
2833
return as_quantity(eval(Meta.parse(s)))::Quantity{DEFAULT_VALUE_TYPE,DEFAULT_DIM_TYPE}
@@ -38,6 +43,11 @@ as_quantity(x) = error("Unexpected type evaluated: $(typeof(x))")
3843
Parse a string containing an expression of units and return the
3944
corresponding `Quantity` object with `Float64` value. For example,
4045
`u"km/s^2"` would be parsed to `Quantity(1000.0, length=1, time=-2)`.
46+
47+
Note that inside this expression, you also have access to the `Constants`
48+
module. So, for example, `u"Constants.c^2 * Hz^2"` would evaluate to
49+
the quantity corresponding to the speed of light multiplied by Hertz,
50+
squared.
4151
"""
4252
macro u_str(s)
4353
return esc(uparse(s))

0 commit comments

Comments
 (0)