class NumRu::NetCDFVar

Public Class Methods

new(file,varname,mode="r",share=false) click to toggle source
# File lib/netcdf.rb, line 279
def new(file,varname,mode="r",share=false)
   if(file.is_a?(String))
      file = NetCDF.open(file,mode,share)
   elsif(!file.is_a?(NetCDF))
     raise TypeError, "1st arg must be a NetCDF (file object) or a String (path)"
   end
   file.var(varname)
end
Also aliased as: open, open
open(file,varname,mode="r",share=false)
Alias for: new
unpack_type() click to toggle source
# File lib/netcdf.rb, line 385
def unpack_type
  @@unpack_type
end
unpack_type=(na_type) click to toggle source
# File lib/netcdf.rb, line 388
def unpack_type=(na_type)
  if [NArray::BYTE, NArray::SINT, NArray::INT, 
      NArray::SFLOAT, NArray::FLOAT, nil].include?(na_type)
    @@unpack_type = na_type
  else
    raise ArgumentError, "Arg must be one of NArray::BYTE, NArray::SINT, NArray::INT, NArray::SFLOAT, NArray::FLOAT"
  end
end

Public Instance Methods

[](*a) click to toggle source
# File lib/netcdf.rb, line 637
def [](*a)
  if a.length == 0
    return self.get
  end
  a = __rubber_expansion(a)
  first = Array.new
  last = Array.new
  stride = Array.new
  set_stride = false
  a.each{|i|
    if(i.is_a?(Fixnum))
      first.push(i)
      last.push(i)
      stride.push(1)
    elsif(i.is_a?(Range))
      first.push(i.first)
      last.push(i.exclude_end? ? i.last-1 : i.last)
      stride.push(1)
    elsif(i.is_a?(Hash))
      r = (i.to_a[0])[0]
      s = (i.to_a[0])[1]
      if ( !( r.is_a?(Range) ) || ! ( s.is_a?(Integer) ) )
         raise TypeError, "Hash argument must be {a_Range, step}"
      end
      first.push(r.first) 
      last.push(r.exclude_end? ? r.last-1 : r.last)
      stride.push(s)
      set_stride = true
    elsif(i.is_a?(TrueClass))
      first.push(0)
      last.push(-1)
      stride.push(1)
    elsif( i.is_a?(Array) || i.is_a?(NArray))
      a_new = a.dup
      at = a.index(i)
      i = NArray.to_na(i) if i.is_a?(Array)
      for n in 0..i.length-1
        a_new[at] = i[n]..i[n]
        na_tmp = self[*a_new]
        if n==0 then
          k = at
          if at > 0
            a[0..at-1].each{|x| if x.is_a?(Fixnum) then k -= 1 end}
          end
          shape_tmp = na_tmp.shape
          shape_tmp[k] = i.length
          na = na_tmp.class.new(na_tmp.typecode,*shape_tmp)
          index_tmp = Array.new(shape_tmp.length,true)
        end
        index_tmp[k] = n..n
        na[*index_tmp] = na_tmp
      end
      return na
    else
      raise TypeError, "argument must be Fixnum, Range, Hash, TrueClass, Array, or NArray"
    end
  }

  if(set_stride)
    na = self.get({"start"=>first, "end"=>last, "stride"=>stride})
  else
    na = self.get({"start"=>first, "end"=>last})
  end
  shape = na.shape
  (a.length-1).downto(0){ |i|
      shape.delete_at(i) if a[i].is_a?(Fixnum)
   }
   na.reshape!( *shape )
  na
