Skip to content

Commit

Permalink
Add working flexible unit conversion, including for arrays.
Browse files Browse the repository at this point in the history
 modified:   Project.toml                 v0.2.0
 modified:   README.md                    Update example, goals
 modified:   src/import_export_units.jl   Add Nmm
 modified:   test/conversion_promotion.jl Flexible conversion OK!
  • Loading branch information
hustf committed Jul 20, 2019
1 parent d7c0b49 commit e692b59
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 82 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "MechanicalUnits"
uuid = "e6be9192-89dc-11e9-36e6-5dbcb28f419e"
authors = ["hustf <[email protected]>"]
version = "0.1.0"
version = "0.2.0"

[deps]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Expand Down
143 changes: 72 additions & 71 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
- [License](#license)


### Low-effort calculator with units in the REPL
Units can be part of the side calculations mechanical and other engineers do every few minutes of a work day. Using units must be quick, nice and easy. That's the aim of this package, built on [Unitful.jl](https://github.com/PainterQubits/Unitful.jl).
### Convenient units in the REPL
Units can be part of the side calculations mechanical and other engineers do every few minutes of a work day. Using units must be quick, nice and easy. That's the aim of this package, built on a slight modification of [Unitful.jl](https://github.com/hustf/Unitful.jl).

The benefits?
* Fewer mistakes
Expand All @@ -36,7 +36,7 @@ The benefits?
| N daN kN MN GN lbf kip | Force | ᴸ∙ ᴹ ∙ ᵀ⁻² |
| Pa kPa MPa GPa atm bar | Pressure | ᴹ ∙ ᴸ⁻¹ ∙ ᵀ⁻² |
| J kJ MJ GJ | Energy | ᴸ² ∙ ᴹ ∙ ᵀ⁻² |
| Nm daNm kNm MNm GNm | Moment | ᴸ² ∙ ᴹ ∙ ᵀ⁻² |
| Nmm Nm daNm kNm MNm GNm | Moment | ᴸ² ∙ ᴹ ∙ ᵀ⁻² |
| l dl cl ml | Volume | ᴸ³ |
| g | Acceleration | ᴸ ∙ ᵀ⁻² |

Expand All @@ -60,65 +60,50 @@ Colors won't show here. But let us do some side calculations:
```julia
julia> using MechanicalUnits

julia> c_p = 1.00kJ/(kg*K) ; T1 = 0°C ; T2 = 1000°C ; m_air = 1kg;
julia> m_air = 1000kg; c_p = 1.00kJ/(kg*K)
1.0kJkg⁻¹K⁻¹

julia> m_air*c_p*(T2-T1)
1000.0kJ
julia> @import_expand ~W # Watt = Joule / Second is not exported by default.

julia> begin
"Work, heating air at constant pressure"
Q_cp(T1, T2) = m_air*c_p*(T2-T1)
end
Q_cp
julia> Q_cp(T1, T2) = m_air*c_p*(T2-T1) |> (kW*h)
Q_cp (generic function with 1 method)

julia> Q_cp(20°C, 25°C)
5.0kJ
julia> Q_cp(20°C, 985°C)
268.05555555555554kWh

julia> year_and_a_day = 1yr + 6*7d
(35186400//1)s

julia> 2year_and_a_day |> yr
(1086//487)yr

julia> 1dm|>upreferred
(100//1)mm

julia> exit()

PS C:\Users\F> julia --banner=no

julia> using MechanicalUnits
julia> dm |> upreferred
mm

julia> preferunits(m)

julia> 1dm|>upreferred
(1//10)m
julia> m_s = [30kg/m 28.8lb/ft]
1×2 Array{Float64{kgm⁻¹},2}:
30.0 42.8591

julia> exit()
julia> l_s = 93ft*[3 4]m/s
372ft

PS C:\Users\F> julia --banner=no
julia> m_s.*l_s |> (kg*m)
1×2 Array{Float64{kgms⁻¹},2}:
2551.18 4859.61

julia> using MechanicalUnits

julia> # Estimate deflection

julia> E=206GPa; h = 100mm; b = 30mm; I = 1/12 * b * h^3
julia> E=206GPa; h_y = 100mm; b = 30mm; I = 1/12 * b * h_y^3
2.5e6mm⁴

julia> F=100kg*g; L = 2m
2m
julia> L = 2m; F=100kg*g |> N
980.665N

julia> F*L^3/(3E*I) |> mm
5.0778770226537215mm

julia> # Pick a corresponding wire rope

julia> l_wire = 20m

julia> k(d) = E * 0.691 * π/4 * d^2 / l_wire |> N/mm
k (generic function with 1 method)

julia> k(30mm)
10061.845827027584Nmm^-1
julia> k.([5 6 8]mm)
1×3 Array{Float64{Nmm⁻¹},2}:
139.748 201.237 357.755

julia> δ(d)= F / k(d) |> mm
δ (generic function with 1 method)
Expand All @@ -135,48 +120,64 @@ Stacktrace:
[1] top-level scope at none:0

julia> dimension(d)
Time

julia> 1d |> s
(86400//1)s

julia> @import_expand ~V ~W ~A
julia> @import_expand ~V ~W ~A G

julia> sqrt(1G²)
6.67408e-11kg^-1s^-2
6.6743e-11kg⁻¹s⁻²

julia> [1V*12.0A 2J/s 1kg*g*1m/2s] .|> W
1×3 Array{Float64{W},2}:
12.0 2.0 4.90332
julia> [1V*12.0A 2W 1kg*g*1m/2s]*30minute |> kJ
1×3 Array{Float64{kJ},2}:
21.6 3.6 8.82598

```
julia> ω = 50*2π*rad/s
π = 3.1415926535897...rads⁻¹

julia> t = (0:0.006:0.02)s
0.0s:0.006s:0.018s

Tip:
- use dimension(ans)
julia> u = 220V*exp.(imt))
4-element Array{Complex{Float64}{V},1}:
220.0 + 0.0im
-67.98373876248841 + 209.2324335849338im
-177.98373876248843 - 129.31275550434407im
177.98373876248843 - 129.31275550434412im


