rb-grib-0.4.0/0000755000175000017500000000000012772262773012712 5ustar uwabamiuwabamirb-grib-0.4.0/BSDL0000644000175000017500000000242412772262773013363 0ustar uwabamiuwabamiCopyright (C) 2011-2016 Seiya Nishizawa and GFD Dennou Club. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. rb-grib-0.4.0/LICENSE.txt0000644000175000017500000000510312772262773014534 0ustar uwabamiuwabamirb-GRIB is copyrighted free software by Seiya Nishizawa and GFD Dennou Club. You can redistribute it and/or modify it under either the terms of the 2-clause BSDL (see the file BSDL), or the conditions below: 1. You may make and give away verbatim copies of the source form of the software without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may modify your copy of the software in any way, provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or by allowing the author to include your modifications in the software. b) use the modified software only within your corporation or organization. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 3. You may distribute the software in object code or binary form, provided that you do at least ONE of the following: a) distribute the binaries and library files of the software, together with instructions (in the manual page or equivalent) on where to get the original distribution. b) accompany the distribution with the machine-readable source of the software. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 4. You may modify and include the part of the software into any other software (possibly commercial). But some files in the distribution are not written by the authors, so that they are not under these terms. The data files in the "data" directory are provided by GRIB API (http://www.ecmwf.int/products/data/software/grib_api.html) under the GNU Lesser General Public License. 5. The scripts and library files supplied as input to or produced as output from the software do not automatically fall under the copyright of the software, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this software. 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. rb-grib-0.4.0/rb-grib.gemspec0000644000175000017500000000167412772262773015613 0ustar uwabamiuwabami# -*- encoding: utf-8 -*- $:.push File.expand_path("../lib", __FILE__) require "numru/grib/version" Gem::Specification.new do |s| s.name = "rb-grib" s.version = NumRu::Grib::VERSION s.authors = ["Seiya Nishizawa"] s.email = ["seiya@gfd-dennou.org"] s.homepage = "http://ruby.gfd-dennou.org/products/rb-grib/" s.summary = %q{Ruby class library to hanlde GRIB file} s.description = %q{This class library enable you to handle GRIB file.} s.rubyforge_project = "rb-grib" s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ["lib"] s.extensions << "ext/extconf.rb" # specify any dependencies here; for example: s.add_development_dependency "rspec" s.add_runtime_dependency "numru-narray" s.add_runtime_dependency "narray_miss" end rb-grib-0.4.0/lib/0000755000175000017500000000000012772262773013460 5ustar uwabamiuwabamirb-grib-0.4.0/lib/numru/0000755000175000017500000000000012772262773014626 5ustar uwabamiuwabamirb-grib-0.4.0/lib/numru/grib.rb0000644000175000017500000000113612772262773016077 0ustar uwabamiuwabamirequire "narray_miss" require "date" require "numru/grib/setenv.rb" require "numru/grib/version.rb" require "numru/grib.so" require "numru/grib/grib.rb" if defined?(NumRu::NArray) unless NumRu::Grib::SUPPORT_BIGMEM $stderr.print < "", 2 => "n", 3 => "p"} def ensemble_member pn = get_value("perturbationNumber") te = get_value("typeOfEnsembleForecast") name = "" name << pn.to_s if pn name << (MEMBER_NAME[te] || te.to_s) if te name end def gtype get_value("typeOfGrid") end def missing_value get_value("missingValue") end def get_xy lo, la, = get_data case gtype when "regular_ll", "regular_gg" lon = Hash.new lat = Hash.new if get_value("jPointsAreConsecutive") == 1 lon["ij"] = 1 lat["ij"] = 0 shape = [get_value("Nj"), get_value("Ni")] else lon["ij"] = 0 lat["ij"] = 1 shape = [get_value("Ni"), get_value("Nj")] end lo.reshape!(*shape) la.reshape!(*shape) lon["short_name"] = "lon" lon["long_name"] = "longitude" lon["units"] = "degrees_east" idx = [0,0]; idx[lon["ij"]] = true lon["value"] = lo[*idx] lat["short_name"] = "lat" lat["long_name"] = "latitude" lat["units"] = "degrees_north" idx = [0,0]; idx[lat["ij"]] = true lat["value"] = la[*idx] return [lon,lat] else raise "not defined yet: #{gtype}" end end end # class GribMessage class GribVar Day0 = DateTime.new(1900) MAXNDIM = 7 # lon, lat, lev, t, step, timeInterval, ensemble def rank @dims.length end alias :ndims :rank def total @dims.inject(1){|t,d| t*d.length} end def dim_names @dims.collect{|d| d.name} end def shape @dims.collect{|d| d.length} end def dim(index) index = dim_names.index(index) if String===index return nil if index.nil? @dims[index] end def def_dim(name,index) d = ::NumRu::GribDim.new(self,name) if index == -1 @dims.push(d) else @dims[index] = d end return d end def put_att(key,val) @attr[key] = val end alias :set_att :put_att def att(key) @attr[key] end def att_names @attr.keys end def typecode if missing_value NArrayMiss::FLOAT else NArray::FLOAT end end def missing_value @msgs[0].missing_value end def get(*indices) sha = shape mask = nil first = Array.new(rank-@xy_dims,0) if indices.length != 0 if indices.include?(false) sha2 = sha.dup sha2.delete(false) raise ArgumentError, 'multiple "false" in indices' if sha.length - sha2.length > 1 indices[indices.index(false)] = [true]*(sha.length-indices.length+1) indices.flatten! end rank.times{|n| ind = indices[n] case ind when true indices[n] = 0..sha[n]-1 when Fixnum sha[n] = 1 when Range f = ind.first e = ind.end e = sha[n]-1 if e==-1 e -= 1 if ind.exclude_end? sha[n] = e-f+1 indices[n] = f..e else raise "invalid indices" end } if rank > @xy_dims mask = NArray.byte(*shape[@xy_dims..-1]) mask[*indices[@xy_dims..-1]] = 1 (rank-@xy_dims).times do |i| ind = indices[@xy_dims+i] case ind when Fixnum first[i] = ind when Range first[i] = ind.first first[i] += shape[@xy_dims+i] if first[i] < 0 end end end end shape2 = shape.dup sha2 = sha.dup @del_dims.each do |i| shape2.insert(i,1) sha2.insert(i,1) first.insert(i-@xy_dims,0) end mask.reshape!(*shape2[@xy_dims..-1]) if mask value = missing_value ? NArrayMiss.sfloat(*sha2) : NArray.sfloat(*sha2) index = Array.new(MAXNDIM-2) @msgs.each_with_index do |msg,i| idx = @idx[i] next if (mask && mask[*idx]==0) val = msg.get_value("values") if @xy_dims > 0 val.reshape!(*shape[0...@xy_dims]) # val = msg.get_data[2].reshape!(*shape[0...@xy_dims]) unless indices.length==0 || indices[0...@xy_dims].inject(true){|t,v| t &&= v==true} val = val.slice(*indices[0...@xy_dims]) end end (MAXNDIM-2).times do |i| index[i] = idx[i]-first[i] end value[*(Array.new(@xy_dims,true)+index)] = val end ns = sha.length ns.times do |ii| i = ns-ii-1 sha.delete_at(i) if indices[i].kind_of?(Fixnum) end value.reshape!(*sha) if missing_value value.set_mask value.get_array!.ne(missing_value) end return value end alias :[] :get alias :val :get def inspect "GribVar: #{name} in #{file.path}, [#{shape.join(",")}]" end private def get_time(date) (DateTime.parse(date) - Day0).to_f*24 end def init @attr = Hash.new @dims = Array.new msgs = get_messages msg = msgs[0] put_att("long_name", msg.name) # put_att("standard_name",std_name) put_att("units",msg.units) if msg.units put_att("grid_type", msg.gtype) put_att("missing_value", [msg.missing_value]) if msg.missing_value vdim = Array.new xy_dims = 0 msg.get_xy.sort{|x,y| x["ij"]<=>y["ij"] }.each do |xy| val = xy.delete("value") sname = xy.delete("short_name") ij = xy.delete("ij") if val.length > 1 d = def_dim(sname, -1) d.put(val) xy.each{|k,v| d.put_att(k,v)} xy_dims += 1 else #xy.each{|k,v| va.put_att(k,v)} end end z = Array.new t = Array.new st = Array.new ti = Array.new en = Array.new hash = Hash.new msgs.each_with_index do |msg,i| zv = msg.z_value tv = msg.date_raw stv = msg.step tiv = msg.time_interval env = msg.ensemble_member z.push zv t.push tv st.push stv ti.push tiv en.push env ary = [zv,tv,stv,tiv,env] if hash[ary] # error m1 = msgs[hash[ary]] m2 = msgs[i] a1 = m1.get_keys.map{|k| [k,m1.get_value(k)]} a2 = m2.get_keys.map{|k| [k,m2.get_value(k)]} a = Array.new a1.length.times{|j| a.push [a1[j],a2[j]] if a1[j]!=a2[j]} warn "BUG: send the following message to the developers" p self p ary p a raise("error") end hash[ary] = i end [z, t, st, ti, en].each{|a| a.uniq!} # [z, t, st, ti, en].each{|a| a.uniq!; a.sort!} @idx = Array.new(msgs.length) hash.each do |ary, i| zv, tv, stv, tiv, env = ary @idx[i] = [z.index(zv), t.index(tv), st.index(stv), ti.index(tiv), en.index(env)] end del_dims = Array.new if z.length == 1 put_att("level_type", msg.z_type) put_att("level_value", z[0].kind_of?(Numeric) ? [z[0]] : z[0]) put_att("level_units", msg.z_units) if msg.z_units del_dims.push xy_dims else d = def_dim(msg.z_sname, -1) d.put_att("long_name", msg.z_type) d.put_att("units", msg.z_units) if msg.z_units d.put(NArray.to_na(z)) end if t.length == 1 put_att("time", msg.date.to_s) del_dims.push xy_dims + 1 else d = def_dim("time", -1) d.put_att("long_name","time") d.put_att("units","hours since #{Day0.strftime('%Y-%m-%d %H:%M:%S')}") d.put(NArray.to_na(t.map{|tv|get_time(tv)})) end if st.length == 1 put_att("step", [msg.step]) if msg.step put_att("step_units", msg.step_units) if msg.step_units del_dims.push xy_dims + 2 else d = def_dim("step", -1) d.put_att("long_name", "step") d.put_att("units", msg.step_units) if msg.step_units d.put(NArray.to_na(st)) end if ti.length == 1 del_dims.push xy_dims + 3 else d = def_dim("time_interval", -1) d.put_att("long_name", "time_interval") d.put_att("units", msg.step_units) if msg.step_units d.put(NArray.to_na(ti)) end if en.length == 1 del_dims.push xy_dims + 4 else d = def_dim("member", -1) d.put_att("long_name", "ensemble_member") d.put(NArray.to_na(en)) end @xy_dims = xy_dims @del_dims = del_dims @msgs = msgs end end # class GribVar class GribDim attr_reader :var, :length, :name def initialize(var,name) @var = var @name = name @attr = Hash.new end alias :total :length def get @ary end def typecode if NArray===@ary @ary.typecode elsif Array===@ary @ary[0]["value"].typecode end end def val return @ary end def [](*ind) return val[*ind] end def put(ary) @ary = ary @length = val.length return @ary end def put_att(key,val) @attr[key]=val end alias :set_att :put_att def att(key) @attr[key] end def att_names @attr.keys end def inspect "GribDim: #{name} length=#{length}" end end # class GribDim end # module NumRu ##################################################### if $0 == __FILE__ include NumRu if ARGV.length>0 infname = ARGV.shift else infname = "../../../testdata/T.jan.grib" end Grib.is_a_Grib?(infname) || raise("file is not a Grib dataset") p grib = Grib.open(infname) print "\nVars\n" grib.var_names.each{|vn| p v = grib.var(vn) p v.dim_names v.dim_names.each{|dn| p dn; p v.dim(dn).get } p v.shape v.att_names.each{|an| print an, " => ", v.att(an), "\n" } puts "\n" p v.val } end rb-grib-0.4.0/lib/numru/grib/version.rb0000644000175000017500000000007212772262773017562 0ustar uwabamiuwabamimodule NumRu class Grib VERSION = "0.4.0" end end rb-grib-0.4.0/Rakefile0000644000175000017500000000021012772262773014350 0ustar uwabamiuwabamirequire "bundler/gem_tasks" require "rspec/core/rake_task" desc "Run all spec" RSpec::Core::RakeTask.new(:spec) task :default => :spec rb-grib-0.4.0/data/0000755000175000017500000000000012772262773013623 5ustar uwabamiuwabamirb-grib-0.4.0/data/regular_gaussian_pressure_level.grib10000644000175000017500000003215412772262773023230 0ustar uwabamiuwabamiGRIB4l4bd 0001 @W8W8sD 4 B F|3ឌf2`61 ]En*M 4Os8$ Fb-@DF"|C L"FB6Џ$q& @JZ&9O0)ALtTBPb+A\ W诅z+]V³xL*N \RB@'=O"yПE(QEDS"X~,j ]b†&1 f#6,)dK:Z.IplZ2ĕ&(BoKŬ+RPPzxD$!DP@P:!uC@@z$*|LmD'= O)K hS E.(B Mb]xDh"PA}Cц8D!! dC)ȓ(X H^Ɔ*0yhWX%*DIJ> @3 PXB`BW1 e v6+iz kS}38ѽj=p>E 4QԎn#CRP0 EA)tv*3ArÀ@8.N @@ gCt(dxGf8 Tp)jDisx(7Ѭ ^Dp*J PT¸$ 1A ;aPDBC%2Q`&:AO=AwC˟AaSU E'8ɔKzVҮԲ%),H6j44 '^6ѕKWr"!t6 I (OB>pQh4~ QB3(sT9 ic/h8$0$ 0At@ц6 hNB `: @b2|H#.V7A opm=)Px)>JS"5[+ TXOfԖt&%.i9Gz,4Y"J?r#lм6#F(!D"(pĆ&[tqC G^5a ]#G 6[Bņp4 a0%)GB@@PX9PӇP?"#F?BZF6 p&C2էG*[VjUŕ+NIFP0DLYB xH':_"؃Ed#)l ~4AdL xj,164Mdž ~\8hw#ʝFf.YQ ~Ba hdÿ%Q] pURA_»@F>2*&Q/ A1S ;Y2l0IxOrZؚ$$G<(u#V^#AdCx.X"L c,+A|d<'Y|N~'HTR'E cT֢b]/$HjC芤PG4|JVB|E,#GP:qŇ1 &]K\bƔ@GP;Aˍh#Ah&>Qpĺ!`<+-.4 s(\ pDz/Q؆!)E(p.IL^̘D()EUWr!=>NpS*}"Adɥ- ZJjNC|զ8k%A4ECixR]C*L[c801pSbm H2 @D!NYB͖l,`*WzŖ5 j*U2Tt&';+hF=MnC:(f803GIA1Q}Cͦ?2 N] Iȣ?Qt&?M:bF'!7iNZA4QPd΢D4e˜lƦ5ѕ}#QHLKGP$5)U Q_S%ZZVpү| YjԸ'&:at;Nq<(hAaM9f<mf/0z_h6@zѪ%;1Td*UjVjŅ, [T—SިX=\Rה‹̲%b%Ɯ3A; ͎bocTI eʣGufkb"լ]K#^ 0w]\zղe 3D PbD ьhKZU5-uLf4Y4 .n˟`kæ15^bU|!6ɽM2a@J" ?qp'Qy}G 7ƚ#) HeI”V>.郬iC>YP631,f :1\_ɔel+j+mUf;y (@`ި3 H1XzL&5aNzs(?4;HHRIƦֶ1;OJwDY@*rTڦ֌1*as %鯭Sd Xq6jU^w) dpµQ\"ժ&7jd3ܨۗ9i׮rÔ\' u̚c$Fql\ }4Ŷs[4֦qMkCRtϷ kGYu.iak_`ٔ67Mo'}k^q1 fOeaC^KYZZuLc֩-nn~z77Mo z~ƯdC Em=aڴUd'Af &gN:r{zƳaLf[9YڸQMmqDه5t x6%_lh|}>Y mNpv_1eJbk+p"8ۯ~\_/cOrTex/}L~h3Gb6r4Qmcj#Kڨvӧ48nCq\6]-$gc ؒe0Y]bOdzLgO}#h-o}bG>aO{_X>MoU{ (IJRJ= vIrt&O1BGb:RD4RG>1O_:P-u E?,`&A~ P, 1H:A+"Ogھ5f{ ǽO|>o|Xψ{`ӾO~~ߚ>O~S8YE3H51Dd$iQAR_=G$?<.!q HOv?l .@)`@Z P`(T%?1/}߆ȿ|;8Ƿ=in{^=l} :?>|ߞ79O~`Y<h 0 U8t: qu{ߞזjzl<Qz#Ξþ/} п}ψ{#Ҟh/`#g?`1j03 Mx?E,*! HFoՀ\ q)Pi  ApɅ|/! dCr0`@lA8 @b .!9 8DA OlW@M~\?1|^=o{׽>MOߞG>ycng=ϴ9 Ol@F)HD1 am Hx> ~H p}V@DkxKŽ𘃤'MA*74_h8AZ0t$[@ p#ac o~_X;ap{؞Ǥ=}}x?)bz;^lg)/ˀ`S@S_>~wC=O$(A /A |?uϝ}?3AwG hBb pD5a' HbBZ߆d)! Gp}"?P4 3*>aVz^p `@~r? |_:WC7H=O, ?ނ  (AІ`yHEApȂ q8,Ž0ĉU"? HXzɆd-@ 0A)@~B7o2y{^y1Nw79O_G޾ ?M|g>)z^GB>х!M@o _>ώ|=Owwk]7VАt6"q0y`i@u/~ @R3JGb p6oH;RĊ" TCvДd'`:A2Ok Gh!Ao~GMo}3_=oHzNGu{] gPI} ?C_>ϫ{ʞ񧖼uu{T79rHPDkHfCb È 5@i0 {>{>bCHFWS Ǥh4A> L qY ?A*O~ss{^ǢYAz^Z7{< vGI:eN}sM7}@>m|{X7;=ntӯ@rbm{ކwpծt;NRSF]?P_>7?Yop{#\~W;1ܯy;џ@#>qzk^Lg<-w^0W;v 29ɏ s?m/ yty O}zvqàD7*bd >o|=eO*xpOv]Uaܯ w1O&>@~3g491.v{]O~כCyk7^).sæ]ruæ0%95ďHG%9x񧉻{^t] >ܲetbG>ky#Z;u]TB:؎uí7=9a͎xlǃ͹pW[|]l' %Ɏ1t3܂߾}|C^f'P9Nw㵝wL14r\P.t덜 g8E ;rsR;-wCҟG<1ٮsÜ9zS'A.tW89iaqKw*r \'8au06-lcXZ巋/y]ZF81 q?HyƝVg/7p˛ G6!-p [9s}[6)n~߰w; ˍmo[9nt發AՎr܄vescu]t\.nncrFݶ5ͪp <6-lkcZ׶qmqmk?-:xSP㷥 TlcvFNtێF뵵1jSdp8% nۆ8ENrCyFٹR|^'M-jUצ q Tb}Vn3XzÖ 1! l t"GiscV-n#bZ6koFYe;"eLecZv߸.tܢ7E,iKVѷ-kkSZdՆ3g9ɶIZjS*Жqq}ZҶ3}c0ƣ%rkNZ4ѶM&kk[f5Ma "i+t^f4e Lj+RZƣɓfSBZѦ^u,!dM0˖@\BՖr.y] 8f pk 7Me;Z64 g3&FG1,ec8Φ c,Φ-nCmӦ2٩$|+Fe81LxfHv49pW̧HXXbX~laY:.]s\~20~ _s.l+Vr¯ko[v`vmdZV4=`T2a FbnۮvkbXxMy!`pMXjKٞ&k2͇n+_ھҖ~4Qle  .r˝^4*/q>RT&(JeTZr,aj\.1^k&YR͖eүayk[",T*rSpuf:Yb f6d61QK]J~0} [z-j+_SX80}~]W$1vbz.{,aS آ_zꖜu,mZ*Yb¥ \OoSZ( C(RBU6J*WShE-*1SVŖrSWp,u?O…zF*X*VU°ն/)~k_؈a+\De!^W2pq\Yߗ%sQX2>k ,W²\E},-`YVµ%-ulSYCEX عմ+uN*8Me4'5:PB%7YEIO |T(J*pU2EU+aVZڣ'=PPWU^Ej,rk\Ve-p+]򗞺u,ZWj5(K Tʷ.anK.W]*eOjpSX~,5_W⿕֭s+_ VRUE!GXzǖfAC)L\Ɨ&7O"}Si:NpS㧁AETB|E8T*S禡3iOڑ5/yMsS*2MQ[D[ȭkKXZ%![T T&7Oj-=fUҢM*=O wTz쥥8*YJVZ KU2Td?jUڴUED(:)K\֖Խ&1 LhSXϦ}5Mm(GVS(u@IMjd'u? QTNjTN)KVr:ubWھ歕V1O*XPx'i;INqS57qU TԾEAuTjTʣTE+)N*]QS')<Pڄ&6iO xSq/)rJ Q0IK\d&1)Ld:tMGRR*$'-5Mtƞ$A Mhn&7IOrwӾu5*iR nSTu)(Ej#QJTGJ*P2ydE9iNs'C*DĦ6ɦLrex&3LWm6iO rJ% &1IT晤'y0u˥,T8P/QLjep&6;n{4 h3>φ4Mllqg 8iMoo0F4Mg;fU2!L6`2He,cKX01i3a::w D+|D.ΩD1D4:D7pD:JD=D?ɐDB^DDHDGDIDJDLDMDNeDO|DO(DO8DO_DNDMI\DKDInDFLDCD@D=D9ID5U8D1@bD-+D(PD$9D AD*DD.D7CnC"ZCC>CoCQC7C$C \B B65VAi5>;I/F>#\>Ay>o{O>0K?zS?F?%?3;?E?Z{?u0 ?b?'?8@;@@@1@!{@'&@-N@3@:a@Br)@J@SS@\O@f2I@o@y@fM@,b@}@f*@@@s@ @˞V@@@!@@,@ft@E%@@5@s@9!@*@dA4 B@ Tf5)Mg:f[2̎d&-1)6aS%/yy˺]2%,dKWeQ*IPJrSR%)G>R2))yMJrTDee+y^YԖ칥/ɄLRd3.Ҧ6r=OTe7B Ц.u [BP(?iOz̞'S9"otl'o;)ζuT'K:9rsS')99N>q&5d {*IFIKI$9!9*ARdQ#I!JL2r eA*]KY֖.vK]򗴾0ٌLgT|c=iКT}M4R ՂU%l\W~ﯽ,` Z–-}\:U⩵m/)F R~ߦ' F-Q':ip34)9NFpoΦ7/pKU$$YȆAz#Gb;qߏ$zZD44$(KʶXؗl1y~cæ0i"a,&6=-4CW*2VMMt۷:Wž!xn/1,Ja7λ}-9c:UbVZ+i FZ)Q"@ (>MeT$'I~OԵ/vˆYҸ d&0IJH4$ 8@ I#!jOe0Ra2t/̾jSs'm;O&zse(LjUV -xa1˦gcfw3n~_=FjTsSwʖ4~\~+uXZT4'2gJMRXԙ)IWK"\&5̆^r%8>-OLqE2nHL;&u3{D%.Ip˾a34B06Զ5:*KWY)0KLS/ǽMnGn[cNi pˆ|n|jHV͈ 6%[:jt=df]1̆ged'{;*n3dd7:YMcc[D'qQeyG?Q|l9HFCt'-=)|slfg1IK_sLh]MغVl`;fo3mm|69nt;:mo>4OPu^:n׾t789VF gsVx'@jvڞS9yMZg;/9ɼLV7U"#E2Q4d&Y0IZI6HLr6MmSD,nLeSQeNZW.mk^vrt#=g7x<9)͎= Dz/?|nr۔ S&pssVVl ]|lqf;$Wβ5@/hZ2薌d%4J6V2L[hF92 e1̖_dS$H˦eH&wپw2FXu%}\c%9KRr;|W{_|e;u7'h5Υs']Զu2e|%_6VuoCxv eVQ<{INAR&o6M`|.ɺO圌-9aYۗ|e%Fv5&_3ɖXrv# I.˺o&:[XʞRDk#Jycu5>6s]O\zծr\(8%7vޏ 9U;ڎso|fųuܚo|vĴEjHiT6ٸq3n,Φ>CSte'>*_r'y8IBr=gQ<9ΦoA$d!H~NrT/Pⵗ2pq(FͶU^r+{'|m&xg>8qݧٿz^w޻s|{曲G+ݦw[]ߚyO~K vY{1?)zܞW'ۮFu2LM`w8{P2ܞd,ٍ%`r4׬kYvRkZY*նX=?WTcmuaT4H?PN5S*]DzHJBҒc1O}o-geoϾ4m{mO~<~}~W=jx;ߏy3ɞCw+~.pq7|bx[3);9ul_VjUzݪml Fپzݡ-kk0Z^7 N+[f3X\n[vV%ADJQ5kT*M^5q"r[q3yFzib[F:>wwǬ|篡wݾYw.O\ֶt7}tlXnnq3M|e!Nqsl"fk7nMuۮvxMioF[7q -9v|X~mW-Yzmr֗kL [l`y̠M'4IyM΋/KLWc &wrc5ڈ&6m'wz/R ~˼|'6Mw#Ƕ8ىeS$N@g[)9qˍLk# -/y_ v o~_斷ml;^ź.7~6ȶtqKVں6.'\Վ mb~tsd7R|8-{,ifGAj6C ͎hṙb-ʶ/Λt?u1ƥL?m.qk]x(17*yǞ3 `~VQn8RŖm-r[ުw z"Ӗ5i:v5ӮMeWl-XRx}f9)vƧݒ,n\b vnhka3WQIjXX~1gP{tEY,Yf9},g{@R̖.g+gڶ6CkqYjް Bh_5`I@xp#,rƶ),^hm~Td W#`9 0rJ#I#J&OR؜UQ;IXҷ dq([L~jQiI`TR\NSjZ嗀4j`TL&.y:Y% kaӪ5%eYM:mTʩ4Lj\knUֳdX"_ )fu-9~ʪL?GW]))u3]7E8/8{#h %.whGj9l&],I)KWd_c y-J]3 '9bPjҎsPT#GB`DiVL~tu@RvO )Tjڬ5UIc&XrT 3yMfr[K( [;Yծoۏۮg Y{zZ16m~-ѩܛ&7J"Kqɍt])!=~UtY0 dNMKBOh蚵(?iΖgr? f5(2-R&A: >Z/8O% R0ޠz+WUbg >:P*{s@t#8B" IS^^1/A|+F n"Q?$I"HDN(nLl/x=q$ 'RʒOid[4jI6Fcle#-r*1,&#-yTM#$+yKIAӍe,VȲ8r*ē!y(&FRۦ;L2c(CJ*Sv_MY*UꑴI':پ~h$I.ɦA_:W@Q}cQȎFE6j#gG>=L!HEd-uJXח &4XOR[%S.NrW4%& HF2 d#iHAQte7,Y`Nxĥ_.9\֙U69aRG`TʲmByOJT\ m@Nnet#7GJFQ卌C)BF"R26I 9HOy.rJP2,6n3#,-4t*Q2{'yLjT2JLd%0b8ѽ$g%):ILWU0ɉK]|hCPF4&;Lfse)S:6Ep_RkT`G:Ϊkse%9)9\JWÔ~! yĶ&q8lf%Dr=ŏԓU!I,J[S.l&_3irnUA2v-f4iXҖdeG)iPIEԒ*WZ/Tlw$K%IMnXĕ16ٽdAVʮVάCiIy*t bev&-kR kM-)SH:ͺks4&'/IN*RRTq HEb( ,gc$&dž3qŏ)ym˂ZԘͦ9&YjmN]>d駧=2fSte'Ce* F*Qw ?!9K~aRg/;9OsUVc0[Wl U*nSM-Un]r&'.uZגᨕ'@M~_r]ܥ(NLVȉFW"hFJ1䒤*W>URۙ;5`P:bZ< Mni31e%xG5D%{%hG5,$(O̦inhUA.P4_m[kxǖnjKJvv'y^xNVNh"f%$8H1dI D9 Q؋%2DNĢ$m d!H@Ol&7yQu;)MFBF3흌f39zKb<$"XD/t&9I?qL&7N:kE$iQGj7Rjeou !92PqY{K~Zm5|&O-&Lpnm_m#)MJv774e"`!ɋE!E)#A xö"Ql,^ FN/QӐdd/ɨRx'uA:!ue'7ʺa3=/q|d*^TrgI:YFnS -Mz]bh}zl2\Ķ۾q+^' 7V\^7(fH Qv šPvU 8Ŗ"QQPm?|n?!HFv?Vy'TJNQ2feIHH~Q,D([ %7j}3|&M0M:bD[K*VY~wȞ7僻~ڗ%ž.%w;]&wJUSY"ΕjE$اF&/p{Hps#"i6221W!?ozĝwI)nz 8YB1:t]#5 GrFr3DU(GZG,egþ%Dy1yOyTfU+9BKT|)^"Y6v-gwk'92K^VSzޒӷejKwTί-8`As觯j q|c&~KO㌜L 5@|ݮg:YҎvs_nċ Xc;A2#SHF4ɥ!hC&؊h$-iS;d%?&LJJIZ}`[VL -Is`>v^UVMxKar6Hqc;J8$U8*yݢ0=Dv&YLT1Q"{{& ~#fC:}Ҏt̞𗄾~Ɗl\6?ۍgc =JFKԤdCn&Qdk#SKWd YKWRZ,(Yj:•F݊mv ^5zkYۦEk_:Ӷ E+)q\:f- N{3_B?F#%"Yp>1YEL _8B9̎@qKt}0DP#HD1Ǝ]"YJPҳ$cCZ+2$/ X3D4M6_򔎤MeUΦ4wukga̷/9W⩴/ucl|< Zt$)<h'E叒tG>*zbM97Qa7bgHG3QFD0Gc9xr'===bIWr6Ab{ GTȒl#%Xb"1͓ԣ$#hE2r<ܑ$5YP]L&q5Rta%AkM[YJ϶,m+ ɟm-fKUvu$DbghH6+2g,?YΟT^H>uN3*a INj< b &i9FOÞU(AnTo+5HZI򌓟Dfu<NZ|\hIπv+T>߈ ^@8nwSهL?I$pö V¢$1 ئD^:$ܕ"A؍bƍ܇d)HHH ! YDqt5ؔPsd,PZd?f*G{a^? EB i |L&h,a#50 -gKw:8=tcg;|ۯTf8Inq^ <Ѭh6ARPTE K8~F&3rsbhtò0ɋjw XVD63v1%v)͈-qgCOrdڥ8$rI#=9˪bҴ,!IEH/q1T5%OAwkg91+W".~L\c@Y1ݗmLn+\&:uܮqq&c7-hcG 7ř,g w> H6Dv&QdB͍T} {`U=0'v7r%T#؀Â1)v\r$_x@A:ܢfd]:u [چ6 Rz+Z:\RX[eK. Nqm,i;F79+\k޲IkjkWk;Ox7A,J!أC6 pvlqa:rNx%"=QD4% xNqF,y" hkE5$L'$<2|Cĕ0ݎiEƖFnQՊe%BOrS4&-)T³Uŗ}] 19vJIV+ bP/kKecC7.n\W =P,'"IHvM0gV8ſn*v#TG9z^ǵ=>t : {FZscn%/vk^ڲE~,mTiMڌTj( -D1Q@D'cCz.XTMLjRO'G Q^,dO]$6z5ݫMe!: P4 BA}{C7MNt \z捷/yۤ6ۼNeoC\7z<nrۚF7@9Nrk`YfֻQގDl+>1OTr~ӰĿ]0iJi %H{@xc{4ا5n~D YCy3"IMBTȧ5.OYJޗ&̀^*B6x[H@-u8m ohԖ4Mj(B%b+ũc/Znؖ2͟Ml(׀N5cVbˤY$Hj-ZFBDR gX7 ldBs*ak.o#8vdÄ5(NHb[lA:S곖v5Y+QU2V6-mVp]dw9kIVlb H.r]V .~\VD1ɀ}Y٘6P1L^`ksV:dQ9bvAœԥ*[RHO#1[쿦 0vZS4GB*.'2i3K}Ԯi9I*oMwZ=qc-6 a:&/wknXuN6j]W45'(AOTBu-EjTR/oNiS؟%%LC3LEx,n 4fKlǚ=k.l"QF r  LtȣF*qRK^܇A3$ hF>.9&}DLSJ¦=:1Tz./u~KYRc(:N"ZRL$)OJoHjaSZD(N*fQrԔ%D)CXDr >\(B kC<$e&GJV8&5LYȘ4hT>2z(HLGF (D`32D"4Q#AiyC m2<P}vFBQ$PcP}֤mD |6 X`pP H \0EH@`- ip>;@q8 op`1 Z@+X X-` Sx@ `7`@P!< f & @> `@0@ H P ` @ `( x&` hJ/ hp`<@~  A0"D(@`# HH&4 Nx@ )H `S(< M7777rb-grib-0.4.0/data/regular_gaussian_surface.grib10000644000175000017500000003415412772262773021623 0ustar uwabamiuwabamiGRIB8l4b 0001 @W8W8sD 8 BVY6`` j5HsF3X Z0B/b .tK.XBK. o-RKa-RKn-ķB݋v-ȷBދ.Pˡ.ˠ.K.닱.Ȼ/2/.Kx- ,4++,D̋D-\˚.̼ 0cL2C9M4tӃS`5b 6Xh͟GcQfE5TJB=Τ9C^2ţ/".0BKM,bKa.ۋ6, L(`p &<2hɺ'X H)̨J*B$'<2b&Ho'hJ*)¤Jx)P"(r&|n' +Dˠ/42 i1 -< )› q)XJe*Я˥0t+ 5tLM3~9cQ*2 J&H% zzuZyA!2:&Т2-OI$ M/\M,P3`s:#:D1PY=4ڒiu6gV]hUlWIU= M*ԑK4QDO;,6 k/0)4 كn8CΨ7c! :0C̭5C5Cd͑7RLS*Ӎf9gM40PĒ08܊+1RgudPDMH }/3T9 c(5PM}3L@Ø:7lcG1t#(N/=4 /8tW@dPC9dR?% ^ B $RZJ6.B). 5S*ࣝ=%i'jmpɷ#tfyQF6p;q1ǧjMvu;eUWZuN;%PNŃTSDSP'`P G5c

2QI41&M!)$G똌c]Ig ?S$FП<\vxgYt0 #OL6Ռ3ID :ȢM2c+M5H8Ȕ&JDdVWyN3l.cu=էxyg{Iy}jZuYȗ۸kVNg&mc鉶\bPC"UHL87GmQIO}Vj?DTnT1|f'{T6f$ZoYFl}Y&c U>MmhA\OdT*A2 CC$A|;ړlT9AZ(!PRoEرd[{sWB]yɟ|]|%^{˞2t7ofXI]ц\dq}rD[}bV(VYKL cOI37K0LA SD8vӤSQtVzYP Pfn5fonmۖoaNr='%tʦHXb^[fNITc7Rv :)ȵB&8CŐN1_5j휔qGJ(`,~'Qٟ@~v ^xWMq&؏Wha5WQOeCUXQ]Չ=D zA[eҺK5$'-D>48-QiU%SMї֎lsrΗBLtQЗL(v%ww]t5շyY^1wFd%MD搑2Rj9t{O%A,ԑVvRo7/x)w{jG _ۃ~Mr$]wV[cfca#W:UH.Jm:laו.F(NR! Gv~ ~i8zUqiYqY_lՁT=%>8Di q8%J+G{U+?QfZ]ZZ\jJnq\or]y9w|ܟS~ *{gsaY)a&UL)/WrUղ\f.Hd=&@lxqn`(~<ɋ.⃈F b >8%&{'xmUjv9dC/#Sgd.ce4H.dc_@Fܜ&vU8g MuH4\Z\7cOr=v+tߑ2 ℇ~""/bNrGy14N<䃔K ғPYE䟐;bӉhaaMjq+Y=dѷ' ޭrXi &Re9ieUZeaB#1#]rK?dNYS%ag\u%ԏ&2#쑦I)T!*NLwJEޞtot^Ee6 kGr1zibc3H⸊. cR9_i则`ʗXketRYbeCN@r&8m t1cNf=fh}4\_.rU[ȒnJ9VIcvU9z6XiLe}FQ%A%3RD(eEbI>:䎍XQ]"-eA[9fY_Tx_'㗏OI|jay~<[yj%әi8nY&c&JYe|Ld@F8؊^, ]ݪ}* Oe֟Ieqɜhi惙ZcɉeZ]XsZ~Xv祠[%Zz9Xd2HX"ꏦ5='C >>x*?x#1R@Bf=XK&JVcQߏ{H: 2Ky;hqI'w)%pʧ@Jzܧs nҚaWICdđnBc.H#~&]~8gĝr}y'rb}9fϛm){hfR`ىܖU0h*v&:tdeZo:e]JK9/e(P LPI'e`j#ڜv'葡8$NjYŜڏj0(vbߠh7~ Ryy[Rp &ם2pfQ[fS^K < ^L9KMjAIgp nd ~Yfbiæmif͚j9ȖZٌTjx(ȩʌ 8h&j^#fi*ۮ:%iF+e6Xr&Z`i)ogΠ<讞excܒbI%~9h]N@:;ţZ衢Z(^{gߞvsi暚p&bhi&U9E$ƒPfUg洅5ٓfeh|CFpg~vg2qi濘dwk)ȨJ;ij(]:ifzh+c:M(ȒH&i&۪:jh[~[i{ޗȜZ(2#ev9iv:E)ގ 6֢R*)(Q 'ŞtfJpI̦ÛivhI挙r9vfڝ҂ H7(ꊪ'|'Zzgug:l'f{z@+jjꩳ"j/Zl7[r*M)'xygZ{_j (䣂uާji'J6Lh:hajT= !h:|'Ebuܧr'7n &s})SR:f9CZ L_}I'Vw'7?0-*FƬK;-kj{*ʎ$Rz磡Z!{ڔThꦺsj*IґOi(2h6 {飥zTnSi j::(ߣ#(6Z|A}tۧt焝s窟2z([&~Y*hނIV%te:h*I'Ȟ| 縠^J\*˻C-,b[mf{$ :nƁl ʯ)'^y(!|j2^*pꗤ"JȤjM)NdZ9i~Wi7b:^ejZ:`ʍ5'V6y'Ýu窞z'2heh ʊ43098^XɆcJh/!(`:h|ҏ)cjĥj)㫀^ jj9hnz#(~XŤR%Dr)~z%认Ru>ijR(Ҥ2iZLib覡ʌJ/(ؠ bzg{)g~yѦ:rgft 玞6'r19ϙJQJxJhs7(ގ3͢~:6ݦ&)":w)ϦΓçy٨ߡNmܟ*hwj.,2o)ΌJ)o2#b7gӝszʊ((N:n"Z:hNZ;Z'㠲ݞ}i_wާH{\vIjg'h}' g[SbiemJ(ԥҔKhD&.HΓcĦJ`)ZJdiԦڥ*.*{+e 'ނ*iʓW6"ʂj.:lhvs袒j9IQ&ȢN:(ѤJu)JTQ+-: hFIgWZuܧHtYFr¦ԚFpg4ogdjyg&:(8sNz'r9'trl)JꖪF{ hcjS)?>;(MV6NۣfRZx(nS Wi%:)MRnѦbF+nJ^)bZ6((6~?izf銤@趣Nj>֡ZJ瘞~ Ş2y'wᧁ>w灞y~I縍zgwoۧtJ)E)hң;ڣ>3&+hhj5)*xʀۣڑ+{n(ʇh6J(h짦Q~ç^zNעjP) %Zi)TwWCjS> drh& hg})'|x^Z()"gqt 6oimti珗&Ĝ~oog(ʥ>z;hJ(oچZ(nƁ(S^gwZ؛RmݧN*+wRY襣6FJ ԤFE)3Vc:(ͤc6J~麦*+ƅ2H⑊6*8h}::hI~d*tY&њg擙oiԧ;if:u&"{(?uA)LƉ:6 g埆(%w'=YIU波Zw ) ^INjV)ۡjzJ;áچIhށhdڌZ>(n6軦E)Ү h~) J*Qɟ+h:i: h,}i((`چ9gq)&Ze`hi&hh6'myfe)l*(~I'*vigcZh&_)ʦןJx[Cꥪca:rq*-6-jhZ(@}i翟;i>p>GirP(Vg&ƚ:)/j/(à~gmw&śk&xlf6k*VʳkqmJ'tog[|1(WƇ*+3Z'ꠎyyr爝vv¦2a&qfkIf?fs>mҧ}9u&xIV"(etgj&Lja[khҙ:(DCހ!grz ӧnfva}cɩ&N ڣ*gbjL(kL_Failh&(-^oygztɸ',vfꘚXُfʜRlI_cf82Xv#F)(3ru(~IthzΧ%Zjimb9f6iI-R*ɤ6j4ơyfygFnj&Wag弗^&no86eI' ߛdHm{)怖nU]\9oL2gܟꂉ'EdY焝Jr ƦJ>milO^og$vefQF\MFʞni甞jx']d9fϠ"ig=Rsffj^I].JU(ڠgםr|gy&fc&3`&J"^m%QT Pe Gg:K3䍌Fi[&n6歝u%O+$W97sr6zIs^]i~&qh &6c9zeYjel˦j`i1%fZOy*ߟJ^t!F^ك%ŗjɈf@x'\qԘaeV x&ߞN~9 nYfhf7WIKe`P]X JTigePA%,Zђ~C卾68Q8m<n*HI1$.SI6/j殙gyʕJYcFW)vX9N%nWIG.N]XQ,d$2F_&rgk%-HCe)MW&NR^9fZoɰ&ZWiG$A9JehَV`xf!ZcezWO䶐nC!d^I NL$>F -Z@ic" dMI,Q2dRYݖN#6&XcqA!dדL9-I9.M$J6"/8b=8j0hc+ăbs0HAHheUR$1.H#3:#}2#O0zb!(#F~>X棡?8#BI6%qNm4|NQIc$s"89#>8cR"-(bD$TKy)8N/~Eh!؈$hⷊr4H#"%H"C*"_#xbFnH] t HࠂdbZ9ۤK h!j ⮋5x"Ɗ's nᡄXka܊)x~A^2$E^Ac42($ۜJRi ƈ/H֣HZ e!Ņ>m!("Ō^$v{1Nza臥dz97(~ ,:+r68~3aS<`~7_A}5'ᨄJX"3#aj υ_!݉'Htᣇ& 6 `"0aYN(SaĈ"ȋbӋr+x"D. 䎋#"A2)ؓ(J% A=_jD`䁶wdSuQ[4tҧIvaᷓ^{]RuDy釫_}%_|_L|׭ޓ{|)͞{G_w8}Xa< h8+b8_a}']րX`X !V:U!.j a .jJ :րngٟ(|ׂywz}^7su̧&ܡrqgt)7Or!uЧW]wI߷~x)z]rw܇h]vqs]w^Wxg|g_nH' ((~7_My㧵z=GC|w怒O}5}執~7}EwK}YG_ {9wxmht3*umǎxK]o鿦oupaq%7[p \Qru6u\jtjuwW6sw?]tGi]v!7nvIGyvŸ%|ɟj}ܟ~z|7^z7 uN3uugI~G]xנިzLjz57^{=7Nw퇉 ya姄tIpm sק[@t',nuZn[p) \paV[oMnVrʇܛq.rq'&܁q Tq@u%D!tχIFtP y'|ɞ{)ǯ^z9g{wuG/\`qM rR^${5觬xiw^:y!xx׆ wG^NrLJ>rrgmQ[q9ć\rr lqm&ۉmf䛗m6ʛn1nuG[p!#pin pfq!'"zrMg+s5sɷs}w7z]wui]tΗ"po' ,pq \tdvmWjwixv[u7W&sY$[mY 8qö[mI[nݺvmfOlY\m6QmVcm6՛em6}n oY[nٺᛃn[o)oapQfoŻ\@qƗp9cp`qg;p&n}ۮo [o9[pgtҧQIt'[]Cu!H r5iqݛ#kѪlvlvkYZluě(kƹ[WlV-lM/ljٹf۱o5enVljijElfaF|ىeZl)vja!Hadϖ;haSaM*@N4;3N9#] 1t3.i0\K-D C(2Ƌ3dtRd5&01eI;hfZijͫvjni֖Chfjqjͦښk5rcO5Y:trT3Ƀ.h2 O0RK)+2%2+c Ā!H2*"|#H")$LPIx'DR +سs.#& 9 %PYRT6QFIL$4mG5rxEbI)RH)RcHIt7=<3oCDHC $бD)#4RtIa(d/=<\s5ӃM,)ȥ";(r r*+b .'a f%HK $:#h." 2H _!1H$g (J,2/2 ;Xr 4s̎F>CTVa[eKRF;R9C4GmCF4c;Le/2LZ5.9䓗r8ճl7CO-4P=2Pd1c,l«ʍ$E#2=$<M ?$ؑ:"08 tAG{a釚D6DEB}E#`E:EQEks#ESXE8EE@EE=EkE7hFҀF8FF@F$F/F;:FFFR4F] Fi*FtX8F&@F@FFF9FFFFFFPFpFFFF)FݦFF0FA,FtFDFe&FUTFEF4\F#@FFE9PEƏ`EvhE1EinE<"ZEC>DXD5D_dDCbC" BXX@k;O4>^7ie8eJt9 97H:p::;50K;Ҙ;*0<>>4Q8>N[L>jф>R>*>>r>d>߲0>5Z?fM? ,b?}? f*?)?2?;s?C ?KV?R?Y?`!?e?j,?oft?sE%?v?y5?{s?}9!?~*?d? C @ 4Tf5)Mg:f[2̎d&-1)6aS%/yy˺]2%,dKWeQ*IPJrSR%)G>R2))yMJrTDee+y^YԖ칥/ɄLRd3.Ҧ6r=OTe7B Ц.u [BP(?iOz̞'S9"otl'o;)ζuT'K:9rsS')99N>q&5d {*IFIKI$9!9*ARdQ#I!JL2r eA*]KY֖.vK]򗴾0ٌLgT|c=iКT}M4R ՂU%l\W~ﯽ,` Z–-}\:U⩵m/)F R~ߦ' F-Q':ip34)9NFpoΦ7/pKU$$YȆAz#Gb;qߏ$zZD44$(KʶXؗl1y~cæ0i"a,&6=-4CW*2VMMt۷:Wž!xn/1,Ja7λ}-9c:UbVZ+i FZ)Q"@ (>MeT$'I~OԵ/vˆYҸ d&0IJH4$ 8@ I#!jOe0Ra2t/̾jSs'm;O&zse(LjUV -xa1˦gcfw3n~_=FjTsSwʖ4~\~+uXZT4'2gJMRXԙ)IWK"\&5̆^r%8>-OLqE2nHL;&u3{D%.Ip˾a34B06Զ5:*KWY)0KLS/ǽMnGn[cNi pˆ|n|jHV͈ 6%[:jt=df]1̆ged'{;*n3dd7:YMcc[D'qQeyG?Q|l9HFCt'-=)|slfg1IK_sLh]MغVl`;fo3mm|69nt;:mo>4OPu^:n׾t789VF gsVx'@jvڞS9yMZg;/9ɼLV7U"#E2Q4d&Y0IZI6HLr6MmSD,nLeSQeNZW.mk^vrt#=g7x<9)͎= Dz/?|nr۔ S&pssVVl ]|lqf;$Wβ5@/hZ2薌d%4J6V2L[hF92 e1̖_dS$H˦eH&wپw2FXu%}\c%9KRr;|W{_|e;u7'h5Υs']Զu2e|%_6VuoCxv eVQ<{INAR&o6M`|.ɺO圌-9aYۗ|e%Fv5&_3ɖXrv# I.˺o&:[XʞRDk#Jycu5>6s]O\zծr\(8%7vޏ 9U;ڎso|fųuܚo|vĴEjHiT6ٸq3n,Φ>CSte'>*_r'y8IBr=gQ<9ΦoA$d!H~NrT/Pⵗ2pq(FͶU^r+{'|m&xg>8qݧٿz^w޻s|{曲G+ݦw[]ߚyO~K vY{1?)zܞW'ۮFu2LM`w8{P2ܞd,ٍ%`r4׬kYvRkZY*նX=?WTcmuaT4H?PN5S*]DzHJBҒc1O}o-geoϾ4m{mO~<~}~W=jx;ߏy3ɞCw+~.pq7|bx[3);9ul_VjUzݪml Fپzݡ-kk0Z^7 N+[f3X\n[vV%ADJQ5kT*M^5q"r[q3yFzib[F:>wwǬ|篡wݾYw.O\ֶt7}tlXnnq3M|e!Nqsl"fk7nMuۮvxMioF[7q -9v|X~mW-Yzmr֗kL [l`y̠M'4IyM΋/KLWc &wrc5ڈ&6m'wz/R ~˼|'6Mw#Ƕ8ىeS$N@g[)9qˍLk# -/y_ v o~_斷ml;^ź.7~6ȶtqKVں6.'\Վ mb~tsd7R|8-{,ifGAj6C ͎hṙb-ʶ/Λt?u1ƥL?m.qk]x(17*yǞ3 `~VQn8RŖm-r[ުw z"Ӗ5i:v5ӮMeWl-XRx}f9)vƧݒ,n\b vnhka3WQIjXX~1gP{tEY,Yf9},g{@R̖.g+gڶ6CkqYjް Bh_5`I@xp#,rƶ),^hm~Td W#`9 0rJ#I#J&OR؜UQ;IXҷ dq([L~jQiI`TR\NSjZ嗀4j`TL&.y:Y% kaӪ5%eYM:mTʩ4Lj\knUֳdX"_ )fu-9~ʪL?GW]))u3]7E8/8{#h %.whGj9l&],I)KWd_c y-J]3 '9bPjҎsPT#GB`DiVL~tu@RvO )Tjڬ5UIc&XrT 3yMfr[K( [;Yծoۏۮg Y{zZ16m~-ѩܛ&7J"Kqɍt])!=~UtY0 dNMKBOh蚵(?iΖgr? f5(2-R&A: >Z/8O% R0ޠz+WUbg >:P*{s@t#8B" IS^^1/A|+F n"Q?$I"HDN(nLl/x=q$ 'RʒOid[4jI6Fcle#-r*1,&#-yTM#$+yKIAӍe,VȲ8r*ē!y(&FRۦ;L2c(CJ*Sv_MY*UꑴI':پ~h$I.ɦA_:W@Q}cQȎFE6j#gG>=L!HEd-uJXח &4XOR[%S.NrW4%& HF2 d#iHAQte7,Y`Nxĥ_.9\֙U69aRG`TʲmByOJT\ m@Nnet#7GJFQ卌C)BF"R26I 9HOy.rJP2,6n3#,-4t*Q2{'yLjT2JLd%0b8ѽ$g%):ILWU0ɉK]|hCPF4&;Lfse)S:6Ep_RkT`G:Ϊkse%9)9\JWÔ~! yĶ&q8lf%Dr=ŏԓU!I,J[S.l&_3irnUA2v-f4iXҖdeG)iPIEԒ*WZ/Tlw$K%IMnXĕ16ٽdAVʮVάCiIy*t bev&-kR kM-)SH:ͺks4&'/IN*RRTq HEb( ,gc$&dž3qŏ)ym˂ZԘͦ9&YjmN]>d駧=2fSte'Ce* F*Qw ?!9K~aRg/;9OsUVc0[Wl U*nSM-Un]r&'.uZגᨕ'@M~_r]ܥ(NLVȉFW"hFJ1䒤*W>URۙ;5`P:bZ< Mni31e%xG5D%{%hG5,$(O̦inhUA.P4_m[kxǖnjKJvv'y^xNVNh"f%$8H1dI D9 Q؋%2DNĢ$m d!H@Ol&7yQu;)MFBF3흌f39zKb<$"XD/t&9I?qL&7N:kE$iQGj7Rjeou !92PqY{K~Zm5|&O-&Lpnm_m#)MJv774e"`!ɋE!E)#A xö"Ql,^ FN/QӐdd/ɨRx'uA:!ue'7ʺa3=/q|d*^TrgI:YFnS -Mz]bh}zl2\Ķ۾q+^' 7V\^7(fH Qv šPvU 8Ŗ"QQPm?|n?!HFv?Vy'TJNQ2feIHH~Q,D([ %7j}3|&M0M:bD[K*VY~wȞ7僻~ڗ%ž.%w;]&wJUSY"ΕjE$اF&/p{Hps#"i6221W!?ozĝwI)nz 8YB1:t]#5 GrFr3DU(GZG,egþ%Dy1yOyTfU+9BKT|)^"Y6v-gwk'92K^VSzޒӷejKwTί-8`As觯j q|c&~KO㌜L 5@|ݮg:YҎvs_nċ Xc;A2#SHF4ɥ!hC&؊h$-iS;d%?&LJJIZ}`[VL -Is`>v^UVMxKar6Hqc;J8$U8*yݢ0=Dv&YLT1Q"{{& ~#fC:}Ҏt̞𗄾~Ɗl\6?ۍgc =JFKԤdCn&Qdk#SKWd YKWRZ,(Yj:•F݊mv ^5zkYۦEk_:Ӷ E+)q\:f- N{3_B?F#%"Yp>1YEL _8B9̎@qKt}0DP#HD1Ǝ]"YJPҳ$cCZ+2$/ X3D4M6_򔎤MeUΦ4wukga̷/9W⩴/ucl|< Zt$)<h'E叒tG>*zbM97Qa7bgHG3QFD0Gc9xr'===bIWr6Ab{ GTȒl#%Xb"1͓ԣ$#hE2r<ܑ$5YP]L&q5Rta%AkM[YJ϶,m+ ɟm-fKUvu$DbghH6+2g,?YΟT^H>uN3*a INj< b &i9FOÞU(AnTo+5HZI򌓟Dfu<NZ|\hIπv+T>߈ ^@8nwSهL?I$pö V¢$1 ئD^:$ܕ"A؍bƍ܇d)HHH ! YDqt5ؔPsd,PZd?f*G{a^? EB i |L&h,a#50 -gKw:8=tcg;|ۯTf8Inq^ <Ѭh6ARPTE K8~F&3rsbhtò0ɋjw XVD63v1%v)͈-qgCOrdڥ8$rI#=9˪bҴ,!IEH/q1T5%OAwkg91+W".~L\c@Y1ݗmLn+\&:uܮqq&c7-hcG 7ř,g w> H6Dv&QdB͍T} {`U=0'v7r%T#؀Â1)v\r$_x@A:ܢfd]:u [چ6 Rz+Z:\RX[eK. Nqm,i;F79+\k޲IkjkWk;Ox7A,J!أC6 pvlqa:rNx%"=QD4% xNqF,y" hkE5$L'$<2|Cĕ0ݎiEƖFnQՊe%BOrS4&-)T³Uŗ}] 19vJIV+ bP/kKecC7.n\W =P,'"IHvM0gV8ſn*v#TG9z^ǵ=>t : {FZscn%/vk^ڲE~,mTiMڌTj( -D1Q@D'cCz.XTMLjRO'G Q^,dO]$6z5ݫMe!: P4 BA}{C7MNt \z捷/yۤ6ۼNeoC\7z<nrۚF7@9Nrk`YfֻQގDl+>1OTr~ӰĿ]0iJi %H{@xc{4ا5n~D YCy3"IMBTȧ5.OYJޗ&̀^*B6x[H@-u8m ohԖ4Mj(B%b+ũc/Znؖ2͟Ml(׀N5cVbˤY$Hj-ZFBDR gX7 ldBs*ak.o#8vdÄ5(NHb[lA:S곖v5Y+QU2V6-mVp]dw9kIVlb H.r]V .~\VD1ɀ}Y٘6P1L^`ksV:dQ9bvAœԥ*[RHO#1[쿦 0vZS4GB*.'2i3K}Ԯi9I*oMwZ=qc-6 a:&/wknXuN6j]W45'(AOTBu-EjTR/oNiS؟%%LC3LEx,n 4fKlǚ=k.l"QF r  LtȣF*qRK^܇A3$ hF>.9&}DLSJ¦=:1Tz./u~KYRc(:N"ZRL$)OJoHjaSZD(N*fQrԔ%D)CXDr >\(B kC<$e&GJV8&5LYȘ4hT>2z(HLGF (D`32D"4Q#AiyC m2<P}vFBQ$PcP}֤mD |6 X`pP H \0EH@`- ip>;@q8 op`1 Z@+X X-` Sx@ `7`@P!< f & @> `@0@ H P ` @ `( x&` hJ/ hp`<@~  A0"D(@`# HH&4 Nx@ )H `S(< M7777rb-grib-0.4.0/data/regular_latlon_surface.grib10000644000175000017500000000211412772262773021271 0ustar uwabamiuwabamiGRIBL4b 0001 `u0 Cx""% B1+!$&&q$Z"! /|7 [''(((''g%O'!mQ,'())'*=+b+-# ,k,c,**+s)042.%mXl3!0++$/.L!.;/p'*$6,9_:98$3@ (2.1;+u%+$,vAx682+w++$;*(33.03W{[]Cc0|G=5<_6<=563) BCB B BA?!2B6Ap98&E LHGKHDGE3OF4*uO0 @#rV$$5+q 0T> z $ Nm ]  N M 'v ,+'D X5zNW}W z,?d/" $zMIZ   ^z~}shZ#0d,*:arp ."gBX1)G]A%39P@%" 98 ~_ `7777GRIBL4b   0001 `u0,\GcF6d0r5 if iZp yh]l(!V4 f7_ ,2$PK1v-g /63w r$$J-!3Q KD-()q,{  BtUA?OLbA7/" (={ ;3rVWWHpTd/#,2kc*;fsd'"U)& #B"(%SW\C@X j]Z  DF3j   5$f!f~qU?%-b!- Pg--:GyaI{O=@@BB<,i~51fRBD4X=AU&6#<#0i "wh6Nr%O7777GRIBL4b  $ 0001 `u0#k2KG[Ti5# . (0ajA3QP33,$Tz iaC}EYsG :x U tCN wu''OwCCyL@9ځ D @TI7FP^\'@9*( 52y k5:%cd7777GRIBL4b  0 0001 `u0"Jp$)c 4 *e5*\ ? +%_&9w  ZW^] ,D  n ( . p X2 2;+%{ 2CmjJ+  {p ^* cR6jNO&K$ |-$NcrmPCH zG 4*p[<qn>*  BMA[gp$px? 1#5= [/ =D Y<* (.L]  I(%]v/  . W n4<W"RL#O}"5M j G"|aF;T*!T 0 %gD*iY/# 7777rb-grib-0.4.0/data/regular_gaussian_pressure_level.grib20000644000175000017500000003230412772262773023226 0ustar uwabamiuwabamiGRIB4b 0001H (@<0<J?*T "d Cjʀ 4F|3ឌf2`61 ]En*M 4Os8$ Fb-@DF"|C L"FB6Џ$q& @JZ&9O0)ALtTBPb+A\ W诅z+]V³xL*N \RB@'=O"yПE(QEDS"X~,j ]b†&1 f#6,)dK:Z.IplZ2ĕ&(BoKŬ+RPPzxD$!DP@P:!uC@@z$*|LmD'= O)K hS E.(B Mb]xDh"PA}Cц8D!! dC)ȓ(X H^Ɔ*0yhWX%*DIJ> @3 PXB`BW1 e v6+iz kS}38ѽj=p>E 4QԎn#CRP0 EA)tv*3ArÀ@8.N @@ gCt(dxGf8 Tp)jDisx(7Ѭ ^Dp*J PT¸$ 1A ;aPDBC%2Q`&:AO=AwC˟AaSU E'8ɔKzVҮԲ%),H6j44 '^6ѕKWr"!t6 I (OB>pQh4~ QB3(sT9 ic/h8$0$ 0At@ц6 hNB `: @b2|H#.V7A opm=)Px)>JS"5[+ TXOfԖt&%.i9Gz,4Y"J?r#lм6#F(!D"(pĆ&[tqC G^5a ]#G 6[Bņp4 a0%)GB@@PX9PӇP?"#F?BZF6 p&C2էG*[VjUŕ+NIFP0DLYB xH':_"؃Ed#)l ~4AdL xj,164Mdž ~\8hw#ʝFf.YQ ~Ba hdÿ%Q] pURA_»@F>2*&Q/ A1S ;Y2l0IxOrZؚ$$G<(u#V^#AdCx.X"L c,+A|d<'Y|N~'HTR'E cT֢b]/$HjC芤PG4|JVB|E,#GP:qŇ1 &]K\bƔ@GP;Aˍh#Ah&>Qpĺ!`<+-.4 s(\ pDz/Q؆!)E(p.IL^̘D()EUWr!=>NpS*}"Adɥ- ZJjNC|զ8k%A4ECixR]C*L[c801pSbm H2 @D!NYB͖l,`*WzŖ5 j*U2Tt&';+hF=MnC:(f803GIA1Q}Cͦ?2 N] Iȣ?Qt&?M:bF'!7iNZA4QPd΢D4e˜lƦ5ѕ}#QHLKGP$5)U Q_S%ZZVpү| YjԸ'&:at;Nq<(hAaM9f<mf/0z_h6@zѪ%;1Td*UjVjŅ, [T—SިX=\Rה‹̲%b%Ɯ3A; ͎bocTI eʣGufkb"լ]K#^ 0w]\zղe 3D PbD ьhKZU5-uLf4Y4 .n˟`kæ15^bU|!6ɽM2a@J" ?qp'Qy}G 7ƚ#) HeI”V>.郬iC>YP631,f :1\_ɔel+j+mUf;y (@`ި3 H1XzL&5aNzs(?4;HHRIƦֶ1;OJwDY@*rTڦ֌1*as %鯭Sd Xq6jU^w) dpµQ\"ժ&7jd3ܨۗ9i׮rÔ\' u̚c$Fql\ }4Ŷs[4֦qMkCRtϷ kGYu.iak_`ٔ67Mo'}k^q1 fOeaC^KYZZuLc֩-nn~z77Mo z~ƯdC Em=aڴUd'Af &gN:r{zƳaLf[9YڸQMmqDه5t x6%_lh|}>Y mNpv_1eJbk+p"8ۯ~\_/cOrTex/}L~h3Gb6r4Qmcj#Kڨvӧ48nCq\6]-$gc ؒe0Y]bOdzLgO}#h-o}bG>aO{_X>MoU{ (IJRJ= vIrt&O1BGb:RD4RG>1O_:P-u E?,`&A~ P, 1H:A+"Ogھ5f{ ǽO|>o|Xψ{`ӾO~~ߚ>O~S8YE3H51Dd$iQAR_=G$?<.!q HOv?l .@)`@Z P`(T%?1/}߆ȿ|;8Ƿ=in{^=l} :?>|ߞ79O~`Y<h 0 U8t: qu{ߞזjzl<Qz#Ξþ/} п}ψ{#Ҟh/`#g?`1j03 Mx?E,*! HFoՀ\ q)Pi  ApɅ|/! dCr0`@lA8 @b .!9 8DA OlW@M~\?1|^=o{׽>MOߞG>ycng=ϴ9 Ol@F)HD1 am Hx> ~H p}V@DkxKŽ𘃤'MA*74_h8AZ0t$[@ p#ac o~_X;ap{؞Ǥ=}}x?)bz;^lg)/ˀ`S@S_>~wC=O$(A /A |?uϝ}?3AwG hBb pD5a' HbBZ߆d)! Gp}"?P4 3*>aVz^p `@~r? |_:WC7H=O, ?ނ  (AІ`yHEApȂ q8,Ž0ĉU"? HXzɆd-@ 0A)@~B7o2y{^y1Nw79O_G޾ ?M|g>)z^GB>х!M@o _>ώ|=Owwk]7VАt6"q0y`i@u/~ @R3JGb p6oH;RĊ" TCvДd'`:A2Ok Gh!Ao~GMo}3_=oHzNGu{] gPI} ?C_>ϫ{ʞ񧖼uu{T79rHPDkHfCb È 5@i0 {>{>bCHFWS Ǥh4A> L qY ?A*O~ss{^ǢYAz^Z7{< vGI:eN}sM7}@>m|{X7;=ntӯ@rbm{ކwpծt;NRSF]?P_>7?Yop{#\~W;1ܯy;џ@#>qzk^Lg<-w^0W;v 29ɏ s?m/ yty O}zvqàD7*bd >o|=eO*xpOv]Uaܯ w1O&>@~3g491.v{]O~כCyk7^).sæ]ruæ0%95ďHG%9x񧉻{^t] >ܲetbG>ky#Z;u]TB:؎uí7=9a͎xlǃ͹pW[|]l' %Ɏ1t3܂߾}|C^f'P9Nw㵝wL14r\P.t덜 g8E ;rsR;-wCҟG<1ٮsÜ9zS'A.tW89iaqKw*r \'8au06-lcXZ巋/y]ZF81 q?HyƝVg/7p˛ G6!-p [9s}[6)n~߰w; ˍmo[9nt發AՎr܄vescu]t\.nncrFݶ5ͪp <6-lkcZ׶qmqmk?-:xSP㷥 TlcvFNtێF뵵1jSdp8% nۆ8ENrCyFٹR|^'M-jUצ q Tb}Vn3XzÖ 1! l t"GiscV-n#bZ6koFYe;"eLecZv߸.tܢ7E,iKVѷ-kkSZdՆ3g9ɶIZjS*Жqq}ZҶ3}c0ƣ%rkNZ4ѶM&kk[f5Ma "i+t^f4e Lj+RZƣɓfSBZѦ^u,!dM0˖@\BՖr.y] 8f pk 7Me;Z64 g3&FG1,ec8Φ c,Φ-nCmӦ2٩$|+Fe81LxfHv49pW̧HXXbX~laY:.]s\~20~ _s.l+Vr¯ko[v`vmdZV4=`T2a FbnۮvkbXxMy!`pMXjKٞ&k2͇n+_ھҖ~4Qle  .r˝^4*/q>RT&(JeTZr,aj\.1^k&YR͖eүayk[",T*rSpuf:Yb f6d61QK]J~0} [z-j+_SX80}~]W$1vbz.{,aS آ_zꖜu,mZ*Yb¥ \OoSZ( C(RBU6J*WShE-*1SVŖrSWp,u?O…zF*X*VU°ն/)~k_؈a+\De!^W2pq\Yߗ%sQX2>k ,W²\E},-`YVµ%-ulSYCEX عմ+uN*8Me4'5:PB%7YEIO |T(J*pU2EU+aVZڣ'=PPWU^Ej,rk\Ve-p+]򗞺u,ZWj5(K Tʷ.anK.W]*eOjpSX~,5_W⿕֭s+_ VRUE!GXzǖfAC)L\Ɨ&7O"}Si:NpS㧁AETB|E8T*S禡3iOڑ5/yMsS*2MQ[D[ȭkKXZ%![T T&7Oj-=fUҢM*=O wTz쥥8*YJVZ KU2Td?jUڴUED(:)K\֖Խ&1 LhSXϦ}5Mm(GVS(u@IMjd'u? QTNjTN)KVr:ubWھ歕V1O*XPx'i;INqS57qU TԾEAuTjTʣTE+)N*]QS')<Pڄ&6iO xSq/)rJ Q0IK\d&1)Ld:tMGRR*$'-5Mtƞ$A Mhn&7IOrwӾu5*iR nSTu)(Ej#QJTGJ*P2ydE9iNs'C*DĦ6ɦLrex&3LWm6iO rJ% &1IT晤'y0u˥,T8P/QLjep&6;n{4 h3>φ4Mllqg 8iMoo0F4Mg;fU2!L6`2He,cKX01i3a::w 2 i1 -< )› q)XJe*Я˥0t+ 5tLM3~9cQ*2 J&H% zzuZyA!2:&Т2-OI$ M/\M,P3`s:#:D1PY=4ڒiu6gV]hUlWIU= M*ԑK4QDO;,6 k/0)4 كn8CΨ7c! :0C̭5C5Cd͑7RLS*Ӎf9gM40PĒ08܊+1RgudPDMH }/3T9 c(5PM}3L@Ø:7lcG1t#(N/=4 /8tW@dPC9dR?% ^ B $RZJ6.B). 5S*ࣝ=%i'jmpɷ#tfyQF6p;q1ǧjMvu;eUWZuN;%PNŃTSDSP'`P G5c

