光学的深さが1の意味を探る実験
光学的深さ(厚み)が1とは
光学的深さが1というの、その問題にしている媒質(地球大気とか恒星大気とか星間物質とか)を透過する光(電磁波)が、吸収や散乱などにより弱められて元の強さの1/eになる深さのことである。 これは定義である、と言えるのであるが、では、なぜ「光学的深さが1は、強度が1/eになるように定義する」のか「その1とはいったい何のこと?」については、大抵の教科書に説明はない。
これについて、腑に落ちる説明が中田好一先生の講義資料の「J.」の一部にあったので、それを実験するソフトを作ってみた。
なお、中田先生の講義資料全体はこちら
シミュレーションの実施例
使用した言語はRubyで、そのGUI開発にshoesを使った。実際にはこのサイトからdownloadするとRuby自体も一緒にインストールされます。なお、対応するOSは、Linux・MacOS・Windows(7用32bit版ですが10でも動きました)。
設定パネル
下の実験結果の説明
左上:光源をすっぽり覆う(タウ=1、衝突断面積の延べ面積が100%に対応)黒紙を10x10の紙片に切り
右上:それをばらまくと、重なったり隙間ができたりする。透過率は0.43程度(被覆率は0.57)
左下:紙片の数を40x40に増やしてばらまくと、透過率は0.39に
右下:さらに紙片を100x100に増やすと、透過率は0.37‥‥程度になり、紙片を無限個にした極限の理論値1/e=0.3678‥‥に近づく
光学的深さが2になると、切る前の紙を2枚にして、切り刻み、ばらまくことに対応する。同様に光学的深さ0.1だと、もとの紙の全面積が1/10枚分にしたものを紙片に分割してばらまいたことに対応する。
実行結果;4種類の条件
プログラムリスト(ソースコード)
被覆率を求めるアルゴリズムは次のとおりです。
(1)窓枠のサイズと紙片の数から1つの紙片の大きさを決め
(2)1つの紙片の位置を、乱数発生により決める
(3)窓全体のピクセルに対応する配列を0で初期化しておいて
(4)1つの紙片が覆うピクセルの配列の値を1に置き換える。
(5)全紙片について覆うピクセルの値を1に置き換える
(6)全配列(全ピクセル)の値の合計を求め、全ピクセルで割れば、被覆率が求まる
透過率は、1−被覆率で得られる。
このアルゴリズムでは、1ピクセルより細かく分解できないので、紙片の1辺の長さが1ピクセル以下の端数になる場合は、繰り上げか切り捨てになるので計算が不正確になる。
従って、シミュレーション結果が不正確にならないようするには、窓の大きさを紙片の数で割った値が整数になるように留意して、値を入力する必要がある。
#"opticalDepth.rb" #光学的厚み、被覆率、透過率のシミュレーション # 2017.10.13 by O.Ohshima with Ruby+Shoes Shoes.app :title => "Optical Depth Simulator" , :width => 300, :height => 300 do para "Light Box Window Size" ws = edit_line 400, :width => 40 para "\n \n" para"Flagment Numbers / axis" n = edit_line 10, :width => 40 stack do para "alignment of Flagments?" flow { @bb=radio :stn; para strong("Random")} flow { @aa=radio :stn; para strong("Aligned")} button "Start" do xx=ws.text.to_i yy=xx nn=n.text.to_i para "n=",nn, " " dx=xx/nn dy=yy/nn para " dx=",dx, "\n" if @aa.checked? then align=1 para "Aligned is selected\n" elsif @bb.checked? then align=0 para "Random is selected\n" end window :title => "Tau = 1; Window size is #{ws.text} x {ws.text}", :width => xx, :height => yy do background lightskyblue ar=Array.new(xx).map{Array.new(yy,0)} nn.times do |mx| nn.times do |my| fill rgb(0.5,0.5,0.5) if align==1 then x=dx*mx y=dy*my elsif align==0 then x=rand(0-dx..xx) y=rand(0-dy..yy) end rect x, y, dx,dy dx.times do |ddx| dy.times do |ddy| if (((x+ddx >= 0) && (xx > x+ddx )) && ((y+ddy >= 0) && (xx > y+ddy ))) then ar[x+ddx][y+ddy] = 1 end end end end end b= ar.flatten c=b.inject(:+) cvr = sprintf( "%5.3f", c/(xx*yy).to_f) trm = sprintf( "%5.3f", (xx*yy-c)/(xx*xx).to_f ) tagline "Flagments =", nn,"x",nn,"\n", :stroke => white tagline "covered rate =",cvr,"\n", :stroke => white tagline "transmittance=",trm,"\n", :stroke => white end end end end
Ruby+Shoesの使い方
リンク
私は主に次のURLを参考にしてプログラミングしました。
4250
Keyword(s):[光学的深さ] [optical depth]
References:[技術的な覚書き]