carray-netcdf 1.0.1 → 1.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 42bc2741ed1cb9934d9920bb3c27ae63a67d64cc
4
- data.tar.gz: cb002d9c44eeb1ae1b21a82676e23994a99744d5
2
+ SHA256:
3
+ metadata.gz: d5cff7f2cb0bb02ab816789ac1e1a6e068f0aea38d0769badc5da009716f47bc
4
+ data.tar.gz: c157b4c60c74ce53571340ee9c6f933f518aba41e3aabb3d333c0861fddd78e5
5
5
  SHA512:
6
- metadata.gz: 5835fce18272746e19bed82b402f541c9051269b1f7162e5a0742235e1a652165ef0c1cf6899b16b3e8caf315f2f9af739cc2d7f59df3f98ab1e75eb558a7e98
7
- data.tar.gz: 0e597194080519c77cbc8906feeb6f11db456e3d04c65595ab266003c92019453519aebd90e1afbb072c9374ce46c054a0e5afaa5a6091218ad422c9ed39baf3
6
+ metadata.gz: 8843d604eb32cd7e89e206ff4fdc08881172a8e1d5cf1b31b2cf4724c9ef5f41dd4b7cad5de631a80945670d757dd27b68b700dccb6e9ee491fc7d478956978a
7
+ data.tar.gz: f97a3893d3399ae4f23e61ae22e2536570ee87aa731bc40a6e39e827ff9a3fa572517ddf870234872c68cc88c58b33466e59c4ca6b3efe33398983b7882e8580
data/API.md CHANGED
@@ -5,7 +5,7 @@ CArray/NetCDF library API document
5
5
  ------------------
6
6
 
7
7
  gem install carray-netcdf
8
-
8
+
9
9
  require "carray-netcdf"
10
10
 
11
11
  2. Methods
@@ -15,7 +15,7 @@ This API provides the way of calling functions
15
15
 
16
16
  include NC
17
17
  nc_funcname(...)
18
-
18
+
19
19
  NC.funcname(...)
20
20
 
21
21
  ### 2.1. Data types
@@ -30,27 +30,27 @@ This API provides the way of calling functions
30
30
  mode : NC_CLOBBER - permit overwrite
31
31
  NC_NOCLOBBER - inhibit overwrite
32
32
  NC_SHARE - no buffering
33
-
33
+
34
34
  fd = nc_open(FILENAME[, mode=NC_NOWRITE])
35
35
 
36
36
  mode : NC_NOWRITE - readonly
37
37
  NC_WRTIE - writable
38
38
  NC_SHARE - no buffering
39
-
39
+
40
40
  nc_close(fd)
41
-
41
+
42
42
  nc_redef(fd)
43
43
  nc_enddef(fd)
44
-
44
+
45
45
  nc_sync(fd)
46
-
46
+
47
47
  ndims = nc_inq_ndims(fd)
48
48
  nvars = nc_inq_nvars(fd)
49
49
  natts = nc_inq_natts(fd)
50
50
  unlimdim = nc_inq_unlimdim(fd)
51
-
51
+
52
52
  oldmode = nc_set_fill(mode)
53
-
53
+
54
54
  mode : NC_FILL
55
55
  NC_NOFILL
56
56
 
@@ -58,73 +58,73 @@ This API provides the way of calling functions
58
58
 
59
59
  dimid = nc_def_dim(fd, dimname, len)
60
60
  dimid = nc_inq_dimid(fd, dimname) => Integer | nil
61
-
61
+
62
62
  dimname = nc_inq_dimname(fd, dimid)
63
63
  dimlen = nc_inq_dimlen(fd, dimid)
64
-
64
+
65
65
  nc_rename_dim(fd, dimid, newname)
66
66
 
67
67
  ### 2.4. NetCDF Variable
68
68
 
69
69
  varid = nc_def_var(fd, varname, type, dim)
70
70
  varid = nc_inq_varid(fd, varname) => Integer | nil
71
-
71
+
72
72
  vartype = nc_inq_vartype(fd, varid)
73
73
  varndims = nc_inq_varndims(fd, varid)
74
74
  vardimid = nc_inq_varndimid(fd, varid) => Array of dimids
75
-
75
+
76
76
  nc_put_var1(fd, varid, [i,j,..], val)
77
77
  nc_put_var(fd, varid, ca)
78
78
  nc_put_vara(fd, varid, start, count, ca)
79
79
  nc_put_vars(fd, varid, start, count, stride, ca)
80
80
  nc_put_varm(fd, varid, start, count, stride, imap, ca)
81
-
81
+
82
82
  + with data_type conversion
83
-
83
+
84
84
  val = nc_get_var1(fd, varid, [i,j,..])
85
85
  ca = nc_get_var(fd, varid) [useful]
86
86
  ca = nc_get_vara(fd, varid, start, count) [useful]
87
87
  ca = nc_get_vars(fd, varid, start, count, stride) [useful]
88
88
  ca = nc_get_varm(fd, varid, start, count, stride, imap) [useful]
89
-
89
+
90
90
  + no data_type conversion
91
-
91
+
92
92
  nc_get_var(fd, varid, ca) [pedantic]
93
93
  nc_get_vara(fd, varid, start, count, ca) [pedantic]
94
94
  nc_get_vars(fd, varid, start, count, stride, ca) [pedantic]
95
95
  nc_get_varm(fd, varid, start, count, stride, imap, ca) [pedantic]
96
-
96
+
97
97
  + with data_type conversion.
98
-
98
+
99
99
  nc_rename_var(fd, varid, newname)
100
100
 
101
101
  ### 2.5. NetCDF Attribute
102
102
 
