Skip to content

Commit f38db8e

Browse files
committed
Merge tag 'v0.4.0' into abstract-types-2
2 parents d3b1081 + 71eb92d commit f38db8e

File tree

9 files changed

+155
-31
lines changed

9 files changed

+155
-31
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.3.0"
4+
version = "0.4.0"
55

66
[deps]
77
Requires = "ae029012-a4dd-5104-9daa-d747884805df"

docs/Project.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
[deps]
22
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
3-
DynamicQuantities = "06fc5a27-2a28-4c7c-a15d-362465fb6821"

docs/make.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using DynamicQuantities
2+
import DynamicQuantities.Units
23
using Documenter
34

45
DocMeta.setdocmeta!(DynamicQuantities, :DocTestSetup, :(using DynamicQuantities); recursive=true)
@@ -26,7 +27,7 @@ open(dirname(@__FILE__) * "/src/index.md", "w") do io
2627
end
2728

2829
makedocs(;
29-
modules=[DynamicQuantities],
30+
modules=[DynamicQuantities, DynamicQuantities.Units],
3031
authors="MilesCranmer <[email protected]> and contributors",
3132
repo="https://github.com/SymbolicML/DynamicQuantities.jl/blob/{commit}{path}#{line}",
3233
sitename="DynamicQuantities.jl",

docs/src/api.md

Lines changed: 83 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,91 @@
1-
```@meta
2-
CurrentModule = DynamicQuantities
1+
# Usage
2+
3+
## Types
4+
5+
```@docs
6+
Quantity
7+
Dimensions
8+
```
9+
10+
## Utilities
11+
12+
The two main general utilities for working
13+
with quantities are `ustrip` and `dimension`:
14+
15+
```@docs
16+
ustrip
17+
dimension
318
```
419

5-
# API Reference
20+
### Accessing dimensions
621

7-
API Reference for [DynamicQuantities](https://github.com/SymbolicML/DynamicQuantities.jl).
22+
Utility functions to extract specific dimensions are as follows:
823

9-
```@index
24+
```@docs
25+
ulength
26+
umass
27+
utime
28+
ucurrent
29+
utemperature
30+
uluminosity
31+
uamount
1032
```
1133

1234
```@autodocs
1335
Modules = [DynamicQuantities]
14-
Order = [:type, :function]
15-
```
36+
Pages = ["utils.jl"]
37+
Filter = t -> !(t in [ustrip, dimension, ulength, umass, utime, ucurrent, utemperature, uluminosity, uamount])
38+
```
39+
40+
## Units
41+
42+
The two main functions for working with units are `uparse` and `u_str`:
43+
44+
```@docs
45+
@u_str
46+
uparse
47+
```
48+
49+
### Available units
50+
51+
The base SI units are as follows.
52+
Instead of calling directly, it is recommended to access them via
53+
the `@u_str` macro, which evaluates the expression
54+
in a namespace with all the units available.
55+
56+
```@docs
57+
Units.m
58+
Units.g
59+
Units.s
60+
Units.A
61+
Units.K
62+
Units.cd
63+
Units.mol
64+
```
65+
66+
Several derived SI units are available as well:
67+
68+
```@docs
69+
Units.Hz
70+
Units.N
71+
Units.Pa
72+
Units.J
73+
Units.W
74+
Units.C
75+
Units.V
76+
Units.F
77+
Units.Ω
78+
Units.T
79+
Units.L
80+
Units.bar
81+
```
82+
83+
## Internals
84+
85+
### FixedRational
86+
87+
```@docs
88+
DynamicQuantities.FixedRational
89+
DynamicQuantities.denom
90+
```
91+

ext/DynamicQuantitiesUnitfulExt.jl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ end
1313
# This lets the user override the preferred units:
1414
function unitful_equivalences()
1515
si_units = (length=u"m", mass=u"kg", time=u"s", current=u"A", temperature=u"K", luminosity=u"cd", amount=u"mol")
16-
return NamedTuple((k => Unitful.upreferred(si_units[k]) for k in keys(si_units)))
16+
for k in keys(si_units)
17+
if Unitful.upreferred(si_units[k]) !== si_units[k]
18+
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.")
19+
end
20+
end
21+
return NamedTuple((k => si_units[k] for k in keys(si_units)))
1722
end
1823

1924
Base.convert(::Type{Unitful.Quantity}, x::DynamicQuantities.Quantity) =

src/fixed_rational.jl

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
A rational number with a fixed denominator. Significantly
55
faster than `Rational{T}`, as it never needs to compute
66
the `gcd` apart from when printing.
7+
Access the denominator with `denom(F)` (which converts to `T`).
8+
9+
# Fields
10+
11+
- `num`: numerator of type `T`. The denominator is fixed to the type parameter `den`.
712
"""
813
struct FixedRational{T<:Integer,den} <: Real
914
num::T
@@ -44,9 +49,9 @@ Base.convert(::Type{Rational}, x::F) where {F<:FixedRational} = Rational{eltype(
4449
Base.convert(::Type{AF}, x::F) where {AF<:AbstractFloat,F<:FixedRational} = convert(AF, x.num) / convert(AF, denom(F))
4550
Base.round(::Type{T}, x::F) where {T,F<:FixedRational} = div(convert(T, x.num), convert(T, denom(F)), RoundNearest)
4651
Base.promote(x::Integer, y::F) where {F<:FixedRational} = (F(x), y)
47-
Base.promote(x::F, y::Integer) where {F<:FixedRational} = (x, F(y))
52+
Base.promote(x::F, y::Integer) where {F<:FixedRational} = reverse(promote(y, x))
4853
Base.promote(x, y::F) where {F<:FixedRational} = promote(x, convert(Rational, y))
49-
Base.promote(x::F, y) where {F<:FixedRational} = promote(convert(Rational, x), y)
54+
Base.promote(x::F, y) where {F<:FixedRational} = reverse(promote(y, x))
5055
Base.show(io::IO, x::F) where {F<:FixedRational} = show(io, convert(Rational, x))
5156
Base.zero(::Type{F}) where {F<:FixedRational} = unsafe_fixed_rational(0, eltype(F), val_denom(F))
5257

src/types.jl

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ constructor_of(::Type{Q}) where {T,Q<:AbstractQuantity{T}} = Q.body.name.wrapper
1111
constructor_of(::Type{Q}) where {T,R,Q<:AbstractQuantity{T,R}} = Q.name.wrapper
1212

1313
"""
14-
Dimensions
14+
Dimensions{R}
1515
1616
A type representing the dimensions of a quantity, with each
1717
field giving the power of the corresponding dimension. For
1818
example, the dimensions of velocity are `Dimensions(length=1, time=-1)`.
19+
Each of the 7 dimensions are stored using the type `R`,
20+
which is by default a rational number.
1921
2022
# Fields
2123
@@ -26,6 +28,15 @@ example, the dimensions of velocity are `Dimensions(length=1, time=-1)`.
2628
- `temperature`: temperature dimension (i.e., K^(temperature))
2729
- `luminosity`: luminosity dimension (i.e., cd^(luminosity))
2830
- `amount`: amount dimension (i.e., mol^(amount))
31+
32+
# Constructors
33+
34+
- `Dimensions(args...)`: Pass all the dimensions as arguments. `R` is set to `DEFAULT_DIM_TYPE`.
35+
- `Dimensions(; kws...)`: Pass a subset of dimensions as keyword arguments. `R` is set to `DEFAULT_DIM_TYPE`.
36+
- `Dimensions(::Type{R}; kws...)` or `Dimensions{R}(; kws...)`: Pass a subset of dimensions as keyword arguments, with the output type set to `Dimensions{R}`.
37+
- `Dimensions{R}(args...)`: Pass all the dimensions as arguments, with the output type set to `Dimensions{R}`.
38+
- `Dimensions{R}(d::Dimensions)`: Copy the dimensions from another `Dimensions` object, with the output type set to `Dimensions{R}`.
39+
2940
"""
3041
struct Dimensions{R<:Real} <: AbstractDimensions{R}
3142
length::R
@@ -46,22 +57,31 @@ end
4657

4758

4859
"""
49-
Quantity{T}
60+
Quantity{T,R}
5061
51-
Physical quantity with value `value` of type `T` and dimensions `dimensions`.
62+
Physical quantity with value `value` of type `T` and dimensions `dimensions` of type `Dimensions{R}`.
5263
For example, the velocity of an object with mass 1 kg and velocity
5364
2 m/s is `Quantity(2, mass=1, length=1, time=-1)`.
5465
You should access these fields with `ustrip(q)`, and `dimensions(q)`.
5566
You can access specific dimensions with `ulength(q)`, `umass(q)`, `utime(q)`,
5667
`ucurrent(q)`, `utemperature(q)`, `uluminosity(q)`, and `uamount(q)`.
5768
5869
Severals operators in `Base` are extended to work with `Quantity` objects,
59-
including `*`, `+`, `-`, `/`, `^`, `sqrt`, and `cbrt`.
70+
including `*`, `+`, `-`, `/`, `abs`, `^`, `sqrt`, and `cbrt`, which manipulate
71+
dimensions according to the operation.
6072
6173
# Fields
6274
63-
- `value::T`: value of the quantity of some type `T`
64-
- `dimensions::Dimensions`: dimensions of the quantity
75+
- `value::T`: value of the quantity of some type `T`. Access with `ustrip(::Quantity)`
76+
- `dimensions::Dimensions{R}`: dimensions of the quantity with dimension type `R`. Access with `dimension(::Quantity)`
77+
78+
# Constructors
79+
80+
- `Quantity(x; kws...)`: Construct a quantity with value `x` and dimensions given by the keyword arguments. The value type is inferred from `x`. `R` is set to `DEFAULT_DIM_TYPE`.
81+
- `Quantity(x, ::Type{R}; kws...)`: Construct a quantity with value `x`. The dimensions parametric type is set to `R`.
82+
- `Quantity(x, d::Dimensions{R})`: Construct a quantity with value `x` and dimensions `d`.
83+
- `Quantity{T}(q::Quantity)`: Construct a quantity with value `q.value` and dimensions `q.dimensions`, but with value type converted to `T`.
84+
- `Quantity{T,R}(q::Quantity)`: Construct a quantity with value `q.value` and dimensions `q.dimensions`, but with value type converted to `T` and dimensions parametric type set to `R`.
6585
"""
6686
struct Quantity{T,R} <: AbstractQuantity{T,R}
6787
value::T

src/units.jl

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
module Units
22

3+
export uparse, @u_str
4+
35
import ..DEFAULT_DIM_TYPE
46
import ..DEFAULT_VALUE_TYPE
57
import ..Quantity
@@ -27,12 +29,19 @@ function _add_prefixes(base_unit::Symbol, prefixes)
2729
end
2830

2931
# SI base units
32+
"Length in meters. Available variants: `fm`, `pm`, `nm`, `μm` (/`um`), `cm`, `dm`, `mm`, `km`, `Mm`, `Gm`."
3033
const m = Quantity(1.0, length=1)
34+
"Mass in grams. Available variants: `μg` (/`ug`), `mg`, `kg`."
3135
const g = Quantity(1e-3, mass=1)
36+
"Time in seconds. Available variants: `fs`, `ps`, `ns`, `μs` (/`us`), `ms`, `min`, `h` (/`hr`), `day`, `yr`, `kyr`, `Myr`, `Gyr`."
3237
const s = Quantity(1.0, time=1)
38+
"Current in Amperes. Available variants: `nA`, `μA` (/`uA`), `mA`, `kA`."
3339
const A = Quantity(1.0, current=1)
40+
"Temperature in Kelvin. Available variant: `mK`."
3441
const K = Quantity(1.0, temperature=1)
42+
"Luminosity in candela. Available variant: `mcd`."
3543
const cd = Quantity(1.0, luminosity=1)
44+
"Amount in moles. Available variant: `mmol`."
3645
const mol = Quantity(1.0, amount=1)
3746

3847
@add_prefixes m (f, p, n, μ, u, c, d, m, k, M, G)
@@ -44,15 +53,26 @@ const mol = Quantity(1.0, amount=1)
4453
@add_prefixes mol (m,)
4554

4655
# SI derived units
56+
"Frequency in Hertz. Available variants: `kHz`, `MHz`, `GHz`."
4757
const Hz = inv(s)
58+
"Force in Newtons."
4859
const N = kg * m / s^2
60+
"Pressure in Pascals. Available variant: `kPa`."
4961
const Pa = N / m^2
62+
"Energy in Joules. Available variant: `kJ`."
5063
const J = N * m
64+
"Power in Watts. Available variants: `kW`, `MW`, `GW`."
5165
const W = J / s
66+
"Charge in Coulombs."
5267
const C = A * s
68+
"Voltage in Volts. Available variants: `kV`, `MV`, `GV`."
5369
const V = W / A
70+
"Capacitance in Farads."
5471
const F = C / V
72+
"Resistance in Ohms. Available variant: `mΩ`. Also available is ASCII `ohm` (with variant `mohm`)."
5573
const= V / A
74+
const ohm =
75+
"Magnetic flux density in Teslas."
5676
const T = N / (A * m)
5777

5878
@add_prefixes Hz (k, M, G)
@@ -64,6 +84,7 @@ const T = N / (A * m)
6484
@add_prefixes V (m, k, M, G)
6585
@add_prefixes F ()
6686
@add_prefixes Ω (m,)
87+
@add_prefixes ohm (m,)
6788
@add_prefixes T ()
6889

6990
# Common assorted units
@@ -81,11 +102,13 @@ const yr = 365.25 * day
81102
@add_prefixes yr (k, M, G)
82103

83104
## Volume
105+
"Volume in liters. Available variants: `mL`, `dL`."
84106
const L = dm^3
85107

86108
@add_prefixes L (m, d)
87109

88110
## Pressure
111+
"Pressure in bars."
89112
const bar = 100 * kPa
90113

91114
@add_prefixes bar ()
@@ -100,8 +123,8 @@ const bar = 100 * kPa
100123
uparse(s::AbstractString)
101124
102125
Parse a string containing an expression of units and return the
103-
corresponding `Quantity` object. For example, `uparse("m/s")`
104-
would be parsed to `Quantity(1.0, length=1, time=-1)`.
126+
corresponding `Quantity` object with `Float64` value. For example,
127+
`uparse("m/s")` would be parsed to `Quantity(1.0, length=1, time=-1)`.
105128
"""
106129
function uparse(s::AbstractString)
107130
return as_quantity(eval(Meta.parse(s)))::Quantity{DEFAULT_VALUE_TYPE,DEFAULT_DIM_TYPE}
@@ -112,14 +135,14 @@ as_quantity(x::Number) = Quantity(convert(DEFAULT_VALUE_TYPE, x), DEFAULT_DIM_TY
112135
as_quantity(x) = error("Unexpected type evaluated: $(typeof(x))")
113136

114137
"""
115-
@u_str(s::AbstractString)
138+
u"[unit expression]"
116139
117140
Parse a string containing an expression of units and return the
118-
corresponding `Quantity` object. For example, `u"km/s^2"`
119-
would be parsed to `Quantity(1000.0, length=1, time=-2)`.
141+
corresponding `Quantity` object with `Float64` value. For example,
142+
`u"km/s^2"` would be parsed to `Quantity(1000.0, length=1, time=-2)`.
120143
"""
121144
macro u_str(s)
122145
return esc(uparse(s))
123146
end
124147

125-
end
148+
end

test/test_unitful.jl

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,13 @@ import Ratios: SimpleRatio
66
import SaferIntegers: SafeInt16
77
using Test
88

9-
# Try to work with different preferred units:
10-
Unitful.preferunits(u"km")
11-
129
risapprox(x::Unitful.Quantity, y::Unitful.Quantity; kws...) =
1310
let (xfloat, yfloat) = (Unitful.ustrip Unitful.upreferred).((x, y))
1411
return isapprox(xfloat, yfloat; kws...)
1512
end
1613

17-
factor_for_preferred_units = 1e-3
18-
1914
for T in [DEFAULT_VALUE_TYPE, Float16, Float32, Float64], R in [DEFAULT_DIM_TYPE, Rational{Int16}, Rational{Int32}, SimpleRatio{Int}, SimpleRatio{SafeInt16}]
20-
x = DynamicQuantities.Quantity(T(0.2*factor_for_preferred_units), R, length=1, amount=2, current=-1 // 2, luminosity=2 // 5)
15+
x = DynamicQuantities.Quantity(T(0.2), R, length=1, amount=2, current=-1 // 2, luminosity=2 // 5)
2116
x_unitful = T(0.2)u"m*mol^2*A^(-1//2)*cd^(2//5)"
2217

2318
@test risapprox(convert(Unitful.Quantity, x), x_unitful; atol=1e-6)

0 commit comments

Comments
 (0)