netcdf-nmatrix 0.8.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.
data/doc/to_html ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/csh
2
+ nkf -e Ref_man_jp.rd | rd2 | \
3
+ sed -e 's/<dt>/<dt><h4>/' -e 's/<\/dt>/<\/h4><\/dt>/' \
4
+ >! Ref_man_jp.html
5
+ rd2 Ref_man.rd | \
6
+ sed -e 's/<dt>/<dt><h4>/' -e 's/<\/dt>/<\/h4><\/dt>/' \
7
+ >! Ref_man.html
data/extconf.rb ADDED
@@ -0,0 +1,173 @@
1
+ require "mkmf"
2
+ require "rubygems" unless defined?(Gem)
3
+
4
+ ar = ARGV.grep( /^--with-netcdf-version=/ )
5
+ if ar.length > 0
6
+ ncversion = ar[0].sub(/^--with-netcdf-version=/,"")
7
+ else
8
+ ncversion = nil
9
+ end
10
+
11
+ if Gem.respond_to?(:find_files)
12
+ require "rbconfig"
13
+ so = RbConfig::CONFIG["DLEXT"]
14
+ nmatrix_include = File.expand_path(File.dirname(Gem.find_files("nmatrix.h")[0]))
15
+ nmatrix_lib = File.expand_path(File.dirname(Gem.find_files("nmatrix." + so)[0]))
16
+ else
17
+ gem_home=(`gem environment GEM_HOME`).chomp
18
+ nmatrix_dir = Dir.glob("#{gem_home}/gems/nmatrix-*").sort[-1]
19
+ if nmatrix_dir
20
+ nmatrix_include = nmatrix_lib = nmatrix_dir
21
+ else
22
+ nmatrix_include = nmatrix_lib = [ $sitearchdir, $vendorarchdir]
23
+ end
24
+ end
25
+ dir_config('nmatrix', nmatrix_include, nmatrix_lib)
26
+
27
+ dir_config('netcdf', '/usr/local')
28
+
29
+ if ( ! ( have_header("nmatrix.h") ) ) then
30
+ print <<EOS
31
+ ** configure error **
32
+ Header nmatrix.h or nmatrix_config.h is not found. If you have these files in
33
+ /nmatrixdir/include, try the following:
34
+
35
+ % ruby extconf.rb --with-nmatrix-include=/nmatrixdir/include
36
+
37
+ EOS
38
+ exit(-1)
39
+ end
40
+
41
+ unless ncversion
42
+ # configure netcdf version
43
+ if xsystem("nc-config --version")
44
+ ncversion = `nc-config --version`.chomp!.sub!(/^n.* /i,"") # rm "netCDF "
45
+ ncversion.sub!(/^([^\.]+\.[^\.]+\.[^\.]+).+$/,'\1') # e.g. 4.2.1.1 -> 4.2.1
46
+ else
47
+ ncversion = "3.0.0" # assume version 3 (only for compilation)
48
+ # For compilation, there is no difference among subversions of netcdf 3
49
+ end
50
+ end
51
+
52
+ ncver0 = ncversion[0..0] # "3" or "4"
53
+ ncver = ncversion.gsub(/\./,'')
54
+ unless /^\d\d\d$/ =~ ncver # 3 digits
55
+ raise("Invalid netcdf version: #{ncversion}. Use --with-netcdf-version=")
56
+ end
57
+ $CFLAGS += ' -DNCVER='+ncver
58
+
59
+ case ncver0
60
+ when "4"
61
+ if xsystem("nc-config --libs") # for NetCDF 4
62
+ cflags = `nc-config --cflags`.gsub(/\n/, " ")
63
+ libs = `nc-config --libs`.gsub(/\n/, " ")
64
+ prefix_nc = `nc-config --prefix`.gsub(/\n/, "")
65
+
66
+ dir_config("netcdf",prefix_nc)
67
+ $CFLAGS += ' ' + cflags
68
+ $LOCAL_LIBS += ' ' + libs
69
+ end
70
+ when "3"
71
+ # for NetCDF 3, which needs external libraries for OpenDAP
72
+ if xsystem("ncdap-config --libs")
73
+ libncdods = "nc-dap"
74
+ cflags = `ncdap-config --cflags`.gsub(/\n/, " ")
75
+ libs = `ncdap-config --libs`.gsub(/\n/, " ")
76
+ prefix_dods = `ncdap-config --prefix`.gsub(/\n/, "")
77
+ elsif xsystem("opendap-config --libs")
78
+ libncdods = "nc-dods"
79
+ cflags = `opendap-config --cflags`.gsub(/\n/, " ")
80
+ libs = `opendap-config --libs-nc`.gsub(/\n/, " ")
81
+ prefix_dods = `opendap-config --prefix`.gsub(/\n/, "")
82
+ end
83
+ if (enable_config('opendap',true) && ( xsystem("opendap-config --libs") ||
84
+ xsystem("ncdap-config --libs") ) )
85
+
86
+ dir_config(libncdods,prefix_dods)
87
+
88
+ if (!have_library(libncdods))
89
+ print <<-EOS
90
+ ** ERROR ** Library not found: nc-dods (OPeNDAP/DODS-enabled NetCDF lib)
91
+ Install it, or run extconf.rb with option --disable-opendap.
92
+ ^^^^^^^^^^^^^^^^^
93
+ EOS
94
+ exit(-1)
95
+ else
96
+ print <<-EOS
97
+ ** Message ** Compiling with OPeNDAP/DODS-enabled NetCDF library.
98
+
99
+ This is because the command opendap-config is found in your system.
100
+ If you want to use the ordinary (non-DODS) version of NetCDF,
101
+ run extconf.rb with option --disable-opendap.
102
+ ^^^^^^^^^^^^^^^^^
103
+ EOS
104
+ end
105
+
106
+ $CFLAGS += ' '+cflags
107
+ $LOCAL_LIBS += ' ' + libs
108
+
109
+ # non portable treatments: should be improved (by Horinouchi)
110
+ CONFIG['LDSHARED'].sub!(/gcc/,'g++')
111
+ $LIBS.sub!(/-lc\s/,'') ; $LIBS.sub!(/-lc$/,'')
112
+ print <<-EOS
113
+ ** Warning ** non-portable treatments are made,
114
+ which was sucessfull redhat linux 9:
115
+ * gcc was replaced with g++ in CONFIG['LDSHARED']
116
+ * -lc library was removed if in $LIBS
117
+
118
+ EOS
119
+ # p '@@@'
120
+ # ary = []
121
+ # CONFIG.each{|k,v| ary.push([k,v])}
122
+ # ary.sort.each{|x| p x}
123
+ else
124
+ if ( ! ( have_header("netcdf.h") && have_library("netcdf") ) )then
125
+ print <<-EOS
126
+ ** configure error **
127
+ Header netcdf.h or the compiled netcdf library is not found.
128
+ If you have the library installed under /netcdfdir (that is, netcdf.h is
129
+ in /netcdfdir/include and the library in /netcdfdir/lib/),
130
+ try the following:
131
+
132
+ % ruby extconf.rb --with-netcdf-dir=/netcdfdir
133
+
134
+ Alternatively, you can specify the two directory separately
135
+ with --with-netcdf-include and --with-netcdf-lib.
136
+ EOS
137
+ exit(-1)
138
+ end
139
+ end
140
+ else
141
+ raise "Netcdf version #{ncver0} is not supported"
142
+ end
143
+
144
+
145
+
146
+ if /cygwin|mingw/ =~ RUBY_PLATFORM
147
+ have_library("nmatrix") || raise("ERROR: nmatrix library is not found")
148
+ end
149
+
150
+ create_makefile "numru/netcdfraw"
151
+
152
+ ###### Modify Makefile: #######
153
+ File.rename("Makefile","Makefile.orig")
154
+ oldmkfl = File.open("Makefile.orig")
155
+ newmkfl = File.open("Makefile","w")
156
+ oldmkfl.each_line{ |line|
157
+ case(line)
158
+ when /^distclean:/
159
+ newmkfl.puts(line)
160
+ newmkfl.puts("\t\t@$(RM) *.nc demo/*.nc demo/*~ lib/*~ doc/*~ test/*.nc test/*~ Makefile.orig")
161
+ when /^all:/
162
+ newmkfl.puts(line)
163
+ newmkfl.puts("")
164
+ newmkfl.puts("test: all") # insert the "test" target
165
+ newmkfl.puts("\t\t@cd test && ruby test.rb && echo 'test did not fail :-p (please ignore the warnings)' && cd ..")
166
+ # when /lib\/netcdf/
167
+ # line = line.chomp! + "/"
168
+ # newmkfl.puts(line)
169
+ else
170
+ newmkfl.puts(line)
171
+ end
172
+ }
173
+ newmkfl.close
data/lib/netcdf.rb ADDED
@@ -0,0 +1,804 @@
1
+ require 'nmatrix'
2
+ require 'numru/netcdfraw'
3
+
4
+
5
+ module NumRu
6
+ class NetCDF
7
+
8
+ Max_Try = 100
9
+
10
+ NCVERSION = NetCDF.libvers
11
+
12
+ if NCVERSION[0..0] >= "4"
13
+ @@nc4 = true
14
+ else
15
+ @@nc4 = false
16
+ end
17
+ def NetCDF.nc4?
18
+ @@nc4
19
+ end
20
+
21
+ @@cr_format = 0
22
+
23
+ def NetCDF.creation_format=(cmode)
24
+ raise("This method is available only for NetCDF >= 4") unless @@nc4
25
+ case cmode
26
+ when 0, nil, NC_CLASSIC_MODEL, /^CLASSIC$/i # classic netcdf ver 3 fmt
27
+ @@cr_format = 0
28
+ when NC_64BIT_OFFSET, /^64BIT_OFFSET$/i
29
+ @@cr_format = NC_64BIT_OFFSET
30
+ when NC_NETCDF4, /^NETCDF4$/i
31
+ @@cr_format = NC_NETCDF4
32
+ when ( NC_NETCDF4 | NC_CLASSIC_MODEL), /^NETCDF4_CLASSIC$/i
33
+ # NetCDF4 but disabling new data models
34
+ @@cr_format = NC_NETCDF4 | NC_CLASSIC_MODEL
35
+ else
36
+ raise ArgumentError, "Unsupported creation mode: #{cmod.to_s}"
37
+ end
38
+ end
39
+
40
+ def NetCDF.creation_format
41
+ raise("This method is available only for NetCDF >= 4") unless @@nc4
42
+ case @@cr_format
43
+ when 0
44
+ "TRADITIONAL"
45
+ when NC_64BIT_OFFSET
46
+ "64BIT_OFFSET"
47
+ when NC_NETCDF4
48
+ "NETCDF4"
49
+ when NC_NETCDF4 | NC_CLASSIC_MODEL
50
+ "NETCDF4_CLASSIC"
51
+ end
52
+ end
53
+
54
+ def NetCDF.open(filename,mode="r",share=false)
55
+ call_create=false # false-> nc_open; true->nc_create
56
+ case(mode)
57
+ when "r","rb" # read only
58
+ mode=NC_NOWRITE
59
+ when "w","w+","wb","w+b" # overwrite if exits
60
+ call_create=true
61
+ mode=NC_CLOBBER
62
+ when "a","a+","r+","ab","a+b","r+b" # append if exits
63
+ if( File.exists?(filename) )
64
+ mode=NC_WRITE
65
+ else
66
+ call_create=true #(nonexsitent --> create)
67
+ mode=NC_CLOBBER
68
+ end
69
+ else
70
+ raise NetcdfError, "Mode #{mode} is not supported"
71
+ end
72
+ case(share)
73
+ when false
74
+ share=0
75
+ when true
76
+ share=NC_SHARE
77
+ else
78
+ raise NetcdfError, "We can't use the sharing mode you typed"
79
+ end
80
+ omode = mode | share
81
+ if(!call_create)
82
+ nc_open(filename,omode)
83
+ else
84
+ nc_create(filename,omode)
85
+ end
86
+ end
87
+
88
+ class << NetCDF
89
+ alias new open
90
+ end
91
+
92
+
93
+ def NetCDF.create(filename,noclobber=false,share=false)
94
+ case(noclobber)
95
+ when false
96
+ noclobber=NC_CLOBBER
97
+ when true
98
+ noclobber=NC_NOCLOBBER
99
+ else
100
+ raise NetcdfError,"noclobber (2nd argument) must be true or false"
101
+ end
102
+ case(share)
103
+ when false
104
+ share=0
105
+ when true
106
+ share=NC_SHARE
107
+ else
108
+ raise NetcdfError,"share (3rd argument) must be true or false"
109
+ end
110
+
111
+ cmode=noclobber | share | @@cr_format
112
+ nc_create(filename,cmode)
113
+ end
114
+
115
+ class << NetCDF
116
+ def clean_tmpfile(path)
117
+ proc {
118
+ print "removing ", path, "..." if $DEBUG
119
+ if File.exist?(path)
120
+ File.unlink(path)
121
+ end
122
+ print "done\n" if $DEBUG
123
+ }
124
+ end
125
+ protected :clean_tmpfile
126
+ end
127
+
128
+ def NetCDF.create_tmp(tmpdir=ENV['TMPDIR']||ENV['TMP']||ENV['TEMP']||'.',
129
+ share=false)
130
+ basename = 'temp'
131
+ if $SAFE > 0 and tmpdir.tainted?
132
+ tmpdir = '.'
133
+ end
134
+
135
+ n = 0
136
+ while true
137
+ begin
138
+ tmpname = sprintf('%s/%s%d_%d.nc', tmpdir, basename, $$, n)
139
+ unless File.exist?(tmpname)
140
+ netcdf = NetCDF.create(tmpname, true, share)
141
+ ObjectSpace.define_finalizer(netcdf,
142
+ NetCDF.clean_tmpfile(tmpname))
143
+ break
144
+ end
145
+ rescue
146
+ raise NetcdfError, "cannot generate tempfile `%s'" % tmpname if n >= Max_Try
147
+ end
148
+ n += 1
149
+ end
150
+ netcdf
151
+ end
152
+
153
+
154
+ def put_att(attname,val,atttype=nil)
155
+ put_attraw(attname,val,atttype)
156
+ end
157
+
158
+ def def_var_with_dim(name, vartype, shape_ul0, dimnames)
159
+ # Same as def_var but defines dimensions first if needed.
160
+ # Use zero in shape to define an unlimited dimension.
161
+ if (shape_ul0.length != dimnames.length ) then
162
+ raise ArgumentError, 'lengths of shape and dimnames do not agree'
163
+ end
164
+ dims = []
165
+ dimnames.each_index{ |i|
166
+ dim = self.dim( dimnames[i] )
167
+ if ( dim != nil ) then
168
+ # dim exists --> check the length
169
+ if (shape_ul0[i] != dim.length_ul0 ) then
170
+ raise ArgumentError, "dimension length do not agree: #{i}th dim: "+\
171
+ "#{shape_ul0[i]} and #{dim.length_ul0}"
172
+ end
173
+ dims.push(dim)
174
+ else
175
+ # dim does not exist --> define it
176
+ dims.push( def_dim( dimnames[i], shape_ul0[i] ) )
177
+ end
178
+ }
179
+ def_var(name, vartype, dims)
180
+ end
181
+
182
+ # Iterators:
183
+ def each_dim
184
+ num_dim=ndims()
185
+ for dimid in 0..num_dim-1
186
+ obj_Dim=id2dim(dimid)
187
+ yield(obj_Dim)
188
+ end
189
+ end
190
+
191
+ def each_var
192
+ num_var=nvars()
193
+ for varid in 0..num_var-1
194
+ obj_Var=id2var(varid)
195
+ yield(obj_Var)
196
+ end
197
+ end
198
+
199
+ def each_att
200
+ num_att=natts()
201
+ for attnum in 0..num_att-1
202
+ obj_Att=id2att(attnum)
203
+ yield(obj_Att)
204
+ end
205
+ end
206
+
207
+ def dims( names=nil ) # return all if names==nil
208
+ if names == nil
209
+ dims = (0..ndims()-1).collect{|dimid| id2dim(dimid)}
210
+ else
211
+ raise TypeError, "names is not an array" if ! names.is_a?(Array)
212
+ dims = names.collect{|name| dim(name)}
213
+ raise ArgumentError, "One or more dimensions do not exist" if dims.include?(nil)
214
+ end
215
+ dims
216
+ end
217
+
218
+ def vars( names=nil ) # return all if names==nil
219
+ if names == nil
220
+ vars = (0..nvars()-1).collect{ |varid| id2var(varid) }
221
+ else
222
+ raise TypeError, "names is not an array" if ! names.is_a?(Array)
223
+ vars = names.collect{|name| var(name)}
224
+ raise ArgumentError, "One or more variables do not exist" if vars.include?(nil)
225
+ end
226
+ vars
227
+ end
228
+
229
+ def dim_names
230
+ num_dim=ndims()
231
+ names=[]
232
+ for dimid in 0..num_dim-1
233
+ obj_Dim=id2dim(dimid)
234
+ names=names+[obj_Dim.name]
235
+ end
236
+ return names
237
+ end
238
+
239
+ def var_names
240
+ num_var=nvars()
241
+ names=[]
242
+ for varid in 0..num_var-1
243
+ obj_Var=id2var(varid)
244
+ names=names+[obj_Var.name]
245
+ end
246
+ return names
247
+ end
248
+
249
+ def att_names
250
+ num_att=natts()
251
+ names=[]
252
+ for attnum in 0..num_att-1
253
+ obj_Att=id2att(attnum)
254
+ names=names+[obj_Att.name]
255
+ end
256
+ return names
257
+ end
258
+
259
+ def inspect
260
+ "NetCDF:"+path
261
+ end
262
+
263
+ end
264
+
265
+ class NetCDFVar
266
+
267
+ class << NetCDFVar
268
+ def new(file,varname,mode="r",share=false)
269
+ if(file.is_a?(String))
270
+ file = NetCDF.open(file,mode,share)
271
+ elsif(!file.is_a?(NetCDF))
272
+ raise TypeError, "1st arg must be a NetCDF (file object) or a String (path)"
273
+ end
274
+ file.var(varname)
275
+ end
276
+
277
+ alias open new
278
+ end
279
+
280
+ alias :rank :ndims
281
+
282
+ def each_att
283
+ num_att=natts()
284
+ for attnum in 0..num_att-1
285
+ obj_Att=id2att(attnum)
286
+ yield(obj_Att)
287
+ end
288
+ end
289
+
290
+ def dim_names
291
+ ary = Array.new()
292
+ dims.each{|dim| ary.push(dim.name)}
293
+ ary
294
+ end
295
+
296
+ def att_names
297
+ num_att=natts()
298
+ names=[]
299
+ for attnum in 0..num_att-1
300
+ obj_Att=id2att(attnum)
301
+ names=names+[obj_Att.name]
302
+ end
303
+ return names
304
+ end
305
+
306
+ def put_att(attname,val,atttype=nil)
307
+ put_attraw(attname,val,atttype)
308
+ end
309
+
310
+ def shape_ul0
311
+ sh = []
312
+ dims.each{|d|
313
+ if d.unlimited? then
314
+ sh.push(0)
315
+ else
316
+ sh.push(d.length)
317
+ end
318
+ }
319
+ sh
320
+ end
321
+
322
+ def shape_current
323
+ sh = []
324
+ dims.each{|d|
325
+ sh.push(d.length)
326
+ }
327
+ sh
328
+ end
329
+
330
+ # The put and get methods in the NetCDFVar class
331
+
332
+ def pack(na)
333
+ sf = att('scale_factor')
334
+ ao = att('add_offset')
335
+ if ( sf == nil && ao == nil ) then
336
+ na
337
+ else
338
+ na = NArray.to_na(na) if na.is_a?(Array)
339
+ if sf
340
+ csf = sf.get
341
+ raise NetcdfError,"scale_factor is not a numeric" if csf.is_a?(String)
342
+ raise NetcdfError, "scale_factor is not unique" if csf.length != 1
343
+ raise NetcdfError, "zero scale_factor" if csf[0] == 0
344
+ else
345
+ csf = nil
346
+ end
347
+ if ao
348
+ cao = ao.get
349
+ raise NetcdfError, "add_offset is not a numeric" if cao.is_a?(String)
350
+ raise NetcdfError, "add_offset is not unique" if cao.length != 1
351
+ else
352
+ cao = nil
353
+ end
354
+ if csf and cao
355
+ packed = (na - cao) / csf
356
+ elsif csf
357
+ packed = na / csf
358
+ elsif cao
359
+ packed = na - cao
360
+ end
361
+ if self.typecode <= NArray::LINT
362
+ packed = packed.round
363
+ end
364
+ packed
365
+ end
366
+ end
367
+
368
+ def scaled_put(var,hash=nil)
369
+ simple_put( pack(var), hash)
370
+ end
371
+
372
+ @@unpack_type = nil
373
+ class << NetCDFVar
374
+ def unpack_type
375
+ @@unpack_type
376
+ end
377
+ def unpack_type=(na_type)
378
+ if [NArray::BYTE, NArray::SINT, NArray::INT,
379
+ NArray::SFLOAT, NArray::FLOAT, nil].include?(na_type)
380
+ @@unpack_type = na_type
381
+ else
382
+ raise ArgumentError, "Arg must be one of NArray::BYTE, NArray::SINT, NArray::INT, NArray::SFLOAT, NArray::FLOAT"
383
+ end
384
+ end
385
+
386
+ end
387
+
388
+ def unpack(na)
389
+ sf = att('scale_factor')
390
+ ao = att('add_offset')
391
+ if ( sf == nil && ao == nil ) then
392
+ na
393
+ else
394
+ if sf
395
+ csf = sf.get
396
+ raise NetcdfError,"scale_factor is not a numeric" if csf.is_a?(String)
397
+ raise NetcdfError, "scale_factor is not unique" if csf.length != 1
398
+ raise NetcdfError, "zero scale_factor" if csf[0] == 0
399
+ else
400
+ csf =nil
401
+ end
402
+ if ao
403
+ cao = ao.get
404
+ raise NetcdfError, "add_offset is not a numeric" if cao.is_a?(String)
405
+ raise NetcdfError, "add_offset is not unique" if cao.length != 1
406
+ else
407
+ cao = nil
408
+ end
409
+ if csf and cao
410
+ una = na * csf + cao # csf & cao are NArray -> coerced to their types
411
+ elsif csf
412
+ una = na * csf
413
+ elsif cao
414
+ una = na + cao
415
+ end
416
+ una = una.to_type(@@unpack_type) if @@unpack_type
417
+ una
418
+ end
419
+ end
420
+
421
+ def scaled_get(hash=nil)
422
+ unpack( simple_get(hash) )
423
+ end
424
+
425
+ def simple_put(var,hash=nil)
426
+ if hash==nil
427
+ if self.vartype == "char"
428
+ put_var_char(var)
429
+ elsif self.vartype == "byte"
430
+ put_var_byte(var)
431
+ elsif self.vartype == "int16"
432
+ put_var_sint(var)
433
+ elsif self.vartype == "int32"
434
+ put_var_int(var)
435
+ elsif self.vartype == "float32"
436
+ put_var_sfloat(var)
437
+ elsif self.vartype == "float64"
438
+ put_var_float(var)
439
+ else
440
+ raise NetcdfError,"variable type isn't supported in netCDF"
441
+ end
442
+ elsif hash.key?("index")==true
443
+ if self.vartype == "char"
444
+ put_var1_char(var,hash["index"])
445
+ elsif self.vartype=="byte"
446
+ put_var1_byte(var,hash["index"])
447
+ elsif self.vartype=="int16"
448
+ put_var1_sint(var,hash["index"])
449
+ elsif self.vartype == "int32"
450
+ put_var1_int(var,hash["index"])
451
+ elsif self.vartype == "float32"
452
+ put_var1_sfloat(var,hash["index"])
453
+ elsif self.vartype == "float64"
454
+ put_var1_float(var,hash["index"])
455
+ else
456
+ raise NetcdfError,"variable type isn't supported in netCDF"
457
+ end
458
+ elsif hash.key?("start")==true
459
+ if hash.key?("end")==false && hash.key?("stride")==false
460
+ if self.vartype == "char"
461
+ put_vars_char(var,hash["start"],nil,nil)
462
+ elsif self.vartype=="byte"
463
+ put_vars_byte(var,hash["start"],nil,nil)
464
+ elsif self.vartype=="int16"
465
+ put_vars_sint(var,hash["start"],nil,nil)
466
+ elsif self.vartype=="int32"
467
+ put_vars_int(var,hash["start"],nil,nil)
468
+ elsif self.vartype=="float32"
469
+ put_vars_sfloat(var,hash["start"],nil,nil)
470
+ elsif self.vartype=="float64"
471
+ put_vars_float(var,hash["start"],nil,nil)
472
+ else
473
+ raise NetcdfError, "variable type isn't supported in netCDF"
474
+ end
475
+ elsif hash.key?("end")==true && hash.key?("stride") == false
476
+ if self.vartype == "char"
477
+ put_vars_char(var,hash["start"],hash["end"],nil)
478
+ elsif self.vartype=="byte"
479
+ put_vars_byte(var,hash["start"],hash["end"],nil)
480
+ elsif self.vartype=="int16"
481
+ put_vars_sint(var,hash["start"],hash["end"],nil)
482
+ elsif self.vartype=="int32"
483
+ put_vars_int(var,hash["start"],hash["end"],nil)
484
+ elsif self.vartype == "float32"
485
+ put_vars_sfloat(var,hash["start"],hash["end"],nil)
486
+ elsif self.vartype =="float64"
487
+ put_vars_float(var,hash["start"],hash["end"],nil)
488
+ else
489
+ raise NetcdfError, "variable type isn't supported in netCDF"
490
+ end
491
+ elsif hash.key?("end")==false && hash.key?("stride")==true
492
+ if self.vartype == "char"
493
+ put_vars_char(var,hash["start"],nil,hash["stride"])
494
+ elsif self.vartype=="byte"
495
+ put_vars_byte(var,hash["start"],nil,hash["stride"])
496
+ elsif self.vartype=="int16"
497
+ put_vars_sint(var,hash["start"],nil,hash["stride"])
498
+ elsif self.vartype=="int32"
499
+ put_vars_int(var,hash["start"],nil,hash["stride"])
500
+ elsif self.vartype=="float32"
501
+ put_vars_sfloat(var,hash["start"],nil,hash["stride"])
502
+ elsif self.vartype=="float64"
503
+ put_vars_float(var,hash["start"],nil,hash["stride"])
504
+ else
505
+ raise NetcdfError, "variable type isn't supported in netCDF"
506
+ end
507
+ else hash.key?("end")==true && hash.key?("stride")==true
508
+ if self.vartype == "char"
509
+ put_vars_char(var,hash["start"],hash["end"],hash["stride"])
510
+ elsif self.vartype=="byte"
511
+ put_vars_byte(var,hash["start"],hash["end"],hash["stride"])
512
+ elsif self.vartype=="int16"
513
+ put_vars_sint(var,hash["start"],hash["end"],hash["stride"])
514
+ elsif self.vartype=="int32"
515
+ put_vars_int(var,hash["start"],hash["end"],hash["stride"])
516
+ elsif self.vartype=="float32"
517
+ put_vars_sfloat(var,hash["start"],hash["end"],hash["stride"])
518
+ elsif self.vartype=="float64"
519
+ put_vars_float(var,hash["start"],hash["end"],hash["stride"])
520
+ else
521
+ raise NetcdfError, "variable type isn't supported in netCDF"
522
+ end
523
+ end
524
+ else
525
+ raise ArgumentError,"{'start'}=>[ARRAY] or {'index'}=>[ARRAY] is needed"
526
+ end
527
+ end
528
+
529
+ alias put simple_put
530
+
531
+ def simple_get(hash=nil)
532
+ t_var = self.vartype
533
+ if hash == nil
534
+ if t_var == "char"
535
+ get_var_char
536
+ elsif t_var == "byte"
537
+ get_var_byte
538
+ elsif t_var == "int16"
539
+ get_var_sint
540
+ elsif t_var == "int32"
541
+ get_var_int
542
+ elsif t_var == "float32"
543
+ get_var_sfloat
544
+ elsif t_var == "float64"
545
+ get_var_float
546
+ else
547
+ raise NetcdfError, "variable type #{t_var} isn't supported in netCDF"
548
+ end
549
+ elsif hash.key?("index")==true
550
+ ind = hash["index"]
551
+ if t_var == "char"
552
+ get_var1_char(ind)
553
+ elsif t_var == "byte"
554
+ get_var1_byte(ind)
555
+ elsif t_var == "int16"
556
+ get_var1_sint(ind)
557
+ elsif t_var == "int32"
558
+ get_var1_int(ind)
559
+ elsif t_var == "float32"
560
+ get_var1_sfloat(ind)
561
+ elsif t_var == "float64"
562
+ get_var1_float(ind)
563
+ else
564
+ raise NetcdfError,"variable type #{t_var} isn't supported in netCDF"
565
+ end
566
+ elsif hash.key?("start")==true
567
+ h_sta = hash["start"]
568
+ h_end = hash["end"] # can be nill
569
+ h_str = hash["stride"] # can be nill
570
+ if false && NetCDF.nc4? && h_str && ((xstr=h_str[-1]) != 1)
571
+ # Tentative treatment for the very slow netcdf-4 reading with step.
572
+ # Reading with step is generally slow with NetCDF 4, but it is
573
+ # particularly so for the last (fastest) dimension.
574
+ # Ref: http://www.unidata.ucar.edu/mailing_lists/archives/netcdfgroup/2013/msg00311.html
575
+ h_str[-1] = 1
576
+ nc4remedy = true
577
+ else
578
+ nc4remedy = false
579
+ end
580
+ if t_var == "char"
581
+ v = get_vars_char(h_sta,h_end,h_str)
582
+ elsif t_var == "byte"
583
+ v = get_vars_byte(h_sta,h_end,h_str)
584
+ elsif t_var == "int16"
585
+ v = get_vars_sint(h_sta,h_end,h_str)
586
+ elsif t_var == "int32"
587
+ v = get_vars_int(h_sta,h_end,h_str)
588
+ elsif t_var == "float32"
589
+ v = get_vars_sfloat(h_sta,h_end,h_str)
590
+ elsif t_var == "float64"
591
+ v = get_vars_float(h_sta,h_end,h_str)
592
+ else
593
+ raise NetcdfError, "variable type #{t_var} isn't supported in netCDF"
594
+ end
595
+ if nc4remedy
596
+ idx = []
597
+ (0...v.shape[-1]).step(xstr){|k| idx.push(k)}
598
+ newshape = v.shape
599
+ newshape[-1] = idx.size
600
+ newv = NMatrix.new(newshape, dtype: v.dtype)
601
+ idx.each_with_index do |iold, inew|
602
+ newv[*[:*]*(v.dim-1), inew] = v[*[:*]*(v.dim-1), iold] # equiv to [false,iold] for narray
603
+ end
604
+ v = newv
605
+ #v = v.slice(idx,*[:*]*(v.dim-1)) # equiv to [idx, false] for narray
606
+ end
607
+ v
608
+ else
609
+ raise ArgumentError,"{'start'}=>{ARRAY} or {'index'}=>{ARRAY} is needed"
610
+ end
611
+ end
612
+
613
+ alias get simple_get
614
+
615
+ def __rubber_expansion( args )
616
+ if (id = args.index(false)) # substitution into id
617
+ # false is incuded
618
+ alen = args.length
619
+ if args.rindex(false) != id
620
+ raise ArguemntError,"only one rubber dimension is permitted"
621
+ elsif alen > rank+1
622
+ raise ArgumentError, "too many args"
623
+ end
624
+ ar = ( id!=0 ? args[0..id-1] : [] )
625
+ args = ar + [true]*(rank-alen+1) + args[id+1..-1]
626
+ elsif args.length == 0 # to support empty [], []=
627
+ args = [true]*rank
628
+ end
629
+ args
630
+ end
631
+ private :__rubber_expansion
632
+
633
+ def [](*a)
634
+ if a.length == 0
635
+ return self.get
636
+ end
637
+ a = __rubber_expansion(a)
638
+ first = Array.new
639
+ last = Array.new
640
+ stride = Array.new
641
+ set_stride = false
642
+ a.each{|i|
643
+ if(i.is_a?(Fixnum))
644
+ first.push(i)
645
+ last.push(i)
646
+ stride.push(1)
647
+ elsif(i.is_a?(Range))
648
+ first.push(i.first)
649
+ last.push(i.exclude_end? ? i.last-1 : i.last)
650
+ stride.push(1)
651
+ elsif(i.is_a?(Hash))
652
+ r = (i.to_a[0])[0]
653
+ s = (i.to_a[0])[1]
654
+ if ( !( r.is_a?(Range) ) || ! ( s.is_a?(Integer) ) )
655
+ raise TypeError, "Hash argument must be {a_Range, step}"
656
+ end
657
+ first.push(r.first)
658
+ last.push(r.exclude_end? ? r.last-1 : r.last)
659
+ stride.push(s)
660
+ set_stride = true
661
+ elsif(i.is_a?(TrueClass))
662
+ first.push(0)
663
+ last.push(-1)
664
+ stride.push(1)
665
+ elsif( i.is_a?(Array) || i.is_a?(NArray))
666
+ a_new = a.dup
667
+ at = a.index(i)
668
+ i = NArray.to_na(i) if i.is_a?(Array)
669
+ for n in 0..i.length-1
670
+ a_new[at] = i[n]..i[n]
671
+ na_tmp = self[*a_new]
672
+ if n==0 then
673
+ k = at
674
+ if at > 0
675
+ a[0..at-1].each{|x| if x.is_a?(Fixnum) then k -= 1 end}
676
+ end
677
+ shape_tmp = na_tmp.shape
678
+ shape_tmp[k] = i.length
679
+ na = na_tmp.class.new(na_tmp.typecode,*shape_tmp)
680
+ index_tmp = Array.new(shape_tmp.length,true)
681
+ end
682
+ index_tmp[k] = n..n
683
+ na[*index_tmp] = na_tmp
684
+ end
685
+ return na
686
+ else
687
+ raise TypeError, "argument must be Fixnum, Range, Hash, TrueClass, Array, or NArray"
688
+ end
689
+ }
690
+
691
+ if(set_stride)
692
+ na = self.get({"start"=>first, "end"=>last, "stride"=>stride})
693
+ else
694
+ na = self.get({"start"=>first, "end"=>last})
695
+ end
696
+ shape = na.shape
697
+ (a.length-1).downto(0){ |i|
698
+ shape.delete_at(i) if a[i].is_a?(Fixnum)
699
+ }
700
+ na.reshape!( *shape )
701
+ na
702
+ end
703
+
704
+ def []=(*a)
705
+ val = a.pop
706
+ a = __rubber_expansion(a)
707
+ first = Array.new
708
+ last = Array.new
709
+ stride = Array.new
710
+ set_stride = false
711
+ a.each{|i|
712
+ if(i.is_a?(Fixnum))
713
+ first.push(i)
714
+ last.push(i)
715
+ stride.push(1)
716
+ elsif(i.is_a?(Range))
717
+ first.push(i.first)
718
+ last.push(i.exclude_end? ? i.last-1 : i.last)
719
+ stride.push(1)
720
+ elsif(i.is_a?(Hash))
721
+ r = (i.to_a[0])[0]
722
+ s = (i.to_a[0])[1]
723
+ if ( !( r.is_a?(Range) ) || ! ( s.is_a?(Integer) ) )
724
+ raise ArgumentError, "Hash argument must be {first..last, step}"
725
+ end
726
+ first.push(r.first)
727
+ last.push(r.exclude_end? ? r.last-1 : r.last)
728
+ stride.push(s)
729
+ set_stride = true
730
+ elsif(i.is_a?(TrueClass))
731
+ first.push(0)
732
+ last.push(-1)
733
+ stride.push(1)
734
+ elsif(i.is_a?(Array) || i.is_a?(NArray))
735
+ a_new = a.dup
736
+ at = a.index(i)
737
+ i = NArray.to_na(i) if i.is_a?(Array)
738
+ val = NArray.to_na(val) if val.is_a?(Array)
739
+ rank_of_subset = a.dup.delete_if{|v| v.is_a?(Fixnum)}.length
740
+ if val.rank != rank_of_subset
741
+ raise "rank of the rhs (#{val.rank}) is not equal to the rank "+
742
+ "of the subset specified by #{a.inspect} (#{rank_of_subset})"
743
+ end
744
+ k = at
745
+ a[0..at-1].each{|x| if x.is_a?(Fixnum) then k -= 1 end}
746
+ if i.length != val.shape[k]
747
+ raise "length of the #{k+1}-th dim of rhs is incorrect "+
748
+ "(#{i.length} for #{val.shape[k]})"
749
+ end
750
+ index_tmp = Array.new(val.rank,true) if !val.is_a?(Numeric) #==>Array-like
751
+ for n in 0..i.length-1
752
+ a_new[at] = i[n]..i[n]
753
+ if !val.is_a?(Numeric) then
754
+ index_tmp[k] = n..n
755
+ self[*a_new] = val[*index_tmp]
756
+ else
757
+ self[*a_new] = val
758
+ end
759
+ end
760
+ return self
761
+ else
762
+ raise TypeError, "argument must be Fixnum, Range, Hash, TrueClass, Array, or NArray"
763
+ end
764
+ }
765
+
766
+ if(set_stride)
767
+ self.put(val, {"start"=>first, "end"=>last, "stride"=>stride})
768
+ else
769
+ self.put(val, {"start"=>first, "end"=>last})
770
+ end
771
+ end
772
+
773
+ def inspect
774
+ 'NetCDFVar:'+file.path+'?var='+name
775
+ end
776
+
777
+ end
778
+
779
+ class NetCDFAtt
780
+
781
+ def put(val,atttype=nil)
782
+ putraw(val,atttype)
783
+ end
784
+
785
+ def inspect
786
+ 'NetCDFAtt:'+name
787
+ end
788
+ end
789
+
790
+ class NetCDFDim
791
+ def inspect
792
+ 'NetCDFDim:'+name
793
+ end
794
+
795
+ def length_ul0
796
+ if unlimited?
797
+ 0
798
+ else
799
+ length
800
+ end
801
+ end
802
+
803
+ end
804
+ end