end
[]=(*a) click to toggle source
# File lib/netcdf.rb, line 708
def []=(*a)
  val = a.pop
  a = __rubber_expansion(a)
  first = Array.new
  last = Array.new
  stride = Array.new
  set_stride = false
  a.each{|i|
    if(i.is_a?(Fixnum))
      first.push(i)
      last.push(i)
      stride.push(1)
    elsif(i.is_a?(Range))
      first.push(i.first)
      last.push(i.exclude_end? ? i.last-1 : i.last)
      stride.push(1)
    elsif(i.is_a?(Hash))
      r = (i.to_a[0])[0]
      s = (i.to_a[0])[1]
      if ( !( r.is_a?(Range) ) || ! ( s.is_a?(Integer) ) )
         raise ArgumentError, "Hash argument must be {first..last, step}"
      end
      first.push(r.first) 
      last.push(r.exclude_end? ? r.last-1 : r.last)
      stride.push(s)
      set_stride = true
    elsif(i.is_a?(TrueClass))
      first.push(0)
      last.push(-1)
      stride.push(1)
    elsif(i.is_a?(Array) || i.is_a?(NArray))
      a_new = a.dup
      at = a.index(i)
      i = NArray.to_na(i) if i.is_a?(Array)
      val = NArray.to_na(val) if val.is_a?(Array)
      rank_of_subset = a.dup.delete_if{|v| v.is_a?(Fixnum)}.length
      if val.rank != rank_of_subset
        raise "rank of the rhs (#{val.rank}) is not equal to the rank "+
              "of the subset specified by #{a.inspect} (#{rank_of_subset})"
      end
      k = at
      a[0..at-1].each{|x| if x.is_a?(Fixnum) then k -= 1 end}
      if i.length != val.shape[k]
        raise "length of the #{k+1}-th dim of rhs is incorrect "+
              "(#{i.length} for #{val.shape[k]})"
      end
      index_tmp = Array.new(val.rank,true) if !val.is_a?(Numeric) #==>Array-like
      for n in 0..i.length-1
        a_new[at] = i[n]..i[n]
        if !val.is_a?(Numeric) then
          index_tmp[k] = n..n
          self[*a_new] = val[*index_tmp]
        else
          self[*a_new] = val
        end
      end
      return self
    else
      raise TypeError, "argument must be Fixnum, Range, Hash, TrueClass, Array, or NArray"
    end
  }

  if(set_stride)
     self.put(val, {"start"=>first, "end"=>last, "stride"=>stride})
  else
     self.put(val, {"start"=>first, "end"=>last})
  end
end
att_names() click to toggle source
# File lib/netcdf.rb, line 307
def att_names
  num_att=natts()
  names=[]
  for attnum in 0..num_att-1
    obj_Att=id2att(attnum)
    names=names+[obj_Att.name]
  end
  return names
end
dim_names() click to toggle source
# File lib/netcdf.rb, line 301
def dim_names
  ary = Array.new()
  dims.each{|dim| ary.push(dim.name)}
  ary
end
each_att() { |obj_Att| ... } click to toggle source
# File lib/netcdf.rb, line 293
def each_att
  num_att=natts()
  for attnum in 0..num_att-1
    obj_Att=id2att(attnum)
    yield(obj_Att)
  end
end
get(hash=nil)
Alias for: simple_get
get_with_miss(*args) click to toggle source
# File lib/netcdf_miss.rb, line 8
def get_with_miss(*args)
  __interpret_missing_params if !defined?(@missval)
  data = simple_get(*args)
  if @vmin || @vmax
    if @vmin
      mask = (data >= @vmin) 
      mask = mask.and(data <= @vmax) if @vmax
    else
      mask = (data <= @vmax)
    end
    data = NArrayMiss.to_nam(data, mask)
  elsif @missval    # only missing_value is present.
    mask = (data.ne(@missval)) 
    data = NArrayMiss.to_nam(data, mask)
  end
  data