103
103
  varnatts = nc_inq_varnatts(fd, varid)
104
104
  attid = nc_inq_attid(fd, varid, attname)
105
-
105
+
106
106
  attname = nc_inq_attname(fd, varid, attid)
107
107
  atttype = nc_inq_atttype(fd, varid, attname)
108
108
  attlen = nc_inq_attlen(fd, varid, attname)
109
-
109
+
110
110
  nc_put_att(fd, varid, attname, val)
111
-
111
+
112
112
  varid : NC_GLOBAL for global att
113
113
  val : String -> NC_CHAR
114
114
  Integer -> NC_INT
115
115
  Float -> NC_DOUBLE
116
116
  CArray -> NC.nc_type(val.data_type)
117
-
118
-
117
+
118
+
119
119
  val = nc_get_att(fd, varid, attname) => String | Numeric | CArray | nil
120
-
120
+
121
121
  varid : NC_GLOBAL for global att
122
-
122
+
123
123
  nc_get_att(fd, varid, attname, ca) [pedantic]
124
-
124
+
125
125
  nc_rename_att(fd, varid, attname, newname)
126
126
  nc_del_att(fd, varid, attname)
127
-
127
+
128
128
  nc_copy_att(fd1, varid1, attname, fd2, varid2)
129
129
 
130
130
  ### 2.6 Constants
@@ -135,24 +135,24 @@ This API provides the way of calling functions
135
135
  NC_INT
136
136
  NC_FLOAT
137
137
  NC_DOUBLE
138
-
138
+
139
139
  NC_NOERR - status of API routines
140
-
140
+
141
141
  NC_CLOBBER - permit overwrite [nc_create]
142
142
  NC_NOCLOBBER - inhibit overwrite [nc_create]
143
143
  NC_NOWRITE - readonly [nc_open]
144
144
  NC_WRITE - writable [nc_open]
145
145
  NC_SHARE - no buffering [nc_create, nc_open]
146
-
146
+
147
147
  NC_GLOBAL - varid for global attributes
148
-
148
+
149
149
  NC_NOFILL - nc_set_fill(fd, varid, NC_NOFILL)
150
150
  NC_FILL - nc_set_fill(fd, varid, NC_FILL)
151
-
151
+
152
152
  NC_MAX_NAME
153
153
  NC_MAX_VAR_DIMS
154
154
  NC_MAX_DIMS
155
-
155
+
156
156
  NC_LOCK - ???
157
157
  NC_SIZEHINT_DEFAULT - ???
158
158
 
@@ -164,7 +164,7 @@ NCFile interface provides the way of *READ-ONLY* access to the netcdf file.
164
164
  ### 3.1. NCFile
165
165
 
166
166
  nc = NCFile.open(FILENAME)
167
-
167
+
168
168
  nc = NCFile.new(file_id)
169
169
  file_id: return value of nc_open in read-only mode
170
170
 
@@ -172,7 +172,7 @@ NCFile interface provides the way of *READ-ONLY* access to the netcdf file.
172
172
 
173
173
  nc.has_dim?(DIMNAME)
174
174
  nc.dims - Array of dimension
175
-
175
+
176
176
  dim = nc.dim(DIMNAME) - NCDim object or nil
177
177
  dim.to_i - size of dimension
178
178
  dim.to_ca
@@ -181,14 +181,14 @@ NCFile interface provides the way of *READ-ONLY* access to the netcdf file.
181
181
 
182
182
  nc.has_var?(VARNAME)
183
183
  nc.vars - Array of variables
184
-
184
+
185
185
  var = nc.var(VARNAME) - NCVar object or nil
186
186
  var.is_dim? - true if dimension variable
187
187
  var.to_ca - get array as CArray object
188
188
  var[...] - Cooked value array with CArray-like indexing
189
189
  var.get!(...) - same as [...]
190
190
  var.get(...) - Non-cooked value array with CArray-like indexing
191
-
191
+
192
192
  var.get_var1(...) - interface to original get function
193
193
  var.get_var()
194
194
  var.get_vara(start, count)
@@ -207,7 +207,7 @@ All attributes are already read in initializing process of NCFile object.
207
207
  nc.attributes - Hash
208
208
  dim.attributes
209
209
  var.attributes
210
-
210
+
211
211
  nc.attribute(ATTNAME) - accessor
212
212
  dim.attribute(ATTNAME)
213
213
  var.attribute(ATTNAME)
@@ -230,41 +230,34 @@ It provides simple interface to create netcdf file.
230
230
  If you want the detailed controling to create netcdf, use nc_function API.
231
231
 
232
232
  out = NCFileWrite.new("test.nc")