2QI41&M!)$G똌c]Ig ?S$FП<\vxgYt0 #OL6Ռ3ID :ȢM2c+M5H8Ȕ&JDdVWyN3l.cu=էxyg{Iy}jZuYȗ۸kVNg&mc鉶\bPC"UHL87GmQIO}Vj?DTnT1|f'{T6f$ZoYFl}Y&c U>MmhA\OdT*A2 CC$A|;ړlT9AZ(!PRoEرd[{sWB]yɟ|]|%^{˞2t7ofXI]ц\dq}rD[}bV(VYKL cOI37K0LA SD8vӤSQtVzYP Pfn5fonmۖoaNr='%tʦHXb^[fNITc7Rv :)ȵB&8CŐN1_5j휔qGJ(`,~'Qٟ@~v ^xWMq&؏Wha5WQOeCUXQ]Չ=D zA[eҺK5$'-D>48-QiU%SMї֎lsrΗBLtQЗL(v%ww]t5շyY^1wFd%MD搑2Rj9t{O%A,ԑVvRo7/x)w{jG _ۃ~Mr$]wV[cfca#W:UH.Jm:laו.F(NR! Gv~ ~i8zUqiYqY_lՁT=%>8Di q8%J+G{U+?QfZ]ZZ\jJnq\or]y9w|ܟS~ *{gsaY)a&UL)/WrUղ\f.Hd=&@lxqn`(~<ɋ.⃈F b >8%&{'xmUjv9dC/#Sgd.ce4H.dc_@Fܜ&vU8g MuH4\Z\7cOr=v+tߑ2 ℇ~""/bNrGy14N<䃔K ғPYE䟐;bӉhaaMjq+Y=dѷ' ޭrXi &Re9ieUZeaB#1#]rK?dNYS%ag\u%ԏ&2#쑦I)T!*NLwJEޞtot^Ee6 kGr1zibc3H⸊. cR9_i则`ʗXketRYbeCN@r&8m t1cNf=fh}4\_.rU[ȒnJ9VIcvU9z6XiLe}FQ%A%3RD(eEbI>:䎍XQ]"-eA[9fY_Tx_'㗏OI|jay~<[yj%әi8nY&c&JYe|Ld@F8؊^, ]ݪ}* Oe֟Ieqɜhi惙ZcɉeZ]XsZ~Xv祠[%Zz9Xd2HX"ꏦ5='C >>x*?x#1R@Bf=XK&JVcQߏ{H: 2Ky;hqI'w)%pʧ@Jzܧs nҚaWICdđnBc.H#~&]~8gĝr}y'rb}9fϛm){hfR`ىܖU0h*v&:tdeZo:e]JK9/e(P LPI'e`j#ڜv'葡8$NjYŜڏj0(vbߠh7~ Ryy[Rp &ם2pfQ[fS^K < ^L9KMjAIgp nd ~Yfbiæmif͚j9ȖZٌTjx(ȩʌ 8h&j^#fi*ۮ:%iF+e6Xr&Z`i)ogΠ<讞excܒbI%~9h]N@:;ţZ衢Z(^{gߞvsi暚p&bhi&U9E$ƒPfUg洅5ٓfeh|CFpg~vg2qi濘dwk)ȨJ;ij(]:ifzh+c:M(ȒH&i&۪:jh[~[i{ޗȜZ(2#ev9iv:E)ގ 6֢R*)(Q 'ŞtfJpI̦ÛivhI挙r9vfڝ҂ H7(ꊪ'|'Zzgug:l'f{z@+jjꩳ"j/Zl7[r*M)'xygZ{_j (䣂uާji'J6Lh:hajT= !h:|'Ebuܧr'7n &s})SR:f9CZ L_}I'Vw'7?0-*FƬK;-kj{*ʎ$Rz磡Z!{ڔThꦺsj*IґOi(2h6 {飥zTnSi j::(ߣ#(6Z|A}tۧt焝s窟2z([&~Y*hނIV%te:h*I'Ȟ| 縠^J\*˻C-,b[mf{$ :nƁl ʯ)'^y(!|j2^*pꗤ"JȤjM)NdZ9i~Wi7b:^ejZ:`ʍ5'V6y'Ýu窞z'2heh ʊ43098^XɆcJh/!(`:h|ҏ)cjĥj)㫀^ jj9hnz#(~XŤR%Dr)~z%认Ru>ijR(Ҥ2iZLib覡ʌJ/(ؠ bzg{)g~yѦ:rgft 玞6'r19ϙJQJxJhs7(ގ3͢~:6ݦ&)":w)ϦΓçy٨ߡNmܟ*hwj.,2o)ΌJ)o2#b7gӝszʊ((N:n"Z:hNZ;Z'㠲ݞ}i_wާH{\vIjg'h}' g[SbiemJ(ԥҔKhD&.HΓcĦJ`)ZJdiԦڥ*.*{+e 'ނ*iʓW6"ʂj.:lhvs袒j9IQ&ȢN:(ѤJu)JTQ+-: hFIgWZuܧHtYFr¦ԚFpg4ogdjyg&:(8sNz'r9'trl)JꖪF{ hcjS)?>;(MV6NۣfRZx(nS Wi%:)MRnѦbF+nJ^)bZ6((6~?izf銤@趣Nj>֡ZJ瘞~ Ş2y'wᧁ>w灞y~I縍zgwoۧtJ)E)hң;ڣ>3&+hhj5)*xʀۣڑ+{n(ʇh6J(h짦Q~ç^zNעjP) %Zi)TwWCjS> drh& hg})'|x^Z()"gqt 6oimti珗&Ĝ~oog(ʥ>z;hJ(oچZ(nƁ(S^gwZ؛RmݧN*+wRY襣6FJ ԤFE)3Vc:(ͤc6J~麦*+ƅ2H⑊6*8h}::hI~d*tY&њg擙oiԧ;if:u&"{(?uA)LƉ:6 g埆(%w'=YIU波Zw ) ^INjV)ۡjzJ;áچIhށhdڌZ>(n6軦E)Ү h~) J*Qɟ+h:i: h,}i((`چ9gq)&Ze`hi&hh6'myfe)l*(~I'*vigcZh&_)ʦןJx[Cꥪca:rq*-6-jhZ(@}i翟;i>p>GirP(Vg&ƚ:)/j/(à~gmw&śk&xlf6k*VʳkqmJ'tog[|1(WƇ*+3Z'ꠎyyr爝vv¦2a&qfkIf?fs>mҧ}9u&xIV"(etgj&Lja[khҙ:(DCހ!grz ӧnfva}cɩ&N ڣ*gbjL(kL_Failh&(-^oygztɸ',vfꘚXُfʜRlI_cf82Xv#F)(3ru(~IthzΧ%Zjimb9f6iI-R*ɤ6j4ơyfygFnj&Wag弗^&no86eI' ߛdHm{)怖nU]\9oL2gܟꂉ'EdY焝Jr ƦJ>milO^og$vefQF\MFʞni甞jx']d9fϠ"ig=Rsffj^I].JU(ڠgםr|gy&fc&3`&J"^m%QT Pe Gg:K3䍌Fi[&n6歝u%O+$W97sr6zIs^]i~&qh &6c9zeYjel˦j`i1%fZOy*ߟJ^t!F^ك%ŗjɈf@x'\qԘaeV x&ߞN~9 nYfhf7WIKe`P]X JTigePA%,Zђ~C卾68Q8m<n*HI1$.SI6/j殙gyʕJYcFW)vX9N%nWIG.N]XQ,d$2F_&rgk%-HCe)MW&NR^9fZoɰ&ZWiG$A9JehَV`xf!ZcezWO䶐nC!d^I NL$>F -Z@ic" dMI,Q2dRYݖN#6&XcqA!dדL9-I9.M$J6"/8b=8j0hc+ăbs0HAHheUR$1.H#3:#}2#O0zb!(#F~>X棡?8#BI6%qNm4|NQIc$s"89#>8cR"-(bD$TKy)8N/~Eh!؈$hⷊr4H#"%H"C*"_#xbFnH] t HࠂdbZ9ۤK h!j ⮋5x"Ɗ's nᡄXka܊)x~A^2$E^Ac42($ۜJRi ƈ/H֣HZ e!Ņ>m!("Ō^$v{1Nza臥dz97(~ ,:+r68~3aS<`~7_A}5'ᨄJX"3#aj υ_!݉'Htᣇ& 6 `"0aYN(SaĈ"ȋbӋr+x"D. 䎋#"A2)ؓ(J% A=_jD`䁶wdSuQ[4tҧIvaᷓ^{]RuDy釫_}%_|_L|׭ޓ{|)͞{G_w8}Xa< h8+b8_a}']րX`X !V:U!.j a .jJ :րngٟ(|ׂywz}^7su̧&ܡrqgt)7Or!uЧW]wI߷~x)z]rw܇h]vqs]w^Wxg|g_nH' ((~7_My㧵z=GC|w怒O}5}執~7}EwK}YG_ {9wxmht3*umǎxK]o鿦oupaq%7[p \Qru6u\jtjuwW6sw?]tGi]v!7nvIGyvŸ%|ɟj}ܟ~z|7^z7 uN3uugI~G]xנިzLjz57^{=7Nw퇉 ya姄tIpm sק[@t',nuZn[p) \paV[oMnVrʇܛq.rq'&܁q Tq@u%D!tχIFtP y'|ɞ{)ǯ^z9g{wuG/\`qM rR^${5觬xiw^:y!xx׆ wG^NrLJ>rrgmQ[q9ć\rr lqm&ۉmf䛗m6ʛn1nuG[p!#pin pfq!'"zrMg+s5sɷs}w7z]wui]tΗ"po' ,pq \tdvmWjwixv[u7W&sY$[mY 8qö[mI[nݺvmfOlY\m6QmVcm6՛em6}n oY[nٺᛃn[o)oapQfoŻ\@qƗp9cp`qg;p&n}ۮo [o9[pgtҧQIt'[]Cu!H r5iqݛ#kѪlvlvkYZluě(kƹ[WlV-lM/ljٹf۱o5enVljijElfaF|ىeZl)vja!Hadϖ;haSaM*@N4;3N9#] 1t3.i0\K-D C(2Ƌ3dtRd5&01eI;hfZijͫvjni֖Chfjqjͦښk5rcO5Y:trT3Ƀ.h2 O0RK)+2%2+c Ā!H2*"|#H")$LPIx'DR +سs.#& 9 %PYRT6QFIL$4mG5rxEbI)RH)RcHIt7=<3oCDHC $бD)#4RtIa(d/=<\s5ӃM,)ȥ";(r r*+b .'a f%HK $:#h." 2H _!1H$g (J,2/2 ;Xr 4s̎F>CTVa[eKRF;R9C4GmCF4c;Le/2LZ5.9䓗r8ճl7CO-4P=2Pd1c,l«ʍ$E#2=$<M ?$ؑ:"08 tAG{a釚 #include #include "ruby.h" #include "grib_api.h" #include "narray.h" #ifndef NARRAY_BIGMEM typedef int na_shape_t; #endif #define MAX_VALUE_LENGTH 1024 #define CHECK_ERROR(func) raise_error(func, #func) // error check static void raise_error(int code, const char* func) { if (code) rb_raise(rb_eRuntimeError, "grib-api function failed:\n function: %s\n message: %s", func, grib_get_error_message(code)); }; // flexible length array #define BUF_SIZE 256 #define MAX_BUF_NUM 1000 typedef struct { grib_handle ***buffer; size_t size; size_t len; } msg_array; static msg_array* alloc_msg_array(void) { msg_array *ary = ALLOC(msg_array); if (ary) { ary->buffer = (grib_handle***) malloc(sizeof(grib_handle**)*MAX_BUF_NUM); if (ary->buffer) { ary->buffer[0] = (grib_handle**) malloc(sizeof(grib_handle*)*BUF_SIZE); if (ary->buffer[0]) { ary->size = BUF_SIZE; ary->len = 0; return ary; } free(ary->buffer); } free(ary); } return NULL; } static void free_msg_array(msg_array *ary) { int i, j; int num = ary->size/BUF_SIZE; int len; for (i=0; ilen%BUF_SIZE : BUF_SIZE; for (j=0; jbuffer[i][j]); free(ary->buffer[i]); } free(ary->buffer); free(ary); } static void push_msg(msg_array *ary, grib_handle *handle) { int idx = ary->size/BUF_SIZE-1; if (ary->len >= ary->size) { idx += 1; if (idx < MAX_BUF_NUM) { ary->buffer[idx] = (grib_handle**)malloc(sizeof(grib_handle*)*BUF_SIZE); if (ary->buffer[idx]) { ary->size += BUF_SIZE; } else { rb_raise(rb_eRuntimeError, "cannot allocate memory"); } } else { rb_raise(rb_eRuntimeError, "cannot allocate memory"); } } ary->buffer[idx][ary->len%BUF_SIZE] = handle; ary->len += 1; } static grib_handle* get_msg(msg_array *ary, size_t index) { if (index < ary->len) { return ary->buffer[index/BUF_SIZE][index%BUF_SIZE]; } else { rb_raise(rb_eRuntimeError, "index exceed size of array"); } return NULL; } // variable list typedef struct var_list var_list; struct var_list { char *vname; long ni; long nj; char *gtype; long ltype_id; char *ltype; msg_array *ary; var_list *next; VALUE file; long disc; long mtabl; long cent; long ltabl; long categ; long pnum; }; static var_list* var_list_alloc(VALUE file) { var_list *var = ALLOC(var_list); if (var) { var->ary = alloc_msg_array(); if (var->ary) { var->vname = (char*) malloc(sizeof(char)*MAX_VALUE_LENGTH*2); if (var->vname) { var->gtype = (char*) malloc(sizeof(char)*MAX_VALUE_LENGTH); if (var->gtype) { var->ltype = (char*) malloc(sizeof(char)*MAX_VALUE_LENGTH); if (var->ltype) { var->next = NULL; var->file = file; return var; } free(var->gtype); } free(var->vname); } free_msg_array(var->ary); } free(var); } return NULL; } static void var_list_free(var_list *var) { var_list *next; while(var) { free_msg_array(var->ary); free(var->vname); free(var->gtype); free(var->ltype); var->file = Qnil; next = var->next; free(var); var = next; } } static void push_msg_var(var_list **pvar, grib_handle *handle, VALUE file) { size_t len = MAX_VALUE_LENGTH; char vname[MAX_VALUE_LENGTH]; /* if (grib_get_string(handle, "shortName", vname, &len) != GRIB_SUCCESS || strcmp("unknown", vname) == 0) { long id; if (grib_get_long(handle, "indicatorOfParameter", &id) == GRIB_SUCCESS || grib_get_long(handle, "parameterNumber", &id) == GRIB_SUCCESS) { sprintf(vname, "id%ld", id); } else { printf("%s\n", vname); rb_raise(rb_eRuntimeError, "cannot get variable name"); } } */ long edition; long cent, mtabl, pnum; long disc, ltabl, categ; long ni, nj, ltype_id; char gtype[MAX_VALUE_LENGTH]; len = MAX_VALUE_LENGTH; grib_get_long(handle, "editionNumber", &edition); grib_get_long(handle, "centre", ¢); if(grib_get_long(handle, "Ni", &ni) != GRIB_SUCCESS || grib_get_long(handle, "Nj", &nj) != GRIB_SUCCESS || grib_get_string(handle, "typeOfGrid", gtype, &len) != GRIB_SUCCESS || (grib_get_long(handle, "indicatorOfTypeOfLevel", <ype_id) != GRIB_SUCCESS && grib_get_long(handle, "typeOfFirstFixedSurface", <ype_id) != GRIB_SUCCESS)) rb_raise(rb_eRuntimeError, "connot identify grid type"); switch (edition) { case 1: if(grib_get_long(handle, "table2Version", &mtabl) != GRIB_SUCCESS || grib_get_long(handle, "indicatorOfParameter", &pnum) != GRIB_SUCCESS) rb_raise(rb_eRuntimeError, "connot identify variable"); break; case 2: if (grib_get_long(handle, "tablesVersion", &mtabl) != GRIB_SUCCESS || grib_get_long(handle, "parameterNumber", &pnum) != GRIB_SUCCESS || grib_get_long(handle, "discipline", &disc) != GRIB_SUCCESS || grib_get_long(handle, "localTablesVersion", <abl) != GRIB_SUCCESS || grib_get_long(handle, "parameterCategory", &categ) != GRIB_SUCCESS) rb_raise(rb_eRuntimeError, "connot identify variable"); } var_list *last = NULL; var_list *var = pvar[0]; if (var) { while (var) { if (var->cent == cent && var->mtabl == mtabl && var->pnum == pnum && var->ni == ni && var->nj == nj && strcmp(var->gtype,gtype)==0 && var->ltype_id==ltype_id) { if (edition == 1) push_msg(var->ary, handle); else if (edition == 2 && var->disc == disc && var->ltabl == ltabl && var->categ == categ) push_msg(var->ary, handle); return; } last = var; var = var->next; } } var_list *var_new = var_list_alloc(file); if (var_new == NULL) rb_raise(rb_eRuntimeError, "cannot allocate memory"); var_new->cent = cent; var_new->mtabl = mtabl; var_new->pnum = pnum; if (edition == 2) { var_new->disc = disc; var_new->ltabl = ltabl; var_new->categ = categ; } var_new->ni = ni; var_new->nj = nj; var_new->ltype_id = ltype_id; strcpy(var_new->gtype, gtype); len = MAX_VALUE_LENGTH; bzero(vname, len); if (grib_get_string(handle, "shortName", vname, &len) != GRIB_SUCCESS || strcmp("unknown", vname) == 0) { sprintf(vname, "id%ld", pnum); } strcpy(var_new->vname, vname); len = MAX_VALUE_LENGTH; bzero(vname, len); CHECK_ERROR(grib_get_string(handle, "typeOfLevel", vname, &len)); if (strcmp(vname, "unknown")==0 || strcmp(vname,"isobaricInhPa")== 0 || strcmp(vname,"pl")==0) strcpy(var_new->ltype, vname); else { int i, j; var_new->ltype[0] = vname[0]; for (i=1,j=1; i=65 && vname[i]<=90) { var_new->ltype[j] = vname[i]+32; j++; } } if (j==1) strcpy(var_new->ltype, vname); else var_new->ltype[j] = 0; } push_msg(var_new->ary, handle); if (last) last->next = var_new; else pvar[0] = var_new; } VALUE cGrib; VALUE cVar; VALUE cMessage; typedef struct { FILE *file; char *fname; var_list *var; } rg_file; typedef struct { VALUE file; var_list *var_list; } rg_var; typedef struct { VALUE file; grib_handle *handle; } rg_message; static void message_free(rg_message *message) { if (message) free(message); } static void message_mark(rg_message *message) { if (message && message->file != Qnil) rb_gc_mark(message->file); } static VALUE message_alloc(VALUE klass) { rg_message *message = ALLOC(rg_message); message->file = Qnil; return Data_Wrap_Struct(klass, message_mark, message_free, message); } static void var_free(rg_var *var) { if (var) free(var); } static void var_mark(rg_var *var) { if (var && var->file != Qnil) rb_gc_mark(var->file); } static VALUE var_alloc(VALUE klass) { rg_var *var = ALLOC(rg_var); var->file = Qnil; return Data_Wrap_Struct(klass, var_mark, var_free, var); } static void file_close(rg_file *gfile) { if (gfile) { if (gfile->var) { var_list_free(gfile->var); gfile->var = NULL; } if (gfile->file) { fclose(gfile->file); gfile->file = NULL; } if (gfile->fname) { free(gfile->fname); gfile->fname = NULL; } } } static void file_free(rg_file *gfile) { if (gfile) { file_close(gfile); free(gfile); } } static VALUE file_alloc(VALUE klass) { rg_file *gfile = ALLOC(rg_file); gfile->file = NULL; gfile->fname = NULL; gfile->var = NULL; return Data_Wrap_Struct(klass, 0, file_free, gfile); } /* NumRu::Grib.multi=(flag) -> True/False */ static VALUE rg_multi(VALUE self, VALUE flag) { if (flag == Qtrue) grib_multi_support_on(0); else if (flag == Qfalse) grib_multi_support_off(0); else rb_raise(rb_eArgError, "flag must be true or false"); return flag; } /* NumRu::Grib#initialize(filename, [, mode]) */ static VALUE rg_file_initialize(int argc, VALUE *argv, VALUE self) { char *fname, *mode; VALUE rfname, rmode; rb_scan_args(argc, argv, "11", &rfname, &rmode); fname = StringValueCStr(rfname); if (rmode == Qnil) mode = "r"; else mode = StringValueCStr(rmode); FILE *file = fopen(fname, mode); if (!file) rb_raise(rb_eRuntimeError, "unable to open file %s", fname); rg_file *gfile; Data_Get_Struct(self, rg_file, gfile); gfile->file = file; gfile->fname = ALLOC_N(char, strlen(fname)+1); strcpy(gfile->fname, fname); int error; grib_handle *handle; var_list *var = NULL; while ((handle = grib_handle_new_from_file(0, file, &error))) { raise_error(error, "grib_handle_new_from_file(0, file, &error)"); if (handle == NULL) rb_raise(rb_eRuntimeError, "unable to create handle in %s", fname); push_msg_var(&var, handle, self); } gfile->var = var; var_list *var2; const char *vname; char buf[MAX_VALUE_LENGTH]; int first_ltype, first_gtype; int i; while (var) { vname = var->vname; var2 = var->next; i = 0; first_ltype = 1; first_gtype = 1; while (var2) { if (strcmp(var2->vname, vname) == 0) { if (var->ltype_id != var2->ltype_id) { if (first_ltype) { if (strcmp(var->ltype,"isobaricInhPa") != 0 && strcmp(var->ltype,"pl") !=0) { if (strcmp(var->ltype, "unknown")==0) sprintf(buf, "%s_level%ld", var->vname, var->ltype_id); else sprintf(buf, "%s_%s", var->vname, var->ltype); strcpy(var->vname, buf); } first_ltype = 0; } if (strcmp(var2->ltype,"isobaricInhPa") != 0 && strcmp(var2->ltype,"pl") != 0) { if (strcmp(var2->ltype, "unknown")==0) sprintf(buf, "%s_level%ld", var2->vname, var2->ltype_id); else sprintf(buf, "%s_%s", var2->vname, var2->ltype); strcpy(var2->vname, buf); } } else if (strcmp(var->gtype, var2->gtype) != 0) { if (first_gtype) { sprintf(buf, "%s_%s", var->vname, var->gtype); strcpy(var->vname, buf); first_gtype = 0; } sprintf(buf, "%s_%s", var2->vname, var2->gtype); strcpy(var2->vname, buf); } else { if (i==0) { sprintf(buf, "%s_%d", var->vname, i); strcpy(var->vname, buf); i += 1; } sprintf(buf, "%s_%d", var2->vname, i); strcpy(var2->vname, buf); i += 1; } } var2 = var2->next; } var = var->next; } return self; } /* NumRu::Grib#close() -> nil */ static VALUE rg_file_close(VALUE self) { rg_file *gfile; Data_Get_Struct(self, rg_file, gfile); file_close(gfile); return Qnil; } /* NumRu::Grib#path() -> String */ static VALUE rg_file_path(VALUE self) { rg_file *gfile; Data_Get_Struct(self, rg_file, gfile); return rb_str_new2(gfile->fname); } /* NumRu::Grib#var_names() -> Array */ static VALUE rg_file_var_names(VALUE self) { rg_file *gfile; Data_Get_Struct(self, rg_file, gfile); VALUE ary = rb_ary_new(); var_list *var = gfile->var; while (var) { rb_ary_push(ary, rb_str_new2(var->vname)); var = var->next; } return ary; } static VALUE id_init; /* NumRu::Grib#var(String) -> NumRu::GribVar */ static VALUE rg_file_var(VALUE self, VALUE rvname) { char *vname = StringValueCStr(rvname); rg_file *gfile; Data_Get_Struct(self, rg_file, gfile); var_list *var_list = gfile->var; while (var_list) { if (strcmp(var_list->vname, vname) == 0) { VALUE rvar = var_alloc(cVar); rg_var *var; Data_Get_Struct(rvar, rg_var, var); var->file = self; var->var_list = var_list; rb_funcall(rvar, id_init, 0); return rvar; } var_list = var_list->next; } rb_raise(rb_eArgError, "cannot find variable: %s", vname); } /* NumRu::GribVar#file() -> NumRu::Grib */ static VALUE rg_var_file(VALUE self) { rg_var *var; Data_Get_Struct(self, rg_var, var); return var->file; } /* NumRu::GribVar#name() -> String */ static VALUE rg_var_name(VALUE self) { rg_var *var; Data_Get_Struct(self, rg_var, var); return rb_str_new2(var->var_list->vname); } /* NumRu::GribVar#get_messages() -> Array */ static VALUE rg_var_get_messages(VALUE self) { rg_var *var; Data_Get_Struct(self, rg_var, var); var_list *var_list = var->var_list; size_t len = var_list->ary->len; VALUE ary = rb_ary_new2(len); rg_message *message; VALUE rmessage; int i; for (i=0; ifile = self; message->handle = get_msg(var_list->ary, i); rb_ary_store(ary, i, rmessage); } return ary; } /* NumRu::GribMessage#initialize() */ static VALUE rg_message_initialize(VALUE self, VALUE file) { rg_message *message; Data_Get_Struct(self, rg_message, message); message->file = file; return self; } /* NumRu::GribMessage#get_keys() -> Array */ static VALUE rg_message_get_keys(int argc, VALUE *argv, VALUE self) { VALUE rflag, rns; unsigned long flag = GRIB_KEYS_ITERATOR_SKIP_READ_ONLY || GRIB_KEYS_ITERATOR_SKIP_COMPUTED; // unsigned long flag = GRIB_KEYS_ITERATOR_ALL_KEYS; char *name_space = NULL; rb_scan_args(argc, argv, "02", &rflag, &rns); if (rflag != Qnil) flag = NUM2ULONG(rflag); if (rns != Qnil) name_space = StringValueCStr(rns); rg_message *message; Data_Get_Struct(self, rg_message, message); grib_keys_iterator *ki = NULL; ki = grib_keys_iterator_new(message->handle, flag, name_space); if (!ki) rb_raise(rb_eRuntimeError, "unable to create key iterator"); VALUE keys = rb_ary_new(); while (grib_keys_iterator_next(ki)) { const char *name = grib_keys_iterator_get_name(ki); rb_ary_push(keys, rb_str_new2(name)); } grib_keys_iterator_delete(ki); return keys; } /* NumRu::GribMessage#get_value(name [,type]) -> String */ static VALUE rg_message_get_value(int argc, VALUE *argv, VALUE self) { VALUE rname, rtype; rb_scan_args(argc, argv, "11", &rname, &rtype); char *name = StringValueCStr(rname); int type; rg_message *message; Data_Get_Struct(self, rg_message, message); if (rtype == Qnil) grib_get_native_type(message->handle, name, &type); else type = NUM2INT(rtype); size_t len; VALUE ret = Qnil; grib_get_size(message->handle, name, &len); switch (type) { case GRIB_TYPE_UNDEFINED: case GRIB_TYPE_STRING: case GRIB_TYPE_LABEL: { char value[MAX_VALUE_LENGTH]; len = MAX_VALUE_LENGTH; bzero(value, len); if (grib_get_string(message->handle, name, value, &len) == GRIB_SUCCESS) { if (value[len-1] == '\0') len--; ret = rb_str_new(value, len); } } break; case GRIB_TYPE_BYTES: { unsigned char value[MAX_VALUE_LENGTH]; len = MAX_VALUE_LENGTH; bzero(value, len); if (grib_get_bytes(message->handle, name, value, &len) == GRIB_SUCCESS) ret = rb_str_new((char*)value, len); } break; case GRIB_TYPE_LONG: { if (len == 1) { long l; if (rtype == Qnil) { char value[MAX_VALUE_LENGTH]; len = MAX_VALUE_LENGTH; bzero(value, len); if (grib_get_string(message->handle, name, value, &len) == GRIB_SUCCESS) { CHECK_ERROR(grib_get_long(message->handle, name, &l)); if (atol(value) == l) ret = LONG2NUM(l); else ret = rb_str_new2(value); } } else { CHECK_ERROR(grib_get_long(message->handle, name, &l)); ret = LONG2NUM(l); } } else { na_shape_t shape[1]; struct NARRAY *nary; shape[0] = len; VALUE rnary = na_make_object(NA_LINT, 1, shape, cNArray); GetNArray(rnary, nary); if (grib_get_long_array(message->handle, name, (long*)nary->ptr, &len) == GRIB_SUCCESS) ret = rnary; } } break; case GRIB_TYPE_DOUBLE: { if (len == 1) { double value; if (grib_get_double(message->handle, name, &value) == GRIB_SUCCESS) ret = rb_float_new(value); } else { na_shape_t shape[1]; struct NARRAY *nary; shape[0] = len; VALUE rnary = na_make_object(NA_DFLOAT, 1, shape, cNArray); GetNArray(rnary, nary); if (grib_get_double_array(message->handle, name, (double*)nary->ptr, &len) == GRIB_SUCCESS) ret = rnary; } } break; default: rb_raise(rb_eArgError, "type is invalid: %d", type); } return ret; } /* NumRu::GribMessage#get_data() -> [lon, lat, value] */ static VALUE rg_message_get_data(VALUE self) { rg_message *message; Data_Get_Struct(self, rg_message, message); int error; grib_iterator *iter = grib_iterator_new(message->handle, 0, &error); raise_error(error, "grib_iterator_new(message->handle, 0, &error);"); long np; CHECK_ERROR(grib_get_long(message->handle, "numberOfPoints", &np)); double *lon, *lat, *value; VALUE na_lon, na_lat, na_value; struct NARRAY *nary; na_shape_t shape[1]; shape[0] = np; na_lon = na_make_object(NA_DFLOAT, 1, shape, cNArray); GetNArray(na_lon, nary); lon = (double*) nary->ptr; na_lat = na_make_object(NA_DFLOAT, 1, shape, cNArray); GetNArray(na_lat, nary); lat = (double*) nary->ptr; na_value = na_make_object(NA_DFLOAT, 1, shape, cNArray); GetNArray(na_value, nary); value = (double*) nary->ptr; int n = 0; double lo, la, val; while( grib_iterator_next(iter, &la, &lo, &val) ) { lat[n] = la; lon[n] = lo; value[n] = val; n++; } grib_iterator_delete(iter); return rb_ary_new3(3, na_lon, na_lat, na_value); } void Init_grib() { // rb_require("narray"); id_init = rb_intern("init"); VALUE mNumRu = rb_define_module("NumRu"); cGrib = rb_define_class_under(mNumRu, "Grib", rb_cObject); cVar = rb_define_class_under(mNumRu, "GribVar", rb_cObject); cMessage = rb_define_class_under(mNumRu, "GribMessage", rb_cObject); grib_multi_support_on(0); //rb_define_singleton_method(cGrib, "open", rg_open, -1); rb_define_singleton_method(cGrib, "multi=", rg_multi, 1); rb_define_alloc_func(cGrib, file_alloc); rb_define_method(cGrib, "initialize", rg_file_initialize, -1); rb_define_method(cGrib, "close", rg_file_close, 0); rb_define_method(cGrib, "path", rg_file_path, 0); rb_define_method(cGrib, "var_names", rg_file_var_names, 0); rb_define_method(cGrib, "var", rg_file_var, 1); rb_define_alloc_func(cVar, var_alloc); rb_define_method(cVar, "file", rg_var_file, 0); rb_define_method(cVar, "name", rg_var_name, 0); rb_define_method(cVar, "get_messages", rg_var_get_messages, 0); rb_define_alloc_func(cMessage, message_alloc); rb_define_method(cMessage, "initialize", rg_message_initialize, 1); rb_define_method(cMessage, "get_keys", rg_message_get_keys, -1); rb_define_method(cMessage, "get_value", rg_message_get_value, -1); rb_define_method(cMessage, "get_data", rg_message_get_data, 0); rb_define_const(cGrib, "TYPE_UNDEFINED", INT2NUM(GRIB_TYPE_UNDEFINED)); rb_define_const(cGrib, "TYPE_LONG", INT2NUM(GRIB_TYPE_LONG)); rb_define_const(cGrib, "TYPE_DOUBLE", INT2NUM(GRIB_TYPE_DOUBLE)); rb_define_const(cGrib, "TYPE_STRING", INT2NUM(GRIB_TYPE_STRING)); rb_define_const(cGrib, "TYPE_BYTES", INT2NUM(GRIB_TYPE_BYTES)); rb_define_const(cGrib, "TYPE_SECTION", INT2NUM(GRIB_TYPE_SECTION)); rb_define_const(cGrib, "TYPE_LABEL", INT2NUM(GRIB_TYPE_LABEL)); rb_define_const(cGrib, "TYPE_MISSING", INT2NUM(GRIB_TYPE_MISSING)); rb_define_const(cGrib, "NEAREST_SAME_GRID", ULONG2NUM(GRIB_NEAREST_SAME_GRID)); rb_define_const(cGrib, "NEAREST_SAME_DATA", ULONG2NUM(GRIB_NEAREST_SAME_DATA)); rb_define_const(cGrib, "NEAREST_SAME_POINT", ULONG2NUM(GRIB_NEAREST_SAME_POINT)); rb_define_const(cGrib, "KEYS_ITERATOR_ALL_KEYS", ULONG2NUM(GRIB_KEYS_ITERATOR_ALL_KEYS)); rb_define_const(cGrib, "KEYS_ITERATOR_SKIP_READ_ONLY", ULONG2NUM(GRIB_KEYS_ITERATOR_SKIP_READ_ONLY)); #ifdef NARRAY_BIGMEM rb_define_const(cGrib, "SUPPORT_BIGMEM", Qtrue); #else rb_define_const(cGrib, "SUPPORT_BIGMEM", Qfalse); #endif } rb-grib-0.4.0/README.rdoc0000644000175000017500000000203112772262773014514 0ustar uwabamiuwabami= What's rb-GRIB rb-GRIB is a class library to handle GRIB file. = rb-GRIB home-page The URL of the rb-GRIB home-page is: http://ruby.gfd-dennou.org/products/rb-grib/ = Requires * Ruby (http://www.ruby-lang.org/) * NumRu-NArray (https://github.com/seiya/numru-narray) or NArray (https://masa16.github.io/narray/index.html) * NArrayMiss (http://ruby.gfd-dennou.org/products/narray_miss/) * GRIB API (http://www.ecmwf.int/products/data/software/grib_api.html) = Install # gem install rb-grib = Copying See the file LICENSE.txt. = Usage To use this library, put the following in your script. require 'numru/grib' = Example require 'numru/grib' include NumRu filename = "test.grib" grib = Grib.open(filename) varnames = grib.var_names # => Array varnames.each do |vname| var = grib.var(vname) # => GribVar dimnames = var.dim_names # => Array ary = var.get # => NArray end grib.close = The Author Feel free to send comments and bug reports to the author. The author's e-mail addess is seiya@gfd-dennou.org rb-grib-0.4.0/spec/0000755000175000017500000000000012772262773013644 5ustar uwabamiuwabamirb-grib-0.4.0/spec/spec_helper.rb0000644000175000017500000000044512772262773016465 0ustar uwabamiuwabami$LOAD_PATH.unshift File.expand_path(File.join('..','ext'), File.dirname(__FILE__)) $LOAD_PATH.unshift File.expand_path(File.join('..','lib'), File.dirname(__FILE__)) alias :_require :require def require(arg) arg = "grib.so" if arg == "numru/grib.so" _require(arg) end require "numru/grib" rb-grib-0.4.0/spec/grib_read_spec.rb0000644000175000017500000001443212772262773017125 0ustar uwabamiuwabamirequire File.expand_path(File.join('.','spec_helper'), File.dirname(__FILE__)) include NumRu dir = File.expand_path(File.join('..','data'), File.dirname(__FILE__)) GribData = { File.join(dir, 'regular_gaussian_surface.grib1') => {"2t"=>{:dims=>["lon","lat"], :shape=>[128,64], :val=>{[0,0]=>2.4552479553e2}} }, File.join(dir, 'regular_gaussian_surface.grib2') => {"2t"=>{:dims=>["lon","lat"], :shape=>[128,64], :val=>{[0,0]=>2.4552479553e2}} }, File.join(dir, 'regular_gaussian_model_level.grib1') => {"t"=>{:dims=>["lon","lat"], :shape=>[128,64], :val=>{[0,0]=>1.9907820129e2}} }, File.join(dir, 'regular_gaussian_model_level.grib2') => {"t"=>{:dims=>["lon","lat"], :shape=>[128,64], :val=>{[0,0]=>1.9907820129e2}} }, File.join(dir, 'regular_gaussian_pressure_level.grib1') => {"t"=>{:dims=>["lon","lat"], :shape=>[128,64], :val=>{[0,0]=>2.4746011353e2}} }, File.join(dir, 'regular_gaussian_pressure_level.grib2') => {"t"=>{:dims=>["lon","lat"], :shape=>[128,64], :val=>{[0,0]=>2.4746011353e2}} }, File.join(dir, 'regular_gaussian_pressure_level_constant.grib1') => {"t"=>{:dims=>["lon","lat"], :shape=>[128,64], :val=>{[0,0]=>1.0}} }, File.join(dir, 'regular_gaussian_pressure_level_constant.grib2') => {"t"=>{:dims=>["lon","lat"], :shape=>[128,64], :val=>{[0,0]=>1.0}} }, File.join(dir, 'regular_latlon_surface.grib1') => {"2t"=>{:dims=>["lon","lat"], :shape=>[16,31], :val=>{[0,0]=>279.0}} }, File.join(dir, 'regular_latlon_surface.grib2') => {"2t"=>{:dims=>["lon","lat"], :shape=>[16,31], :val=>{[0,0]=>279.0}} }, File.join(dir, 'regular_latlon_surface_constant.grib1') => {"2t"=>{:dims=>["lon","lat"], :shape=>[16,31], :val=>{[0,0]=>1.0}} }, File.join(dir, 'regular_latlon_surface_constant.grib2') => {"2t"=>{:dims=>["lon","lat"], :shape=>[16,31], :val=>{[0,0]=>1.0}} }, File.join(dir, 'tp_ecmwf.grib') => {"tp"=>{:dims=>["lon","lat","step"], :shape=>[16,31,4], :val=>{[0,0,0]=>2.0546913147e-3}} } } fname_not_exist = 'not_exist' describe NumRu::Grib do describe 'Grib.is_a_Grib?' do it 'returns whether the specific file is a GRIB1/2 file' do GribData.each do |fname, hash| expect(NumRu::Grib.is_a_Grib?(fname)).to eq true end end end describe 'Grib.open' do before { @files = [] } after { @files.each{|file| file.close} } it 'returns Grib object' do GribData.each do |fname, hash| file = NumRu::Grib.open(fname) expect(file).to be_instance_of(NumRu::Grib) @files.push file end end it 'raise exception when file name which does not exist is given' do expect { NumRu::Grib.open(fname_not_exist) }.to raise_error(RuntimeError) end end describe '#close' do before do @files = [] GribData.each{|fname,hash| @files.push NumRu::Grib.open(fname) } end it do @files.each do |file| expect {file.close}.not_to raise_error end end end describe 'instance methods' do before do @files = {} GribData.each{|fname,hash| @files[fname] = NumRu::Grib.open(fname) } end after do @files.each{|fname,file| file.close} end it '#path returns path' do @files.each do |fname,file| expect( file.path ).to eq fname end end it '#var_names returns Array of variable names' do @files.each do |fname, file| expect( file.var_names ).to eq GribData[fname].keys end end it '#var returns GribVar object' do @files.each do |fname, file| GribData[fname].each do |vname, hash| expect( file.var(vname) ).to be_instance_of NumRu::GribVar end end end end end describe NumRu::GribVar do before do @files = [] @vars = Hash.new GribData.each do |fname,vars| file = NumRu::Grib.open(fname) @files.push file vars.each{|vname, hash| @vars[file.var(vname)] = hash} end end after { @files.each{|file| file.close}} it '#rank returns rank' do @vars.each{|var,hash| expect(var.rank).to eq hash[:shape].length} end it '#total returns total length' do @vars.each{|var,hash| expect(var.total).to eq hash[:shape].inject(1,:*)} end it '#dim_names returns Array of dimension names' do @vars.each{|var,hash| expect(var.dim_names).to eq hash[:dims]} end it '#shape returns Array of shape' do @vars.each{|var,hash| expect(var.shape).to eq hash[:shape]} end it '#dim returns GribDim' do @vars.each do |var,hash| hash[:dims].each{|dname| expect(var.dim(dname)).to be_instance_of NumRu::GribDim} end end it '#att_names returns Array of attribute names' do @vars.each{|var,hash| expect(var.att_names).to be_instance_of Array} end it '#att returns attribute value' do @vars.each do |var,hash| var.att_names.each{|aname| expect(var.att(aname)).to_not eq nil } end end it '#typecode returns type code' do @vars.each{|var,hash| expect(var.typecode).to be_instance_of Fixnum} end it '#missing_value returns missing value' do @vars.each{|var,hash| expect(var.missing_value).to be_kind_of Numeric} end it '#get returns value' do @vars.each do |var,hash| hash[:val].each do |idx,val| v = var.get[*idx] expect((v-val).abs/((v+val)/2)).to be < 1e-10 end end end end describe NumRu::GribDim do before do @files = [] @dims = Hash.new GribData.each do |fname, vars| file = NumRu::Grib.open(fname) @files.push file vars.each do |vname, hash| var = file.var(vname) hash[:dims].each_with_index do |dname,i| @dims[var.dim(dname)] = hash[:shape][i] end end end end after do @files.each{|file| file.close} end it '#length returns length' do @dims.each{|dim,len| expect(dim.length).to eq len} end it '#val returns value' do @dims.each do |dim,len| expect(dim.val).to be_instance_of NArray expect(dim.val.length).to eq len end end it '#typecode returns typecode' do @dims.each{|dim,len| expect(dim.typecode).to be_instance_of Fixnum} end it '#att_names returns Array of attribute names' do @dims.each{|dim,len| expect(dim.att_names).to be_instance_of Array} end it '#att returns attributes value' do @dims.each do |dim,len| dim.att_names.each{|aname| expect(dim.att(aname)).to_not eq nil } end end end rb-grib-0.4.0/Gemfile0000644000175000017500000000020412772262773014201 0ustar uwabamiuwabamisource "http://rubygems.org" # Specify your gem's dependencies in rb-grib.gemspec gemspec group :development do gem "rspec" end