carray-netcdf 1.0.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.
- checksums.yaml +7 -0
- data/API.html +238 -0
- data/API.md +270 -0
- data/README.md +3 -0
- data/carray-netcdf.gemspec +23 -0
- data/examples/test.rb +1 -0
- data/extconf.rb +11 -0
- data/lib/carray-netcdf.rb +2 -0
- data/lib/io/netcdf.rb +533 -0
- data/rb_netcdflib.c +1914 -0
- metadata +52 -0
data/lib/io/netcdf.rb
ADDED
@@ -0,0 +1,533 @@
|
|
1
|
+
require "carray"
|
2
|
+
require "carray/netcdflib.so"
|
3
|
+
|
4
|
+
module NC
|
5
|
+
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def nc_decode (fd, varid, data)
|
9
|
+
if fill_value = nc_get_att(fd, varid, "_FillValue")
|
10
|
+
data[:eq, fill_value] = UNDEF
|
11
|
+
end
|
12
|
+
if scale_factor = nc_get_att(fd, varid, "scale_factor")
|
13
|
+
data *= scale_factor
|
14
|
+
end
|
15
|
+
if add_offset = nc_get_att(fd, varid, "add_offset")
|
16
|
+
data += add_offset
|
17
|
+
end
|
18
|
+
return data
|
19
|
+
end
|
20
|
+
|
21
|
+
def nc_put_att_simple (fd, varid, name, val)
|
22
|
+
case val
|
23
|
+
when Float
|
24
|
+
nc_put_att(fd, varid, name, CA_DOUBLE(val))
|
25
|
+
when Integer
|
26
|
+
nc_put_att(fd, varid, name, CA_INT(val))
|
27
|
+
else
|
28
|
+
nc_put_att(fd, varid, name, val)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def nc_put_var_all (fd, varid, val)
|
33
|
+
data_type = NC.ca_type(nc_inq_vartype(fd, varid))
|
34
|
+
dim = (0...nc_inq_varndims(fd, varid)).collect do |dimid|
|
35
|
+
nc_inq_dimlen(fd, dimid)
|
36
|
+
end
|
37
|
+
data = CArray.new(data_type, dim) { val }
|
38
|
+
nc_put_var(fd, varid, data)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
class NCObject
|
44
|
+
|
45
|
+
include NC
|
46
|
+
|
47
|
+
def get_attributes (file_id, var_id)
|
48
|
+
attrs = {}
|
49
|
+
varnatts = nc_inq_varnatts(file_id, var_id)
|
50
|
+
varnatts.times do |i|
|
51
|
+
attname = nc_inq_attname(file_id, var_id, i)
|
52
|
+
value = nc_get_att(file_id, var_id, attname)
|
53
|
+
attrs[attname] = value
|
54
|
+
end
|
55
|
+
return attrs.freeze
|
56
|
+
end
|
57
|
+
|
58
|
+
def attribute (name)
|
59
|
+
return @attributes[name]
|
60
|
+
end
|
61
|
+
|
62
|
+
attr_reader :attributes
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
class NCVar < NCObject
|
67
|
+
|
68
|
+
include NC
|
69
|
+
|
70
|
+
def initialize (ncfile, var_id)
|
71
|
+
@ncfile = ncfile
|
72
|
+
@file_id = ncfile.file_id
|
73
|
+
@var_id = var_id
|
74
|
+
@name = nc_inq_varname(@file_id, var_id)
|
75
|
+
@vartype = nc_inq_vartype(@file_id, var_id)
|
76
|
+
@dims = ncfile.dims.values_at(*nc_inq_vardimid(@file_id, var_id))
|
77
|
+
@shape = @dims.map{|d| d.len}
|
78
|
+
@attributes = get_attributes(@file_id, var_id)
|
79
|
+
@dims.freeze
|
80
|
+
@shape.freeze
|
81
|
+
end
|
82
|
+
|
83
|
+
attr_reader :name, :dims
|
84
|
+
|
85
|
+
def definition
|
86
|
+
{
|
87
|
+
type: @vartype,
|
88
|
+
dims: dims.map{|x| x.name },
|
89
|
+
attributes: @attributes.dup
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
def inspect
|
94
|
+
return "#{@name}#{@dims}"
|
95
|
+
end
|
96
|
+
|
97
|
+
def is_dim?
|
98
|
+
begin
|
99
|
+
nc_inq_dimlen(@file_id, @var_id)
|
100
|
+
return true
|
101
|
+
rescue RuntimeError
|
102
|
+
return false
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def decode (value)
|
107
|
+
if @attributes.has_key?("_FillValue")
|
108
|
+
fill_value = @attributes["_FillValue"]
|
109
|
+
case value
|
110
|
+
when CArray
|
111
|
+
value[:eq, fill_value] = UNDEF
|
112
|
+
else
|
113
|
+
value = UNDEF if value == fill_value
|
114
|
+
end
|
115
|
+
end
|
116
|
+
if @attributes.has_key?("missing_value")
|
117
|
+
missing_values = [@attributes["missing_value"]].flatten
|
118
|
+
missing_values.each do |mv|
|
119
|
+
case value
|
120
|
+
when CArray
|
121
|
+
value[:eq, mv] = UNDEF
|
122
|
+
else
|
123
|
+
if value == mv
|
124
|
+
value = UNDEF
|
125
|
+
break
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
if @attributes.has_key?("scale_factor")
|
131
|
+
value *= @attributes["scale_factor"]
|
132
|
+
end
|
133
|
+
if @attributes.has_key?("add_offset")
|
134
|
+
value += @attributes["add_offset"]
|
135
|
+
end
|
136
|
+
return value
|
137
|
+
end
|
138
|
+
|
139
|
+
def to_ca
|
140
|
+
return self[]
|
141
|
+
end
|
142
|
+
|
143
|
+
def [] (*argv)
|
144
|
+
return get!(*argv)
|
145
|
+
end
|
146
|
+
|
147
|
+
def get (*argv)
|
148
|
+
if argv.size > 0 and argv[0].is_a?(Struct::CAIndexInfo)
|
149
|
+
info = argv.shift
|
150
|
+
else
|
151
|
+
info = CArray.scan_index(@shape, argv)
|
152
|
+
end
|
153
|
+
out = nil
|
154
|
+
case info.type
|
155
|
+
when CA_REG_ADDRESS
|
156
|
+
addr = info.index[0]
|
157
|
+
index = []
|
158
|
+
(0..@shape.size-1).reverse_each do |i|
|
159
|
+
index[i] = addr % @shape[i]
|
160
|
+
addr /= @shape[i]
|
161
|
+
end
|
162
|
+
out = get_var1(*index)
|
163
|
+
when CA_REG_FLATTEN
|
164
|
+
out = get_var[nil]
|
165
|
+
when CA_REG_POINT
|
166
|
+
out = get_var1(*info.index)
|
167
|
+
when CA_REG_ALL
|
168
|
+
out = get_var()
|
169
|
+
when CA_REG_BLOCK
|
170
|
+
start = []
|
171
|
+
count = []
|
172
|
+
stride = []
|
173
|
+
info.index.each do |idx|
|
174
|
+
case idx
|
175
|
+
when Array
|
176
|
+
start << idx[0]
|
177
|
+
count << idx[1]
|
178
|
+
stride << idx[2]
|
179
|
+
else
|
180
|
+
start << idx
|
181
|
+
count << 1
|
182
|
+
stride << 1
|
183
|
+
end
|
184
|
+
end
|
185
|
+
if stride.all?{|x| x == 1 }
|
186
|
+
out = get_vara(start, count)
|
187
|
+
else
|
188
|
+
out = get_vars(start, count, stride)
|
189
|
+
end
|
190
|
+
when CA_REG_SELECT, CA_REG_GRID
|
191
|
+
out = get_var[*argv]
|
192
|
+
else
|
193
|
+
raise "invalid index"
|
194
|
+
end
|
195
|
+
case out
|
196
|
+
when CArray
|
197
|
+
return out.compact
|
198
|
+
else
|
199
|
+
return out
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def get! (*argv)
|
204
|
+
info = CArray.scan_index(@shape, argv)
|
205
|
+
case info.type
|
206
|
+
when CA_REG_METHOD_CALL
|
207
|
+
return decode(get_var)[*argv]
|
208
|
+
else
|
209
|
+
return decode(get(info, *argv))
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def get_var1 (*index)
|
214
|
+
return nc_get_var1(@file_id, @var_id, index)
|
215
|
+
end
|
216
|
+
|
217
|
+
def get_var1! (*index)
|
218
|
+
return decode(get_var1(*index))
|
219
|
+
end
|
220
|
+
|
221
|
+
def get_var ()
|
222
|
+
return nc_get_var(@file_id, @var_id)
|
223
|
+
end
|
224
|
+
|
225
|
+
def get_var! ()
|
226
|
+
return decode(nc_get_var(@file_id, @var_id))
|
227
|
+
end
|
228
|
+
|
229
|
+
def get_vara (start, count)
|
230
|
+
return nc_get_vara(@file_id, @var_id, start, count)
|
231
|
+
end
|
232
|
+
|
233
|
+
def get_vara! (start, count)
|
234
|
+
return decode(nc_get_vara(@file_id, @var_id, start, count))
|
235
|
+
end
|
236
|
+
|
237
|
+
def get_vars (start, count, stride)
|
238
|
+
return nc_get_vars(@file_id, @var_id, start, count, stride)
|
239
|
+
end
|
240
|
+
|
241
|
+
def get_vars! (start, count, stride)
|
242
|
+
return decode(nc_get_vars(@file_id, @var_id, start, count, stride))
|
243
|
+
end
|
244
|
+
|
245
|
+
def get_varm (start, count, stride, imap)
|
246
|
+
return nc_get_varm(@file_id, @var_id, start, count, stride, imap)
|
247
|
+
end
|
248
|
+
|
249
|
+
def get_varm! (start, count, stride, imap)
|
250
|
+
return decode(nc_get_varm(@file_id, @var_id, start, count, stride, imap))
|
251
|
+
end
|
252
|
+
|
253
|
+
end
|
254
|
+
|
255
|
+
class NCDim < NCObject
|
256
|
+
|
257
|
+
include NC
|
258
|
+
|
259
|
+
def initialize (ncfile, dim_id)
|
260
|
+
@ncfile = ncfile
|
261
|
+
@file_id = ncfile.file_id
|
262
|
+
@dim_id = dim_id
|
263
|
+
@name = nc_inq_dimname(@file_id, @dim_id)
|
264
|
+
@len = nc_inq_dimlen(@file_id, @dim_id)
|
265
|
+
end
|
266
|
+
|
267
|
+
attr_reader :name, :len
|
268
|
+
|
269
|
+
def definition
|
270
|
+
return @len
|
271
|
+
end
|
272
|
+
|
273
|
+
def inspect
|
274
|
+
return "#{@name}=#{@len}"
|
275
|
+
end
|
276
|
+
|
277
|
+
def to_i
|
278
|
+
return @len
|
279
|
+
end
|
280
|
+
|
281
|
+
def to_ca
|
282
|
+
return self[]
|
283
|
+
end
|
284
|
+
|
285
|
+
def [] (*argv)
|
286
|
+
return @ncfile[name][*argv]
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|
290
|
+
|
291
|
+
class NCFile < NCObject
|
292
|
+
|
293
|
+
include NC
|
294
|
+
|
295
|
+
def self.open (filename)
|
296
|
+
file_id = NC.open(filename)
|
297
|
+
return NCFile.new(file_id)
|
298
|
+
end
|
299
|
+
|
300
|
+
def initialize (file_id)
|
301
|
+
@file_id = file_id
|
302
|
+
@dims = []
|
303
|
+
@vars = []
|
304
|
+
@name2dim = {}
|
305
|
+
@name2var = {}
|
306
|
+
@attributes = get_attributes(@file_id, NC::NC_GLOBAL)
|
307
|
+
parse_metadata()
|
308
|
+
end
|
309
|
+
|
310
|
+
attr_reader :file_id, :dims, :vars
|
311
|
+
|
312
|
+
def parse_metadata ()
|
313
|
+
ndims = nc_inq_ndims(@file_id)
|
314
|
+
ndims.times do |i|
|
315
|
+
dim = NCDim.new(self, i)
|
316
|
+
@dims[i] = dim
|
317
|
+
@name2dim[dim.name] = dim
|
318
|
+
end
|
319
|
+
@dims.freeze
|
320
|
+
@name2dim.freeze
|
321
|
+
nvars = nc_inq_nvars(@file_id)
|
322
|
+
nvars.times do |i|
|
323
|
+
var = NCVar.new(self, i)
|
324
|
+
@vars[i] = var
|
325
|
+
@name2var[var.name] = var
|
326
|
+
end
|
327
|
+
@vars.freeze
|
328
|
+
@name2var.freeze
|
329
|
+
end
|
330
|
+
|
331
|
+
def definition
|
332
|
+
{
|
333
|
+
dims: @dims.map{|x| [x.name, x.definition] }.to_h,
|
334
|
+
vars: @vars.map{|x| [x.name, x.definition] }.to_h,
|
335
|
+
attributes: @attributes.dup
|
336
|
+
}
|
337
|
+
end
|
338
|
+
|
339
|
+
def [] (name)
|
340
|
+
return @name2var[name]
|
341
|
+
end
|
342
|
+
|
343
|
+
def dim (name)
|
344
|
+
return @name2dim[name]
|
345
|
+
end
|
346
|
+
|
347
|
+
def has_dim?(name)
|
348
|
+
return @name2dim.has_key?(name)
|
349
|
+
end
|
350
|
+
|
351
|
+
def has_var?(name)
|
352
|
+
return @name2var.has_key?(name)
|
353
|
+
end
|
354
|
+
|
355
|
+
end
|
356
|
+
|
357
|
+
class NCFileWriter
|
358
|
+
|
359
|
+
include NC
|
360
|
+
|
361
|
+
class Var
|
362
|
+
|
363
|
+
include NC
|
364
|
+
|
365
|
+
def initialize (ncfile, name, definition)
|
366
|
+
@ncfile = ncfile
|
367
|
+
@file_id = ncfile.file_id
|
368
|
+
@definition = definition
|
369
|
+
@name = name
|
370
|
+
@type = definition[:type]
|
371
|
+
@dims = definition[:dims]
|
372
|
+
@dim_ids = @dims.map{|key| @ncfile.dim(key).dim_id }
|
373
|
+
@shape = @dims.map{|key| @ncfile.dim(key).to_i }
|
374
|
+
@var_id = nc_def_var(@file_id, @name, @type, @dim_ids)
|
375
|
+
@attributes = definition[:attributes].map{|key, value| [key.to_s, value]}.to_h.freeze
|
376
|
+
@attributes.each do |name, value|
|
377
|
+
nc_put_att(@file_id, @var_id, name, value)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
attr_reader :name, :attributes
|
382
|
+
|
383
|
+
def []= (*argv)
|
384
|
+
put(*argv)
|
385
|
+
end
|
386
|
+
|
387
|
+
def put (*argv)
|
388
|
+
value = argv.pop
|
389
|
+
info = CArray.scan_index(@shape, argv)
|
390
|
+
case info.type
|
391
|
+
when CA_REG_ADDRESS
|
392
|
+
addr = info.index[0]
|
393
|
+
index = []
|
394
|
+
(0..@shape.size-1).reverse_each do |i|
|
395
|
+
index[i] = addr % @shape[i]
|
396
|
+
addr /= @shape[i]
|
397
|
+
end
|
398
|
+
put_var1(index, value)
|
399
|
+
when CA_REG_FLATTEN
|
400
|
+
put_var(value)
|
401
|
+
when CA_REG_POINT
|
402
|
+
put_var1(info.index, value)
|
403
|
+
when CA_REG_ALL
|
404
|
+
put_var(value)
|
405
|
+
when CA_REG_BLOCK
|
406
|
+
start = []
|
407
|
+
count = []
|
408
|
+
stride = []
|
409
|
+
info.index.each do |idx|
|
410
|
+
case idx
|
411
|
+
when Array
|
412
|
+
start << idx[0]
|
413
|
+
count << idx[1]
|
414
|
+
stride << idx[2]
|
415
|
+
else
|
416
|
+
start << idx
|
417
|
+
count << 1
|
418
|
+
stride << 1
|
419
|
+
end
|
420
|
+
end
|
421
|
+
if stride.all?{|x| x == 1 }
|
422
|
+
put_vara(start, count, value)
|
423
|
+
else
|
424
|
+
put_vars(start, count, stride, value)
|
425
|
+
end
|
426
|
+
else
|
427
|
+
raise "invalid index"
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
def put_var1 (index, value)
|
432
|
+
return nc_put_var1(@file_id, @var_id, index, value)
|
433
|
+
end
|
434
|
+
|
435
|
+
def put_var (value)
|
436
|
+
return nc_put_var(@file_id, @var_id, value)
|
437
|
+
end
|
438
|
+
|
439
|
+
def put_vara (start, count, value)
|
440
|
+
return nc_put_vara(@file_id, @var_id, start, count, value)
|
441
|
+
end
|
442
|
+
|
443
|
+
def put_vars (start, count, stride, value)
|
444
|
+
return nc_put_vars(@file_id, @var_id, start, count, stride, value)
|
445
|
+
end
|
446
|
+
|
447
|
+
def get_varm (start, count, stride, imap, value)
|
448
|
+
return nc_put_varm(@file_id, @var_id, start, count, stride, imap, value)
|
449
|
+
end
|
450
|
+
|
451
|
+
|
452
|
+
end
|
453
|
+
|
454
|
+
class Dim
|
455
|
+
|
456
|
+
include NC
|
457
|
+
|
458
|
+
def initialize (ncfile, name, len)
|
459
|
+
@ncfile = ncfile
|
460
|
+
@file_id = ncfile.file_id
|
461
|
+
@name = name
|
462
|
+
@len = len
|
463
|
+
@dim_id = nc_def_dim(@file_id, @name, @len)
|
464
|
+
end
|
465
|
+
|
466
|
+
attr_reader :name, :dim_id
|
467
|
+
|
468
|
+
def to_i
|
469
|
+
return @len
|
470
|
+
end
|
471
|
+
|
472
|
+
end
|
473
|
+
|
474
|
+
def initialize (file)
|
475
|
+
@file_id = nc_create(file)
|
476
|
+
@dims = []
|
477
|
+
@name2dim = {}
|
478
|
+
@vars = []
|
479
|
+
@name2var = {}
|
480
|
+
@attributes = nil
|
481
|
+
end
|
482
|
+
|
483
|
+
attr_reader :file_id
|
484
|
+
|
485
|
+
def define (definition)
|
486
|
+
definition[:dims].each do |name, len|
|
487
|
+
dim = Dim.new(self, name.to_s, len.to_i)
|
488
|
+
@dims.push dim
|
489
|
+
@name2dim[name.to_s] = dim
|
490
|
+
end
|
491
|
+
definition[:vars].each do |name, info|
|
492
|
+
var = Var.new(self, name.to_s, info)
|
493
|
+
@vars.push var
|
494
|
+
@name2var[name.to_s] = var
|
495
|
+
end
|
496
|
+
@attributes = definition[:attributes].map{|key, value| [key.to_s, value]}.to_h.freeze
|
497
|
+
@attributes.each do |name, value|
|
498
|
+
nc_put_att(@file_id, NC_GLOBAL, name, value)
|
499
|
+
end
|
500
|
+
nc_enddef(@file_id)
|
501
|
+
end
|
502
|
+
|
503
|
+
def copy_dims (nc, name = nil)
|
504
|
+
if name
|
505
|
+
if @name2dim.has_key?(name) and @name2var.has_key?(name)
|
506
|
+
@name2var[name].put(nc[name].get)
|
507
|
+
end
|
508
|
+
else
|
509
|
+
nc.dims.each do |dim|
|
510
|
+
if @name2dim.has_key?(dim.name) and @name2var.has_key?(dim.name)
|
511
|
+
@name2var[dim.name].put(nc[dim.name].get)
|
512
|
+
end
|
513
|
+
end
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
def dim (name)
|
518
|
+
return @name2dim[name]
|
519
|
+
end
|
520
|
+
|
521
|
+
def [] (name)
|
522
|
+
return @name2var[name]
|
523
|
+
end
|
524
|
+
|
525
|
+
def []= (name, value)
|
526
|
+
return @name2var[name].put(value)
|
527
|
+
end
|
528
|
+
|
529
|
+
def close
|
530
|
+
nc_close(@file_id)
|
531
|
+
end
|
532
|
+
|
533
|
+
end
|