netcdf を新たに作成 (ruby-netcdf)


※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

目次


NetDCF を新たに作る例

以下の手順で NetCDF ファイルを作成することができる

  1. 次元の定義 (def_dim) ・変数の定義 (def_var)・属性の定義 (put_att)
  2. enddef とするとNetCDF ファイルの先頭部分が作成される
  3. put メソッドを用いて値を書き込む
    • 変数の一部にだけ書き込みたい場合などには, "start"や"end"といったオプショナルな引数をつける
      • これは 「ハッシュ」を用いて実現されている

例: nccreate.rb

require "numru/netcdf"
include NumRu

file = NetCDF.create("test.nc")      # 新規作成
nx, ny = 10, 5
file.def_dim("x",nx)                 # 次元の定義
file.def_dim("y",ny)
file.def_dim("t",0)                  # tはUNLIMITED
require "date"
file.put_att("history","created by #{$0}  #{Date.today}")
                                     # グローバル属性の設定
x = file.def_var("x","sfloat",["x"]) # 変数の定義
y = file.def_var("y","sfloat",["y"])
t = file.def_var("t","sfloat",["t"])
v1 = file.def_var("v1","sfloat",["x","y"])
v1.put_att("long_name","test 1")     o# 属性の設定
v1.put_att("units","1")
v2 = file.def_var("v2","sfloat",["x","y","t"])
v2.put_att("long_name","test 2")
v2.put_att("units","1")
file.enddef                          # defineモード終わり


x.put( NArray.float(nx).indgen! )    # 値を入れる
y.put( NArray.float(ny).indgen! )

z = NArray.float(nx,ny).indgen!*0.1
v1.put(z)
v1.put( NArray.float(nx).fill!(20), "start"=>[0,2],"end"=>[-1,2])
                                     # startからendまで値を入れる
v2.put(z, "start"=>[0,0,0],"end"=>[-1,-1,0])
t.put( 0, "index"=>[0])              # indexの場所に値を入れる
v2.put(-z, "start"=>[0,0,1],"end"=>[-1,-1,1])
t.put( 1, "index"=>[1])

file.close
print `ncdump test.nc`               # できたファイルを見る

できたファイルを見る

$ ncdump test.nc
netcdf test {
dimensions:
	x = 10 ;
	y = 5 ;
	t = UNLIMITED ; // (2 currently)
variables:
	float x(x) ;
	float y(y) ;
	float t(t) ;
	float v1(y, x) ;
		v1:long_name = "test 1" ;
		v1:units = "1" ;
	float v2(t, y, x) ;
		v2:long_name = "test 2" ;
		v2:units = "1" ;

// global attributes:
		:history = "created by nccreate.rb  2012-06-09" ;
data:

 x = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ;

 y = 0, 1, 2, 3, 4 ;

 t = 0, 1 ;

 v1 =
  0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9,
  1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9,
  20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
  3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9,
  4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9 ;

 v2 =
  0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9,
  1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9,
  2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9,
  3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9,
  4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9,
  -0, -0.1, -0.2, -0.3, -0.4, -0.5, -0.6, -0.7, -0.8, -0.9,
  -1, -1.1, -1.2, -1.3, -1.4, -1.5, -1.6, -1.7, -1.8, -1.9,
  -2, -2.1, -2.2, -2.3, -2.4, -2.5, -2.6, -2.7, -2.8, -2.9,
  -3, -3.1, -3.2, -3.3, -3.4, -3.5, -3.6, -3.7, -3.8, -3.9,
  -4, -4.1, -4.2, -4.3, -4.4, -4.5, -4.6, -4.7, -4.8, -4.9 ;
}

時間の次元の出力を想定して NetCDF を新たに作る

モデルによる時間積分などを想定して, 時間の次元を出力した形で NetCDF を新たに作る例を示す.

nccreate_time.rb

require "numru/netcdf"
include NumRu

file = NetCDF.create("test2.nc")     # 新規作成
nx, ny = 4, 2
file.def_dim("x",nx)                 # 次元の定義
file.def_dim("y",ny)
file.def_dim("t",0)                  # t~UNLIMITED
require "date"
file.put_att("history","created by #{$0}  #{Date.today}")
                                     # グローバル属性の設定
