配列の各要素の和

[a,b]+[c,d]=[a+c,b+d]
としたい。
まずtranspose methodで[a,b]と[c,d]から[[a,c],[b,d]]という配列を作成し、それぞれの小配列の中身をinject methodを用いて足し合わせる。直観的にはarray1+array2のようにできるとよいのだろうけれど(methodを定義すればよいのだが、ひとまずはこれで)。

[array1,array2].transpose.map{|array| array.inject(&:+)}

IV曲線

[latex] J=J_0T^{1+\alpha} \sinh(\gamma\frac{eV}{kT})|\Gamma(1+\frac{\alpha}{2}+i\gamma\frac{eV}{\pi kT})|^2[/latex]

このIV曲線の式を使ってデータをフィットしようとしたところ、ガンマ関数の引数が複素数になっているのがやっかいだと判明。GnuplotやOriginでは、ガンマ関数の引数は実数しかとれない。しかし、Mathematicaならできるようだ。

model = val1*T^(1 + val2) * Sinh[val3 * x / k / T]* Abs[Gamma[1 + val2/2 + I*val3*x/Pi/k/T]]
fit = FindFit[iv, model, {val1, val2, val3}, x]
Show[Plot[Evaluate[model /. fit], {x, -1, 1}, Frame -> True], ListPlot[iv, PlotStyle -> Red]]

関数の頭文字を大文字にしなければならないとか、引数を[]でくくるとか、いろいろと文法が特殊である。

多次元配列

Rubyでは基本的に配列は一次元。多次元配列を定義する方法はいつくかあるようだが、その中の一つ。

da=Array.new(3).map!{Array.new}

配列の初期化ついては注意が必要。

da=Array.new(3,Array.new(4,0))

のようにnewの引数に初期値を与えると、3個の配列がすべて同じオブジェクトになってしまう。

da[0][1]=7
p da #=> [[0,7,0,0],[0,7,0,0],[0,7,0,0]]
da=Array.new(3).map!{Array.new(4){0}}

のようにブロックを使用すれば大丈夫。

*確認したところ、

da=Array.new(3).map!{Array.new(4,0)}

でも問題なかったが、ブロック文の方が安全か。
一次元配列でさらに確認してみると、

ary=Array.new(3,"foo")
ary[0].capitalize! 
p ary #=>gt;["Foo", "Foo", "Foo"]

とすべての要素が化けてしまうが、最後が破壊的メソッドでなく

ary[0]=ary[0].capitalize

のように代入してしえば一つの要素だけを変更できる。
とりあえず、配列の取扱いは代入を基本としている限りは大丈夫そうだが
念のためブロックを使って初期化するに越したことはない。

空白の消去

元素記号は一文字のもの(H,Oなど)と二文字(Ptとか)のものがあるため、固定長レコードで処理しようとすると2バイト分確保しておく必要がある。そうすると、一文字のものについてはunpackしたときに余分な空白がついてしまう。strip methodで空白を落とせるが、少し煩雑な気がしなくもない。

    buf = rec.unpack("a2")
    printf("%3s\n",buf[0].strip)

バイナリデータの読み書き

open methodの第2変数にbを追加すると、”バイナリモード(ここでの「バイナリ」は改行方式を指すのみであって、取り扱うデータ自体がバイナリかそうでないかは特に関係がない)”で書き込みが行われる。

bin = open("test.bin", "wb")

pack methodで配列中のデータを変換する。下は、配列barの中身を2バイトの文字列と8バイトの倍精度実数x3、計26バイトの固定長に変換する。4バイトの単精度実数にしたい場合は、d→fと変更すればよい。

bin.print(bar.pack("a2d3"))

生成したファイルの容量が、きっかり26バイトになっているのにはちょっと感動。Fortranだと、単にwrite, readするだけでデータ長はほとんど意識しないので。読み取りにはunpackメソッドを用いる。

bin = open("test.bin", "rb")
while rec = bin.read(26)
 buf = rec.unpack("a2d3")
end

さらに、seek methodでデータ読み取り(書き込みも)の開始位置を指定できる。
一行のデータがrecバイトのとき、

 bin.seek(n*rec)

でn行読み飛ばし、

bin.read(rec)

でn+1行目から読んでいくことができる。これは便利。