rb-grib 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/BSDL +22 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +13 -12
- data/README.rdoc +23 -0
- data/Rakefile +5 -0
- data/data/tp_ecmwf.grib +0 -0
- data/ext/grib.c +376 -68
- data/lib/numru/grib.rb +5 -1
- data/lib/numru/grib/definitions/grib1/localConcepts/kwbc/name.def +125 -0
- data/lib/numru/grib/definitions/grib1/localConcepts/kwbc/paramId.def +126 -0
- data/lib/numru/grib/definitions/grib1/localConcepts/kwbc/shortName.def +125 -0
- data/lib/numru/grib/definitions/grib1/localConcepts/kwbc/units.def +126 -0
- data/lib/numru/grib/definitions/grib2/localConcepts/rjtd/name.def +30 -0
- data/lib/numru/grib/definitions/grib2/localConcepts/rjtd/paramId.def +30 -0
- data/lib/numru/grib/definitions/grib2/localConcepts/rjtd/shortName.def +30 -0
- data/lib/numru/grib/definitions/grib2/localConcepts/rjtd/units.def +30 -0
- data/lib/numru/grib/grib.rb +132 -182
- data/lib/numru/grib/setenv.rb +12 -0
- data/lib/numru/grib/version.rb +1 -1
- data/rb-grib.gemspec +2 -1
- data/spec/grib_read_spec.rb +105 -76
- metadata +48 -7
@@ -0,0 +1,30 @@
|
|
1
|
+
#Total precipitation
|
2
|
+
'Total precipitation' = {
|
3
|
+
discipline = 0 ;
|
4
|
+
parameterCategory = 1 ;
|
5
|
+
parameterNumber = 8 ;
|
6
|
+
}
|
7
|
+
#Total cloud cover
|
8
|
+
'Total cloud cover' = {
|
9
|
+
discipline = 0 ;
|
10
|
+
parameterCategory = 6 ;
|
11
|
+
parameterNumber = 1 ;
|
12
|
+
}
|
13
|
+
#Low cloud cover
|
14
|
+
'Low cloud cover' = {
|
15
|
+
discipline = 0 ;
|
16
|
+
parameterCategory = 6 ;
|
17
|
+
parameterNumber = 3 ;
|
18
|
+
}
|
19
|
+
#Medium cloud cover
|
20
|
+
'Medium cloud cover' = {
|
21
|
+
discipline = 0 ;
|
22
|
+
parameterCategory = 6 ;
|
23
|
+
parameterNumber = 4 ;
|
24
|
+
}
|
25
|
+
#High cloud cover
|
26
|
+
'High cloud cover' = {
|
27
|
+
discipline = 0 ;
|
28
|
+
parameterCategory = 6 ;
|
29
|
+
parameterNumber = 5 ;
|
30
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#Total precipitation
|
2
|
+
'228' = {
|
3
|
+
discipline = 0 ;
|
4
|
+
parameterCategory = 1 ;
|
5
|
+
parameterNumber = 8 ;
|
6
|
+
}
|
7
|
+
#Total cloud cover
|
8
|
+
'164' = {
|
9
|
+
discipline = 0 ;
|
10
|
+
parameterCategory = 6 ;
|
11
|
+
parameterNumber = 1 ;
|
12
|
+
}
|
13
|
+
#Low cloud cover
|
14
|
+
'186' = {
|
15
|
+
discipline = 0 ;
|
16
|
+
parameterCategory = 6 ;
|
17
|
+
parameterNumber = 3 ;
|
18
|
+
}
|
19
|
+
#Medium cloud cover
|
20
|
+
'187' = {
|
21
|
+
discipline = 0 ;
|
22
|
+
parameterCategory = 6 ;
|
23
|
+
parameterNumber = 4 ;
|
24
|
+
}
|
25
|
+
#High cloud cover
|
26
|
+
'188' = {
|
27
|
+
discipline = 0 ;
|
28
|
+
parameterCategory = 6 ;
|
29
|
+
parameterNumber = 5 ;
|
30
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#Total precipitation
|
2
|
+
'tp' = {
|
3
|
+
discipline = 0 ;
|
4
|
+
parameterCategory = 1 ;
|
5
|
+
parameterNumber = 8 ;
|
6
|
+
}
|
7
|
+
#Total cloud cover
|
8
|
+
'tcc' = {
|
9
|
+
discipline = 0 ;
|
10
|
+
parameterCategory = 6 ;
|
11
|
+
parameterNumber = 1 ;
|
12
|
+
}
|
13
|
+
#Low cloud cover
|
14
|
+
'lcc' = {
|
15
|
+
discipline = 0 ;
|
16
|
+
parameterCategory = 6 ;
|
17
|
+
parameterNumber = 3 ;
|
18
|
+
}
|
19
|
+
#Medium cloud cover
|
20
|
+
'mcc' = {
|
21
|
+
discipline = 0 ;
|
22
|
+
parameterCategory = 6 ;
|
23
|
+
parameterNumber = 4 ;
|
24
|
+
}
|
25
|
+
#High cloud cover
|
26
|
+
'hcc' = {
|
27
|
+
discipline = 0 ;
|
28
|
+
parameterCategory = 6 ;
|
29
|
+
parameterNumber = 5 ;
|
30
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#Total precipitation
|
2
|
+
'kg m**-2' = {
|
3
|
+
discipline = 0 ;
|
4
|
+
parameterCategory = 1 ;
|
5
|
+
parameterNumber = 8 ;
|
6
|
+
}
|
7
|
+
#Total cloud cover
|
8
|
+
'%' = {
|
9
|
+
discipline = 0 ;
|
10
|
+
parameterCategory = 6 ;
|
11
|
+
parameterNumber = 1 ;
|
12
|
+
}
|
13
|
+
#Low cloud cover
|
14
|
+
'%' = {
|
15
|
+
discipline = 0 ;
|
16
|
+
parameterCategory = 6 ;
|
17
|
+
parameterNumber = 4 ;
|
18
|
+
}
|
19
|
+
#Medium cloud cover
|
20
|
+
'%' = {
|
21
|
+
discipline = 0 ;
|
22
|
+
parameterCategory = 6 ;
|
23
|
+
parameterNumber = 4 ;
|
24
|
+
}
|
25
|
+
#High cloud cover
|
26
|
+
'%' = {
|
27
|
+
discipline = 0 ;
|
28
|
+
parameterCategory = 6 ;
|
29
|
+
parameterNumber = 5 ;
|
30
|
+
}
|
data/lib/numru/grib/grib.rb
CHANGED
@@ -1,8 +1,3 @@
|
|
1
|
-
require "narray_miss"
|
2
|
-
require "date"
|
3
|
-
require "numru/grib.so"
|
4
|
-
|
5
|
-
|
6
1
|
module NumRu
|
7
2
|
class Grib
|
8
3
|
class << self
|
@@ -45,45 +40,9 @@ module NumRu
|
|
45
40
|
return false
|
46
41
|
end
|
47
42
|
|
48
|
-
def var_names
|
49
|
-
parse_vars unless @vars
|
50
|
-
return @vars.keys
|
51
|
-
end
|
52
|
-
def var(name)
|
53
|
-
parse_vars unless @vars
|
54
|
-
var = @vars[name]
|
55
|
-
return nil if var.nil?
|
56
|
-
return ::NumRu::GribVar.parse(self, var, name)
|
57
|
-
end
|
58
43
|
def inspect
|
59
44
|
"Grib: #{path}"
|
60
45
|
end
|
61
|
-
private
|
62
|
-
def parse_vars
|
63
|
-
vars = Hash.new
|
64
|
-
get_messages.each do |msg|
|
65
|
-
name = msg.sname
|
66
|
-
# zn = msg.z_sname
|
67
|
-
# name << "_" << zn unless /\A(pl|isobaricIn)/ =~ zn
|
68
|
-
hash = (vars[name] ||= Hash.new)
|
69
|
-
nij = [msg.get_value("Ni"), msg.get_value("Nj"), msg.gtype, msg.z_type]
|
70
|
-
if hash[nij]
|
71
|
-
hash[nij][1].push msg
|
72
|
-
else
|
73
|
-
hash[nij] = [hash.length, [msg]]
|
74
|
-
end
|
75
|
-
end
|
76
|
-
@vars = Hash.new
|
77
|
-
vars.each do |name,hash|
|
78
|
-
if hash.length == 1
|
79
|
-
@vars[name] = hash.values[0][1]
|
80
|
-
else
|
81
|
-
hash.each do |k,ary|
|
82
|
-
@vars[name+"_"+ary[0].to_s] = ary[1]
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
46
|
end # class Grib
|
88
47
|
|
89
48
|
class GribMessage
|
@@ -110,7 +69,7 @@ module NumRu
|
|
110
69
|
get_value("indicatorOfTypeOfLevel") || get_value("typeOfLevel") || "level"
|
111
70
|
end
|
112
71
|
def z_value
|
113
|
-
get_value("level")
|
72
|
+
get_value("levels") || get_value("level")
|
114
73
|
end
|
115
74
|
def z_units
|
116
75
|
get_value("pressureUnits")
|
@@ -120,8 +79,8 @@ module NumRu
|
|
120
79
|
h = get_value("dataTime").to_s.rjust(4,"0")
|
121
80
|
return DateTime.parse(d << h)
|
122
81
|
end
|
123
|
-
def
|
124
|
-
get_value("
|
82
|
+
def step
|
83
|
+
get_value("step")
|
125
84
|
end
|
126
85
|
def time_interval
|
127
86
|
get_value("lengthOfTimeRange")
|
@@ -180,136 +139,7 @@ module NumRu
|
|
180
139
|
|
181
140
|
class GribVar
|
182
141
|
Day0 = DateTime.new(1900)
|
183
|
-
MAXNDIM = 7 # lon, lat, lev, t,
|
184
|
-
class << self
|
185
|
-
def parse(file,msgs,name)
|
186
|
-
msg = msgs[0]
|
187
|
-
va = ::NumRu::GribVar.new(file,name)
|
188
|
-
va.put_att("long_name", msg.name)
|
189
|
-
# va.put_att("standard_name",std_name)
|
190
|
-
va.put_att("units",msg.units) if msg.units
|
191
|
-
va.put_att("grid_type", msg.gtype)
|
192
|
-
va.put_att("missing_value", [msg.missing_value]) if msg.missing_value
|
193
|
-
vdim = Array.new
|
194
|
-
xy_dims = 0
|
195
|
-
msg.get_xy.sort{|x,y| x["ij"]<=>y["ij"] }.each do |xy|
|
196
|
-
val = xy.delete("value")
|
197
|
-
sname = xy.delete("short_name")
|
198
|
-
ij = xy.delete("ij")
|
199
|
-
if val.length > 1
|
200
|
-
d = va.def_dim(sname, -1)
|
201
|
-
d.put(val)
|
202
|
-
xy.each{|k,v| d.put_att(k,v)}
|
203
|
-
xy_dims += 1
|
204
|
-
else
|
205
|
-
#xy.each{|k,v| va.put_att(k,v)}
|
206
|
-
end
|
207
|
-
end
|
208
|
-
z = Array.new
|
209
|
-
t = Array.new
|
210
|
-
ft = Array.new
|
211
|
-
ti = Array.new
|
212
|
-
en = Array.new
|
213
|
-
hash = Hash.new
|
214
|
-
msgs.each_with_index do |msg,i|
|
215
|
-
zv = msg.z_value
|
216
|
-
tv = get_time(msg.date)
|
217
|
-
ftv = msg.forecast_time
|
218
|
-
tiv = msg.time_interval
|
219
|
-
env = msg.ensemble_member
|
220
|
-
z.push zv
|
221
|
-
t.push tv
|
222
|
-
ft.push ftv
|
223
|
-
ti.push tiv
|
224
|
-
en.push env
|
225
|
-
ary = [zv,tv,ftv,tiv,env]
|
226
|
-
if hash[ary] # error
|
227
|
-
m1 = msgs[hash[ary]]
|
228
|
-
m2 = msgs[i]
|
229
|
-
a1 = m1.get_keys.map{|k| [k,m1.get_value(k)]}
|
230
|
-
a2 = m2.get_keys.map{|k| [k,m2.get_value(k)]}
|
231
|
-
a = Array.new
|
232
|
-
a1.length.times{|j| a.push [a1[j],a2[j]] if a1[j]!=a2[j]}
|
233
|
-
warn "BUG: send the following message to the developers"
|
234
|
-
p ary
|
235
|
-
p a
|
236
|
-
raise("error")
|
237
|
-
end
|
238
|
-
hash[ary] = i
|
239
|
-
end
|
240
|
-
hash = hash.invert
|
241
|
-
[z, t, ft, ti, en].each{|a| a.uniq!}
|
242
|
-
# [z, t, ft, ti, en].each{|a| a.uniq!; a.sort!}
|
243
|
-
idx = Array.new(msgs.length) do |i|
|
244
|
-
zv, tv, ftv, tiv, env = hash[i]
|
245
|
-
[z.index(zv), t.index(tv), ft.index(ftv), ti.index(tiv), en.index(env)]
|
246
|
-
end
|
247
|
-
del_dims = Array.new
|
248
|
-
if z.length == 1
|
249
|
-
va.put_att("level_type", msg.z_type)
|
250
|
-
va.put_att("level_value", [z[0]])
|
251
|
-
va.put_att("level_units", msg.z_units) if msg.z_units
|
252
|
-
del_dims.push xy_dims
|
253
|
-
else
|
254
|
-
d = va.def_dim(msg.z_sname, -1)
|
255
|
-
d.put_att("long_name", msg.z_type)
|
256
|
-
d.put_att("units", msg.z_units) if msg.z_units
|
257
|
-
d.put(NArray.to_na(z))
|
258
|
-
end
|
259
|
-
if t.length == 1
|
260
|
-
va.put_att("time", msg.date.to_s)
|
261
|
-
del_dims.push xy_dims + 1
|
262
|
-
else
|
263
|
-
d = va.def_dim("time", -1)
|
264
|
-
d.put_att("long_name","time")
|
265
|
-
d.put_att("units","hours since #{Day0.strftime('%Y-%m-%d %H:%M:%S')}")
|
266
|
-
d.put(NArray.to_na(t))
|
267
|
-
end
|
268
|
-
if ft.length == 1
|
269
|
-
va.put_att("forecast_time", [msg.forecast_time]) if msg.forecast_time
|
270
|
-
va.put_att("forcast_time_units", msg.step_units) if msg.step_units
|
271
|
-
del_dims.push xy_dims + 2
|
272
|
-
else
|
273
|
-
d = va.def_dim("forecast_time", -1)
|
274
|
-
d.put_att("long_name", "forecast_time")
|
275
|
-
d.put_att("units", msg.step_units) if msg.step_units
|
276
|
-
d.put(NArray.to_na(ft))
|
277
|
-
end
|
278
|
-
if ti.length == 1
|
279
|
-
del_dims.push xy_dims + 3
|
280
|
-
else
|
281
|
-
d = va.def_dim("time_interval", -1)
|
282
|
-
d.put_att("long_name", "time_interval")
|
283
|
-
d.put_att("units", msg.step_units) if msg.step_units
|
284
|
-
d.put(NArray.to_na(ti))
|
285
|
-
end
|
286
|
-
if en.length == 1
|
287
|
-
del_dims.push xy_dims + 4
|
288
|
-
else
|
289
|
-
d = va.def_dim("member", -1)
|
290
|
-
d.put_att("long_name", "ensemble_member")
|
291
|
-
d.put(NArray.to_na(en))
|
292
|
-
end
|
293
|
-
va.set_msgs(msgs, idx, xy_dims, del_dims)
|
294
|
-
return va
|
295
|
-
end
|
296
|
-
def get_time(date)
|
297
|
-
((date - Day0)*24).to_f
|
298
|
-
end
|
299
|
-
end # class << self
|
300
|
-
attr_reader :file, :name
|
301
|
-
def initialize(file,name)
|
302
|
-
@file = file
|
303
|
-
@name = name
|
304
|
-
@attr = Hash.new
|
305
|
-
@dims = Array.new
|
306
|
-
end
|
307
|
-
def set_msgs(msgs, idx, xy_dims, del_dims)
|
308
|
-
@msgs = msgs
|
309
|
-
@idx = idx
|
310
|
-
@xy_dims = xy_dims
|
311
|
-
@del_dims = del_dims
|
312
|
-
end
|
142
|
+
MAXNDIM = 7 # lon, lat, lev, t, step, timeInterval, ensemble
|
313
143
|
def rank
|
314
144
|
@dims.length
|
315
145
|
end
|
@@ -362,13 +192,14 @@ module NumRu
|
|
362
192
|
mask = nil
|
363
193
|
first = Array.new(rank-@xy_dims,0)
|
364
194
|
if indices.length != 0
|
365
|
-
if indices
|
366
|
-
|
367
|
-
|
368
|
-
indices
|
369
|
-
|
370
|
-
|
195
|
+
if indices.include?(false)
|
196
|
+
sha2 = sha.dup
|
197
|
+
sha2.delete(false)
|
198
|
+
raise ArgumentError, 'multiple "false" in indices' if sha.length - sha2.length > 1
|
199
|
+
indices[indices.index(false)] = [true]*(sha.length-indices.length+1)
|
200
|
+
indices.flatten!
|
371
201
|
end
|
202
|
+
|
372
203
|
rank.times{|n|
|
373
204
|
ind = indices[n]
|
374
205
|
case ind
|
@@ -422,7 +253,7 @@ module NumRu
|
|
422
253
|
val.reshape!(*shape[0...@xy_dims])
|
423
254
|
# val = msg.get_data[2].reshape!(*shape[0...@xy_dims])
|
424
255
|
unless indices.length==0 || indices[0...@xy_dims].inject(true){|t,v| t &&= v==true}
|
425
|
-
val = val
|
256
|
+
val = val.slice(*indices[0...@xy_dims])
|
426
257
|
end
|
427
258
|
end
|
428
259
|
(MAXNDIM-2).times do |i| index[i] = idx[i]-first[i] end
|
@@ -442,7 +273,126 @@ module NumRu
|
|
442
273
|
alias :[] :get
|
443
274
|
alias :val :get
|
444
275
|
def inspect
|
445
|
-
"GribVar: #{name} in #{
|
276
|
+
"GribVar: #{name} in #{file.path}, [#{shape.join(",")}]"
|
277
|
+
end
|
278
|
+
private
|
279
|
+
def get_time(date)
|
280
|
+
(date - Day0).to_f*24
|
281
|
+
end
|
282
|
+
def init
|
283
|
+
@attr = Hash.new
|
284
|
+
@dims = Array.new
|
285
|
+
msgs = get_messages
|
286
|
+
msg = msgs[0]
|
287
|
+
put_att("long_name", msg.name)
|
288
|
+
# put_att("standard_name",std_name)
|
289
|
+
put_att("units",msg.units) if msg.units
|
290
|
+
put_att("grid_type", msg.gtype)
|
291
|
+
put_att("missing_value", [msg.missing_value]) if msg.missing_value
|
292
|
+
vdim = Array.new
|
293
|
+
xy_dims = 0
|
294
|
+
msg.get_xy.sort{|x,y| x["ij"]<=>y["ij"] }.each do |xy|
|
295
|
+
val = xy.delete("value")
|
296
|
+
sname = xy.delete("short_name")
|
297
|
+
ij = xy.delete("ij")
|
298
|
+
if val.length > 1
|
299
|
+
d = def_dim(sname, -1)
|
300
|
+
d.put(val)
|
301
|
+
xy.each{|k,v| d.put_att(k,v)}
|
302
|
+
xy_dims += 1
|
303
|
+
else
|
304
|
+
#xy.each{|k,v| va.put_att(k,v)}
|
305
|
+
end
|
306
|
+
end
|
307
|
+
z = Array.new
|
308
|
+
t = Array.new
|
309
|
+
st = Array.new
|
310
|
+
ti = Array.new
|
311
|
+
en = Array.new
|
312
|
+
hash = Hash.new
|
313
|
+
msgs.each_with_index do |msg,i|
|
314
|
+
zv = msg.z_value
|
315
|
+
tv = get_time(msg.date)
|
316
|
+
stv = msg.step
|
317
|
+
tiv = msg.time_interval
|
318
|
+
env = msg.ensemble_member
|
319
|
+
z.push zv
|
320
|
+
t.push tv
|
321
|
+
st.push stv
|
322
|
+
ti.push tiv
|
323
|
+
en.push env
|
324
|
+
ary = [zv,tv,stv,tiv,env]
|
325
|
+
if hash[ary] # error
|
326
|
+
m1 = msgs[hash[ary]]
|
327
|
+
m2 = msgs[i]
|
328
|
+
a1 = m1.get_keys.map{|k| [k,m1.get_value(k)]}
|
329
|
+
a2 = m2.get_keys.map{|k| [k,m2.get_value(k)]}
|
330
|
+
a = Array.new
|
331
|
+
a1.length.times{|j| a.push [a1[j],a2[j]] if a1[j]!=a2[j]}
|
332
|
+
warn "BUG: send the following message to the developers"
|
333
|
+
p self
|
334
|
+
p ary
|
335
|
+
p a
|
336
|
+
raise("error")
|
337
|
+
end
|
338
|
+
hash[ary] = i
|
339
|
+
end
|
340
|
+
[z, t, st, ti, en].each{|a| a.uniq!}
|
341
|
+
# [z, t, st, ti, en].each{|a| a.uniq!; a.sort!}
|
342
|
+
@idx = Array.new(msgs.length)
|
343
|
+
hash.each do |ary, i|
|
344
|
+
zv, tv, stv, tiv, env = ary
|
345
|
+
@idx[i] = [z.index(zv), t.index(tv), st.index(stv), ti.index(tiv), en.index(env)]
|
346
|
+
end
|
347
|
+
del_dims = Array.new
|
348
|
+
if z.length == 1
|
349
|
+
put_att("level_type", msg.z_type)
|
350
|
+
put_att("level_value", z[0].kind_of?(Numeric) ? [z[0]] : z[0])
|
351
|
+
put_att("level_units", msg.z_units) if msg.z_units
|
352
|
+
del_dims.push xy_dims
|
353
|
+
else
|
354
|
+
d = def_dim(msg.z_sname, -1)
|
355
|
+
d.put_att("long_name", msg.z_type)
|
356
|
+
d.put_att("units", msg.z_units) if msg.z_units
|
357
|
+
d.put(NArray.to_na(z))
|
358
|
+
end
|
359
|
+
if t.length == 1
|
360
|
+
put_att("time", msg.date.to_s)
|
361
|
+
del_dims.push xy_dims + 1
|
362
|
+
else
|
363
|
+
d = def_dim("time", -1)
|
364
|
+
d.put_att("long_name","time")
|
365
|
+
d.put_att("units","hours since #{Day0.strftime('%Y-%m-%d %H:%M:%S')}")
|
366
|
+
d.put(NArray.to_na(t))
|
367
|
+
end
|
368
|
+
if st.length == 1
|
369
|
+
put_att("step", [msg.step]) if msg.step
|
370
|
+
put_att("step_units", msg.step_units) if msg.step_units
|
371
|
+
del_dims.push xy_dims + 2
|
372
|
+
else
|
373
|
+
d = def_dim("step", -1)
|
374
|
+
d.put_att("long_name", "step")
|
375
|
+
d.put_att("units", msg.step_units) if msg.step_units
|
376
|
+
d.put(NArray.to_na(st))
|
377
|
+
end
|
378
|
+
if ti.length == 1
|
379
|
+
del_dims.push xy_dims + 3
|
380
|
+
else
|
381
|
+
d = def_dim("time_interval", -1)
|
382
|
+
d.put_att("long_name", "time_interval")
|
383
|
+
d.put_att("units", msg.step_units) if msg.step_units
|
384
|
+
d.put(NArray.to_na(ti))
|
385
|
+
end
|
386
|
+
if en.length == 1
|
387
|
+
del_dims.push xy_dims + 4
|
388
|
+
else
|
389
|
+
d = def_dim("member", -1)
|
390
|
+
d.put_att("long_name", "ensemble_member")
|
391
|
+
d.put(NArray.to_na(en))
|
392
|
+
end
|
393
|
+
@xy_dims = xy_dims
|
394
|
+
@del_dims = del_dims
|
395
|
+
@msgs = msgs
|
446
396
|
end
|
447
397
|
end # class GribVar
|
448
398
|
|