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