233
-
233
+
234
234
  out.define(
235
- dims: { ### dimension
236
- lon: 230, name: Integer
235
+ dimensions: { ### dimension
236
+ lon: 230, ### name: Integer
237
237
  lat: 120,
238
238
  time: 24
239
239
  },
240
- vars: { ### variables
240
+ variables: { ### variables
241
241
  temp: { name: definition
242
- type: NC::NC_FLOAT, type: Integer
243
- dims: ["time", "lat", "lon"], dims: Array of dim names
244
- attributes: { attributes: Hash
245
- long_name: "air temperature",
246
- units: "degC"
247
- }
242
+ type: int, type: Integer or string (default NC::NC_FLOAT)
243
+ one of byte,short,int,float,double
244
+ dim: ["time", "lat", "lon"], dim: Array of dim names
245
+ long_name: "air temperature", attributes for variable are parallel with type, dim
246
+ units: "degC"
247
+ param1: { float: 1.2 }
248
+ param2: { int: 10 }
248
249
  }
249
250
  },
250
- attributes: { ### global attributes (Hash)
251
- creator: "foobar"
251
+ attributes: {
252
+ creator: "foobar" ### global attributes (Hash)
252
253
  }
253
254
  )
254
-
255
+
255
256
  out["lon"] = lon
256
257
  out["lat"] = lat
257
258
  out["time"] = time
258
259
  out["temp"][nil] = temp ### CArray index can be used
259
260
  out.write ### call nc_close
260
-
261
-
261
+
262
262
  nc = NCFile.open("test.nc")
263
263
  nc.definition ### return definition Hash
264
-
265
-
266
-
267
-
268
-
269
-
270
-
@@ -1,6 +1,6 @@
1
1
 
2
2
  Gem::Specification::new do |s|
3
- version = "1.0.1"
3
+ version = "1.0.2"
4
4
 
5
5
  files = Dir.glob("**/*") - [
6
6
  Dir.glob("carray-*.gem"),
data/examples/test.nc CHANGED
Binary file
data/examples/test.rb CHANGED
@@ -1 +1,41 @@
1
- require "carray-netcdf"
1
+ require "carray"
2
+ require "time"
3
+ require "yaml"
4
+ require "carray-netcdf"
5
+
6
+ metadata = YAML.load %{
7
+ dimensions:
8
+ time: 1440
9
+ variables:
10
+ time:
11
+ type: float
12
+ dim: [time]
13
+ standard_name: time
14
+ long_name: time
15
+ units: minutes since 2018-01-01 00:00:00 +09:00
16
+ }
17
+
18
+ out = NCFileWriter.new("test.nc", compression: 1)
19
+ out.define metadata
20
+
21
+ out["time"] = CArray.float(1440).seq(1)
22
+
23
+ out.close
24
+
25
+ nc = NCFile.open("test.nc")
26
+
27
+ time = nc["time"].to_time
28
+
29
+ p time[0].to_s
30
+
31
+ y = CArray.float(1440).seq(0,4*Math::PI/1440).sin
32
+
33
+ #timezone = "UTC"
34
+ timezone = ""
35
+
36
+ CA.gnuplot {
37
+ plot [time(time,"UTC"), y],
38
+ xtime: true,
39
+ x: ["Time (UTC)", nil, "%H:%M"]
40
+ }
41
+
data/examples/time.rb ADDED
@@ -0,0 +1,11 @@
1
+ require "time"
2
+ require "date"
3
+
4
+ t1 = Time.parse("2018-01-01 00:00:00 +08")
5
+ t2 = Time.parse("2018-01-01 00:00:00 UTC")
6
+ t3 = DateTime.parse("2018-01-01 00:00:00 ADT")
7
+
8
+ p t1.zone
9
+ p t2
10
+ p t3.to_time.gmt_offset
11
+
data/lib/io/netcdf.rb CHANGED
@@ -54,6 +54,25 @@ class NCObject
54
54
  end
55
55
  return attrs.freeze
56
56
  end
57
+
58
+ def get_attributes! (file_id, var_id)
59
+ attrs = {}
60
+ varnatts = nc_inq_varnatts(file_id, var_id)
61
+ varnatts.times do |i|
62
+ attname = nc_inq_attname(file_id, var_id, i)
63
+ type = nc_inq_atttype(file_id, var_id, attname)
64
+ case type
65
+ when NC_CHAR
66
+ value = nc_get_att(file_id, var_id, attname)
67
+ else
68
+ len = nc_inq_attlen(file_id, var_id, attname)
69
+ value = CArray.new(NC.ca_type(type), [len])
70
+ nc_get_att(file_id, var_id, attname, value)
71
+ end
72
+ attrs[attname] = value
73
+ end
74
+ return attrs.freeze
75
+ end
57
76
 
58
77
  def attribute (name)
59
78
  return @attributes[name]
@@ -67,6 +86,15 @@ class NCVar < NCObject
67
86
 
68
87
  include NC
69
88
 
89
+ TYPENAME = {
90
+ NC_CHAR => "char",
91
+ NC_BYTE => "byte",
92
+ NC_SHORT => "short",
93
+ NC_INT => "int",
94
+ NC_FLOAT => "float",
95
+ NC_DOUBLE => "double",
96
+ }
97
+
70
98
  def initialize (ncfile, var_id)
71
99
  @ncfile = ncfile
72
100
  @file_id = ncfile.file_id
@@ -79,14 +107,20 @@ class NCVar < NCObject
79
107
  @dims.freeze
80
108
  @shape.freeze
81
109
  end
82
-
110
+
83
111
  attr_reader :name, :dims
84
112
 
85
113
  def definition
86
- {
87
- type: @vartype,
88
- dim: dims.map{|x| x.name }
89
- }.update(@attributes)
114
+ defs = { "type" => TYPENAME[@vartype] }
115
+ if not dims.empty?
116
+ defs["dim"] = dims.map{|x| x.name }
117
+ end
118
+ atts = {}
119
+ get_attributes!(@file_id, @var_id).each do |k,v|
120
+ atts[k] = NCFile.convert_attribute_value(v)
121
+ end
122
+ defs.update(atts)
123
+ return defs
90
124
  end
91
125
 
92
126
  def inspect
@@ -139,6 +173,40 @@ class NCVar < NCObject
139
173
  return self[]
140
174
  end
141
175
 
176
+ TIME_UNITS = {
177
+ "day" => 86400,
178
+ "days" => 86400,
179
+ "d" => 86400,
180
+ "hour" => 3600,
181
+ "hours" => 3600,
182
+ "hr" => 3600,
183
+ "h" => 3600,
184
+ "minute" => 60,
185
+ "minutes" => 60,
186
+ "min" => 60,
187
+ "second" => 1,
188
+ "seconds" => 1,
189
+ "sec" => 1,
190
+ "s" => 1,
191
+ }
192
+
193
+ def to_time
194
+
195
+ if not @attributes.has_key?("units")
196
+ raise "variable #{@name} has no attribute 'units'"
197
+ elsif @attributes["units"] =~ /\A(.+?)\s+since\s+(.+)\Z/
198
+ interval = TIME_UNITS[$1]
199
+ basetime = Time.parse($2)
200
+ if interval
201
+ return self[].convert(:object) {|x| basetime + interval*x }
202
+ else
203
+ raise "#{$1} is invalid for time units"
204
+ end
205
+ else
206
+ raise "format of #{@name}:units is not valid for time"
207
+ end
208
+ end
209
+
142
210
  def [] (*argv)
143
211
  return get!(*argv)
144
212
  end
@@ -327,11 +395,54 @@ class NCFile < NCObject
327
395
  @name2var.freeze
328
396
  end
329
397
 
398
+ def self.convert_attribute_value (value)
399
+ case value
400
+ when CArray
401
+ if value.length == 1
402
+ case value.data_type
403
+ when CA_UINT8
404
+ value = { "char" => value[0] }
405
+ when CA_BYTE
406
+ value = { "byte" => value[0] }
407
+ when CA_SHORT
408
+ value = { "short" => value[0] }
409
+ when CA_INT
410
+ value = { "int" => value[0] }
411
+ when CA_FLOAT
412
+ value = { "float" => value[0] }
413
+ when CA_DOUBLE
414
+ value = { "double" => value[0] }
415
+ end
416
+ else
417
+ case value.data_type
418
+ when CA_UINT8
419
+ value = { "char" => value.to_a }
420
+ when CA_BYTE
421
+ value = { "byte" => value.to_a }
422
+ when CA_SHORT
423
+ value = { "short" => value.to_a }
424
+ when CA_INT
425
+ value = { "int" => value.to_a }
426
+ when CA_FLOAT
427
+ value = { "float" => value.to_a }
428
+ when CA_DOUBLE
429
+ value = { "double" => value.to_a }
430
+ end
431
+ end
432
+ end
433
+ return value
434
+ end
435
+
330
436
  def definition
437
+ atts = {}
438
+ get_attributes!(@file_id, NC_GLOBAL).each do |k,v|
439
+ atts[k] = NCFile.convert_attribute_value(v)
440
+ end
331
441
  {
332
- dimensions: @dims.map{|x| [x.name, x.definition] }.to_h,
333
- variables: @vars.map{|x| [x.name, x.definition] }.to_h
334
- }.update(@attributes)
442
+ "dimensions" => @dims.map{|x| [x.name, x.definition] }.to_h,
443
+ "variables" => @vars.map{|x| [x.name, x.definition] }.to_h,
444
+ "attributes" => atts
445
+ }
335
446
  end
336
447
 
337
448
  def [] (name)
@@ -360,20 +471,48 @@ class NCFileWriter
360
471
 
361
472
  include NC
362
473
 
363
- def initialize (ncfile, name, definition)
474
+ TYPEMAP = {
475
+ "char" => NC_CHAR,
476
+ "byte" => NC_BYTE,
477
+ "short" => NC_SHORT,
478
+ "int" => NC_INT,
479
+ "float" => NC_FLOAT,
480
+ "double" => NC_DOUBLE,
481
+ }
482
+
483
+ def initialize (ncfile, name, definition, compression = 0)
364
484
  @ncfile = ncfile
365
485
  @file_id = ncfile.file_id
366
486
  @name = name
367
487
  @type = definition["type"] || NC_FLOAT
488
+ if @type.is_a?(String)
489
+ if TYPEMAP.include?(@type)
490
+ @type = TYPEMAP[@type]
491
+ else
492
+ raise "invalid variable data type"
493
+ end
494
+ end
368
495
  @dims = definition["dim"]
369
- @shape = @dims.map{|key| @ncfile.dim(key).to_i }
370
- dim_ids = @dims.map{|key| @ncfile.dim(key).dim_id }
496
+ if @dims
497
+ @shape = @dims.map{|key| @ncfile.dim(key).to_i }
498
+ dim_ids = @dims.map{|key| @ncfile.dim(key).dim_id }
499
+ else
500
+ dim_ids = []
501
+ end
371
502
  @var_id = nc_def_var(@file_id, @name, @type, dim_ids)
503
+ if compression != 0
504
+ nc_def_var_deflate(@file_id, @var_id, 1, 1, compression)
505
+ end
372
506
  @attributes = definition.dup
373
507
  @attributes.delete("type")
374
508
  @attributes.delete("dim")
375
509
  @attributes.each do |name, value|
376
- nc_put_att(@file_id, @var_id, name, value)
510
+ value = NCFileWriter.convert_attribute_value(value)
511
+ begin
512
+ nc_put_att(@file_id, @var_id, name, value)
513
+ rescue => e
514
+ raise(e.class, e.message + " {#{name}: #{value}}")
515
+ end
377
516
  end
378
517
  @attributes.freeze
379
518
  end
@@ -471,17 +610,32 @@ class NCFileWriter
471
610
 
472
611
  end
473
612
 
474
- def initialize (file)
475
- @file_id = nc_create(file)
613
+ TYPEMAP = {
614
+ "char" => NC_CHAR,
615
+ "byte" => NC_BYTE,
616
+ "short" => NC_SHORT,
617
+ "int" => NC_INT,
618
+ "float" => NC_FLOAT,
619
+ "double" => NC_DOUBLE,
620
+ }
621
+
622
+ def initialize (file, mode = 0, compression: 0)
623
+ if compression > 0
624
+ @file_id = nc_create(file, mode|NC_NETCDF4)
625
+ else
626
+ @file_id = nc_create(file, mode)
627
+ end
476
628
  @dims = []
477
629
  @name2dim = {}
478
630
  @vars = []
479
631
  @name2var = {}
632
+ @compression = compression
480
633
  @attributes = nil
481
634
  end
482
635
 
483
636
  attr_reader :file_id
484
637
 
638
+ # key of Hash in definition should be String
485
639
  def normalize_definition (definition)
486
640
  out = {}
487
641
  definition.each do |key, value|
@@ -492,43 +646,99 @@ class NCFileWriter
492
646
  end
493
647
  return out
494
648
  end
495
-
649
+
650
+ def check_definition (definition)
651
+ if definition.has_key?("dimensions")
652
+ dim_keys = definition["dimensions"].keys
653
+ else
654
+ raise "NetCDF definition shoud have 'dimensions' entry"
655
+ end
656
+ if definition.has_key?("variables")
657
+ definition["variables"].each do |name, var_def|
658
+ unless var_def.has_key?("type")
659
+ warn "NetCDF Variable '#{name}' does not have 'type' entry in definition"
660
+ else
661
+ unless ["char","byte","short","int","float","double"].include?(var_def["type"])
662
+ raise "invalid type of NetCDF Variable '#{name}'"
663
+ end
664
+ end
665
+ unless var_def.has_key?("dim")
666
+ warn "NetCDF Variable '#{name}' does not have 'dim' entry in definition"
667
+ else
668
+ unless var_def["dim"].is_a?(Array)
669
+ raise "'dim' of NetCDF Variable '#{name}' should be an Array"
670
+ else
671
+ var_def["dim"].each do |dim|
672
+ unless dim_keys.include?(dim)
673
+ raise "invalid dimension '#{dim}' for NetCDF Variable '#{name}'"
674
+ end
675
+ end
676
+ end
677
+ end
678
+ var_def.each do |k, v|
679
+ case v
680
+ when Hash
681
+ if v.size > 1 or not ["byte","short","int","float","double"].include?(v.keys[0])
682
+ raise "invalid specification in attribute '#{k}' for NetCDF Variable '#{name}'"
683
+ end
684
+ end
685
+ end
686
+ end
687
+ end
688
+ end
689
+
690
+ def self.convert_attribute_value (value)
691
+ case value
692
+ when Hash
693
+ type, value = *value.first
694
+ case type
695
+ when "char"
696
+ value = CA_UINT8(value)
697
+ when "byte"
698
+ value = CA_BYTE(value)
699
+ when "short"
700
+ value = CA_SHORT(value)
701
+ when "int"
702
+ value = CA_INT(value)
703
+ when "float"
704
+ value = CA_FLOAT(value)
705
+ when "double"
706
+ value = CA_DOUBLE(value)
707
+ end
708
+ end
709
+ return value
710
+ end
711
+
496
712
  def define (definition)
497
713
  definition = normalize_definition(definition)
714
+ check_definition(definition)
498
715
  definition["dimensions"].each do |name, len|
499
716
  dim = Dim.new(self, name, len.to_i)
500
717
  @dims.push dim
501
718
  @name2dim[name] = dim
502
719
  end
503
720
  definition["variables"].each do |name, info|
504
- var = Var.new(self, name, info)
721
+ var = Var.new(self, name, info, @compression)
505
722
  @vars.push var
506
723
  @name2var[name] = var
507
724
  end
508
- @attributes = definition.dup
509
- @attributes.delete("dimensions")
510
- @attributes.delete("variables")
511
- @attributes.each do |name, value|
512
- nc_put_att(@file_id, NC_GLOBAL, name, value)
513
- end
514
- @attributes.freeze
515
- nc_enddef(@file_id)
516
- end
517
-
518
- def copy_dims (nc, name = nil)
519
- if name
520
- if @name2dim.has_key?(name) and @name2var.has_key?(name)
521
- @name2var[name].put(nc[name].get)
522
- end
523
- else
524
- nc.dims.each do |dim|
525
- if @name2dim.has_key?(dim.name) and @name2var.has_key?(dim.name)
526
- @name2var[dim.name].put(nc[dim.name].get)
725
+ if definition.has_key?("attributes")
726
+ @attributes = definition["attributes"]
727
+ @attributes.each do |name, value|
728
+ value = NCFileWriter.convert_attribute_value(value)
729
+ begin
730
+ nc_put_att(@file_id, NC_GLOBAL, name, value)
731
+ rescue => e
732
+ raise(e.class, e.error_message + " {#{name}: #{value}}")
527
733
  end
528
734
  end
735
+ @attributes.freeze
736
+ else
737
+ @attributes = {}.freeze
529
738
  end
739
+ nc_enddef(@file_id)
530
740
  end
531
-
741
+
532
742
  def dim (name)
533
743
  return @name2dim[name]
534
744
  end
@@ -545,4 +755,36 @@ class NCFileWriter
545
755
  nc_close(@file_id)
546
756
  end
547
757
 
548
- end
758
+ end
759
+
760
+ class NCFileWriter
761
+
762
+ def self.scaled_integer (type, value)
763
+ min, max = value.min, value.max
764
+ case type
765
+ when :short
766
+ short_max = (0x7fff-1).to_f
767
+ fillvalue = CA_SHORT(0x7fff+1)[0]
768
+ scale_factor = (max - min)/short_max
769
+ add_offset = min + short_max*scale_factor
770
+ packed = ((value - add_offset)/scale_factor).short
771
+ when :int
772
+ int_max = (0x7fffffff-1).to_f
773
+ fillvalue = CA_INT(0x7fffffff+1)[0]
774
+ scale_factor = (max - min)/int_max
775
+ add_offset = min + int_max*scale_factor
776
+ packed = ((value - add_offset)/scale_factor).int
777
+ else
778
+ raise
779
+ end
780
+ packed.attribute["scale_factor"] = scale_factor
781
+ packed.attribute["add_offset"] = add_offset
782
+ if value.has_mask?
783
+ packed[:is_masked] = fillvalue
784
+ packed.attribute["_FillValue"] = fillvalue
785
+ end
786
+ return packed
787
+ end
788
+
789
+ end
790
+
data/rb_netcdflib.c CHANGED
@@ -559,6 +559,51 @@ rb_nc_def_var (int argc, VALUE *argv, VALUE mod)
559
559
  return LONG2NUM(varid);
560
560
  }
561
561
 
562
+ static VALUE
563
+ rb_nc_def_var_deflate (int argc, VALUE *argv, VALUE mod)
564
+ {
565
+ int status;
566
+
567
+ CHECK_ARGC(5);
568
+ CHECK_TYPE_ID(argv[0]);
569
+ CHECK_TYPE_ID(argv[1]);
570
+ CHECK_TYPE_INT(argv[2]);
571
+ CHECK_TYPE_INT(argv[3]);
572
+ CHECK_TYPE_INT(argv[4]);
573
+
574
+ status = nc_def_var_deflate(NUM2LONG(argv[0]), NUM2LONG(argv[1]),
575
+ NUM2LONG(argv[2]), NUM2LONG(argv[3]), NUM2LONG(argv[4]));
576
+
577
+
578
+ CHECK_STATUS(status);
579
+
580
+ return Qnil;
581
+ }
582
+
583
+ static VALUE
584
+ rb_nc_inq_var_deflate (int argc, VALUE *argv, VALUE mod)
585
+ {
586
+ volatile VALUE retval;
587
+ int shuffle, deflate, deflate_level;
588
+ int status;
589
+
590
+ CHECK_ARGC(2);
591
+ CHECK_TYPE_ID(argv[0]); /* nc_id */
592
+ CHECK_TYPE_ID(argv[1]); /* var_id */
593
+
594
+ status = nc_inq_var_deflate(NUM2LONG(argv[0]), NUM2LONG(argv[1]),
595
+ &shuffle, &deflate, &deflate_level);
596
+
597
+ CHECK_STATUS(status);
598
+
599
+ retval = rb_ary_new();
600
+ rb_ary_store(retval, 0, ULONG2NUM(shuffle));
601
+ rb_ary_store(retval, 1, ULONG2NUM(deflate));
602
+ rb_ary_store(retval, 2, ULONG2NUM(deflate_level));
603
+
604
+ return retval;
605
+ }
606
+
562
607
 
563
608
  static VALUE
564
609
  rb_nc_del_att (int argc, VALUE *argv, VALUE mod)
@@ -1847,6 +1892,12 @@ Init_netcdflib ()
1847
1892
  rb_define_singleton_method(mNetCDF, "def_dim", rb_nc_def_dim, -1);
1848
1893
  rb_define_module_function(mNetCDF, "nc_def_var", rb_nc_def_var, -1);
1849
1894
  rb_define_singleton_method(mNetCDF, "def_var", rb_nc_def_var, -1);
1895
+
1896
+ rb_define_module_function(mNetCDF, "nc_def_var_deflate", rb_nc_def_var_deflate, -1);
1897
+ rb_define_singleton_method(mNetCDF, "def_var_deflate", rb_nc_def_var_deflate, -1);
1898
+ rb_define_module_function(mNetCDF, "nc_inq_var_deflate", rb_nc_inq_var_deflate, -1);
1899
+ rb_define_singleton_method(mNetCDF, "inq_var_deflate", rb_nc_inq_var_deflate, -1);
1900
+
1850
1901
  rb_define_module_function(mNetCDF, "nc_rename_dim", rb_nc_rename_dim, -1);
1851
1902
  rb_define_singleton_method(mNetCDF, "rename_dim", rb_nc_rename_dim, -1);
1852
1903
  rb_define_module_function(mNetCDF, "nc_rename_var", rb_nc_rename_var, -1);
@@ -1894,6 +1945,8 @@ Init_netcdflib ()
1894
1945
  rb_define_const(mNetCDF, "NC_LOCK", INT2FIX(NC_LOCK));
1895
1946
  rb_define_const(mNetCDF, "NC_CLOBBER", INT2FIX(NC_CLOBBER));
1896
1947
  rb_define_const(mNetCDF, "NC_NOCLOBBER", INT2FIX(NC_NOCLOBBER));
1948
+ rb_define_const(mNetCDF, "NC_NETCDF4", INT2FIX(NC_NETCDF4));
1949
+ rb_define_const(mNetCDF, "NC_CLASSIC_MODEL", INT2FIX(NC_CLASSIC_MODEL));
1897
1950
  rb_define_const(mNetCDF, "NC_SIZEHINT_DEFAULT", INT2FIX(NC_SIZEHINT_DEFAULT));
1898
1951
 
1899
1952
  rb_define_const(mNetCDF, "NC_GLOBAL", INT2FIX(NC_GLOBAL));
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carray-netcdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hiroki Motoyoshi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-04 00:00:00.000000000 Z
11
+ date: 2018-11-27 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: " Extension for manipulating NetCDF3 file with CArray\n"
14
14
  email: ''
@@ -17,13 +17,12 @@ extensions:
17
17
  - extconf.rb
18
18
  extra_rdoc_files: []
19
19
  files:
20
- - API.html
21
20
  - API.md
22
21
  - README.md
23
22
  - carray-netcdf.gemspec
24
23
  - examples/test.nc
25
24
  - examples/test.rb
26
- - examples/write.rb
25
+ - examples/time.rb
27
26
  - extconf.rb
28
27
  - lib/carray-netcdf.rb
29
28
  - lib/io/netcdf.rb
@@ -47,7 +46,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
47
46
  version: '0'
48
47
  requirements: []
49
48
  rubyforge_project:
50
- rubygems_version: 2.6.11
49
+ rubygems_version: 2.7.7
51
50
  signing_key:
52
51
  specification_version: 4
53
52
  summary: Extension for manipulating NetCDF3 file with CArray
data/API.html DELETED
@@ -1,238 +0,0 @@
1
-
2
- <html>
3
- <head><title>API.md</title></head>
4
- <body>
5
- <h1>CArray/NetCDF library API document</h1>
6
-
7
- <h2>1. Loading library</h2>
8
-
9
- <pre><code>gem install carray-netcdf
10
-
11
- require "carray-netcdf"
12
- </code></pre>
13
-
14
- <h2>2. Methods </h2>
15
-
16
- <p>This API provides the way of calling functions</p>
17
-
18
- <pre><code>include NC
19
- nc_funcname(...)
20
-
21
- NC.funcname(...)
22
- </code></pre>
23
-
24
- <h3>2.1. Data types</h3>
25
-
26
- <pre><code>data_type = NC.ca_type(xtype)
27
- xtype = NC.nc_type(data_type)
28
- </code></pre>
29
-
30
- <h3>2.2. NetCDF File</h3>
31
-
32
- <pre><code>fd = nc_create(FILENAME[, mode=NC_CLOBBER])
33
-
34
- mode : NC_CLOBBER - permit overwrite
35
- NC_NOCLOBBER - inhibit overwrite
36
- NC_SHARE - no buffering
37
-
38
- fd = nc_open(FILENAME[, mode=NC_NOWRITE])
39
-
40
- mode : NC_NOWRITE - readonly
41
- NC_WRTIE - writable
42
- NC_SHARE - no buffering
43
-
44
- nc_close(fd)
45
-
46
- nc_redef(fd)
47
- nc_enddef(fd)
48
-
49
- nc_sync(fd)
50
-
51
- ndims = nc_inq_ndims(fd)
52
- nvars = nc_inq_nvars(fd)
53
- natts = nc_inq_natts(fd)
54
- unlimdim = nc_inq_unlimdim(fd)
55
-
56
- oldmode = nc_set_fill(mode)
57
-
58
- mode : NC_FILL
59
- NC_NOFILL
60
- </code></pre>
61
-
62
- <h3>2.3. NetCDF Dimension</h3>
63
-
64
- <pre><code>dimid = nc_def_dim(fd, dimname, len)
65
- dimid = nc_inq_dimid(fd, dimname) =&gt; Integer | nil
66
-
67
- dimname = nc_inq_dimname(fd, dimid)
68
- dimlen = nc_inq_dimlen(fd, dimid)
69
-
70
- nc_rename_dim(fd, dimid, newname)
71
- </code></pre>
72
-
73
- <h3>2.4. NetCDF Variable</h3>
74
-
75
- <pre><code>varid = nc_def_var(fd, varname, type, dim)
76
- varid = nc_inq_varid(fd, varname) =&gt; Integer | nil
77
-
78
- vartype = nc_inq_vartype(fd, varid)
79
- varndims = nc_inq_varndims(fd, varid)
80
- vardimid = nc_inq_varndimid(fd, varid) =&gt; Array of dimids
81
-
82
- nc_put_var1(fd, varid, [i,j,..], val)
83
- nc_put_var(fd, varid, ca)
84
- nc_put_vara(fd, varid, start, count, ca)
85
- nc_put_vars(fd, varid, start, count, stride, ca)
86
- nc_put_varm(fd, varid, start, count, stride, imap, ca)
87
-
88
- + with data_type conversion
89
-
90
- val = nc_get_var1(fd, varid, [i,j,..])
91
- ca = nc_get_var(fd, varid) [useful]
92
- ca = nc_get_vara(fd, varid, start, count) [useful]
93
- ca = nc_get_vars(fd, varid, start, count, stride) [useful]
94
- ca = nc_get_varm(fd, varid, start, count, stride, imap) [useful]
95
-
96
- + no data_type conversion
97
-
98
- nc_get_var(fd, varid, ca) [pedantic]
99
- nc_get_vara(fd, varid, start, count, ca) [pedantic]
100
- nc_get_vars(fd, varid, start, count, stride, ca) [pedantic]
101
- nc_get_varm(fd, varid, start, count, stride, imap, ca) [pedantic]
102
-
103
- + with data_type conversion.
104
-
105
- nc_rename_var(fd, varid, newname)
106
- </code></pre>
107
-
108
- <h3>2.5. NetCDF Attribute</h3>
109
-
110
- <pre><code>varnatts = nc_inq_varnatts(fd, varid)
111
- attid = nc_inq_attid(fd, varid, attname)
112
-
113
- attname = nc_inq_attname(fd, varid, attid)
114
- atttype = nc_inq_atttype(fd, varid, attname)
115
- attlen = nc_inq_attlen(fd, varid, attname)
116
-
117
- nc_put_att(fd, varid, attname, val)
118
-
119
- varid : NC_GLOBAL for global att
120
- val : String -&gt; NC_CHAR
121
- Integer -&gt; NC_INT
122
- Float -&gt; NC_DOUBLE
123
- CArray -&gt; NC.nc_type(val.data_type)
124
-
125
-
126
- val = nc_get_att(fd, varid, attname) =&gt; String | Numeric | CArray | nil
127
-
128
- varid : NC_GLOBAL for global att
129
-
130
- nc_get_att(fd, varid, attname, ca) [pedantic]
131
-
132
- nc_rename_att(fd, varid, attname, newname)
133
- nc_del_att(fd, varid, attname)
134
-
135
- nc_copy_att(fd1, varid1, attname, fd2, varid2)
136
- </code></pre>
137
-
138
- <h3>2.6 Constants</h3>
139
-
140
- <pre><code>NC_NAT
141
- NC_BYTE
142
- NC_SHORT
143
- NC_INT
144
- NC_FLOAT
145
- NC_DOUBLE
146
-
147
- NC_NOERR - status of API routines
148
-
149
- NC_CLOBBER - permit overwrite [nc_create]
150
- NC_NOCLOBBER - inhibit overwrite [nc_create]
151
- NC_NOWRITE - readonly [nc_open]
152
- NC_WRITE - writable [nc_open]
153
- NC_SHARE - no buffering [nc_create, nc_open]
154
-
155
- NC_GLOBAL - varid for global attributes
156
-
157
- NC_NOFILL - nc_set_fill(fd, varid, NC_NOFILL)
158
- NC_FILL - nc_set_fill(fd, varid, NC_FILL)
159
-
160
- NC_MAX_NAME
161
- NC_MAX_VAR_DIMS
162
- NC_MAX_DIMS
163
-
164
- NC_LOCK - ???
165
- NC_SIZEHINT_DEFAULT - ???
166
- </code></pre>
167
-
168
- <h2>3. NCFile interface</h2>
169
-
170
- <p>NCFile interface provides the way of <em>READ-ONLY</em> access to the netcdf file.</p>
171
-
172
- <h3>3.1. NCFile</h3>
173
-
174
- <pre><code>nc = NCFile.open(FILENAME)
175
-
176
- nc = NCFile.new(file_id)
177
- file_id: return value of nc_open in read-only mode
178
- </code></pre>
179
-
180
- <h3>3.2. Dimensions</h3>
181
-
182
- <pre><code>nc.has_dim?(DIMNAME)
183
- nc.dims - Array of dimension
184
-
185
- dim = nc.dim(DIMNAME) - NCDim object or nil
186
- dim.to_i - size of dimension
187
- dim.to_ca
188
- </code></pre>
189
-
190
- <h3>3.3. Variables</h3>
191
-
192
- <pre><code>nc.has_var?(VARNAME)
193
- nc.vars - Array of variables
194
-
195
- var = nc[VARNAME] - NCVar object or nil
196
- var.is_dim? - true if dimension variable
197
- var.to_ca - get array as CArray object
198
- var[...] - Cooked value array with CArray-like indexing
199
- var.get!(...) - same as [...]
200
- var.get(...) - Non-cooked value array with CArray-like indexing
201
-
202
- var.get_var1(...) - interface to original get function
203
- var.get_var()
204
- var.get_vara(start, count)
205
- var.get_vars(start, count, stride)
206
- var.get_varm(start, count, stride, imap)
207
- var.get_var1!(...)
208
- var.get_var!()
209
- var.get_vara!(start, count)
210
- var.get_vars!(start, count, stride)
211
- var.get_varm!(start, count, stride, imap)
212
- </code></pre>
213
-
214
- <h3>3.4. Attributes</h3>
215
-
216
- <p>All attributes are already read in initializing process of NCFile object.</p>
217
-
218
- <pre><code>nc.attributes - Hash
219
- dim.attributes
220
- var.attributes
221
-
222
- nc.attribute(ATTNAME) - accessor
223
- dim.attribute(ATTNAME)
224
- var.attribute(ATTNAME)
225
- </code></pre>
226
-
227
- <h3>3.5. Iteration</h3>
228
-
229
- <p>No iteration methods is provided, but accessor methods for dims, vars, attributes can be used.</p>
230
-
231
- <pre><code>ex)
232
-
233
- nc.attributes.each {|key, value| ... }
234
- nc.dims.each {|dim| ... }
235
- nc.vars.each {|var| ... }
236
- </code></pre>
237
- </body>
238
- </html>
data/examples/write.rb DELETED
@@ -1,47 +0,0 @@
1
- require "pp"
2
- require "carray-netcdf"
3
- include NC
4
-
5
- =begin
6
- definition = {
7
- dims: {
8
- time: 24
9
- },
10
- vars: {
11
- time: {
12
- dims: ["time"],
13
- long_name: "time from 00UT"
14
- },
15
- temp: {
16
- dims: ["time"],
17
- }
18
- }
19
- }
20
- =end
21
-
22
- require "yaml"
23
-
24
- definition = YAML.load %{
25
- dimensions:
26
- time: 24
27
- variables:
28
- time:
29
- dim: ["time"]
30
- long_name: "time from 00UT"
31
- temp:
32
- type: #{NC_DOUBLE}
33
- dim: ["time"]
34
- creator: "foobar"
35
- }
36
-
37
- pp definition
38
-
39
- out = NCFileWriter.new("test.nc")
40
- out.define definition
41
- out["time"] = CArray.int(24).seq
42
- out["temp"] = CArray.float(24).random
43
- out.close
44
-
45
- nc = NCFile.open("test.nc")
46
-
47
- pp nc.definition