end
get_with_miss_and_scaling(*args) click to toggle source
# File lib/netcdf_miss.rb, line 26
def get_with_miss_and_scaling(*args)
  __interpret_missing_params if !defined?(@missval)
  data = simple_get(*args)
  if @vmin || @vmax
    if @vmin
      mask = (data >= @vmin) 
      mask = mask.and(data <= @vmax) if @vmax
    else
      mask = (data <= @vmax)
    end
    data = NArrayMiss.to_nam(data, mask)
  elsif @missval    # only missing_value is present.
    mask = (data.ne(@missval))
    data = NArrayMiss.to_nam(data, mask)
  end
  data = unpack( data )
  data
end
inspect() click to toggle source
# File lib/netcdf.rb, line 777
def inspect
  'NetCDFVar:'+file.path+'?var='+name
end
pack(na) click to toggle source

The put and get methods in the NetCDFVar class

# File lib/netcdf.rb, line 343
def pack(na)
  sf = att('scale_factor')
  ao = att('add_offset')
  if ( sf == nil && ao == nil ) then
    na
  else
    na = NArray.to_na(na) if na.is_a?(Array)
    if sf
      csf = sf.get
      raise NetcdfError,"scale_factor is not a numeric" if csf.is_a?(String)
      raise NetcdfError, "scale_factor is not unique" if csf.length != 1
      raise NetcdfError, "zero scale_factor" if csf[0] == 0
    else
      csf = nil
    end
    if ao
      cao = ao.get
      raise NetcdfError, "add_offset is not a numeric" if cao.is_a?(String)
      raise NetcdfError, "add_offset is not unique" if cao.length != 1
    else
      cao = nil
    end
    if csf and cao
      packed = (na - cao) / csf
    elsif csf
      packed = na / csf
    elsif cao
      packed = na - cao
    end
    if self.typecode <= NArray::LINT
      packed = packed.round
    end
    packed
  end
end
put(var,hash=nil)
Alias for: simple_put
put_att(attname,val,atttype=nil) click to toggle source
# File lib/netcdf.rb, line 317
def put_att(attname,val,atttype=nil)
   put_attraw(attname,val,atttype)
end
put_with_miss(data, *args) click to toggle source
# File lib/netcdf_miss.rb, line 45
def put_with_miss(data, *args)
  if data.is_a?( NArrayMiss )
    __interpret_missing_params if !defined?(@missval)
    if @missval
      simple_put(data.to_na(@missval), *args)
    else
      simple_put(data.to_na, *args)
    end
  else
    simple_put(data, *args)
  end
end
put_with_miss_and_scaling(data, *args) click to toggle source
# File lib/netcdf_miss.rb, line 58
def put_with_miss_and_scaling(data, *args)
  if data.is_a?( NArrayMiss )
    __interpret_missing_params if !defined?(@missval)
    if @missval
      data = pack( data )
      data = data.to_na(@missval)
    else
      data = pack( data )
      data = data.to_na
    end
    simple_put(data, *args)
  else
    scaled_put(data, *args)
  end
end
scaled_get(hash=nil) click to toggle source
# File lib/netcdf.rb, line 432
def scaled_get(hash=nil)
  unpack( simple_get(hash) )
end
scaled_put(var,hash=nil) click to toggle source
# File lib/netcdf.rb, line 379
def scaled_put(var,hash=nil)
  simple_put( pack(var), hash)
end
shape_current() click to toggle source
# File lib/netcdf.rb, line 333
def shape_current
   sh = []
   dims.each{|d|
      sh.push(d.length)
   }
   sh
end
shape_ul0() click to toggle source
# File lib/netcdf.rb, line 321
def shape_ul0
   sh = []
   dims.each{|d|
      if d.unlimited? then
         sh.push(0)
      else
         sh.push(d.length)
      end
   }
   sh
