Unitful - Automatic conversion to preferred units under multiplication and division

97 Views Asked by At

I've just started using Unitful.jl to automatically perform dimensional analysis and unit conversion in my code. This does exactly what I want if I add or subtract variables - I work with atoms and generally want data in atomic units, but sometimes have data in other units, such as Angstroms (Å) or nano- or pico-metres and Unitful automagically does the conversion, so avoiding one of the classic bugs in the scientific area:

ijb@LAPTOP-GUG8KQ9I:~$ julia -O3
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.9.0 (2023-05-07)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> using Revise, OhMyREPL, Debugger, Test, Pkg, Unitful, UnitfulAtomic

julia> using Unitful.DefaultSymbols

julia> Unitful.preferunits(u"bohr")

julia> x=1.0u"bohr"
1.0 a₀

julia> y=1.0u"Å"
1.0 Å

julia> x+y
2.88972612462577 a₀

julia> x-y
-0.8897261246257702 a₀

julia> x+y*y
ERROR: DimensionError: 1.0 a₀ and 1.0 Å^2 are not dimensionally compatible.
Stacktrace:
 [1] +(x::Quantity{Float64, , Unitful.FreeUnits{(a₀,), , nothing}}, y::Quantity{Float64, ^2, Unitful.FreeUnits{(Å^2,), ^2, nothing}})
   @ Unitful ~/.julia/packages/Unitful/eFar5/src/quantities.jl:137
 [2] top-level scope
   @ REPL[39]:1


As a huge fan of unit and dimensional analysis I think this is utterly wonderful ... I wish my main language (Fortran) had similar in the language.

The problem comes with multiplication and division - Unitful doesn't do anything wrong per se, but it returns the result in units that are merely the product of the units provided, not the preferred units for the dimensionality of the units:

julia> x
1.0 a₀

julia> y
1.0 Å

julia> upreferred(dimension(x*y))
a₀^2

julia> x*y
1.0 Å a₀

Division is similar:

julia> x
1.0 a₀

julia> y
1.0 Å

julia> auconvert(x*y)^C

julia> x
1.0 a₀

julia> y
1.0 Å

julia> upreferred(dimension(x/y))


julia> x/y
1.0 a₀ Å^-1



Now I can manually perform the conversions:


julia> x
1.0 a₀

julia> y
1.0 Å

julia> upreferred(dimension(x*y))
a₀^2

julia> auconvert(x*y)
1.8897261246257702 a₀^2

julia> uconvert(upreferred(dimension(x)*dimension(y)),x*y) # More flexible
1.8897261246257702 a₀^2

julia> uconvert(upreferred(dimension(x)/dimension(y)),x/y) # Division works as well
0.529177210903

However is there any way I can automate this through Unitful? I could of course provide appropriate methods for multiplication and division of the types I am employing, but undoubtedly I will miss one, so revisiting the "classic bug" which I am trying to avoid; having Unitful do it automagically would be so much better.

0

There are 0 best solutions below