rb-grib 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rb-grib.gemspec
4
+ gemspec
@@ -0,0 +1,57 @@
1
+ Ruby-GRIB is copyrighted free software by Seiya Nishizawa and the
2
+ GFD Dennou Club.
3
+ You can redistribute it and/or modify it under either the terms of the
4
+ GPL, or the conditions below, which is idential to Ruby's license
5
+ (http://www.ruby-lang.org/en/LICENSE.txt):
6
+
7
+ 1. You may make and give away verbatim copies of the source form of the
8
+ software without restriction, provided that you duplicate all of the
9
+ original copyright notices and associated disclaimers.
10
+
11
+ 2. You may modify your copy of the software in any way, provided that
12
+ you do at least ONE of the following:
13
+
14
+ a) place your modifications in the Public Domain or otherwise
15
+ make them Freely Available, such as by posting said
16
+ modifications to Usenet or an equivalent medium, or by allowing
17
+ the author to include your modifications in the software.
18
+
19
+ b) use the modified software only within your corporation or
20
+ organization.
21
+
22
+ c) rename any non-standard executables so the names do not conflict
23
+ with standard executables, which must also be provided.
24
+
25
+ d) make other distribution arrangements with the author.
26
+
27
+ 3. You may distribute the software in object code or executable
28
+ form, provided that you do at least ONE of the following:
29
+
30
+ a) distribute the executables and library files of the software,
31
+ together with instructions (in the manual page or equivalent)
32
+ on where to get the original distribution.
33
+
34
+ b) accompany the distribution with the machine-readable source of
35
+ the software.
36
+
37
+ c) give non-standard executables non-standard names, with
38
+ instructions on where to get the original software distribution.
39
+
40
+ d) make other distribution arrangements with the author.
41
+
42
+ 4. You may modify and include the part of the software into any other
43
+ software (possibly commercial). But some files in the distribution
44
+ are not written by the author, so that they are not under this terms.
45
+
46
+ See each file for the copying condition.
47
+
48
+ 5. The scripts and library files supplied as input to or produced as
49
+ output from the software do not automatically fall under the
50
+ copyright of the software, but belong to whomever generated them,
51
+ and may be sold commercially, and may be aggregated with this
52
+ software.
53
+
54
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
55
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
56
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57
+ PURPOSE.
@@ -0,0 +1,34 @@
1
+ = What's Ruby-GRIB
2
+
3
+ Ruby-GRIB is a class library to handle GRIB file.
4
+
5
+ = Requires
6
+
7
+ * Ruby (http://www.ruby-lang.org/)
8
+ * NArray (http://narray.rubyforge.org/index.html.en)
9
+ * GRIB API (http://www.ecmwf.int/products/data/software/grib_api.html)
10
+
11
+ = Install
12
+
13
+ # gem install rb-grib
14
+
15
+ = Usage
16
+
17
+ To use this library, put the following in your script.
18
+ require 'numru/grib'
19
+
20
+
21
+ = Example
22
+
23
+ require 'numru/grib'
24
+ include NumRu
25
+
26
+ filename = "test.grib"
27
+ grib = Grib.open(filename)
28
+ varnames = grib.var_names # => Array
29
+ varnames.each do |vname|
30
+ var = grib.var(vname) # => GribVar
31
+ dimnames = var.dim_names # => Array
32
+ ary = var.get # => NArray
33
+ end
34
+ grib.close
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,6 @@
1
+ require "mkmf"
2
+
3
+ dir_config("grib_api")
4
+ if have_header("grib_api.h") && have_library("grib_api")
5
+ create_makefile("numru/grib")
6
+ end
@@ -0,0 +1,435 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include "ruby.h"
4
+ #include "grib_api.h"
5
+ #include "narray.h"
6
+
7
+
8
+ #define MAX_VALUE_LENGTH 1024
9
+
10
+ VALUE cGrib;
11
+ VALUE cMessage;
12
+
13
+ typedef struct {
14
+ FILE *file;
15
+ char *fname;
16
+ grib_handle **handles;
17
+ int n;
18
+ } rg_file;
19
+
20
+ typedef struct {
21
+ VALUE file;
22
+ grib_handle *handle;
23
+ } rg_message;
24
+
25
+ static void
26
+ check_error(int code)
27
+ {
28
+ if (code)
29
+ rb_raise(rb_eRuntimeError, grib_get_error_message(code));
30
+ };
31
+
32
+
33
+ static void
34
+ message_free(rg_message *message)
35
+ {
36
+ if (message) {
37
+ free(message);
38
+ }
39
+ }
40
+ static void
41
+ message_mark(rg_message *message)
42
+ {
43
+ if (message && message->file != Qnil)
44
+ rb_gc_mark(message->file);
45
+ }
46
+ static VALUE
47
+ message_alloc(VALUE klass)
48
+ {
49
+ rg_message *message = ALLOC(rg_message);
50
+ message->file = Qnil;
51
+ message->handle = NULL;
52
+ return Data_Wrap_Struct(klass, message_mark, message_free, message);
53
+ }
54
+
55
+ static void
56
+ file_close(rg_file *gfile)
57
+ {
58
+ int i;
59
+ if (gfile) {
60
+ if (gfile->handles) {
61
+ for (i=0; i<gfile->n; i++)
62
+ if (gfile->handles[i]) grib_handle_delete(gfile->handles[i]);
63
+ free(gfile->handles);
64
+ gfile->handles = NULL;
65
+ }
66
+ gfile->n = 0;
67
+ if (gfile->file) {
68
+ fclose(gfile->file);
69
+ gfile->file = NULL;
70
+ }
71
+ if (gfile->fname) {
72
+ free(gfile->fname);
73
+ gfile->fname = NULL;
74
+ }
75
+ }
76
+ }
77
+ static void
78
+ file_free(rg_file *gfile)
79
+ {
80
+ if (gfile) {
81
+ file_close(gfile);
82
+ free(gfile);
83
+ }
84
+ }
85
+ static VALUE
86
+ file_alloc(VALUE klass)
87
+ {
88
+ rg_file *gfile = ALLOC(rg_file);
89
+ gfile->file = NULL;
90
+ gfile->fname = NULL;
91
+ gfile->handles = NULL;
92
+ gfile->n = 0;
93
+ return Data_Wrap_Struct(klass, 0, file_free, gfile);
94
+ }
95
+
96
+ /*
97
+ NumRu::Grib.open(filename [, mode]) -> NumRu::Grib::File
98
+ */
99
+ /*
100
+ static VALUE
101
+ rg_open(int argc, VALUE *argv, VALUE self)
102
+ {
103
+ VALUE rgfile = file_alloc(self);
104
+ return rg_file_initialize(argc, argv, rgfile);
105
+ }
106
+ */
107
+
108
+ /*
109
+ NumRu::Grib.multi=(flag) -> True/False
110
+ */
111
+ static VALUE
112
+ rg_multi(VALUE self, VALUE flag)
113
+ {
114
+ if (flag == Qtrue)
115
+ grib_multi_support_on(0);
116
+ else if (flag == Qfalse)
117
+ grib_multi_support_off(0);
118
+ else
119
+ rb_raise(rb_eArgError, "flag must be true or false");
120
+ return flag;
121
+ }
122
+
123
+ /*
124
+ NumRu::Grib#initialize(filename, [, mode])
125
+ */
126
+ static VALUE
127
+ rg_file_initialize(int argc, VALUE *argv, VALUE self)
128
+ {
129
+ char *fname, *mode;
130
+ VALUE rfname, rmode;
131
+ rb_scan_args(argc, argv, "11", &rfname, &rmode);
132
+ fname = StringValueCStr(rfname);
133
+ if (rmode == Qnil)
134
+ mode = "r";
135
+ else
136
+ mode = StringValueCStr(rmode);
137
+
138
+ FILE *file = fopen(fname, mode);
139
+ if (!file)
140
+ rb_raise(rb_eRuntimeError, "unable to open file %s", fname);
141
+
142
+ rg_file *gfile;
143
+ Data_Get_Struct(self, rg_file, gfile);
144
+ gfile->file = file;
145
+ gfile->fname = ALLOC_N(char, strlen(fname)+1);
146
+ strcpy(gfile->fname, fname);
147
+
148
+ int n = 0;
149
+ int error;
150
+ grib_handle *handle;
151
+ while ((handle = grib_handle_new_from_file(0, file, &error))) {
152
+ check_error(error);
153
+ if (handle == NULL)
154
+ rb_raise(rb_eRuntimeError, "unable to create handle in %s", fname);
155
+ grib_handle_delete(handle);
156
+ n++;
157
+ }
158
+ rewind(file);
159
+ grib_handle **handles = ALLOC_N(grib_handle*, n);
160
+ int i;
161
+ for (i=0; i<n; i++) handles[i] = NULL;
162
+ for (i=0; i<n; i++) {
163
+ handle = grib_handle_new_from_file(0, file, &error);
164
+ check_error(error);
165
+ if (handle == NULL)
166
+ rb_raise(rb_eRuntimeError, "unable to create handle in %s", fname);
167
+ handles[i] = handle;
168
+ }
169
+ gfile->n = n;
170
+ gfile->handles = handles;
171
+ return self;
172
+ }
173
+ /*
174
+ NumRu::Grib#close() -> nil
175
+ */
176
+ static VALUE
177
+ rg_file_close(VALUE self)
178
+ {
179
+ rg_file *gfile;
180
+ Data_Get_Struct(self, rg_file, gfile);
181
+ file_close(gfile);
182
+ return Qnil;
183
+ }
184
+
185
+ /*
186
+ NumRu::Grib#get_messages() -> Array
187
+ */
188
+ static VALUE
189
+ rg_file_get_messages(VALUE self)
190
+ {
191
+ rg_file *gfile;
192
+ Data_Get_Struct(self, rg_file, gfile);
193
+ VALUE ary = rb_ary_new2(gfile->n);
194
+ rg_message *message;
195
+ VALUE rmessage;
196
+ int i;
197
+ for (i=0; i<gfile->n; i++) {
198
+ rmessage = message_alloc(cMessage);
199
+ Data_Get_Struct(rmessage, rg_message, message);
200
+ message->file = self;
201
+ message->handle = gfile->handles[i];
202
+ rb_ary_store(ary, i, rmessage);
203
+ }
204
+ return ary;
205
+ }
206
+
207
+ /*
208
+ NumRu::Grib#path() -> String
209
+ */
210
+ static VALUE
211
+ rg_file_path(VALUE self)
212
+ {
213
+ rg_file *gfile;
214
+ Data_Get_Struct(self, rg_file, gfile);
215
+ return rb_str_new2(gfile->fname);
216
+ }
217
+
218
+ /*
219
+ NumRu::GribMessage#initialize()
220
+ */
221
+ static VALUE
222
+ rg_message_initialize(VALUE self, VALUE file)
223
+ {
224
+ rg_message *message;
225
+ Data_Get_Struct(self, rg_message, message);
226
+ message->file = file;
227
+ return self;
228
+ }
229
+
230
+ /*
231
+ NumRu::GribMessage#get_keys() -> Array
232
+ */
233
+ static VALUE
234
+ rg_message_get_keys(int argc, VALUE *argv, VALUE self)
235
+ {
236
+ VALUE rflag, rns;
237
+ unsigned long flag = GRIB_KEYS_ITERATOR_SKIP_READ_ONLY || GRIB_KEYS_ITERATOR_SKIP_COMPUTED;
238
+ // unsigned long flag = GRIB_KEYS_ITERATOR_ALL_KEYS;
239
+ char *name_space = NULL;
240
+ rb_scan_args(argc, argv, "02", &rflag, &rns);
241
+ if (rflag != Qnil) flag = NUM2ULONG(rflag);
242
+ if (rns != Qnil) name_space = StringValueCStr(rns);
243
+
244
+ rg_message *message;
245
+ Data_Get_Struct(self, rg_message, message);
246
+ grib_keys_iterator *ki = NULL;
247
+ ki = grib_keys_iterator_new(message->handle, flag, name_space);
248
+ if (!ki)
249
+ rb_raise(rb_eRuntimeError, "unable to create key iterator");
250
+ VALUE keys = rb_ary_new();
251
+ while (grib_keys_iterator_next(ki)) {
252
+ const char *name = grib_keys_iterator_get_name(ki);
253
+ rb_ary_push(keys, rb_str_new2(name));
254
+ }
255
+ grib_keys_iterator_delete(ki);
256
+ return keys;
257
+ }
258
+
259
+ /*
260
+ NumRu::GribMessage#get_value(name [,type]) -> String
261
+ */
262
+ static VALUE
263
+ rg_message_get_value(int argc, VALUE *argv, VALUE self)
264
+ {
265
+ VALUE rname, rtype;
266
+ rb_scan_args(argc, argv, "11", &rname, &rtype);
267
+ char *name = StringValueCStr(rname);
268
+ int type;
269
+ rg_message *message;
270
+ Data_Get_Struct(self, rg_message, message);
271
+ if (rtype == Qnil)
272
+ grib_get_native_type(message->handle, name, &type);
273
+ else
274
+ type = NUM2INT(rtype);
275
+ size_t len;
276
+ VALUE ret = Qnil;
277
+ grib_get_size(message->handle, name, &len);
278
+ switch (type) {
279
+ case GRIB_TYPE_UNDEFINED:
280
+ case GRIB_TYPE_STRING:
281
+ case GRIB_TYPE_LABEL:
282
+ {
283
+ char value[MAX_VALUE_LENGTH];
284
+ len = MAX_VALUE_LENGTH;
285
+ bzero(value, len);
286
+ if (grib_get_string(message->handle, name, value, &len) == GRIB_SUCCESS) {
287
+ if (value[len-1] == '\0') len--;
288
+ ret = rb_str_new(value, len);
289
+ }
290
+ }
291
+ break;
292
+ case GRIB_TYPE_BYTES:
293
+ {
294
+ unsigned char value[MAX_VALUE_LENGTH];
295
+ len = MAX_VALUE_LENGTH;
296
+ bzero(value, len);
297
+ if (grib_get_bytes(message->handle, name, value, &len) == GRIB_SUCCESS)
298
+ ret = rb_str_new((char*)value, len);
299
+ }
300
+ break;
301
+ case GRIB_TYPE_LONG:
302
+ {
303
+ if (len == 1) {
304
+ long l;
305
+ if (rtype == Qnil) {
306
+ char value[MAX_VALUE_LENGTH];
307
+ len = MAX_VALUE_LENGTH;
308
+ bzero(value, len);
309
+ if (grib_get_string(message->handle, name, value, &len) == GRIB_SUCCESS) {
310
+ check_error(grib_get_long(message->handle, name, &l));
311
+ if (atol(value) == l)
312
+ ret = LONG2NUM(l);
313
+ else
314
+ ret = rb_str_new2(value);
315
+ }
316
+ } else {
317
+ check_error(grib_get_long(message->handle, name, &l));
318
+ ret = LONG2NUM(l);
319
+ }
320
+ } else {
321
+ int shape[1];
322
+ struct NARRAY *nary;
323
+ shape[0] = len;
324
+ VALUE rnary = na_make_object(NA_LINT, 1, shape, cNArray);
325
+ GetNArray(rnary, nary);
326
+ if (grib_get_long_array(message->handle, name, (long*)nary->ptr, &len) == GRIB_SUCCESS)
327
+ ret = rnary;
328
+ }
329
+ }
330
+ break;
331
+ case GRIB_TYPE_DOUBLE:
332
+ {
333
+ if (len == 1) {
334
+ double value;
335
+ if (grib_get_double(message->handle, name, &value) == GRIB_SUCCESS)
336
+ ret = rb_float_new(value);
337
+ } else {
338
+ int shape[1];
339
+ struct NARRAY *nary;
340
+ shape[0] = len;
341
+ VALUE rnary = na_make_object(NA_DFLOAT, 1, shape, cNArray);
342
+ GetNArray(rnary, nary);
343
+ if (grib_get_double_array(message->handle, name, (double*)nary->ptr, &len) == GRIB_SUCCESS)
344
+ ret = rnary;
345
+ }
346
+ }
347
+ break;
348
+ default:
349
+ rb_raise(rb_eArgError, "type is invalid: %d", type);
350
+ }
351
+ return ret;
352
+ }
353
+
354
+ /*
355
+ NumRu::GribMessage#get_data() -> [lon, lat, value]
356
+ */
357
+ static VALUE
358
+ rg_message_get_data(VALUE self)
359
+ {
360
+ rg_message *message;
361
+ Data_Get_Struct(self, rg_message, message);
362
+ int error;
363
+ grib_iterator *iter = grib_iterator_new(message->handle, 0, &error);
364
+ check_error(error);
365
+ long np;
366
+ check_error(grib_get_long(message->handle, "numberOfPoints", &np));
367
+ double *lon, *lat, *value;
368
+ VALUE na_lon, na_lat, na_value;
369
+ struct NARRAY *nary;
370
+ int shape[1];
371
+ shape[0] = np;
372
+ na_lon = na_make_object(NA_DFLOAT, 1, shape, cNArray);
373
+ GetNArray(na_lon, nary);
374
+ lon = (double*) nary->ptr;
375
+ na_lat = na_make_object(NA_DFLOAT, 1, shape, cNArray);
376
+ GetNArray(na_lat, nary);
377
+ lat = (double*) nary->ptr;
378
+ na_value = na_make_object(NA_DFLOAT, 1, shape, cNArray);
379
+ GetNArray(na_value, nary);
380
+ value = (double*) nary->ptr;
381
+ int n = 0;
382
+ double lo, la, val;
383
+ while( grib_iterator_next(iter, &la, &lo, &val) ) {
384
+ lat[n] = la;
385
+ lon[n] = lo;
386
+ value[n] = val;
387
+ n++;
388
+ }
389
+ grib_iterator_delete(iter);
390
+ return rb_ary_new3(3, na_lon, na_lat, na_value);
391
+ }
392
+
393
+
394
+
395
+ void Init_grib()
396
+ {
397
+ rb_require("narray");
398
+
399
+ VALUE mNumRu = rb_define_module("NumRu");
400
+ cGrib = rb_define_class_under(mNumRu, "Grib", rb_cObject);
401
+ cMessage = rb_define_class_under(mNumRu, "GribMessage", rb_cObject);
402
+
403
+ grib_multi_support_on(0);
404
+
405
+ //rb_define_singleton_method(cGrib, "open", rg_open, -1);
406
+ rb_define_singleton_method(cGrib, "multi=", rg_multi, 1);
407
+
408
+ rb_define_alloc_func(cGrib, file_alloc);
409
+ rb_define_method(cGrib, "initialize", rg_file_initialize, -1);
410
+ rb_define_method(cGrib, "close", rg_file_close, 0);
411
+ rb_define_method(cGrib, "get_messages", rg_file_get_messages, 0);
412
+ rb_define_method(cGrib, "path", rg_file_path, 0);
413
+
414
+ rb_define_alloc_func(cMessage, message_alloc);
415
+ rb_define_method(cMessage, "initialize", rg_message_initialize, 1);
416
+ rb_define_method(cMessage, "get_keys", rg_message_get_keys, -1);
417
+ rb_define_method(cMessage, "get_value", rg_message_get_value, -1);
418
+ rb_define_method(cMessage, "get_data", rg_message_get_data, 0);
419
+
420
+ rb_define_const(cGrib, "TYPE_UNDEFINED", INT2NUM(GRIB_TYPE_UNDEFINED));
421
+ rb_define_const(cGrib, "TYPE_LONG", INT2NUM(GRIB_TYPE_LONG));
422
+ rb_define_const(cGrib, "TYPE_DOUBLE", INT2NUM(GRIB_TYPE_DOUBLE));
423
+ rb_define_const(cGrib, "TYPE_STRING", INT2NUM(GRIB_TYPE_STRING));
424
+ rb_define_const(cGrib, "TYPE_BYTES", INT2NUM(GRIB_TYPE_BYTES));
425
+ rb_define_const(cGrib, "TYPE_SECTION", INT2NUM(GRIB_TYPE_SECTION));
426
+ rb_define_const(cGrib, "TYPE_LABEL", INT2NUM(GRIB_TYPE_LABEL));
427
+ rb_define_const(cGrib, "TYPE_MISSING", INT2NUM(GRIB_TYPE_MISSING));
428
+
429
+ rb_define_const(cGrib, "NEAREST_SAME_GRID", ULONG2NUM(GRIB_NEAREST_SAME_GRID));
430
+ rb_define_const(cGrib, "NEAREST_SAME_DATA", ULONG2NUM(GRIB_NEAREST_SAME_DATA));
431
+ rb_define_const(cGrib, "NEAREST_SAME_POINT", ULONG2NUM(GRIB_NEAREST_SAME_POINT));
432
+
433
+ rb_define_const(cGrib, "KEYS_ITERATOR_ALL_KEYS", ULONG2NUM(GRIB_KEYS_ITERATOR_ALL_KEYS));
434
+ rb_define_const(cGrib, "KEYS_ITERATOR_SKIP_READ_ONLY", ULONG2NUM(GRIB_KEYS_ITERATOR_SKIP_READ_ONLY));
435
+ }
@@ -0,0 +1,2 @@
1
+ require "numru/grib/version"
2
+ require "numru/grib/grib.rb"
@@ -0,0 +1,528 @@
1
+ require "narray_miss"
2
+ require "date"
3
+ require "numru/grib.so"
4
+
5
+
6
+ module NumRu
7
+ class Grib
8
+ class << self
9
+ # cache due to momery leak in the original grib_api library
10
+ @@gribs = Hash.new
11
+ def is_a_Grib?(fname)
12
+ is = false
13
+ File.open(fname) do |file|
14
+ is = (file.read(4) == "GRIB")
15
+ end
16
+ return is
17
+ end
18
+ alias :_new :new
19
+ def new(fname, mode="r")
20
+ key = [fname,mode]
21
+ if (obj = @@gribs[key])
22
+ obj[1] += 1
23
+ return obj[0]
24
+ else
25
+ grib = _new(fname, mode)
26
+ @@gribs[key] = [grib, 1]
27
+ return grib
28
+ end
29
+ end
30
+ alias :open :new
31
+ end # class << self
32
+
33
+ alias :_close :close
34
+ def close
35
+ @@gribs.each do |k, val|
36
+ if self == val[0]
37
+ val[1] -= 1
38
+ if val[1] < 1
39
+ _close
40
+ @@gribs.delete(k)
41
+ return true
42
+ end
43
+ end
44
+ end
45
+ return false
46
+ end
47
+
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
+ def inspect
59
+ "Grib: #{path}"
60
+ 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
+ end # class Grib
88
+
89
+ class GribMessage
90
+ def name
91
+ n = get_value("name")
92
+ return n if (n && n != "unknown")
93
+ get_value("parameterName") || get_value("indicatorOfParameter")
94
+ end
95
+ def sname
96
+ sn = get_value("shortName")
97
+ return sn if (sn && sn != "unknown")
98
+ "id" + (get_value("indicatorOfParameter", ::NumRu::Grib::TYPE_LONG) || get_value("parameterNumber", ::NumRu::Grib::TYPE_LONG)).to_s
99
+ end
100
+ def units
101
+ get_value("parameterUnits") || get_value("units")
102
+ end
103
+ alias :unit :units
104
+ def z_type
105
+ zt = get_value("typeOfLevel")
106
+ return zt if zt && zt != "unknown"
107
+ z_sname
108
+ end
109
+ def z_sname
110
+ get_value("indicatorOfTypeOfLevel") || get_value("typeOfLevel") || "level"
111
+ end
112
+ def z_value
113
+ get_value("level")
114
+ end
115
+ def z_units
116
+ get_value("pressureUnits")
117
+ end
118
+ def date
119
+ d = get_value("dataDate").to_s.rjust(8,"0")
120
+ h = get_value("dataTime").to_s.rjust(4,"0")
121
+ return DateTime.parse(d << h)
122
+ end
123
+ def forecast_time
124
+ get_value("forecastTime")
125
+ end
126
+ def time_interval
127
+ get_value("lengthOfTimeRange")
128
+ end
129
+ def step_units
130
+ get_value("stepUnits")
131
+ end
132
+ MEMBER_NAME = {1 => "", 2 => "n", 3 => "p"}
133
+ def ensemble_member
134
+ pn = get_value("perturbationNumber")
135
+ te = get_value("typeOfEnsembleForecast")
136
+ name = ""
137
+ name << pn.to_s if pn
138
+ name << (MEMBER_NAME[te] || te.to_s) if te
139
+ name
140
+ end
141
+ def gtype
142
+ get_value("typeOfGrid")
143
+ end
144
+ def missing_value
145
+ get_value("missingValue")
146
+ end
147
+ def get_xy
148
+ lo, la, = get_data
149
+ case gtype
150
+ when "regular_ll", "regular_gg"
151
+ lon = Hash.new
152
+ lat = Hash.new
153
+ if get_value("jPointsAreConsecutive") == 1
154
+ lon["ij"] = 1
155
+ lat["ij"] = 0
156
+ shape = [get_value("Nj"), get_value("Ni")]
157
+ else
158
+ lon["ij"] = 0
159
+ lat["ij"] = 1
160
+ shape = [get_value("Ni"), get_value("Nj")]
161
+ end
162
+ lo.reshape!(*shape)
163
+ la.reshape!(*shape)
164
+ lon["short_name"] = "lon"
165
+ lon["long_name"] = "longitude"
166
+ lon["units"] = "degrees_east"
167
+ idx = [0,0]; idx[lon["ij"]] = true
168
+ lon["value"] = lo[*idx]
169
+ lat["short_name"] = "lat"
170
+ lat["long_name"] = "latitude"
171
+ lat["units"] = "degrees_north"
172
+ idx = [0,0]; idx[lat["ij"]] = true
173
+ lat["value"] = la[*idx]
174
+ return [lon,lat]
175
+ else
176
+ raise "not defined yet: #{gtype}"
177
+ end
178
+ end
179
+ end # class GribMessage
180
+
181
+ class GribVar
182
+ Day0 = DateTime.new(1900)
183
+ MAXNDIM = 7 # lon, lat, lev, t, forecastTime, timeInterval, ensemble
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
313
+ def rank
314
+ @dims.length
315
+ end
316
+ alias :ndims :rank
317
+ def total
318
+ @dims.inject(1){|t,d| t*d.length}
319
+ end
320
+ def dim_names
321
+ @dims.collect{|d| d.name}
322
+ end
323
+ def shape
324
+ @dims.collect{|d| d.length}
325
+ end
326
+ def dim(index)
327
+ index = dim_names.index(index) if String===index
328
+ return nil if index.nil?
329
+ @dims[index]
330
+ end
331
+ def def_dim(name,index)
332
+ d = ::NumRu::GribDim.new(self,name)
333
+ if index == -1
334
+ @dims.push(d)
335
+ else
336
+ @dims[index] = d
337
+ end
338
+ return d
339
+ end
340
+ def put_att(key,val)
341
+ @attr[key] = val
342
+ end
343
+ alias :set_att :put_att
344
+ def att(key)
345
+ @attr[key]
346
+ end
347
+ def att_names
348
+ @attr.keys
349
+ end
350
+ def typecode
351
+ if missing_value
352
+ NArrayMiss::DFLOAT
353
+ else
354
+ NArray::DFLOAT
355
+ end
356
+ end
357
+ def missing_value
358
+ @msgs[0].missing_value
359
+ end
360
+ def get(*indices)
361
+ sha = shape
362
+ mask = nil
363
+ first = Array.new(rank-@xy_dims,0)
364
+ if indices.length != 0
365
+ if indices[0] == false
366
+ indices[0] = [true]*(sha.length-indices.length+1)
367
+ elsif indices[-1] == false
368
+ indices[-1] = [true]*(sha.length-indices.length+1)
369
+ elsif indices.include?(false) || indices.length != rank
370
+ raise "invalid indices"
371
+ end
372
+ rank.times{|n|
373
+ ind = indices[n]
374
+ case ind
375
+ when true
376
+ indices[n] = 0..sha[n]-1
377
+ when Fixnum
378
+ sha[n] = 1
379
+ when Range
380
+ f = ind.first
381
+ e = ind.end
382
+ e = sha[n]-1 if e==-1
383
+ e -= 1 if ind.exclude_end?
384
+ sha[n] = e-f+1
385
+ indices[n] = f..e
386
+ else
387
+ raise "invalid indices"
388
+ end
389
+ }
390
+ if rank > @xy_dims
391
+ mask = NArray.byte(*shape[@xy_dims..-1])
392
+ mask[*indices[@xy_dims..-1]] = 1
393
+ (rank-@xy_dims).times do |i|
394
+ ind = indices[@xy_dims+i]
395
+ case ind
396
+ when Fixnum
397
+ first[i] = ind
398
+ when Range
399
+ first[i] = ind.first
400
+ first[i] += shape[@xy_dims+i] if first[i] < 0
401
+ end
402
+ end
403
+ end
404
+ end
405
+
406
+ shape2 = shape.dup
407
+ sha2 = sha.dup
408
+ @del_dims.each do |i|
409
+ shape2.insert(i,1)
410
+ sha2.insert(i,1)
411
+ first.insert(i-@xy_dims,0)
412
+ end
413
+ mask.reshape!(*shape2[@xy_dims..-1]) if mask
414
+
415
+ value = missing_value ? NArrayMiss.sfloat(*sha2) : NArray.sfloat(*sha2)
416
+ index = Array.new(MAXNDIM-2)
417
+ @msgs.each_with_index do |msg,i|
418
+ idx = @idx[i]
419
+ next if (mask && mask[*idx]==0)
420
+ val = msg.get_value("values")
421
+ if @xy_dims > 0
422
+ val.reshape!(*shape[0...@xy_dims])
423
+ # val = msg.get_data[2].reshape!(*shape[0...@xy_dims])
424
+ unless indices.length==0 || indices[0...@xy_dims].inject(true){|t,v| t &&= v==true}
425
+ val = val[*indices[0...@xy_dims]]
426
+ end
427
+ end
428
+ (MAXNDIM-2).times do |i| index[i] = idx[i]-first[i] end
429
+ value[*(Array.new(@xy_dims,true)+index)] = val
430
+ end
431
+ ns = sha.length
432
+ ns.times do |ii|
433
+ i = ns-ii-1
434
+ sha.delete_at(i) if indices[i].kind_of?(Fixnum)
435
+ end
436
+ value.reshape!(*sha)
437
+ if missing_value
438
+ value.set_mask value.get_array!.ne(missing_value)
439
+ end
440
+ return value
441
+ end
442
+ alias :[] :get
443
+ alias :val :get
444
+ def inspect
445
+ "GribVar: #{name} in #{@file.path}, [#{shape.join(",")}]"
446
+ end
447
+ end # class GribVar
448
+
449
+ class GribDim
450
+ attr_reader :var, :length, :name
451
+ def initialize(var,name)
452
+ @var = var
453
+ @name = name
454
+ @attr = Hash.new
455
+ end
456
+ alias :total :length
457
+ def get
458
+ @ary
459
+ end
460
+ def typecode
461
+ if NArray===@ary
462
+ @ary.typecode
463
+ elsif Array===@ary
464
+ @ary[0]["value"].typecode
465
+ end
466
+ end
467
+ def val
468
+ return @ary
469
+ end
470
+ def [](*ind)
471
+ return val[*ind]
472
+ end
473
+ def put(ary)
474
+ @ary = ary
475
+ @length = val.length
476
+ return @ary
477
+ end
478
+ def put_att(key,val)
479
+ @attr[key]=val
480
+ end
481
+ alias :set_att :put_att
482
+ def att(key)
483
+ @attr[key]
484
+ end
485
+ def att_names
486
+ @attr.keys
487
+ end
488
+ def inspect
489
+ "GribDim: #{name} length=#{length}"
490
+ end
491
+ end # class GribDim
492
+
493
+ end # module NumRu
494
+
495
+
496
+
497
+
498
+
499
+ #####################################################
500
+ if $0 == __FILE__
501
+
502
+ include NumRu
503
+
504
+ if ARGV.length>0
505
+ infname = ARGV.shift
506
+ else
507
+ infname = "../../../testdata/T.jan.grib"
508
+ end
509
+
510
+
511
+ Grib.is_a_Grib?(infname) || raise("file is not a Grib dataset")
512
+ p grib = Grib.open(infname)
513
+
514
+
515
+
516
+ print "\nVars\n"
517
+ grib.var_names.each{|vn|
518
+ p v = grib.var(vn)
519
+ p v.dim_names
520
+ v.dim_names.each{|dn| p dn; p v.dim(dn).get }
521
+ p v.shape
522
+ v.att_names.each{|an| print an, " => ", v.att(an), "\n" }
523
+ puts "\n"
524
+ p v.val
525
+ }
526
+
527
+
528
+ end
@@ -0,0 +1,5 @@
1
+ module NumRu
2
+ class Grib
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "numru/grib/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rb-grib"
7
+ s.version = NumRu::Grib::VERSION
8
+ s.authors = ["Seiya Nishizawa"]
9
+ s.email = ["seiya@gfd-dennou.org"]
10
+ s.homepage = "http://ruby.gfd-dennu.org/products/rb-grib/"
11
+ s.summary = %q{Ruby class library to hanlde GRIB file}
12
+ s.description = %q{This class library enable you to handle GRIB file.}
13
+
14
+ s.rubyforge_project = "rb-grib"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+ s.extensions << "ext/extconf.rb"
21
+
22
+ # specify any dependencies here; for example:
23
+ # s.add_development_dependency "rspec"
24
+ # s.add_runtime_dependency "rest-client"
25
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rb-grib
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Seiya Nishizawa
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-11-29 00:00:00 Z
19
+ dependencies: []
20
+
21
+ description: This class library enable you to handle GRIB file.
22
+ email:
23
+ - seiya@gfd-dennou.org
24
+ executables: []
25
+
26
+ extensions:
27
+ - ext/extconf.rb
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - .gitignore
32
+ - Gemfile
33
+ - LICENSE.txt
34
+ - README.rdoc
35
+ - Rakefile
36
+ - ext/extconf.rb
37
+ - ext/grib.c
38
+ - lib/numru/grib.rb
39
+ - lib/numru/grib/grib.rb
40
+ - lib/numru/grib/version.rb
41
+ - rb-grib.gemspec
42
+ homepage: http://ruby.gfd-dennu.org/products/rb-grib/
43
+ licenses: []
44
+
45
+ post_install_message:
46
+ rdoc_options: []
47
+
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ hash: 3
56
+ segments:
57
+ - 0
58
+ version: "0"
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ hash: 3
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ requirements: []
69
+
70
+ rubyforge_project: rb-grib
71
+ rubygems_version: 1.8.10
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: Ruby class library to hanlde GRIB file
75
+ test_files: []
76
+