Skip to content

Commit 107b6a5

Browse files
committed
Split up API pages
1 parent 6c8c4a4 commit 107b6a5

File tree

5 files changed

+324
-68
lines changed

5 files changed

+324
-68
lines changed

docs/make.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ makedocs(;
3939
),
4040
pages=[
4141
"Home" => "index.md",
42-
"API" => "api.md",
42+
"Utilities" => "api.md",
43+
"Units" => "units.md",
44+
"Types" => "types.md",
4345
]
4446
)
4547

docs/src/api.md

Lines changed: 2 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,4 @@
1-
# Usage
2-
3-
## Types
4-
5-
```@docs
6-
Quantity
7-
Dimensions
8-
```
9-
10-
There are also abstract types available. There are no required
11-
functions to build an interface, most relevant functions are
12-
defined on the abstract functions (including constructors).
13-
14-
```@docs
15-
AbstractDimensions
16-
AbstractQuantity
17-
```
18-
19-
Note also that the `Quantity` object can take a custom `AbstractDimensions`
20-
as input, so there is often no need to subtype `AbstractQuantity` separately.
21-
22-
## Utilities
1+
# Utilities
232

243
The two main general utilities for working
254
with quantities are `ustrip` and `dimension`:
@@ -29,7 +8,7 @@ ustrip
298
dimension
309
```
3110

32-
### Accessing dimensions
11+
## Accessing dimensions
3312

3413
Utility functions to extract specific dimensions are as follows:
3514

@@ -49,49 +28,6 @@ Pages = ["utils.jl"]
4928
Filter = t -> !(t in [ustrip, dimension, ulength, umass, utime, ucurrent, utemperature, uluminosity, uamount])
5029
```
5130

52-
## Units
53-
54-
The two main functions for working with units are `uparse` and `u_str`:
55-
56-
```@docs
57-
@u_str
58-
uparse
59-
```
60-
61-
### Available units
62-
63-
The base SI units are as follows.
64-
Instead of calling directly, it is recommended to access them via
65-
the `@u_str` macro, which evaluates the expression
66-
in a namespace with all the units available.
67-
68-
```@docs
69-
Units.m
70-
Units.g
71-
Units.s
72-
Units.A
73-
Units.K
74-
Units.cd
75-
Units.mol
76-
```
77-
78-
Several derived SI units are available as well:
79-
80-
```@docs
81-
Units.Hz
82-
Units.N
83-
Units.Pa
84-
Units.J
85-
Units.W
86-
Units.C
87-
Units.V
88-
Units.F
89-
Units.Ω
90-
Units.T
91-
Units.L
92-
Units.bar
93-
```
94-
9531
## Internals
9632