x = file.def_var("lon","sfloat",["x"]) # 変数の定義
y = file.def_var("lat","sfloat",["y"])
t = file.def_var("t","sfloat",["t"])

x.put_att("long_name","longitude") # 属性の設定
x.put_att("units","deg")
y.put_att("long_name","latitude")
y.put_att("units","deg")
t.put_att("long_name","time")
t.put_att("units","s")

velx = file.def_var("VelX","sfloat",["x","y","t"])
velx.put_att("long_name","longitudinal velocity")
velx.put_att("units","m/s")
file.enddef                          # defineモード終わり

x.put( NArray.float(nx).indgen!*120 )    # 値を入れる
y.put( NArray.float(ny).indgen!*20 )

dt = 10.0 # time interval
nt = 3    # total time step  

n=0
for n in 0..(nt-1)
  time = n * dt 
  print "n=#{n}, time=#{time}\n" 
  z = NArray.float(nx,ny).indgen! * n * dt 

  velx.put(z, "start"=>[0,0,n],"end"=>[-1,-1,n])
                                          # startからendまで値を入れる
  t.put( time, "index"=>[n])              # indexの場所に値を入れる
end

file.close
print `ncdump test2.nc`               # できたファイルを見る

実行結果

$ ruby nccreate_time.rb 
n=0, time=0.0
n=1, time=10.0
n=2, time=20.0
netcdf test2 {
dimensions:
	x = 4 ;
	y = 2 ;
	t = UNLIMITED ; // (3 currently)
variables:
	float lon(x) ;
		lon:long_name = "longitude" ;
		lon:units = "deg" ;
	float lat(y) ;
		lat:long_name = "latitude" ;
		lat:units = "deg" ;
	float t(t) ;
		t:long_name = "time" ;
		t:units = "s" ;
	float VelX(t, y, x) ;
		VelX:long_name = "longitudinal velocity" ;
		VelX:units = "m/s" ;

// global attributes:
		:history = "created by nccreate_time.rb  2012-06-10" ;
data:

 lon = 0, 120, 240, 360 ;

 lat = 0, 20 ;

 t = 0, 10, 20 ;

 VelX =
  0, 0, 0, 0,
  0, 0, 0, 0,
  0, 10, 20, 30,
  40, 50, 60, 70,
  0, 20, 40, 60,
  80, 100, 120, 140 ;
}


NetCDFを読んでNetCDFで書き出す

上の演習問題のような、 NetCDFを読みこみ何らかの解析処理を施してNetCDFで書き出す、といったことをおこなうために、 NetCDFクラスを自分用に拡張していきます。まずはNetCDFファイルを読み込み、それをそのままNetCDFファイルに書き出してみます。

例: nccopy.rb

# /usr/bin/env ruby

require "numru/netcdf"
include NumRu

module NumRu
 class NetCDF
  def copy(outfilename)
    outfile = NetCDF.create(outfilename)

    self.each_dim{ |d|
    #  outfile.def_dim(d.name, d.length_ul0)
      outfile.def_dim(d.name, d.length)    # 次元の定義
    }

    vlist = []                             # 変数リスト
    self.each_var{ |v|
    #  vdims = v.dim_names.collect{ |nm| outfile.dim(nm) }
    #  vout = outfile.def_var(v.name, v.vartype, vdims ) 
                                           # 変数の定義
      vout = outfile.def_var(v.name, v.vartype, outfile.dims(v.dim_names) )
      v.each_att{ |a| a.copy(vout) }       # 属性のコピー
      vlist.push(vout)                     # 変数リストの最後に加える
    }
    
    self.each_att{ |a| a.copy(outfile) } # グローバル属性のコピー

    outfile.enddef

    self.each_var{ |v|
      vout = vlist.shift                   # 変数リストの先頭を取り出し
      vout.put(v.get)                      # 変数のコピー
      p vout.name
    }

    outfile.close
  end
 end 
end

file = NetCDF.open("T.jan.nc") # 入力ファイル
file.copy("nccopy.nc")                 # 出力ファイル
file.close

#print `diff T.jan.nc nccopy.nc`

each_dim, each_var, each_att といったイテレータを用いています。イテレータに慣れていないとちょっとややこしいですが、汎用性が高くなっています