rb-grib 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+