end
simple_get(hash=nil) click to toggle source
# File lib/netcdf.rb, line 542
def simple_get(hash=nil)
  t_var = self.vartype
  if hash == nil
    if t_var == "char"
      get_var_char
    elsif t_var == "byte"
      get_var_byte
    elsif t_var == "sint"
      get_var_sint
    elsif t_var == "int"
      get_var_int
    elsif t_var == "sfloat"
      get_var_sfloat
    elsif t_var == "float"
      get_var_float
    else
       raise NetcdfError, "variable type #{t_var} isn't supported in netCDF"
    end
  elsif hash.key?("index")==true
    ind = hash["index"]
    if t_var == "char"
      get_var1_char(ind)
    elsif t_var == "byte"
      get_var1_byte(ind)
    elsif t_var == "sint"
      get_var1_sint(ind)
    elsif t_var == "int"
      get_var1_int(ind)
    elsif t_var == "sfloat"
      get_var1_sfloat(ind)
    elsif t_var == "float"
      get_var1_float(ind)
    else
      raise NetcdfError,"variable type #{t_var} isn't supported in netCDF"
    end
  elsif hash.key?("start")==true
    h_sta = hash["start"]
    h_end = hash["end"]     # can be nill
    h_str = hash["stride"]  # can be nill
    if NetCDF.nc4? && h_str && ((xstr=h_str[0]) != 1)
      # Tentative treatment for the very slow netcdf-4 reading with step.
      # Reading with step is generally slow with NetCDF 4, but it is
      # particularly so for the first dimension.
      # Ref: http://www.unidata.ucar.edu/mailing_lists/archives/netcdfgroup/2013/msg00311.html
      h_str[0] = 1 
      nc4remedy = true
    else
      nc4remedy = false
    end
    if t_var == "char"
      v = get_vars_char(h_sta,h_end,h_str)
    elsif t_var == "byte"
      v = get_vars_byte(h_sta,h_end,h_str)
    elsif t_var == "sint"
      v = get_vars_sint(h_sta,h_end,h_str)
    elsif t_var == "int"
      v = get_vars_int(h_sta,h_end,h_str)
    elsif t_var == "sfloat"
      v = get_vars_sfloat(h_sta,h_end,h_str)
    elsif t_var == "float"
      v = get_vars_float(h_sta,h_end,h_str)
    else
      raise NetcdfError, "variable type #{t_var} isn't supported in netCDF"
    end
    if nc4remedy
      idx = []
      (0...v.shape[0]).step(xstr){|k| idx.push(k)}
      v = v[idx,false]
    end
    v
  else
    raise ArgumentError,"{'start'}=>{ARRAY} or {'index'}=>{ARRAY} is needed"
  end
