[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[dennou-ruby:002978] [BUG] RubyNetcdfの欠損値の扱いのバグ



堀之内様(Cc: dennou-ruby)

大塚です。

RubyNetCDF Ver. 0.6.3 (最新)にバグと思われるものを見つけたので
報告させていただきます。

NetCDFにおいて
"scale_factor" や "add_offset" が定義されている場合に、
netcdf_miss.rb の中の __interpret_missing_params において
"missing_value" の変換を行っているようなのですが、
さらに "valid_*" も定義されている場合に
"missing_value" が "valid_*" の範囲内にある場合に例外を出すように
なっています。

ところが "missing_value" を変換した後で、未変換の "valid_*" と
大小比較を行っているので、場合によっては正常な値なのに
例外を出されてしまいます。

サンプルデータとしては
http://database.rish.kyoto-u.ac.jp/arch/ncep/data/ncep.reanalysis2.derived/gaussian_grid/prate.sfc.mon.mean.nc
があります。以下のようにすると落ちます。

irb(main):001:0> require "numru/gphys"
=> true
irb(main):002:0> include NumRu
=> Object
irb(main):003:0> g = GPhys::IO.open("prate.sfc.mon.mean.nc","prate")
=> <GPhys grid=<3D grid <axis pos=<'lon' in 'prate.sfc.mon.mean.nc'
sfloat[192]>>
        <axis pos=<'lat' in 'prate.sfc.mon.mean.nc'  sfloat[94]>>
        <axis pos=<'time' in 'prate.sfc.mon.mean.nc'  float[349]>>>
   data=<'prate' in 'prate.sfc.mon.mean.nc'  sint[192, 94, 349]>>
irb(main):004:0> g.get_att("missing_value")
=> NArray.sint(1):
[ 32766 ]
irb(main):005:0> g.get_att("valid_range")
=> NArray.sint(2):
[ -32765, 19735 ]
irb(main):006:0> g.mean
RuntimeError: missing_value 0.00655309995636344 is in the valid range
-32765..19735
        from /usr/lib/ruby/1.8/numru/netcdf_miss.rb:129:in
`__interpret_missing_params'
        from /usr/lib/ruby/1.8/numru/netcdf_miss.rb:27:in `get'
        from /usr/lib/ruby/1.8/numru/gphys/varraynetcdf.rb:218:in `val'
        from /usr/lib/ruby/1.8/numru/gphys/varray.rb:955:in `mean'
        from /usr/lib/ruby/1.8/numru/gphys/gphys.rb:781:in `mean'
        from (irb):6
        from :0
irb(main):007:0>

添付のパッチでとりあえず引っ掛からなくなるのですが、
あまり理解していないのでご確認下さい。

-- 
京都大学大学院理学研究科
気象学研究室 D3
大塚成徳 (Shigenori OTSUKA)
email: otsuka@xxxxxxxxxxxxxxxxxx
--- netcdf_miss.rb.org	2007-12-25 20:37:01.000000000 +0900
+++ netcdf_miss.rb	2008-07-11 19:53:54.437500000 +0900
@@ -120,10 +120,6 @@
 
       if @missval
 	@missval = @missval.get   # kept in... (same)
-        mtc = @missval.typecode
-        if mtc != sfao_type and  mtc<=NArray::SINT
-          @missval = unpack(@missval)
-        end
 	if @vmin && @vmax
 	  if @vmin[0] <= @missval[0] && @missval[0] <= @vmax[0]
 	    raise "missing_value #{@missval[0]} is in the valid range #{@vmin[0]}..#{@vmax[0]}"
@@ -135,6 +131,10 @@
 	    raise "missing_value #{@missval[0]} <= valid min #{@vmin[0]}"
 	  end
 	end
+        mtc = @missval.typecode
+        if mtc != sfao_type and  mtc<=NArray::SINT and !@miss_on_packed
+          @missval = unpack(@missval)
+        end
       else
 	if @vmin || @vmax
 	  if (fill=att('_FillValue'))   # equal, not ==