=begin =ToDo list * Support a temporay attribute (@tmp_attr = Attribute.new) =end require "numru/netcdf" require "numru/gphys/varray" require "numru/gphys/attributenetcdf" require "numru/gphys/netcdf_convention" module NumRu ############################### ### /// for write buffering --> class NetCDFVar alias current_put put end # class NetCDFVar module NetCDFDeferred # To be "extend"ed in a NetCDF object to add simgular methods # to support deferred operations. # Used together with NetCDFVarDeferred. def add_deferred(proc,args,length) defined?(@len_stored) ? @len_stored+=length : @len_stored=length @deferred = Array.new if ! defined?(@deferred) || ! @deferred @deferred.push( [proc, args] ) end def flush if @deferred @deferred.each{|opr| if ($DEBUG) print "## flushing ## "; p opr end opr[0].call(opr[1]) } @deferred = nil NetCDFVarDeferred.flushed_length(@len_stored) @len_stored = 0 end end def enddef super flush end def sync if define_mode? enddef super redef else super end end def close enddef rescue nil super end end # module NetCDFDeferred ####### module NetCDFVarDeferred # To be "extend"ed in a NetCDFVar object to add simgular methods # to support deferred operations. # Used together with NetCDFDeferred. @@max_len_store = 1000000 # regardress sizeof(type) @@len_stored = 0 class << self def flushed_length(len) @@len_stored -= len end def max_len_store; max_len_store; end def max_len_store= (l) @@max_len_store = l end end def name=(*args) begin super(*args) rescue file.redef #retry <- this will introduce endless loop super(*args) end end def put_att(*args) begin super(*args) rescue file.redef #retry <- this will introduce endless loop super(*args) end end def put(*args) if(self.file.define_mode?) if (@@len_stored < @@max_len_store) ## put operation is stored in self.file and deferred print "## storing (put) ##\n" if ($DEBUG) len = args[0].is_a?(Numeric) ? 1 : args[0].total self.file.add_deferred( Proc.new{|args| current_put(*args)}, args, len) @@len_stored += len else self.file.enddef current_put(*args) self.file.redef end else self.file.flush current_put(*args) end end end ### <-- for write buffering /// #################################################################### class VArrayNetCDF < VArray ## < initialization redefined > ## def initialize(aNetCDFVar) @name = aNetCDFVar.name @mapping = nil @varray = nil raise ArgumentError,"Not a NetCDVAr" if ! aNetCDFVar.is_a?(NetCDFVar) @ary = aNetCDFVar @ary.extend(NetCDFVarDeferred) @ary.file.extend(NetCDFDeferred) @attr = AttributeNetCDF.new(aNetCDFVar) @convention = NetCDF_Conventions.find(aNetCDFVar.file) extend( @convention::VArray_Mixin ) end def inspect "<'#{@name}' in '#{@ary.file.path}' #{@ary.ntype}#{shape_current.inspect}>" end class << self ## < redefined class methods > ## def new2(file, name, ntype, dimensions, vary=nil) dimensions = dimensions.collect{|dim| if dim.is_a?(String) # specification by name is available for existing dimensions file.dim(dim) || raise("dimension "+dim+" is not in "+file.path) else dim end } va = new( file.def_var(name, ntype, dimensions) ) if vary vary.att_names.each{|name| va.set_att(name, vary.get_att(name))} end va end alias def_var new2 ## < additional class methods > ## def write(file, vary, rename=nil, dimnames=nil) raise ArgumentError, "1st arg: not a NetCDF" if !file.is_a?(NetCDF) raise ArgumentError, "2nd arg: not a VArray" if !vary.is_a?(VArray) rank=vary.rank if dimnames == nil if vary.is_a?(VArrayNetCDF) dimnames = vary.dim_names else dimnames=Array.new for i in 0...rank dimnames[i]='x'+i.to_s end end elsif( rank != dimnames.length) raise ArgumentError, "# of dim names does not agree with the rank of the VArray" end fdimnms = file.dim_names begin shape = vary.shape rescue StandardError, NameError shape = vary.shape_ul0 end dims = Array.new mode_switched = file.redef for i in 0...rank nm = dimnames[i] if fdimnms.include?(nm) dims[i] = dm = file.dim(nm) if dm.length != shape[i] && shape[i] != 0 && dm.length != 0 raise "Length of the dimension #{nm} is #{dims[i].length}, while the #{i}-th dimension of the VArray #{vary.name} is #{shape[i]}" end else dims[i] = file.def_dim(nm,shape[i]) end end nm = ( rename || vary.name ) val = vary.val newvary = new2(file, nm, vary.typecode, dims, vary) newvary.val = val if mode_switched; file.enddef; end newvary end end ## < redefined instance methods > ## def val begin mode_switched = @ary.file.enddef rescue end v = @ary.get begin if mode_switched; @ary.file.redef; end rescue end v end def val=(narray) if narray.is_a?(Numeric) @ary.put( narray ) else if shape_ul0.include?(0) # has unlimited dimension narray = __check_ary_class(narray) slicer = (0...rank).collect{|i| (shape_ul0[i] != 0) ? true : 0...narray.shape[i] } @ary[*slicer] = narray else @ary.put( __check_ary_class(narray) ) end narray end end # It is safer not to have the method "shape" to avoid misconfusion of # shape_ul0 and shape_current: def shape raise "The shape method is not available. Use shape_ul0 or shape_current instead." end def name=(nm) @ary.name = nm @name = nm end def rename!(nm) @ary.name = nm @name = nm self end def rename_no_file_change(nm) @name = nm self end def rename(nm) self.dup.rename_no_file_change(nm) end def ntype @ary.ntype end def total len = 1 @ary.shape_current.each{|i| len *= i} len end alias length total def rank shape_current.length end # def reshape!( *args ) # raise "cannot reshape a #{class}. Use copy first to make it a VArray with NArray" # end undef reshape! def file @ary.file end ## < additional instance methods > ## def dim_names @ary.dim_names end def shape_ul0 @ary.shape_ul0 end def shape_current @ary.shape_current end def file @ary.file end ## Not needed, so far: #def convention # @convention #end end # class VArrayNetCDF end # module NumRu ########################################################### ### < test > if $0 == __FILE__ # $DEBUG = true include NumRu file = NetCDF.create("tmp.nc") dims = [ file.def_dim("x",10), file.def_dim("t",0) ] x = VArrayNetCDF.new2(file,"x","sfloat",dims[0..0]) x.set_att("units", "km") x.val = 10 v = VArrayNetCDF.new2(file,"v","sfloat",dims) v.set_att("units","m/s") v_ = VArrayNetCDF.new2(file,"v_","sfloat",["x","t"]) # file.enddef # (no need to call this) v[0..-1,0] = 99.0 v[0..-1,1] = 66.0 w = VArrayNetCDF.write(file,v,"w") wsub = w[0..-1,1] wsub.val = 22.0 z = VArrayNetCDF.new2(file,"z","sfloat",dims) z.val = NArray.int(10,2).indgen! p w #exit file2 = NetCDF.create("tmp2.nc") vv = VArrayNetCDF.write(file2,v,"vv") vv2 = VArrayNetCDF.write(file2,v/3,"vv2") vv3 = VArrayNetCDF.write(file2,v/3,"vv3") v.copy(vv2) (2*v/3).copy(vv3) p "%%%%",(v + w).val,"#####" p v.length p v.file.path p v[0..2,0].file.path file.close file2.close end