#!/usr/bin/env ruby =begin = rgtview.rb -- netCDF クイックビューア = VER rgtview.rb ver.2.1 = SYNOPSTIC rgtview ((options)) > = DESCRIPTION rgtview は引数に netCDF 形式のファイルに格納された変数から適切な図形表現を表示する 簡易可視化ソフトウェアです. 以下のファイル群によって構成 or 依存しています. * rgtview.rb * libdraw.rb * libgphys-e.rb 上記ファイルの簡単な解説を以下でします. == rgtview.rb このファイル. rgtview のメインプログラム. == libdraw.rb 主に, 描画に関する設定やメソッドの定義を行っている Draw モジュールを定義しているファイル. 特に描画する変数に合わせた描画パラメータの設定はこのファイル内で行っている. == libgphys-e.rb GPhys クラスに対する拡張メソッドを定義しているファイル. = OPTIONS == 全体オプション === いろいろ + -h, --help ヘルプを表示します. + -f, --file 生成した画像を PostScript 形式のファイルに保存します. 保存するファイル名は dcl.ps です. なお, アニメーションモード(--animate, --smooth) で --file を指定した場合, 各々の画像は dcl_001.ps, dcl_002.ps というように適宜番号が振られ名前で保存されます. === 次元操作に関するオプション + --mean dim<,dim2,dim3> 指定した次元 (dim) に沿って平均操作を施します. 複数の次元について平均をとりたい場合は 次元同士を","でつなぎます. このとき空白を挿入してはいけません. 操作を行った次元は縮約され, メモリ上で消滅します. もちろん, 元のファイルの次元は変更されません. ご安心を. + --range dim=(from)..(to) 指定した次元(dim)を開始点(from)と終点(to)で切り取って処理します. === 描画に関するオプション + --line 線グラフを描画します. デフォルトでは指定した操作を行った後の多次元配列の次元から適切な 絵を描画しますが, このオプションを指定すると適当な次元を切り出して, 強制的に線グラフを 描画します. + --bs 表示される絵をあらかじめ画面の裏で描画します. これにより画像の切り替わりが滑らかになります. X のバッキングストア機能を有効にしていなければなりません. + --animate dim=num アニメーションを作成します. 今のところ, アニメーションする軸(dim)および開始する点(num)を指定しなければ なりません. また, num は軸の値ではなく, 配列の添字でなければなりません. 画像の切替えはマウスで絵をクリックするか Enter キー, Space キーで行います. + --datime (ERA40 データのみ有効なオプション) 時間軸が "time" という次元変数で指定されており, かつ 4 つの値(ex. 0, 0600, 1200, 1800) で構成されている場合に, アニメーションを作成すると --animate, --smooth で指定した次元+"time"軸方向にスライドしつつアニメーションを行います. + --nowait アニメーションモードで, マウスやキーボードからの入力を待たずに自動的に切替えを行います. --animate が指定されていないと有効になりません. + --smooth dim=num --animate, --bs, --nowait が同時に指定されているのと等しいです. 引数の与え方は --animate と同じです. + --exch 軸をひっくり返します. + --title title 絵のタイトルを陽に指定します. なおデフォルトのタイトルは, 描画する変数の long_name です. == 等値線図に関するオプション + --noshade トーンを抑制し, 等値線(コンター)のみ描画します. + --nocont コンターを抑制し, 色(もしくはトーンパターン)の塗わけのみ描画します. + --map 地図を重ねます. 今のところメルカトル図法しか対応していません. == 線グラフに対するオプション + 現在なし. =end require "getopts" # for option_parse require "numru/netcdf" class NArray # for deep_copy def self._load(o); to_na(*Marshal::load(o)).ntoh; end def _dump(limit); Marshal::dump([hton.to_s, typecode, *shape]); end end module NumRu class NetCDFVar def scaled_get(hash=nil) sf = att('scale_factor') ao = att('add_offset') if ( sf == nil && ao == nil ) then # no scaling --> just call get simple_get(hash) else if (sf != nil) csf = sf.get if csf.is_a?(NArray) then # --> should be a numeric csf = csf[0] elsif csf.is_a?(String) raise NetcdfError, "scale_factor is not a numeric" end if(csf == 0) then; raise NetcdfError, "zero scale_factor"; end else csf = 1.0 # assume 1 if not defined end if (ao != nil) cao = ao.get if cao.is_a?(NArray) then # --> should be a numeric cao = cao[0] elsif csf.is_a?(String) raise NetcdfError, "add_offset is not a numeric" end else cao = 0.0 # assume 0 if not defined end var = simple_get(hash) var = var.to_type( NArray::FLOAT ) csf*var+cao end end alias put scaled_put alias get scaled_get end end require "libgphys-e" # 内部で numru/ggraph を呼び出している require "libdraw-e" include Draw DCL.glcset('DUPATH','/home/daktu32/.dcldir/') # set User Path for dcldatabase ########################################## # # オプション解析部 unless getopts("hHfnc", "help", "file", "native", "mean:", "itr:", "title:", "range:", "nocont", "noshade", "line", "map", "noannote", "animate:", "smooth:", "bs", "nowait", "exch", "datime", "daytime", "min:", "max:", "default", "mvunit") print "#{$0}:illegal options. please exec this program with -h/--help. \n" exit 1 end if ($OPT_animate) && ($OPT_smooth) print "please set options only animate or smooth\n" exit 1 end file = Array.new # 引数中の nc ファイルを配列に格納 ARGV.each do |i| if i =~ /.nc$/ then p i file << i end end if ARGV[ARGV.size-1] =~ /.nc$/ then var = NetCDF.open(file[0], "r").var_names[-1] else var = ARGV[ARGV.size-1] end p var if file.size == 1 then # 単一ファイルが指定された場合 gphys = GPhys::NetCDF_IO.open(file[0].to_s, var) p $title = File::basename(file[0].to_s, ".nc") else if ($OPT_c) # コンポジット. 引数に与えられたファイルが領域分割されたファイルの場合, それらを仮想的に"くっつけて扱う." gphys = GPhys::NetCDF_IO.open(file, var) else gphys = mean_gphys(file, var) end end if ($OPT_range) range = ($OPT_range).to_s.split(/\s*,\s*/) range.each{|rg| ran = rg.to_s.split(/\s*=\s*/) if ran[1] =~ /\s*\.\.\s*/ rg1=ran[1].split(/\s*\.\.\s*/)[0].to_f rg2=ran[1].split(/\s*\.\.\s*/)[1].to_f gphys = gphys.cut(ran[0] => rg1..rg2) else gphys = gphys.cut(ran[0] => ran[1].to_f) end } end $title = ($OPT_title) if ($OPT_title) if ($OPT_mean) mean = ($OPT_mean).to_s.split(/\s*,\s*/) mean.each{|mn| gphys = gphys.mean(gphys.axnames.index(mn)) } end if ($OPT_daytime) # time-date composit only for ERA40 lonax = gphys.axis(0).pos.val timeax = gphys.axis(1).pos.val dateax = gphys.axis(2).pos.val lnum = gphys.shape[0] tnum = gphys.shape[1] dnum = gphys.shape[2] dataname = gphys.data.name timeunits = 'days since 2001-1-1' atna = NArray.float(tnum*dnum).fill!(0) for i in 0..(dnum-1) for j in 0..(tnum-1) atna[tnum*i+j] = i+0.25*j end end atna = atna+dateax[0] atx = VArray.new(atna).rename("date") data = gphys.data.val datana = NArray.sfloat(lnum,tnum*dnum).fill!(0.0) for i in 0..(dnum-1) for j in 0..(tnum-1) datana[true,4*i+j] = data[true, j, i] end end datana data = VArray.new(datana).rename(dataname) atx = Axis.new(true).set_cell_guess_bounds(atx).set_pos_to_center grid = Grid.new(gphys.axis(0),atx) gphys = GPhys.new(grid, data) gphys.coord(1).set_att('units',timeunits) # end time-date end ########################################## # # 描画オプションの初期値 draw_opts = { # default "levels" => $OPT_levels, # false "patterns" => $OPT_patterns, # false "line" => $OPT_line, # false "cont" => !$OPT_nocont, # true "tone" => !$OPT_noshade, # true "colorbar" => !$OPT_colorbar,# true "colorbar_opts" => nil,# nil "annot" => !$OPT_noannote, # true "map" => $OPT_map, # false "exchange" => $OPT_exch, # false "min" => $OPT_min, # false "max" => $OPT_max # false } ########################################## # # 変数毎に設定読み込み if var == "t" then Draw::settei_T elsif var == "u" || var == "uwnd" then Draw::settei_U(draw_opts) elsif var == "v" then Draw::settei_V(draw_opts) elsif var == "w" then Draw::settei_W(draw_opts) #elsif var == "cp" then # Draw::settei_CP elsif var == "tsrc" then Draw::settei_tsrc(draw_opts) elsif var == "ttr" then Draw::settei_ttr(draw_opts) elsif var == "ttrc" then Draw::settei_ttrc(draw_opts) #elsif var == "lsp" then # Draw::settei_LSP elsif var == "tp" || var == "lsp" || var == "cp" then Draw::settei_TP(draw_opts) elsif ($OPT_native) || ($OPT_n) then Draw::settei_native(draw_opts) elsif var == "psi" then Draw::settei_strm(gphys) elsif var == "theta" then Draw::settei_Theta elsif var == "pbar" then Draw::settei_Available elsif var == "pws" then Draw::settei_PWS(draw_opts) else Draw::settei_default(draw_opts) end Draw::settei_default(draw_opts) if $OPT_default Draw::settei_native(draw_opts) if $OPT_native Draw_opts_main = draw_opts.clone #Marshal.load(Marshal.dump(draw_opts)).clone ########################################## # # 実際に描画部分 DCL.swlset('lalt', true) if ($OPT_bs) || ($OPT_smooth) DCL.uscset('cyspos', 'B' ) if ($OPT_mvunit) if ($OPT_animate) || ($OPT_smooth) DCL.swlset('lwait', false) if ($OPT_nowait) || ($OPT_smooth) # auto animation DCL::swlset('lsep',true) if ($OPT_f) || ($OPT_file) anirange = ($OPT_animate).to_s.split(/\s*,\s*/) if ($OPT_animate) anirange = ($OPT_smooth).to_s.split(/\s*,\s*/) if ($OPT_smooth) anirange.each{|rg| ran = rg.to_s.split(/\s*=\s*/) dimindex = gphys.dim_index(ran[0]) if ($OPT_datime) if ran[1] =~ /\s*\.\.\s*/ # 開始点と終点が指定された場合 arg1 = ran[1].split(/\s*\.\.\s*/)[0].to_i # arg2 = ran[1].split(/\s*\.\.\s*/)[1].to_i # val = gphys.coord(dimindex).val[ran[1].to_i] Draw::mkwin for time in 0..3 Draw::draw(gphys.cut(ran[0]=>val, "time"=>600*time), true, Draw_opts_main) end arg1+1.upto(arg2) do |i| val = gphys.coord(dimindex).val[i] for time in 0..3 val = gphys.coord(dimindex).val[i] Draw::draw(gphys.cut(ran[0]=>val, "time"=>600*time), true, Draw_opts_main) end end else # 開始点のみ指定された場合 val = gphys.coord(dimindex).val[ran[1].to_i] Draw::mkwin for time in 0..3 Draw::draw(gphys.cut(ran[0]=>val, "time"=>600*time), true, Draw_opts_main) end ept = gphys.coord(dimindex).shape_current[0].to_i (ran[1].to_i+1).upto(ept-1) { |i| val = gphys.coord(dimindex).val[i] for time in 0..3 Draw::draw(gphys.cut(ran[0]=>val, "time"=>600*time), true, Draw_opts_main) end } end else if ran[1] =~ /\s*\.\.\s*/ # 開始点と終点が指定された場合 # arg1=ran[1].split(/\s*\.\.\s*/)[0].to_f # 軸の値(緯度経度で指定するばあいのルーチン) # arg2=ran[1].split(/\s*\.\.\s*/)[1].to_f # # grid1 = gphys.coord(dimindex).val.index(arg1) # # grid2 = gphys.coord(dimindex).val.index(arg2) # arg1 = ran[1].split(/\s*\.\.\s*/)[0].to_i # arg2 = ran[1].split(/\s*\.\.\s*/)[1].to_i # val = gphys.coord(dimindex).val[ran[1].to_i] Draw::mkwin Draw::draw(gphys.cut(ran[0]=>val), true, Draw_opts_main) arg1+1.upto(arg2) do |i| val = gphys.coord(dimindex).val[i] Draw::draw(gphys.cut(ran[0]=>val), true, Draw_opts_main) end else # 開始点のみ指定された場合 val = gphys.coord(dimindex).val[ran[1].to_i] Draw::mkwin Draw::draw(gphys.cut(ran[0]=>val), true, Draw_opts_main) ept = gphys.coord(dimindex).shape_current[0].to_i (ran[1].to_i+1).upto(ept-1) { |i| val = gphys.coord(dimindex).val[i] Draw::draw(gphys.cut(ran[0]=>val), true, Draw_opts_main) } end end } else Draw::mkwin # gphys = gphys.stspct_fft("rain") Draw::draw(gphys, true, Draw_opts_main) end Draw::clwin exit