Git Product home page Git Product logo

unitful.jl's People

Contributors

ajkeller34 avatar aplavin avatar beastyblacksmith avatar briochemc avatar c42f avatar chrisrackauckas avatar christiankral avatar cmichelenstrofer avatar cstjean avatar eben60 avatar ggggggggg avatar giordano avatar jefffessler avatar jeffreysarnoff avatar kronosthelate avatar mweastwood avatar nicoleepp avatar non-jedi avatar rafaqz avatar rapus95 avatar rdeits avatar richardreeve avatar sbuercklin avatar simonbyrne avatar singularitti avatar socob avatar sostock avatar staticfloat avatar timholy avatar vtjnash avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

unitful.jl's Issues

Converting between unit systems

It would be nice to have the ability to transform from on unit system, say standard SI, to another, say atomic units, without having to specify the explicit units as with uconvert.

I'm not sure exactly how to go about it. One way would be have a function

system = u"g * km * eV"
simplify(a, system)

We can then project units(simplify(a)) (simplified as in #34) onto the units in the second argument + an orthogonal subspace of units defined by: (i) just SI units, or (ii) the units of simplify(a * system) over each individual dimension. I think I would go for (ii).
One caveat is users entering a unit system that is not linearly independent.

Another possibility is to define a new type with an appropriate * operator. And then proceed in a fairly similar manner. The difference is that the type and associated arithmetic could be made to guarantee that the units are linearly independent. And uconvert(a, system) could be used.

Comments and preferences?

Function to simplify units, e.g. m/ft -> dimensionless

@ajkeller34, unless I'm mistaken, the following functionality (simplify) does not yet exist. Happy to try and implement it if it doesn't:

notsosimple = 1u"m/ft*kg"
simple = simplify(notsosimple)
@assert units(simple) === units(1u"kg")

It should be possible to determine which unit to use of m or ft, the same way it is done for +, viapromote_type

Method to collapse/squash/simplify units

As mentioned in #13 and a few other issues, there is currently no way to squash:

  • something like 7 MeV/keV
  • to 7e+3 (dimensionless)

Can you add a simplify(unitful_variable) method (or something like that) to handle this?

Even if it wasn't robust or kind of wonky at first, I think it still gives a good addition moving forward

defining unit relative to prefixed unit causes problems

I defined a Liter unit based on 1000cm^3, and it seemed to work most of the time, but then failed on some operations. If I instead define it based on m^3, then it seems to work as expected. I added the following lines to Defaults.jl to test this:

@unit L     "L"         Liter       (1//1000)*m^3           true
@unit altL  "altL"      altLiter    1000*cm^3               true
@unit arb   "arb"       Arb         1nA                     true

And then did the following tests at the REPL that all work.

julia> a = 1u"altL"
1 altL
julia> a = 1u"maltL"
1 maltL
julia> dimension(a)
𝐋^3

But then trying to get back to a unitless number fails

julia> Float64(1u"altL/cm^3")
ERROR: DomainError:
Cannot raise an integer x to a negative power -n. 
Make x a float by adding a zero decimal (e.g. 2.0^-n instead of 2^-n), or write 1/x^n, float(x)^-n, or (x//1)^-n.
 in power_by_squaring(::Int64, ::Int64) at ./intfuncs.jl:118
 in basefactorhelper(::Float64, ::Int64, ::Int64, ::Rational{Int64}) at /Users/oneilg/.julia/v0.5/Unitful/src/Unitful.jl:268
 in map(::Unitful.#basefactor, ::Tuple{Unitful.Unit{:Meter},Unitful.Unit{:altLiter}}) at ./tuple.jl:93
 in basefactor(...) at /Users/oneilg/.julia/v0.5/Unitful/src/Unitful.jl:276
 in convfact(...) at /Users/oneilg/.julia/v0.5/Unitful/src/Conversion.jl:85
 in convert at /Users/oneilg/.julia/v0.5/Unitful/src/Conversion.jl:183 [inlined]
 in Float64(::Unitful.Quantity{Int64,Unitful.Dimensions{()},Unitful.Units{(Unitful.Unit{:Meter}(-2,-3//1),Unitful.Unit{:altLiter}(0,1//1)),Unitful.Dimensions{()}}}) at ./sysimg.jl:53

The version based on m^3 works for going to a unitless number

julia> Float64(1u"L/cm^3")
1000.0

And arb (based on nA) shows the same error as altL

julia> Float64(1u"arb/A")
ERROR: DomainError:
Cannot raise an integer x to a negative power -n. 
Make x a float by adding a zero decimal (e.g. 2.0^-n instead of 2^-n), or write 1/x^n, float(x)^-n, or (x//1)^-n.
 in power_by_squaring(::Int64, ::Int64) at ./intfuncs.jl:118
 in basefactorhelper(::Float64, ::Int64, ::Int64, ::Rational{Int64}) at /Users/oneilg/.julia/v0.5/Unitful/src/Unitful.jl:268
 in map(::Unitful.#basefactor, ::Tuple{Unitful.Unit{:Ampere},Unitful.Unit{:Arb}}) at ./tuple.jl:93
 in basefactor(...) at /Users/oneilg/.julia/v0.5/Unitful/src/Unitful.jl:276
 in convfact(...) at /Users/oneilg/.julia/v0.5/Unitful/src/Conversion.jl:85
 in convert at /Users/oneilg/.julia/v0.5/Unitful/src/Conversion.jl:183 [inlined]
 in Float64(::Unitful.Quantity{Int64,Unitful.Dimensions{()},Unitful.Units{(Unitful.Unit{:Ampere}(0,-1//1),Unitful.Unit{:Arb}(0,1//1)),Unitful.Dimensions{()}}}) at ./sysimg.jl:53

Tests which use Unitful have side-effects

The first time I ran a code which used Unitful in the tests when it was not installed it was fine, but the second time I got:

INFO: Building Unitful
WARNING: `Pkg.build("Unitful.jl")` was run, but /home/crackauc/.julia/v0.5/Unitful/deps/Defaults.jl already exists. No action has been taken. If you encounter problems, you might consider backing up then deleting the existing file at /home/crackauc/.julia/v0.5/Unitful/deps/Defaults.jl, then running `Pkg.build("Unitful")` again.

which means that Unitful leaves something behind when it's removed. I think this is related to #33? @tkelman might want to chime in.

multiple granularities within a single physical dimension

With the physical dimension of _Time, and the base relative unit, the unit of _Second,
we define _Minute and _Hour as exact integer multiples of the relative unit.
Adopting a coarser granularity, and granularity based relative unit, the unit of _Month,
we define _Year and _Century as exact integer multiples of the relative unit.

When the situation allows, we prefer to work with granularity based relative unit and
units of measure naturally expressible as exact scalars, relative to the relative unit.

This is distinct from support for multiple systems of units, yet its support, cleanly realized,
may be expressed sharing much of the approach that allows work with different unit systems
without forcing each unit system to be a facade laid over the expression of SI unit values.

Have you developed some design/implementation insight just well-suited?

Type oscillation in promotion

julia> x, y = 10m, 1
(10 m, 1)

julia> px, py = promote(x, y)
(10 m, 1)

julia> ppx, ppy = promote(px, py)
(10 m, 1)

julia> (typeof(y), typeof(py), typeof(ppy))
(Int64, Quantity{Int64, Dimensions:{}, Units:{}}, Int64)

Tip of the hat to @timholy for finding this gem. Guess I should add a damping term to my type oscillator.

Defaults.jl missing from latest master issue?

Hi Andrew,

Is this a problem on my side or am I updating at an unlucky moment?

In the past I had forked the Unitful.jl repository, but the last couple of weeks I just added the oil-field units I needed in my application package. Would it be'safer' for me to go back to forking Unitful.jl?

Thanks and regards,
Rob

Details:

First I got:

julia> using Unitful
INFO: Precompiling module Unitful.
ERROR: LoadError: could not open file /Users/rob/.julia/v0.5/Unitful/deps/Defaults.jl
in include_from_node1(::String) at ./loading.jl:488
in include_from_node1(::String) at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?
in defaults() at /Users/rob/.julia/v0.5/Unitful/src/User.jl:261
in include_from_node1(::String) at ./loading.jl:488
in include_from_node1(::String) at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?
in macro expansion; at ./none:2 [inlined]
in anonymous at ./:?
in eval(::Module, ::Any) at ./boot.jl:234
in eval(::Module, ::Any) at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?
in process_options(::Base.JLOptions) at ./client.jl:239
in _start() at ./client.jl:318
in _start() at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?
while loading /Users/rob/.julia/v0.5/Unitful/src/Unitful.jl, in expression starting on line 878
ERROR: Failed to precompile Unitful to /Users/rob/.julia/lib/v0.5/Unitful.ji.
in compilecache(::String) at ./loading.jl:593
in require(::Symbol) at ./loading.jl:422
in require(::Symbol) at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?

Now I'm getting:

julia> using Unitful
INFO: Precompiling module Unitful.
ERROR: LoadError: could not open file /Users/rob/.julia/v0.5/Unitful/deps/Defaults.jl
in include_from_node1(::String) at ./loading.jl:488
in include_from_node1(::String) at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?
in defaults() at /Users/rob/.julia/v0.5/Unitful/src/User.jl:261
in include_from_node1(::String) at ./loading.jl:488
in include_from_node1(::String) at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?
in macro expansion; at ./none:2 [inlined]
in anonymous at ./:?
in eval(::Module, ::Any) at ./boot.jl:234
in eval(::Module, ::Any) at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?
in process_options(::Base.JLOptions) at ./client.jl:239
in _start() at ./client.jl:318
in _start() at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?
while loading /Users/rob/.julia/v0.5/Unitful/src/Unitful.jl, in expression starting on line 878
ERROR: Failed to precompile Unitful to /Users/rob/.julia/lib/v0.5/Unitful.ji.
in compilecache(::String) at ./loading.jl:593
in require(::Symbol) at ./loading.jl:422
in require(::Symbol) at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?

Better display for units

SIUnits.jl seemed to handle this pretty well. There's no superscript slash in Unicode, so printing rational exponents using Unicode only will be problematic.

Base units not exported?

Hi,

Unless I'm missing something, base units like m and kg are not available after upgrading to the latest master. I wiped the old version and did

Pkg.clone("https://github.com/ajkeller34/Unitful.jl.git")
Pkg.build("Unitful")
using Unitful

After that, I get e.g. ERROR: UndefVarError: kg not defined. This on Julia 0.5-rc3.

Compatibility with Measurements.jl

Let me first express my appreciation for the package, looks really nice! I like very much the possibility to have units with rational exponents, maybe not really physical but useful in calculations. In addition, it appears to be much faster than SIUnits.jl, yet it has more features (for what I can see).

I'd like to ask you whether it is possible to make this package compatible with Measurements.jl, a library for uncertainty propagation. This package provides a new type, Measurement, which is subtype of AbstractFloat and takes AbstractFloat numbers with uncertainty, then instructs most mathematical operations to correctly propagate the uncertainty to the result. You can read here the discussion which led to the final choice: JuliaPhysics/Measurements.jl#1

The main thing that Unitful.jl should do in order to became compatible with Measurements.jl is to make DimensionedQuantity subtype of AbstractFloat.

I understand the change I'm proposing is breaking, but it would be really cool to see error propagation for numbers with their units!

Simplification of units

Hi,

Is there a way to simplify units that are the same, for example if I enter:

1J / (1N*m)

The result is:

1.0 m^-1 N^-1 J

I would have expected just 1.0, like when I do 1J / (1J)

This was on 0.5-rc3 using the master branch, is it recommended to use the rewrite branch instead?

Base overrides

I'm rewriting Images.jl, which currently (sort of) supports encoding of information like the spacing between pixels with unit-ful quantitites (currently via SIUnits). In the rewrite (which will require julia 0.5), I'm struggling with whether to remain with SIUnits or switch to Unitful. The switch faces a number of issues:

  • while Unitful may be more up-to-date than SIUnits, base julia has nevertheless changed considerably since it was first written: Functors have been removed, and the whole promote_op infrastructure has been dramatically simplified with (yay!) finally the ability to rely on inference for many operations
  • you override many functions in base. The number of warnings is a significant disincentive for me to switch.
  • there were some good discussions in JuliaLang/julia#15394 about potential problems with ranges, but those seem to have remained unresolved.
  • this is not registered as a package, which would also be a prerequisite for switching.

I guess I'm posting this largely to try to gauge your enthusiasm for updating Unitful and addressing these issues. Given the number of other packages I maintain/work on I probably don't have the bandwidth to make major changes to this package (nor to SIUnits), so I am trying to read the tea leaves to figure out what will become the future well-supported units package in Julia.

Missing dot operators on julia 0.5

.< and .<= cannot be used to compare two Quantity objects on julia 0.5. This is not an issue for julia 0.6 where the dots are syntax for fused broadcasts.

Fix inbound.

StackOverflowError from @fastmath

Unitful.jl is incompatible with @fastmath. Here's a small example showing how to get the StackOverflowError (requires that you have optimized Julia to your system, like re-built the system image, and I can only get this error on Linux but not Windows)

using Unitful
u = 1.5u"N"
halfΔt = 0.03125u"s"
tmp2 = .25u"N/s"
u+halfΔt*tmp2
@fastmath u+halfΔt*tmp2

SIUnits has the same error at Keno/SIUnits.jl#94

Defaults handling needs improvement

The deps/Defaults.jl file is not regenerated with each invocation of Pkg.build("Unitful") if the file exists already. This is to avoid overwriting user defaults. However, in some cases the defaults need to be changed to be compliant with changes to code in the package. It would be nice if there were a mechanism to handle this so that the user doesn't have to clear out that file or merge their changes manually.

Stripping of units

Unitful is an amazing package and seems to me to be the one superseding all the others - I'd like to consider it (after some further maturity) to get part of the Julia "standard packages" ecosystem.
I'm used to the unit system of CLHEP library used in high-energy physics codes (e.g. manual, git), where the workflow is following:

At the input, all values are multiplied by the input unit, all computations are done with units and at the output (or binary interface or ccall to a library), the variable is divided by the desired unit:

u = 15u"V"
d = 5u"mm"
E = u/d
outE = E/u"V/m"
>3.0 mm^-1 m

I'd like outE v to be an unitless value of 3000.
This would be much more readable than having to write upreferred(outE), or using convert and ustrip functionality. Compare the following easy readable code (as would be in CLHEP)

println("The field intensity is $(E/u"V/m") [V/m] in a gap of $(d/u"m") [m]")
>The field intensity is 3000.0 [V/m] in a gap of 0.005 [m]

with the current verbosity

println("The field intensity is $(ustrip(float(uconvert(u"V/m", E)))) [V/m] in a gap of $(ustrip(float(uconvert(u"m", d)))) [m]")
>The field intensity is 3000.0 [V/m] in a gap of 0.005 [m]

Is it possible to specialize somehow the / operator in such a way that if dimensions of both operands are same, the units are correctly stripped, giving just a float number?
At least for cases where just different unit multiples of the same basic unit are uses, such as mm and m, etc.
Thank you for the advice.

Comparisons fail between dimensionless quantities and unitless numbers

julia> using Unitful

julia> 1u"μm/m" < 1
ERROR: MethodError: no method matching isless(::Unitful.Quantity{Int64,Unitful.Dimensions{()},Unitful.Units{(Unitful.Unit{:Meter}(-6,1//1),Unitful.Unit{:Meter}(0,-1//1)),Unitful.Dimensions{()}}}, ::Int64)
Closest candidates are:
  isless(::Char, ::Integer) at deprecated.jl:49
  isless(::AbstractFloat, ::Real) at operators.jl:42
  isless(::Real, ::Real) at operators.jl:75
  ...
 in <(::Unitful.Quantity{Int64,Unitful.Dimensions{()},Unitful.Units{(Unitful.Unit{:Meter}(-6,1//1),Unitful.Unit{:Meter}(0,-1//1)),Unitful.Dimensions{()}}}, ::Int64) at ./operators.jl:63

Newly defined units unavailable to u_str

Following the docs I tried:

julia> using Unitful

julia> @unit M "M" Molar 1u"mol/L" true
M

julia> 1M
1 M

julia> 1u"M"
ERROR: Symbol M could not be found in registered unit modules.

edit: Expected behavior is that 1M==1u"M"

Base.quadgk fails with Unitful

My guess is that this issue actually arises from Base, but it seems worth having someone with more knowledge look at it first. The docs for quadgk claim that it should work with any type that implements, +, -, multiplication by real values, and norm; all of which seem to work with Quantity.

julia> using Unitful

julia> quadgk(x->x*1u"mm",0,1)
ERROR: Unitful.DimensionError()
 in convfact(...) at /Users/oneilg/.julia/v0.5/Unitful/src/Conversion.jl:79
 in convert at /Users/oneilg/.julia/v0.5/Unitful/src/Conversion.jl:183 [inlined]
 in Base.QuadGK.Segment(::Float64, ::Float64, ::Unitful.Quantity{Float64,Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)},Unitful.Units{(Unitful.Unit{:Meter}(-3,1//1),),Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}}}, ::Unitful.Quantity{Float64,Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)},Unitful.Units{(Unitful.Unit{:Meter}(-3,1//1),),Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}}}) at ./quadgk.jl:40
 in evalrule(::##1#2, ::Float64, ::Float64, ::Array{Float64,1}, ::Array{Float64,1}, ::Array{Float64,1}, ::Base.LinAlg.#vecnorm) at ./quadgk.jl:79
 in do_quadgk(::##1#2, ::Array{Float64,1}, ::Int64, ::Type{Float64}, ::Float64, ::Float64, ::Int64, ::Base.LinAlg.#vecnorm) at ./quadgk.jl:120
 in #quadgk#15(::Array{Any,1}, ::Function, ::Function, ::Int64, ::Int64) at ./quadgk.jl:230
 in quadgk(::Function, ::Int64, ::Int64) at ./quadgk.jl:225

Option to disable automatic conversion

There are some cases where I would like to disable automatic conversion of units, and instead throw an error. Is this something that you would consider? I don't actually know how one would go about implementing it though.

A related issue is when there isn't a fixed conversion between units, e.g. currencies. Is there a way I could define new units that would simply throw an error if I attempted to use them in an incompatible way?

very nice -- fyi: automatic build does not seem to go by itself

Nicely improved -- thank you.

I don't know why Pkg.build does not just happen (Linux v0.5.0rc3).

# this works
julia> Pkg.clone("git://github.com/ajkeller34/Unitful.jl.git")
INFO: Cloning Unitful from git://github.com/ajkeller34/Unitful.jl.git
INFO: Computing changes...
INFO: No packages to install, update or remove

julia> Pkg.build("Unitful")
INFO: Building Unitful
INFO: Default units, dimensions, and logic are set in /home/jas/.julia/v0.5/Unitful/deps/Defaults.jl

julia> using Unitful

#
# this does not build by itself
#
julia> Pkg.rm("Unitful");Pkg.rm("Unitful");

julia> Pkg.clone("git://github.com/ajkeller34/Unitful.jl.git")
INFO: Cloning Unitful from git://github.com/ajkeller34/Unitful.jl.git
INFO: Computing changes...
INFO: No packages to install, update or remove

julia> using Unitful
INFO: Precompiling module Unitful...
ERROR: LoadError: could not open file /home/jas/.julia/v0.5/Unitful/deps/Defaults.jl
 in include_from_node1(::String) at ./loading.jl:426
 in defaults() at /home/jas/.julia/v0.5/Unitful/src/User.jl:219
 in include_from_node1(::String) at ./loading.jl:426
 in macro expansion; at ./none:2 [inlined]
 in anonymous at ./<missing>:?
 in eval(::Module, ::Any) at ./boot.jl:234
 in process_options(::Base.JLOptions) at ./client.jl:239
 in _start() at ./client.jl:318
while loading /home/jas/.julia/v0.5/Unitful/src/Unitful.jl, in expression starting on line 704
ERROR: Failed to precompile Unitful to /home/jas/.julia/lib/v0.5/Unitful.ji
 in compilecache(::String) at ./loading.jl:505
 in require(::Symbol) at ./loading.jl:364

# but forcing the build gets it working
julia> Pkg.build("Unitful")
INFO: Building Unitful
INFO: Default units, dimensions, and logic are set in /home/jas/.julia/v0.5/Unitful/deps/Defaults.jl

julia> using Unitful

julia> quit()

`==` is not symmetric

julia> 1u"g" == 0.001u"kg"
false

julia> 0.001u"kg" == 1u"g"
true

Can this be handled by promotion somehow?

muladd causes StackOverflow errors

using Unitful
muladd(0.1u"s",0.16666666666666666u"N*s^-1",1.0u"N")

Unitful-based tests on OrdinaryDiffEq.jl (DifferentialEquations.jl) have been disabled due to this problem.

Decibel-based unit support

There are a number of decibel-based units in common use (dBm, dBW, dBV, ...). It seems like a lot of work to support them properly, but I would certainly use them.

failed uconvert example

Here is a surprising failed call to uconvert. It works to convert to u"cm^-2" but not to convert to u"1/cm^2".

julia> 1u"1/cm^2"==1u"cm^-2"
true
julia> uconvert(u"cm^-2",1u"fs*W/(eV*cm^2)")
6241.509125883258 cm^-2
julia> uconvert(u"1/cm^2",1u"fs*W/(eV*cm^2)")
ERROR: MethodError: no method matching uconvert(::Unitful.Quantity{Int64,Unitful.Dimensions{(Unitful.Dimension{:Length}(-2//1),)},Unitful.Units{(Unitful.Unit{:Meter}(-2,-2//1),),Unitful.Dimensions{(Unitful.Dimension{:Length}(-2//1),)}}}, ::Unitful.Quantity{Int64,Unitful.Dimensions{(Unitful.Dimension{:Length}(-2//1),)},Unitful.Units{(Unitful.Unit{:Meter}(-2,-2//1),Unitful.Unit{:Second}(-15,1//1),Unitful.Unit{:Watt}(0,1//1),Unitful.Unit{:eV}(0,-1//1)),Unitful.Dimensions{(Unitful.Dimension{:Length}(-2//1),)}}})
Closest candidates are:
  uconvert{T,D,U}(::Unitful.Units{N,D}, ::Unitful.Quantity{T,D,U}) at /Users/oneilg/.julia/v0.5/Unitful/src/Conversion.jl:21
  uconvert(::Unitful.Units{N,D}, ::Number) at /Users/oneilg/.julia/v0.5/Unitful/src/Conversion.jl:58

Reduce to base units?

Is there a function to reduce to base units?

I can do

julia> uconvert(u"m",4u"m^3"/2u"cm^2")
20000.0 m

But only if I already know it has units of meters, but what if I want to just get to base units without knowing what they will be?

something wrong with the length of ranges build from Quantitys

I remember that you had requested change to Base to allow ranges to work correctly, I don't remember if those happened or not. But I think these are unrelated. Here is an example where collect(range) is not even monotonic. The result is not always the same, suggesting this value is initialized. Also the behavior is different when the range is used in a comprehenision vs when used with the new vectorizing dot syntax.

julia> range = 0u"mm":0.001u"mm":5.4167u"mm"
0.0 mm:0.001 mm:5.416 mm
julia> collect(range)[end]
NaN mm #expected 5.416mm
julia> [r.val for r in range][end]
6.934269676051e-310 #expected 5.416
julia> getval(q)=q.val
julia> getval.(range)[end]
5.416 #expected 5.416

Here is an example where the range appears to end two value too soon.

julia> collect(0u"mm":0.001u"mm":5u"mm")[end]
4.998000000000004 mm #expected 5.0 mm
julia> length(0:0.001:5)-length(0u"mm":0.001u"mm":5u"mm")
2

Stripping units

Hi,

It would be useful to easily be able to strip units, e.g. for making arrays to pass to a plotting package, or for using linspace.

I know we can do a/unit(a), but that's a bit verbose since it requires writing the variable name twice. Would a function like this be an acceptable addition:

value(a) = a.val

typo in deps/build.jl

`julia> typeof(u"ha")
Unitful.Units{(Unitful.Unit{:Are}(2,1//1),),Unitful.Dimensions{(Unitful.Dimension{:Length}(1//1),)}}

julia> typeof(u"a")
Unitful.Units{(Unitful.Unit{:Are}(0,1//1),),Unitful.Dimensions{(Unitful.Dimension{:Length}(2//1),)}}
`
The dimension of should be L^2 in both cases, I guess.

const ha = Unitful.Units{(Unitful.Unit{:Are}(2,1//1),), typeof(𝐋^2)}() deps/build.jl: 85

unexpected results of Unitful type hierarchy

Unitful.jl is testament to the fact that physical units are superbly useful, even for computation. In fact, I assert that nondimensional numbers are also superbly useful.

Typically I want to attach units to variables, so whatever units I start with, I can specify how to calculate things correctly with some set of mutually compatible units. Yet after converting inputs to the compatible units, I want the computer to do a nondimensional (often floating point) calculation. Now that there is Unitful, it can express the result in sensible and correct units too.

I would like to be able to dispatch functions specifically on nondimensional Numbers. I don't know how to do this, perhaps because I'm just learning Julia types and methods. I can make methods that dispatch on whether I pass a function, e.g., a ::Pressure or a ::Temperature, but there's no type syntax I know of to dispatch a method to operate particularly on a NonDimensionalNumber. It seems awkward because Quantity <: Number, so that Number includes nondimensional Numbers and nondimensional and dimensional Unitful.Quantitys. My desired NonDimensionalNumber abstract type would include Numbers that are not Quantitys, or at least not dimensional ones. Whether variables have this property can be assessed at run time, but not when the compiler dispatches using type.

julia> Quantity <: Number
true

julia> DimensionlessQuantity <: Quantity
true

julia> isa(1u"m/m",DimensionlessQuantity)
false

julia> isa(1,DimensionlessQuantity)
false

julia> isa(1//1,DimensionlessQuantity)
false

julia> isa(NoUnits(1u"m/μm"),DimensionlessQuantity)
false

There are lots of physically meaningful nondimensional numbers: e.g. ratios of things with the same dimensions. Some nondimensional numbers even have hallowed names like Reynolds and Rayleigh. Scientific computation has made itself very useful dealing entirely with nondimensional numbers, or at any rate not knowing the numbers were dimensional, leaving pesky unit conversions to humans.

Orthogonal work at EngUnits.jl

Good work, I have recently been working on a package called EngUnits.jl. The package extent SIUnits.jl to handle input and output units more gracefully. My two primary concerns when designing the package was:

  • Allow units to be expressed without interfering with variable names and exporting a lot of variables.
    This is handled by a string macro. So you can write: 1*u"kN/m^2" == 1000u"Pa". This allow for having a lot of different units without exporting them from the package and avoids cases where the unit name is overwritten.
  • The other concern of the package where to get rid of the unintuitive display of 1*Newton*1*Meter, which is displayed as 1 kg m²s⁻². Instead the package displays it as J, and the user can specify to get it displayed different by display_unit(u"J", "N m"). The units can also be displayed with a certain prefix as: display_unit(u"MPa", "MPa"). This will cause pressure to always be displayed in MPa. The user can change the default display values by changing a setup file created during build time of the package.

This package seem to be aiming for a versatile implementation of units. I hope some of the concerns, I have raised here can be considered, when furher improvements of this package are made. The string macro implementation, should be quite easy to port to this package. I will be happy to do it in a PR, if people find it appropriate. I do not know how easy it would be, to implement a similar output display system.

Some details for usage in DifferentialEquations

Hey, I was thinking of adding compatibility to this package in differential equations. I have already made the ODE parts fully compatible with SIUnits, though it seems there are limitations to that package which led me here. However, there are a few things I wanted to discuss that I couldn't find in the documentation:

  1. I see that rational dimensions are accepted. This is good since Brownian motion for SDEs has a natural dimension of sqrt(dt). So for reference, does the sqrt function work with Unitful units?
  2. How does \ and sparse matrix multiplication do? Those would be required for the PDE solvers. SIUnits runs into problems with \ since it calls CHOLMOD, either there needs to be a dispatch which strips the units and then puts them back on (and checks afterwards that the units work?). I'm not sure what goes wrong with SIUnits sprase matrix multiplication. I think it makes zeros that aren't unit'd and then the unit checks go wrong.
  3. This package would have to get registered to be a dependency. Is that likely in the future?
  4. Is there a max(x,y) for AbstractArrays of (same dimension) unit'd quantities in Unitful?

(0°C)^n should not equal 0*(°C)^n

Same for °F. Better to convert °C to an absolute scale like K before taking the power, if it is the only unit on the quantity.

Not sure if better to convert °F to °Ra or K since both are absolute scales, and °Ra is more closely related to °F...

Integration with JLD.jl

Might be related to #9:


currently writeing Unitful variables to a JLD file causes the current error:

ERROR: LoadError: LoadError: LoadError: type parameters with objects of type Tuple{Unitful.Dimension{:Length},Unitful.Dimension{:Mass},Unitful.Dimension{:Time}} are currently unsupported

From JLD.jl/src/JLD.jl, it looks like the following condition needs to be satisfied:

isbits(x) && parse(s) === x && !isa(x, Tuple)

Allow testing approx equality

Currently get this error:

  Got an exception of type MethodError outside of a @test
  MethodError: no method matching eps(::Unitful.Quantity{Float64,Unitful.Dimensions{(Unitful.Dimension{:Mass}(1//1),)},Unitful.Units{(Unitful.Unit{:Gram,Unitful.Dimensions{(Unitful.Dimension{:Mass}(1//1),)}}(3,1//1),),Unitful.Dimensions{(Unitful.Dimension{:Mass}(1//1),)}}})
  Closest candidates are:
    eps(!Matched::Date) at dates/types.jl:231
    eps(!Matched::DateTime) at dates/types.jl:230
    eps() at float.jl:499

edit: something along the lines (but as a test macro):

function is_within_error(v_actual, v_approx, rel_error=1e-4)

  if v_actual == v_approx
    return true
  end

  if ( v_actual == typeof(v_actual)(0) )
    v_actual, v_approx = v_approx, v_actual
    # or return false or throw an error?
  end

  relative_error = abs( v_actual - v_approx ) / abs(v_actual)
  relative_error < rel_error

end

Julia Julia Version 0.5.0-dev+3192 requires Core.Intrinsics?

Hi Andrew,

I noticed that with this mornings build of Julia 0.5.0- Intrinsics.box on lines 54 and 55 of Unitful.jl needed to be replaced by Core.Intrinsics.box.

As I have added some oil field units it's a bit tricky to generate a PR, but if that would help I can do it.

Thanks for a great Pkg!

Rob

Add a method to `in` for convenient unit conversion?

julia> import Base:in

julia> in(x::Quantity, y::Unitful.Units) = uconvert(y,x)
in (generic function with 28 methods)

julia> 3u"m"
3 m

julia> ans in u"cm"
300//1 cm

I'm not sure whether to encourage this sort of thing although it's awfully nice at the REPL.

Unitful linear algebra

Some linear algebra operations like \ have a hard time with unitful numbers. Take the following case:

a = [1.0u"N" 2.0u"N"
      3.0u"N" 1.0u"N"]
b = [1.0u"N";3.0u"N"]

If you try \ it gives a dimension error. If you try * then it uses the generic * fallback and not BLAS. The same is true if you use:

A = rand(100,100)u"N"
b = rand(100)u"N"

I suggest trying something like, performing a dimensional analysis, strip the units, use the general * or \, and then re-apply units.

To do this properly, you might need a UnitfulArray instead of an array of Unitful values. I am not sure if stripping the units on an array of Unitful numbers can be done without making a temporary.

dispatch on units of angle

I am interested in adding Unitful as a dependency for a package I maintain, but it is important that I am able to dispatch on units of angle. For example I have a 3-vector type, and it would be nice to provide constructors like (without units all of the arguments are Float64 and you don't get the convenience of having both constructors):

f(x::Unitful.Length, y::Unitful.Length, z::Unitful.Length) = ...
f(r::Unitful.Length, theta::Unitful.Angle, phi::Unitful.Angle) = ...

I am also going to argue that "Angle" should be a fundamental (not derived dimension). The idea that angles are "dimensionless" seems to originate from the idea that it is a length / length (see table 3 http://physics.nist.gov/cuu/Units/units.html), but this is only correct in the small angle approximation. In general you need to use a trig function to get from an angle to something that is truly dimensionless. Or rather you need an inverse trig function to get an angle from something that is dimensionless.

Finally it would also be really cool if sin(1°) dispatched to sind(1).
(see https://github.com/Keno/SIUnits.jl/blob/d25c43483828c954cd63c19cbe3ff209a614bbd1/src/nonsiunits.jl#L15-L22)

Physicist conversions

On master, you can now easily implement conversion between dimensions by multiplying by appropriate fundamental constants (e.g. energy = planck constant * frequency). Currently this is on a case-by-case basis, and is opt-in to avoid confusion:

julia> using Unitful

julia> import Unitful: uconvert, EnergyUnit, Frequency

julia> uconvert(e::EnergyUnit, f::Frequency) = uconvert(e, u"h"*f)
uconvert (generic function with 4 methods)

julia> 1u"GHz" |> u"eV"
4.135667662340165e-6 eV

It'd be cool if we could come up with a mechanism to implement this logic automatically given a set of fundamental constants, although this sort of thing would always need to be opt-in. Perhaps we could define a generalized uconvert called dconvert that attempts to convert quantities between dimensions using a set of fundamental constants when possible. The h vs ħ distinction would be super annoying.

Thoughts on "camera units"?

This is really just a discussion topic, it's not something I think belongs in this package. If you don't find it interesting, just close it.

I'm mulling over the proper framework for expressing values recorded from scientific cameras. Such cameras typically report values as, e.g., UInt16. The existing FixedPointNumbers framework allows one to normalize these numbers to a 0-to-1 scale, where 1 means "saturated" (which is something quite important to keep track of---you want to know when your sensor has been maxed out). For example, a 12-bit camera might return values in the range 0x0000:0x0fff, and representing those as N4f12 numbers (where 0x0fff corresponds to 1) is a good choice because it places what would otherwise be arbitrary integers onto a common scale possessing genuine physical meaning.

However, scientific cameras often have another important feature: there's often a known conversion from "camera units" to "number of photons." This, too, is a very meaningful quantity, since the number of photons gives an estimate of the uncertainty in the intensity measurement (sqrt(N) due to Poisson statistics).

So here we have a raw measurement, expressed in essentially arbitrary units, that might meaningfully be reinterpreted in two distinct ways. This sort of feels like physical units (we can convert microns to inches to light-picoseconds), but it also seems a bit different. It kind of seems to blur the lines between dimensionless numbers and dimensionful numbers. One of the reasons I'm thinking about Unitful is the very nice framework you've developed for custom units, but I think there are conceptual as well as practical issues here. Any particular insights on the right choice of framework for representing such numbers? I'm CCing @rsrock and @Cody-G to see if they have any interest in the discussion topic.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.