end
Also aliased as: get, get
simple_put(var,hash=nil) click to toggle source
# File lib/netcdf.rb, line 436
def simple_put(var,hash=nil)
  if hash==nil
    if self.vartype == "char"
      put_var_char(var)
    elsif self.vartype == "byte"
      put_var_byte(var)
    elsif self.vartype == "sint"
      put_var_sint(var)
    elsif self.vartype == "int"
      put_var_int(var)
    elsif self.vartype == "sfloat"
      put_var_sfloat(var)
    elsif self.vartype == "float"
      put_var_float(var)
    else 
      raise NetcdfError,"variable type isn't supported in netCDF" 
    end
  elsif hash.key?("index")==true 
    if self.vartype == "char"
      put_var1_char(var,hash["index"])
    elsif self.vartype=="byte"
      put_var1_byte(var,hash["index"])
    elsif self.vartype=="sint"
      put_var1_sint(var,hash["index"])
    elsif self.vartype == "int"
      put_var1_int(var,hash["index"])
    elsif self.vartype == "sfloat"
      put_var1_sfloat(var,hash["index"])
    elsif self.vartype == "float"
      put_var1_float(var,hash["index"])
    else 
      raise NetcdfError,"variable type isn't supported in netCDF"
    end
  elsif hash.key?("start")==true
    if hash.key?("end")==false && hash.key?("stride")==false
      if self.vartype == "char"
        put_vars_char(var,hash["start"],nil,nil)
      elsif self.vartype=="byte"
        put_vars_byte(var,hash["start"],nil,nil)
      elsif self.vartype=="sint"
        put_vars_sint(var,hash["start"],nil,nil)
      elsif self.vartype=="int"
        put_vars_int(var,hash["start"],nil,nil)
      elsif self.vartype=="sfloat"
        put_vars_sfloat(var,hash["start"],nil,nil)
      elsif self.vartype=="float"
        put_vars_float(var,hash["start"],nil,nil)
      else
        raise NetcdfError, "variable type isn't supported in netCDF"
      end
    elsif hash.key?("end")==true && hash.key?("stride") == false
      if self.vartype == "char"
        put_vars_char(var,hash["start"],hash["end"],nil)
      elsif self.vartype=="byte"
        put_vars_byte(var,hash["start"],hash["end"],nil)
      elsif self.vartype=="sint"
        put_vars_sint(var,hash["start"],hash["end"],nil)
      elsif self.vartype=="int"
        put_vars_int(var,hash["start"],hash["end"],nil)
      elsif self.vartype == "sfloat"
        put_vars_sfloat(var,hash["start"],hash["end"],nil)
      elsif self.vartype =="float"
        put_vars_float(var,hash["start"],hash["end"],nil)
      else
        raise NetcdfError, "variable type isn't supported in netCDF"
      end
    elsif hash.key?("end")==false && hash.key?("stride")==true
      if self.vartype == "char"
        put_vars_char(var,hash["start"],nil,hash["stride"])
      elsif self.vartype=="byte"
        put_vars_byte(var,hash["start"],nil,hash["stride"])
      elsif self.vartype=="sint"
        put_vars_sint(var,hash["start"],nil,hash["stride"])
      elsif self.vartype=="int"
        put_vars_int(var,hash["start"],nil,hash["stride"])
      elsif self.vartype=="sfloat"
        put_vars_sfloat(var,hash["start"],nil,hash["stride"])
      elsif self.vartype=="float"
        put_vars_float(var,hash["start"],nil,hash["stride"])
      else
        raise NetcdfError, "variable type isn't supported in netCDF"
      end
    else hash.key?("end")==true && hash.key?("stride")==true
      if self.vartype == "char"
        put_vars_char(var,hash["start"],hash["end"],hash["stride"])
      elsif self.vartype=="byte"
        put_vars_byte(var,hash["start"],hash["end"],hash["stride"])
      elsif self.vartype=="sint"
        put_vars_sint(var,hash["start"],hash["end"],hash["stride"])
      elsif self.vartype=="int"
        put_vars_int(var,hash["start"],hash["end"],hash["stride"])
      elsif self.vartype=="sfloat"
        put_vars_sfloat(var,hash["start"],hash["end"],hash["stride"])
      elsif self.vartype=="float"
        put_vars_float(var,hash["start"],hash["end"],hash["stride"])
      else
        raise NetcdfError, "variable type isn't supported in netCDF"
      end
    end
  else
    raise ArgumentError,"{'start'}=>[ARRAY] or {'index'}=>[ARRAY] is needed"
  end
end
Also aliased as: put, put
unpack(na) click to toggle source
# File lib/netcdf.rb, line 399
def unpack(na)
  sf = att('scale_factor')
  ao = att('add_offset')
  if ( sf == nil && ao == nil ) then
    na
  else
    if sf
      csf = sf.get
      raise NetcdfError,"scale_factor is not a numeric" if csf.is_a?(String)
      raise NetcdfError, "scale_factor is not unique" if csf.length != 1
      raise NetcdfError, "zero scale_factor" if csf[0] == 0
    else
      csf =nil
    end
    if ao
      cao = ao.get
      raise NetcdfError, "add_offset is not a numeric" if cao.is_a?(String)
      raise NetcdfError, "add_offset is not unique" if cao.length != 1
    else
      cao = nil
    end
    if csf and cao
      una = na * csf + cao  # csf & cao are NArray -> coerced to their types
    elsif csf
      una = na * csf
    elsif cao
      una = na + cao
    end
    una = una.to_type(@@unpack_type) if @@unpack_type
    una
  end