9733
### FixedRational
@@ -100,4 +36,3 @@ Units.bar
10036
DynamicQuantities.FixedRational
10137
DynamicQuantities.denom
10238
```
103-

docs/src/index.md

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
2+
3+
![logo](https://github.com/SymbolicML/DynamicQuantities.jl/assets/7593028/a278d0c1-2f95-416b-ba04-82750074146b)
4+
5+
[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://symbolicml.org/DynamicQuantities.jl/dev/)
6+
[![Build Status](https://github.com/SymbolicML/DynamicQuantities.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/SymbolicML/DynamicQuantities.jl/actions/workflows/CI.yml?query=branch%3Amain)
7+
[![Coverage](https://coveralls.io/repos/github/SymbolicML/DynamicQuantities.jl/badge.svg?branch=main)](https://coveralls.io/github/SymbolicML/DynamicQuantities.jl?branch=main)
8+
9+
10+
11+
DynamicQuantities defines a simple statically-typed `Quantity` type for Julia.
12+
Physical dimensions are stored as a *value*, as opposed to a parametric type, as in [Unitful.jl](https://github.com/PainterQubits/Unitful.jl).
13+
This is done to allow for calculations where physical dimensions are not known at compile time.
14+
15+
- [Performance](#performance)
16+
- [Usage](#usage)
17+
- [Types](#types)
18+
- [Vectors](#vectors)
19+
20+
## Performance
21+
22+
DynamicQuantities can greatly outperform Unitful
23+
when the compiler cannot infer dimensions in a function:
24+
25+
```julia
26+
julia> using BenchmarkTools, DynamicQuantities; import Unitful
27+
28+
julia> dyn_uni = 0.2u"m^0.5 * kg * mol^3"
29+
0.2 m¹ᐟ² kg mol³
30+
31+
julia> unitful = convert(Unitful.Quantity, dyn_uni)
32+
0.2 kg m¹ᐟ² mol³
33+
34+
julia> f(x, i) = x ^ i * 0.3;
35+
36+
julia> @btime f($dyn_uni, 1);
37+
8.759 ns (0 allocations: 0 bytes)
38+
39+
julia> @btime f($unitful, 1);
40+
30.083 μs (42 allocations: 1.91 KiB)
41+
```
42+
43+
**(Note the μ and n.)**
44+
Here, the DynamicQuantities quantity object allows the compiler to build a function that is type stable,
45+
while the Unitful quantity object, which stores its dimensions in the type, requires type inference at runtime.
46+
47+
However, if the dimensions in your function *can* be inferred by the compiler,
48+
then you can get better speeds with Unitful:
49+
50+
```julia
51+
julia> g(x) = x ^ 2 * 0.3;
52+
53+
julia> @btime g($dyn_uni);
54+
10.051 ns (0 allocations: 0 bytes)
55+
56+
julia> @btime g($unitful);
57+
2.000 ns (0 allocations: 0 bytes)
58+
```
59+
60+
While both of these are type stable,
61+
because Unitful parametrizes the type on the dimensions, functions can specialize
62+
to units and the compiler can optimize away units from the code.
63+
64+
## Usage
65+
66+
You can create a `Quantity` object
67+
by using the convenience macro `u"..."`:
68+
69+
```julia
70+
julia> x = 0.3u"km/s"
71+
300.0 m s⁻¹
72+
73+
julia> y = 42 * u"kg"
74+
42.0 kg
75+
76+
julia> room_temp = 100u"kPa"
77+
100000.0 m⁻¹ kg s⁻²
78+
```
79+
80+
This supports a wide range of SI base and derived units, with common
81+
prefixes.
82+
83+
You can also construct values explicitly with the `Quantity` type,
84+
with a value and keyword arguments for the powers of the physical dimensions
85+
(`mass`, `length`, `time`, `current`, `temperature`, `luminosity`, `amount`):
86+
87+
```julia
88+
julia> x = Quantity(300.0, length=1, time=-1)
89+
300.0 m s⁻¹
90+
```
91+
92+
Elementary calculations with `+, -, *, /, ^, sqrt, cbrt, abs` are supported:
93+
94+
```julia
95+
julia> x * y
96+
12600.0 m kg s⁻¹
97+
98+
julia> x / y
99+
7.142857142857143 m kg⁻¹ s⁻¹
100+
101+
julia> x ^ 3
102+
2.7e7 m³ s⁻³
103+
104+
julia> x ^ -1
105+
0.0033333333333333335 m⁻¹ s
106+
107+
julia> sqrt(x)
108+
17.320508075688775 m¹ᐟ² s⁻¹ᐟ²
109+
110+
julia> x ^ 1.5
111+
5196.152422706632 m³ᐟ² s⁻³ᐟ²
112+
```
113+
114+
Each of these values has the same type, which means we don't need to perform type inference at runtime.
115+
116+
Furthermore, we can do dimensional analysis by detecting `DimensionError`:
117+
118+
```julia
119+
julia> x + 3 * x
120+
1.2 m¹ᐟ² kg
121+
122+
julia> x + y
123+
ERROR: DimensionError: 0.3 m¹ᐟ² kg and 10.2 kg² s⁻² have incompatible dimensions
124+
```
125+
126+
The dimensions of a `Quantity` can be accessed either with `dimension(quantity)` for the entire `Dimensions` object:
127+
128+
```julia
129+
julia> dimension(x)
130+
m¹ᐟ² kg
131+
```
132+
133+
or with `umass`, `ulength`, etc., for the various dimensions:
134+
135+
```julia
136+
julia> umass(x)
137+
1//1
138+
139+
julia> ulength(x)
140+
1//2
141+
```
142+
143+
Finally, you can strip units with `ustrip`:
144+
145+
```julia
146+
julia> ustrip(x)
147+
0.2
148+
```
149+
150+
### Unitful
151+
152+
DynamicQuantities works with quantities that are exclusively
153+
represented by their SI base units. This gives us type stability
154+
and greatly improves performance.
155+
156+
However, performing calculations with physical dimensions
157+
is actually equivalent to working with a standardized unit system.
158+
Thus, you can use Unitful to parse units,
159+
and then use the DynamicQuantities->Unitful extension for conversion:
160+
161+
```julia
162+
julia> using Unitful: Unitful, @u_str; import DynamicQuantities
163+
164+
julia> x = 0.5u"km/s"
165+
0.5 km s⁻¹
166+
167+
julia> y = convert(DynamicQuantities.Quantity, x)
168+
500.0 m s⁻¹
169+
170+
julia> y2 = y^2 * 0.3
171+
75000.0 m² s⁻²
172+
173+
julia> x2 = convert(Unitful.Quantity, y2)
174+
75000.0 m² s⁻²
175+
176+
julia> x^2*0.3 == x2
177+
true
178+
```
179+
180+
## Types
181+
182+
Both a `Quantity`'s values and dimensions are of arbitrary type.
183+
By default, dimensions are stored as a `DynamicQuantities.FixedRational{Int32,C}`
184+
object, which represents a rational number
185+
with a fixed denominator `C`. This is much faster than `Rational`.
186+
187+
```julia
188+
julia> typeof(0.5u"kg")
189+
Quantity{Float64, FixedRational{Int32, 25200}
190+
```
191+
192+
You can change the type of the value field by initializing with a value
193+
explicitly of the desired type.
194+
195+
```julia
196+
julia> typeof(Quantity(Float16(0.5), mass=1, length=1))
197+
Quantity{Float16, FixedRational{Int32, 25200}}
198+
```
199+
200+
or by conversion:
201+
202+
```julia
203+
julia> typeof(convert(Quantity{Float16}, 0.5u"m/s"))
204+
Quantity{Float16, DynamicQuantities.FixedRational{Int32, 25200}}
205+
```
206+
207+
For many applications, `FixedRational{Int8,6}` will suffice,
208+
and can be faster as it means the entire `Dimensions`
209+
struct will fit into 64 bits.
210+
You can change the type of the dimensions field by passing
211+
the type you wish to use as the second argument to `Quantity`:
212+
213+
```julia
214+
julia> using DynamicQuantities
215+
216+
julia> R8 = DynamicQuantities.FixedRational{Int8,6};
217+
218+
julia> R32 = DynamicQuantities.FixedRational{Int32,2^4 * 3^2 * 5^2 * 7}; # Default
219+
220+
julia> q8 = [Quantity(randn(), R8, length=rand(-2:2)) for i in 1:1000];
221+
222+
julia> q32 = [Quantity(randn(), R32, length=rand(-2:2)) for i in 1:1000];
223+
224+
julia> f(x) = @. x ^ 2 * 0.5;
225+
226+
julia> @btime f($q8);
227+
7.750 μs (1 allocation: 15.75 KiB)
228+
229+
julia> @btime f($q32);
230+
8.417 μs (2 allocations: 39.11 KiB)
231+
```
232+
233+
## Vectors
234+
235+
There is not a separate class for vectors, but you can create units
236+
like so:
237+
238+
```julia
239+
julia> randn(5) .* u"m/s"
240+
5-element Vector{Quantity{Float64, DynamicQuantities.FixedRational{Int32, 25200}}}:
241+
1.1762086954956399 m s⁻¹
242+
1.320811324040591 m s⁻¹
243+
0.6519033652437799 m s⁻¹
244+
0.7424822374423569 m s⁻¹
245+
0.33536928068133726 m s⁻¹
246+
```
247+
248+
Because it is type stable, you can have mixed units in a vector too:
249+
250+
```julia
251+
julia> v = [Quantity(randn(), mass=rand(0:5), length=rand(0:5)) for _=1:5]
252+
5-element Vector{Quantity{Float64, DynamicQuantities.FixedRational{Int32, 25200}}}:
253+
0.4309293892461158 kg⁵
254+
1.415520139801276
255+
1.2179414706524276 m³ kg⁴
256+
-0.18804207255117408 m³ kg⁵
257+
0.52123911329638 m³ kg²
258+
```
259+

docs/src/types.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Types
2+
3+
```@docs
4+
Quantity
5+
Dimensions
6+
```
7+
8+
There are also abstract types available. There are no required
9+
functions to build an interface, most relevant functions are
10+
defined on the abstract functions (including constructors).
11+
12+
```@docs
13+
AbstractDimensions
14+
AbstractQuantity
15+
```
16+
17+
Note also that the `Quantity` object can take a custom `AbstractDimensions`
18+
as input, so there is often no need to subtype `AbstractQuantity` separately.

0 commit comments

Comments
 (0)