julia> u*1.5A |> J
4-element Array{Complex{Float64}{Js⁻¹},1}:
330.0 + 0.0im
-101.97560814373261 + 313.8486503774007im
-266.97560814373264 - 193.9691332565161im
266.97560814373264 - 193.9691332565162im

# ~: Also import SI prefixes like mV, kW
```

You may get warning messages when also loading other packages. If that happens, switch from `using MechanicalUnits`to just what you need:
As we encountered above, the global namespace is quite cluttered with units by default. For clarity, import just what you need:
```julia
import MechanicalUnits: N, kg, m, s, MPa
```


## Goals (11/19 reached)
## Goals
This adaption of [Unitful.jl](https://github.com/PainterQubits/Unitful.jl) aims to be a preferable tool for quick side calculations in an office computer with limited user permissions.

This means:
* We adapt to the limitations of Windows Powershell, Julia REPL or VSCode. Substitute symbols which can't be displayed: `𝐓 -> Time`, `𝐋 -> Length`, `𝐌 -> Mass`
* We adapt to the limitations of Windows Powershell, Julia REPL or VSCode. Substitute symbols which can't be displayed.: `𝐓 -> `
* Units have color, which are sort of tweakable: `show(IOContext(stderr, :unitsymbolcolor=>:bold), 1minute)`
* We pick a set of units as commonly used in mechanical industry
* `h` is an hour, not Planck's constant
* `in` is reserved by Julia; `inch` is a unit
* `g` is gravity's acceleration, not a gramme
* Prefer `mm` and `MPa`
* REPL output can always be parsed as input. We define the bullet operator `` (U+2219, \vysmblkcircle + tab) and print e.g. `2.32m∙s^-1`
* Export dimensions to get short type signatures:
* Support division in a similar way as multiplication , thus: `[1,2]m/s`
* REPL output can always be parsed as input. We define the bullet operator `` (U+2219, \vysmblkcircle + tab) and print e.g. `2.32m∙s⁻¹`
* Export dimensions to get shorter type signatures:
```julia
julia> 1m |> typeof
Quantity{Int64,Length,FreeUnits{(m,),Length,nothing}}
Quantity{Int64,,FreeUnits{(Unit{:Meter, ᴸ}(0, 1//1),), ᴸ,nothing}
```
* Units are never plural
* Array output moves the units outside or to the header:
Expand All @@ -189,28 +190,28 @@ julia> dist = [900mm, 1.1m]
julia> print(dist)
[900.0, 1100.0]mm
```
* support unitful complex numbers
* We would like to:
* tweak dimension sorting to customary order, thus: `m∙N -> N∙m`
* tweak dimension sorting to customary order, thus: `m∙N -> N∙m`. A good alternative is e.g.
```julia
julia> 43N*mm |> Nmm
(43//1)Nmm

```
* support rounding and customary engineering number formatting, but in a separate package.
* support unitful complex numbers, as they often appear while solving equations.
* have supporting plot recipes, but in a separate package.
* support division in a similar way as multiplication, thus: `[1,2]m/s` should work as input.
* return, instead of an error: `10m |>s -> 10m∙s^-1∙s`
* support colorful units with Atom's mime type
* register the package and have full code coverage

* not rely on a tweaked fork of Unitful, but the original
* register the package and have full test coverage
## Alternatives


[Unitful.jl](https://github.com/PainterQubits/Unitful.jl) lists similar adaptions for other fields.
## Am I missing some essential feature?
- **Nothing is impossible!**

- Open an [issue](https://github.com/hustf/MechanicalUnits/issues/new) and let's make this better together!
- *Bug reports, feature requests, patches, and well-wishes are always welcome.*
Expand All @@ -219,11 +220,11 @@ julia> print(dist)
- ***Is this for real?***
Yes. Unlike complex numbers. This is not, so far, for complex numbers. What about dual numbers? We have not tested yet.
Yes. And for imaginary units as well. What about dual numbers? We have not tested yet.
*What does this cost?*
It costs nothing if your time is free.
Your time. It may save some, too.
## Contributing
Expand Down
7 changes: 5 additions & 2 deletions src/import_export_units.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,20 @@ const global mech_units = Vector{Symbol}()
# In order to avoid awkwardness like 'm∙N', we define the product as its own unit.
# It is used to represent a moment, rather than energy.
begin
@unit Nm "Nm" NewtonMeter (1//1)N*m false
@unit Nmm "Nmm" NewtonMiliMeter (1//1000)N*m false
@unit Nm "Nm" NewtonMeter (1//1)N*m false
@unit daNm "daNm" dekaNewtonMeter (10//1)N*m false
@unit kNm "kNm" kiloNewtonMeter (1000//1)N*m false
@unit MNm "MNm" MegaNewtonMeter (1000000//1)N*m false
@unit GNm "GNm" GigaNewtonMeter (1000000000//1)N*m false
push!(mech_units, :Nmm)
push!(mech_units, :Nm)
push!(mech_units, :daNm)
push!(mech_units, :kNm)
push!(mech_units, :MNm)
push!(mech_units, :GNm)
export Nm, daNm, kNm, MNm, GNm
export Nmm, Nm, daNm, kNm, MNm, GNm
eval(exponents_superscripts(:Nmm))
eval(exponents_superscripts(:Nm))
eval(exponents_superscripts(:daNm))
eval(exponents_superscripts(:kNm))
Expand Down
37 changes: 29 additions & 8 deletions test/conversion_promotion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,37 @@ using Test
@test v1 !== v2
end

@testset "Conversion factors" begin
@testset "Conversion factors and conversions with identical dimensions" begin
@test convfact(m, cm) == 1//100
@test convfact(kg*m, cm) == (1//100)kg
@test convfact(kg*m, kg*cm) == (1//100)
@test cm(1m) === (100//1)cm
@test cm(1.0m) === 100.0cm
@test cm(2m) === (200//1)cm
@test cm(2.0m) === 200.0cm
@test mm(1.0m) == 1.0e3*mm
@test (N*mm)(1.0N*m) == (1000/1)N*mm
@test kNm(1.0e6N*mm) == 1.0e6N*mm
@test kNm(1.0e6N*mm) !== 1.0e6N*mm
@test kNm(1.0e6N*mm) === kNm(1.0e6N*mm)
end

@testset "Flexible conversions" begin
@test cm(1m) === (100//1)cm
@test cm(1.0m) === 100.0cm
@test cm(1kg*m) == (100//1)cmkg⁻¹
# Actual error: The numeric type needs to be fixed.
@test N*mm(1.0kNm) === 1.0e6*N*mm
@test cm(1.0kg*m) === 100.0cm
@test convfact(m, kg) === (1//1000)kgmm⁻¹
@test cm(1kg*m) === (100//1)kgcm
@test cm(1kg*m) == 1kg*m
@test cm(1kg*m) !== 1kg*m
@test cm(1kg*m) === (100//1)kgcm
@test mm(2.0kg*m) == 2.0kg*m
@test mm(2.0kg*m) !== 2.0kg*m
@test mm(2.0kg*m) === 2000.0kgmm
@test (kg*m)(1ft*lb) 1ft*lb
@test (kg*m)(1ft*lb) === 0.13825495437600002kgm
@test 0.13825495437600002kgm + 1ftlb 2ftlb
@test 0.13825495437600002kgm + 1ftlb === 276.509908752kgmm
end

@testset "Conversions with arrays" begin
v = [1N 2daN]
@test v |> kg == [1000//1 20000//1]kgmms⁻²
@test (v |> kg .=== Array([(1000//1) (20000//1)]kg*mm*s^-2)) == [true true]
end

0 comments on commit e692b59

Please sign in to comment.