end

Private Instance Methods

__interpret_missing_params() click to toggle source

private ##########

# File lib/netcdf_miss.rb, line 76
def __interpret_missing_params
  # Interprets the specification of missing data,
  # either by valid_range, (valid_min and/or valid_max), or missing_value.
  # (unlike the NetCDF User's guide (NUG), missing_value is interpreted, 
  # but valid_* has a higher precedence.)
  # Always sets @missval whether missing_value is defined or not,
  # since it will be used as a fill value for data missing.
  #
  @vmin = att('valid_min')
  @vmin = @vmin.get if @vmin  # kept in a NArray(size==1) to consv type
  @vmax = att('valid_max')
  @vmax = @vmax.get if @vmax  # kept in a NArray(size==1) to consv type
  vrange = att('valid_range')
  vrange = vrange.get if vrange
  if vrange
    vrange.sort!
    @vmin = vrange[0..0]        # kept in... (same)
    @vmax = vrange[-1..-1]      # kept in... (same)
  end
  @missval = att('missing_value') || att('_FillValue')
  @missval = @missval.get if @missval # kept in... (same)

  sf = att('scale_factor')
  ao = att('add_offset')
  if ( sf || ao )
    ## Both NUG & CF conventions requires to specify the valid
    ## range with respect to the external (i.e. packed) values. 
    ## However, some conventions require specification
    ## with respect to unpacked values. The following
    ## is to support such cases as well:
    thres_tp = [ self.typecode, NArray::LINT ].max
    @missval = pack(@missval) if @missval && @missval.typecode > thres_tp
    @vmin = pack(@vmin) if @vmin && @vmin.typecode > thres_tp
    @vmax = pack(@vmax) if @vmax && @vmax.typecode > thres_tp
  end

  if @missval
    if @vmin && @vmax 
      if @vmin[0] <= @missval[0] && @missval[0] <= @vmax[0]
        warn "WARNING: missing_value #{@missval[0]} is in the valid range #{@vmin[0]}..#{@vmax[0]} --> will be ignored (#{__FILE__}:#{__LINE__})"
      end
    else
      if @vmin && @missval[0] >= @vmin[0]
        warn "WARNING: missing_value #{@missval[0]} >= valid min #{@vmin[0]} --> will be ignored (#{__FILE__}:#{__LINE__})"
      elsif @vmax && @missval[0] <= @vmax[0]
        warn "WARNING: missing_value #{@missval[0]} <= valid min #{@vmin[0]} --> will be ignored (#{__FILE__}:#{__LINE__})"
      end
    end
  else
    realtc = NArray::SFLOAT
    if @vmin
      if @vmin[0] >= 0
        @missval = ( @vmin.typecode>=realtc ? 0.99*@vmin : @vmin-1 )
      else
        @missval = ( @vmin.typecode>=realtc ? 1.01*@vmin : @vmin-1 )
      end
    elsif @vmax
      if @vmax[0] >= 0
        @missval = ( @vmax.typecode>=realtc ? 1.01*@vmax : @vmax+1 )
      else
        @missval = ( @vmax.typecode>=realtc ? 0.99*@vmax : @vmax+1 )
      end
    end
  end

end
__rubber_expansion( args ) click to toggle source
# File lib/netcdf.rb, line 619
def __rubber_expansion( args )
  if (id = args.index(false))  # substitution into id
    # false is incuded
    alen = args.length
    if args.rindex(false) != id
      raise ArguemntError,"only one rubber dimension is permitted"
    elsif alen > rank+1
      raise ArgumentError, "too many args"
    end
    ar = ( id!=0 ? args[0..id-1] : [] )
    args = ar + [true]*(rank-alen+1) + args[id+1..-1]
  elsif args.length == 0   # to support empty [], []=
    args = [true]*rank
  end
  args
end