Soki Sakuraiさんruby-dimensionalを使うと、Rubyで単位付きの計算がとても綺麗にできます。

たとえば、X線天文でよく出てくる「地球で観測したfluxから等方的な放射を仮定したときのluminosity(光度)を求める」計算は以下のようにできます。(以下の例は、激変星GK Perのdwarf nova outburst時のある観測の0.5-10 keVのluminosityを計算したときの例)

require "ruby-dimensional"
require "ruby-dimensional-standard"
require "ruby-dimensional-physics"
include Physics

pi          = 3.141592
flux        = 1.6718e-10*:erg/:cm**2/:s
distance    = 477*:pc
surfaceArea = 4 * pi * distance**2
luminosity  = flux * surfaceArea

puts "Luminosity = %.2e erg/s" % luminosity.in(:erg/:s)
puts "Luminosity = %.2e J/s" % luminosity.in(:J/:s)

これを実行すると、以下のようになります。

> ruby calc_luminostiy_gkper.rb
Luminosity = 4.55e+33 erg/s
Luminosity = 4.55e+26 J/s

ruby-dimensionalのインストール

ruby-dimensionalのインストールについては、github上のマニュアルを参照してください。

Homebrewでパッケージ管理している場合は、コマンド2個で簡単にインストールできます。

> brew tap yuasatakayuki/hxisgd
> brew install ruby-dimensional

==> Installing ruby-dimensional from yuasatakayuki/homebrew-hxisgd
==> Downloading https://github.com/yuasatakayuki/ruby-dimensional/archive/0.1.1.zip
Already downloaded: /Library/Caches/Homebrew/ruby-dimensional-0.1.1.zip
==> cmake .
==> make install

---------------------------------------------
Add 'export RUBYLIB=/usr/local/lib/ruby:$RUBYLIB' to .bashrc or .zshrc
---------------------------------------------

/usr/local/Cellar/ruby-dimensional/0.1.1: 2 files, 8.0K, built in 4 seconds

メッセージにあるように、.bashrcや.bash_profileもしくは.zshrcに以下の行を追加しておいてください。

export RUBYLIB=/usr/local/lib/ruby:$RUBYLIB

使い方

ライブラリの読み込み

物理計算を行うときはrequireメソッドで、以下の3個のモジュールを読み込みます。

  • ruby-dimensional
  • ruby-dimensional-standard
  • ruby-dimensional-physics

Physicsという名前空間で定義されている変数をフラットな名前空間から使う場合は、

include Physics

としておきましょう(上のサンプルではPhysics内の定義は参照していないので必須ではないです)。

使い方

基本的に数値は普通の数値として表記し、単位は:cmや:km、:erg、:J等、単位名の前に”:”をつけた形式で表記します。掛け算、割り算、べき上等は普通の感覚で記述できます。

上の例では

flux        = 1.6718e-10*:erg/:cm**2/:s
distance    = 477*:pc

としてflux(単位時間当たりに単位面積を通過するX線光子のエネルギーの和)を定義しています。:pcは「パーセク」という、天文学で使われる距離の単位です。

変数に格納した単位付き数値は、以下の様に別の式で使用することもできます。

surfaceArea = 4 * pi * distance**2
luminosity  = flux * surfaceArea

単位付き数値を、特定の単位に換算したい場合、in(単位)というメソッドを使います。指定した単位の次元が、その単位付き数値の単位の次元と等しい場合、指定した単位で表記した時の数値が戻されます。

l_in_erg_per_s = luminosity.in(:erg/:s)
l_in_J_per_s = luminosity.in(:J/:s)

定義されている単位一覧

irbから読み込んで、UV.showAllUnits()を実行するとその時点で定義されている単位を確認できます。

>irb

irb(main):001:0> require "ruby-dimensional"
=> true

#まずはデフォルトで定義される単位
irb(main):002:0> UV.showAllUnits()
g = 0.001 kg
m = 1.0 m
s = 1.0 s
A = 1.0 A
K = 1.0 K
N = 1.0 kg m s**-2
J = 1.0 kg m**2 s**-2
W = 1.0 kg m**2 s**-3
min = 60.0 s
hr = 3600.0 s
hour = 3600.0 s
day = 86400.0 s
yr = 31536000.0 s
year = 31536000.0 s

#ruby-dimensional-standardで追加された単位も含めて表示
irb(main):003:0> require "ruby-dimensional-standard"
irb(main):004:0> UV.showAllUnits()
g = 0.001 kg
m = 1.0 m
s = 1.0 s
A = 1.0 A
K = 1.0 K
N = 1.0 kg m s**-2
J = 1.0 kg m**2 s**-2
W = 1.0 kg m**2 s**-3
min = 60.0 s
hr = 3600.0 s
hour = 3600.0 s
day = 86400.0 s
yr = 31536000.0 s
year = 31536000.0 s
Angstrom = 1.0e-10 m
Angstroem = 1.0e-10 m
Ang = 1.0e-10 m
parsec = 3.08567758e+16 m
pc = 3.08567758e+16 m
AU = 149597871000.0 m
in = 0.0254 m
inch = 0.0254 m
yd = 0.9144 m
yard = 0.9144 m
shaku = 0.30303030303030304 m
sun = 0.030303030303030304 m
Hz = 1.0 s**-1
eV = 1.60217657e-19 kg m**2 s**-2
erg = 1.0e-07 kg m**2 s**-2
C = 1.0 s A
e = 1.60217657e-19 s A
V = 1.0 kg m**2 s**-3 A**-1
Ohm = 1.0 kg m**2 s**-3 A**-2
F = 1.0 kg**-1 m**-2 s**4 A**2
Wb = 1.0 kg m**2 s**-4 A**-1
T = 1.0 kg s**-4 A**-1
G = 0.0001 kg s**-4 A**-1
H = 1.0 kg m**2 s**-4 A**-2