#!/usr/bin/ruby -Ku class File def each_rec recl self.binmode loop { hdr = self.read(4) break if hdr.nil? frecl = hdr.unpack('L').first unless frecl == recl raise "recl file:#{frecl} != #{recl}" end body = self.read(recl) yield body body = nil frecl2 = self.read(4).unpack('L').first unless frecl2 == recl raise "recl2 file:#{frecl} != #{recl}" end } end end class App def initialize argv @fbin, fcfg, time, span, yygg = argv unless span puts "usage: ruby #$0 file.bin file.cfg time span" exit 1 end @yygg = yygg ? format('%04u', yygg.to_i) : 'YYGG' @cfg = { :nx => 144, :ny => 37, :x0 => 0.0, :y0 => 90.0, :dx => 2.5, :dy => 2.5, :param => [:u0,:u1,:v0,:v1], :t => time.to_f / span.to_f } @stns = [] File.open(fcfg, 'r') {|ifp| for line in ifp line.chomp! case line when /^:(n\w+)\s+/ then @cfg[$1.to_sym] = $'.to_i when /^:([xyd]\w+)\s+/ then @cfg[$1.to_sym] = $'.to_f when /^:(p\w+)\s+/ then @cfg[$1.to_sym] = $'.split(/,/).map{|s|s.to_sym} when /^([-+]\d\d)([-+]\d\d\d)\// then stn = { :reqlat => $1.to_i, :reqlon => $2.to_i } @stns.push stn else STDERR.puts "err #{line.inspect}" end end } @result = nil end def prepare @cfg[:wrecl] = @cfg[:nx] * @cfg[:ny] @cfg[:brecl] = @cfg[:wrecl] * 4 for stn in @stns j = ((stn[:reqlat] - @cfg[:y0]) / @cfg[:dy] + 0.5).floor i = ((stn[:reqlon] - @cfg[:x0]) / @cfg[:dx] + 0.5).floor unless 0...(@cfg[:ny]) === j raise "j=#{j} out of range 0...#{@cfg[:ny]}" end unless 0...(@cfg[:nx]) === i raise "i=#{j} out of range 0...#{@cfg[:nx]}" end stn[:lat] = @cfg[:y0] + j * @cfg[:dy] stn[:lon] = @cfg[:x0] + i * @cfg[:dx] stn[:ofs] = i + j * @cfg[:nx] end end def readbin recname = @cfg[:param].dup File.open(@fbin, 'r') { |fp| fp.each_rec(@cfg[:brecl]) { |rec| param = recname.shift.to_sym for stn in @stns fmt = format('@%uf', stn[:ofs] * 4) val = rec.unpack(fmt).first stn[param] = val end } } end def guess w0 = 1.0 - @cfg[:t] w1 = @cfg[:t] for stn in @stns f0 = Math::hypot(stn[:u0], stn[:v0]) f1 = Math::hypot(stn[:u1], stn[:v1]) u = w0 * stn[:u0] + w1 * stn[:u1] v = w0 * stn[:v0] + w1 * stn[:v1] f = w0 * f0 + w1 * f1 f_tmp = Math::hypot(u, v) stn[:f] = (1.9438 * f + 0.5).floor if stn[:f].zero? then stn[:d] = 0 else d = ((Math::atan2(u, v) / Math::PI + 1.0) * 18 + 0.5).floor d = 36 if d.zero? stn[:d] = d end end end def report puts "SMVB11 DUMY #{@yygg}00\r\r\n" puts "BBXX\r\r\n" for stn in @stns alat = (stn[:lat].abs * 10).floor alon = (stn[:lon].abs * 10).floor qc = if stn[:lat] < 0 then (stn[:lon] < 0) ? 5 : 3 else (stn[:lon] < 0) ? 7 : 1 end printf("BOGUS %.4s3 99%0.3u %1u%0.4u ", @yygg, alat, qc, alon) f = (stn[:f] > 99) ? 99 : stn[:f] printf("46/// /%02d%02d 1//// =\r\r\n", stn[:d], f) end end def run prepare readbin guess report end end App.new(ARGV).run