File: netcdf.rb

package info (click to toggle)
ruby-netcdf 0.6.6-2
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 1,184 kB
  • ctags: 882
  • sloc: ansic: 3,968; ruby: 1,661; makefile: 9; csh: 6
file content (792 lines) | stat: -rw-r--r-- 20,384 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
require 'narray'
require 'numru/netcdfraw'

# NetCDFクラスに関して
module NumRu
  class NetCDF

    Max_Try = 100

    def NetCDF.open(filename,mode="r",share=false)
       call_create=false   # false-> nc_open; true->nc_create
       case(mode)
       when "r","rb"                          # read only
	  mode=NC_NOWRITE
       when "w","w+","wb","w+b"               # overwrite if exits
          call_create=true
	  mode=NC_CLOBBER
       when "a","a+","r+","ab","a+b","r+b"    # append if exits
	  if( File.exists?(filename) )
	     mode=NC_WRITE
	  else
	     call_create=true   #(nonexsitent --> create)
	     mode=NC_CLOBBER
	  end
       else
	  raise NetcdfError, "Mode #{mode} is not supported"
       end
       case(share)
       when false
	  share=0
       when true
	  share=NC_SHARE
       else
	  raise NetcdfError, "We can't use the sharing mode you typed"
       end
       omode = mode | share
       if(!call_create)
	  nc_open(filename,omode)
       else
	  nc_create(filename,omode)
       end
    end
    
    class << NetCDF
      alias new open
    end
    
    
    def NetCDF.create(filename,noclobber=false,share=false)
      case(noclobber)
      when false
	noclobber=NC_CLOBBER
      when true
	noclobber=NC_NOCLOBBER
      else
	raise NetcdfError,"noclobber (2nd argument) must be true or false"
      end
      case(share)
      when false
	share=0
      when true
	share=NC_SHARE
      else
	raise NetcdfError,"share (3rd argument) must be true or false"
      end
      
      cmode=noclobber | share
      nc_create(filename,cmode)
    end
    
    class << NetCDF
       def clean_tmpfile(path)
	  proc {
	     print "removing ", path, "..." if $DEBUG
	     if File.exist?(path)
		File.unlink(path) 
	     end
	     print "done\n" if $DEBUG
	  }
       end
       protected :clean_tmpfile
    end

    def NetCDF.create_tmp(tmpdir=ENV['TMPDIR']||ENV['TMP']||ENV['TEMP']||'.', 
			  share=false)
       basename = 'temp'
       if $SAFE > 0 and tmpdir.tainted?
	  tmpdir = '.'
       end

       n = 0
       while true
	 begin
	   tmpname = sprintf('%s/%s%d_%d.nc', tmpdir, basename, $$, n)
	   unless File.exist?(tmpname)
	      netcdf = NetCDF.create(tmpname, true, share)
	      ObjectSpace.define_finalizer(netcdf, 
					   NetCDF.clean_tmpfile(tmpname))
	      break
	   end
	 rescue
	   raise NetcdfError, "cannot generate tempfile `%s'" % tmpname if n >= Max_Try
	 end
	 n += 1
       end
       netcdf
    end


    def put_att(attname,val,atttype=nil)
       put_attraw(attname,val,atttype)
    end
    
    def def_var_with_dim(name, vartype, shape_ul0, dimnames)
       # Same as def_var but defines dimensions first if needed.
       # Use zero in shape to define an unlimited dimension.
       if (shape_ul0.length != dimnames.length ) then
	  raise ArgumentError, 'lengths of shape and dimnames do not agree'
       end
       dims = []
       dimnames.each_index{ |i|
	  dim = self.dim( dimnames[i] )
	  if ( dim != nil ) then
	     # dim exists --> check the length
	     if (shape_ul0[i] != dim.length_ul0 ) then
		raise ArgumentError, "dimension length do not agree: #{i}th dim: "+\
		"#{shape_ul0[i]} and #{dim.length_ul0}"
	     end
	     dims.push(dim)
	  else
	     # dim does not exist --> define it
	     dims.push( def_dim( dimnames[i], shape_ul0[i] ) )
	  end
       }
       def_var(name, vartype, dims)
    end

    # Iterators:
    def each_dim
      num_dim=ndims()    
      for dimid in 0..num_dim-1
	obj_Dim=id2dim(dimid)
	 yield(obj_Dim)
      end
    end
    
    def each_var
      num_var=nvars()
      for varid in 0..num_var-1
	obj_Var=id2var(varid)
	yield(obj_Var)
      end
    end
    
    def each_att
      num_att=natts()
      for attnum in 0..num_att-1
	obj_Att=id2att(attnum)
	 yield(obj_Att)
      end
    end
    
    def dims( names=nil )   # return all if names==nil
       if names == nil
	  dims = (0..ndims()-1).collect{|dimid| id2dim(dimid)}
       else
	  raise TypeError, "names is not an array" if ! names.is_a?(Array)
	  dims = names.collect{|name| dim(name)}
	  raise ArgumentError, "One or more dimensions do not exist" if dims.include?(nil)
       end
       dims
    end

    def vars( names=nil )   # return all if names==nil
       if names == nil
	  vars = (0..nvars()-1).collect{ |varid| id2var(varid) }
       else
	  raise TypeError, "names is not an array" if ! names.is_a?(Array)
	  vars = names.collect{|name| var(name)}
	  raise ArgumentError, "One or more variables do not exist" if vars.include?(nil)
       end
       vars
    end

    def dim_names
      num_dim=ndims()
      names=[]
      for dimid in 0..num_dim-1
	obj_Dim=id2dim(dimid)    
	names=names+[obj_Dim.name]
      end
      return names
    end    
    
    def var_names
      num_var=nvars()
      names=[]
      for varid in 0..num_var-1
	obj_Var=id2var(varid)
	names=names+[obj_Var.name]
      end
      return names
    end
    
    def att_names
      num_att=natts()
      names=[]
      for attnum in 0..num_att-1
	obj_Att=id2att(attnum)    
	names=names+[obj_Att.name]
      end
      return names
    end
    
    def inspect
      "NetCDF:"+path
    end
    
  end
  
  #NetCDFVar class に関して
  class NetCDFVar
    
    class << NetCDFVar
       def new(file,varname,mode="r",share=false)
	  if(file.is_a?(String))
	     file = NetCDF.open(file,mode,share)
	  elsif(!file.is_a?(NetCDF))
	    raise TypeError, "1st arg must be a NetCDF (file object) or a String (path)"
	  end
	  file.var(varname)
       end

       alias open new
    end

    alias :rank :ndims

    def each_att
      num_att=natts()
      for attnum in 0..num_att-1
	obj_Att=id2att(attnum)
	yield(obj_Att)
      end
    end
    
    def dim_names
      ary = Array.new()
      dims.each{|dim| ary.push(dim.name)}
      ary
    end
    
   def att_names
     num_att=natts()
     names=[]
     for attnum in 0..num_att-1
       obj_Att=id2att(attnum)
       names=names+[obj_Att.name]
     end
     return names
   end
   
   def put_att(attname,val,atttype=nil)
      put_attraw(attname,val,atttype)
   end

   def shape_ul0
      sh = []
      dims.each{|d|
	 if d.unlimited? then
	    sh.push(0)
	 else
	    sh.push(d.length)
	 end
      }
      sh
   end
   
   def shape_current
      sh = []
      dims.each{|d|
	 sh.push(d.length)
      }
      sh
   end
   
   # The put and get methods in the NetCDFVar class

   def pack(na)
     sf = att('scale_factor')
     ao = att('add_offset')
     if ( sf == nil && ao == nil ) then
       na
     else
       na = NArray.to_na(na) if na.is_a?(Array)
       if sf
	 csf = sf.get
	 raise NetcdfError,"scale_factor is not a numeric" if csf.is_a?(String)
	 raise NetcdfError, "scale_factor is not unique" if csf.length != 1
	 raise NetcdfError, "zero scale_factor" if csf[0] == 0
       else
	 csf = nil
       end
       if ao
	 cao = ao.get
	 raise NetcdfError, "add_offset is not a numeric" if cao.is_a?(String)
	 raise NetcdfError, "add_offset is not unique" if cao.length != 1
       else
	 cao = nil
       end
       if csf and cao
	 packed = (na - cao) / csf
       elsif csf
	 packed = na / csf
       elsif cao
	 packed = na - cao
       end
       if self.typecode <= NArray::LINT
         packed = packed.round
       end
       packed
     end
   end
   
   def scaled_put(var,hash=nil)
     simple_put( pack(var), hash)
   end

   @@unpack_type = nil
   class << NetCDFVar
     def unpack_type
       @@unpack_type
     end
     def unpack_type=(na_type)
       if [NArray::BYTE, NArray::SINT, NArray::INT, 
	   NArray::SFLOAT, NArray::FLOAT, nil].include?(na_type)
	 @@unpack_type = na_type
       else
	 raise ArgumentError, "Arg must be one of NArray::BYTE, NArray::SINT, NArray::INT, NArray::SFLOAT, NArray::FLOAT"
       end
     end

   end

   def unpack(na)
     sf = att('scale_factor')
     ao = att('add_offset')
     if ( sf == nil && ao == nil ) then
       na
     else
       if sf
	 csf = sf.get
	 raise NetcdfError,"scale_factor is not a numeric" if csf.is_a?(String)
	 raise NetcdfError, "scale_factor is not unique" if csf.length != 1
	 raise NetcdfError, "zero scale_factor" if csf[0] == 0
       else
	 csf =nil
       end
       if ao
	 cao = ao.get
	 raise NetcdfError, "add_offset is not a numeric" if cao.is_a?(String)
	 raise NetcdfError, "add_offset is not unique" if cao.length != 1
       else
	 cao = nil
       end
       if csf and cao
	 una = na * csf + cao  # csf & cao are NArray -> coerced to their types
       elsif csf
	 una = na * csf
       elsif cao
	 una = na + cao
       end
       una = una.to_type(@@unpack_type) if @@unpack_type
       una
     end
   end

   def scaled_get(hash=nil)
     unpack( simple_get(hash) )
   end

   def simple_put(var,hash=nil)
     if hash==nil
       if self.vartype == "char"
	 put_var_char(var)
       elsif self.vartype == "byte"
	 put_var_byte(var)
       elsif self.vartype == "sint"
	 put_var_sint(var)
       elsif self.vartype == "int"
	 put_var_int(var)
       elsif self.vartype == "sfloat"
	 put_var_sfloat(var)
       elsif self.vartype == "float"
	 put_var_float(var)
       else 
	 raise NetcdfError,"variable type isn't supported in netCDF" 
       end
     elsif hash.key?("index")==true 
       if self.vartype == "char"
	 put_var1_char(var,hash["index"])
       elsif self.vartype=="byte"
	 put_var1_byte(var,hash["index"])
       elsif self.vartype=="sint"
	 put_var1_sint(var,hash["index"])
       elsif self.vartype == "int"
	 put_var1_int(var,hash["index"])
       elsif self.vartype == "sfloat"
	 put_var1_sfloat(var,hash["index"])
       elsif self.vartype == "float"
	 put_var1_float(var,hash["index"])
       else 
	 raise NetcdfError,"variable type isn't supported in netCDF"
       end
     elsif hash.key?("start")==true
       if hash.key?("end")==false && hash.key?("stride")==false
	 if self.vartype == "char"
	   put_vars_char(var,hash["start"],nil,nil)
	 elsif self.vartype=="byte"
	   put_vars_byte(var,hash["start"],nil,nil)
	 elsif self.vartype=="sint"
	   put_vars_sint(var,hash["start"],nil,nil)
	 elsif self.vartype=="int"
	   put_vars_int(var,hash["start"],nil,nil)
	 elsif self.vartype=="sfloat"
	   put_vars_sfloat(var,hash["start"],nil,nil)
	 elsif self.vartype=="float"
	   put_vars_float(var,hash["start"],nil,nil)
	 else
	   raise NetcdfError, "variable type isn't supported in netCDF"
	 end
       elsif hash.key?("end")==true && hash.key?("stride") == false
	 if self.vartype == "char"
	   put_vars_char(var,hash["start"],hash["end"],nil)
	 elsif self.vartype=="byte"
	   put_vars_byte(var,hash["start"],hash["end"],nil)
	 elsif self.vartype=="sint"
	   put_vars_sint(var,hash["start"],hash["end"],nil)
	 elsif self.vartype=="int"
	   put_vars_int(var,hash["start"],hash["end"],nil)
	 elsif self.vartype == "sfloat"
	   put_vars_sfloat(var,hash["start"],hash["end"],nil)
	 elsif self.vartype =="float"
	   put_vars_float(var,hash["start"],hash["end"],nil)
	 else
	   raise NetcdfError, "variable type isn't supported in netCDF"
	 end
       elsif hash.key?("end")==false && hash.key?("stride")==true
	 if self.vartype == "char"
	   put_vars_char(var,hash["start"],nil,hash["stride"])
	 elsif self.vartype=="byte"
	   put_vars_byte(var,hash["start"],nil,hash["stride"])
	 elsif self.vartype=="sint"
	   put_vars_sint(var,hash["start"],nil,hash["stride"])
	 elsif self.vartype=="int"
	   put_vars_int(var,hash["start"],nil,hash["stride"])
	 elsif self.vartype=="sfloat"
	   put_vars_sfloat(var,hash["start"],nil,hash["stride"])
	 elsif self.vartype=="float"
	   put_vars_float(var,hash["start"],nil,hash["stride"])
	 else
	   raise NetcdfError, "variable type isn't supported in netCDF"
	 end
       else hash.key?("end")==true && hash.key?("stride")==true
	 if self.vartype == "char"
	   put_vars_char(var,hash["start"],hash["end"],hash["stride"])
	 elsif self.vartype=="byte"
	   put_vars_byte(var,hash["start"],hash["end"],hash["stride"])
	 elsif self.vartype=="sint"
	   put_vars_sint(var,hash["start"],hash["end"],hash["stride"])
	 elsif self.vartype=="int"
	   put_vars_int(var,hash["start"],hash["end"],hash["stride"])
	 elsif self.vartype=="sfloat"
	   put_vars_sfloat(var,hash["start"],hash["end"],hash["stride"])
	 elsif self.vartype=="float"
	   put_vars_float(var,hash["start"],hash["end"],hash["stride"])
	 else
	   raise NetcdfError, "variable type isn't supported in netCDF"
	 end
       end
     else
       raise ArgumentError,"{'start'}=>[ARRAY] or {'index'}=>[ARRAY] is needed"
     end
   end

   alias put simple_put

   def simple_get(hash=nil)
     t_var = self.vartype
     if hash == nil
       if t_var == "char"
	 get_var_char
       elsif t_var == "byte"
	 get_var_byte
       elsif t_var == "sint"
	 get_var_sint
       elsif t_var == "int"
	 get_var_int
       elsif t_var == "sfloat"
	 get_var_sfloat
       elsif t_var == "float"
	 get_var_float
       else
	  raise NetcdfError, "variable type #{t_var} isn't supported in netCDF"
       end
     elsif hash.key?("index")==true
       ind = hash["index"]
       if t_var == "char"
	 get_var1_char(ind)
       elsif t_var == "byte"
	 get_var1_byte(ind)
       elsif t_var == "sint"
	 get_var1_sint(ind)
       elsif t_var == "int"
	 get_var1_int(ind)
       elsif t_var == "sfloat"
	 get_var1_sfloat(ind)
       elsif t_var == "float"
	 get_var1_float(ind)
       else
	 raise NetcdfError,"variable type #{t_var} isn't supported in netCDF"
       end
     elsif hash.key?("start")==true
       h_sta = hash["start"]
       endq = hash.key?("end")
       strq = hash.key?("stride")
       if endq == false && strq == false
	 if t_var == "char"
	   get_vars_char(h_sta,nil,nil)
	 elsif t_var == "byte"
	   get_vars_byte(h_sta,nil,nil)
	 elsif t_var == "sint" 
	   get_vars_sint(h_sta,nil,nil)
	 elsif t_var == "int"
	   get_vars_int(h_sta,nil,nil)
	 elsif t_var == "sfloat"
	   get_vars_sfloat(h_sta,nil,nil)
	 elsif t_var == "float"
	   get_vars_float(h_sta,nil,nil)
	 else 
	   raise NetcdfError, "varialbe type #{t_var} isn't supported in netCDF"
	 end
       elsif endq == true && strq == false
	 h_end = hash["end"]
 	 if t_var == "char"
	   get_vars_char(h_sta,h_end,nil)
 	 elsif t_var == "byte"
	   get_vars_byte(h_sta,h_end,nil)
	 elsif t_var == "sint"
	   get_vars_sint(h_sta,h_end,nil)
	 elsif t_var == "int"
	   get_vars_int(h_sta,h_end,nil)
	 elsif t_var == "sfloat"
	   get_vars_sfloat(h_sta,h_end,nil)
	 elsif t_var == "float"
	   get_vars_float(h_sta,h_end,nil)
	 else
	   raise NetcdfError, "variable type #{t_var} isn't supported in netCDF"
	 end
       elsif endq == false && strq == true
	 h_str = hash["stride"]
 	 if t_var == "char"
	   get_vars_char(h_sta,nil,h_str)
 	 elsif t_var == "byte"
	   get_vars_byte(h_sta,nil,h_str)
	 elsif t_var == "sint"
	   get_vars_sint(h_sta,nil,h_str)
	 elsif t_var == "int"
	   get_vars_int(h_sta,nil,h_str)
	 elsif t_var == "sfloat"
	   get_vars_sfloat(h_sta,nil,h_str)
	 elsif t_var == "float"
	   get_vars_float(h_sta,nil,h_str)
	 else
	   raise NetcdfError, "variable type #{t_var} isn't supported in netCDF"
	 end
       else endq == true && strq == true
	 h_end = hash["end"]
	 h_str = hash["stride"]
	 if t_var == "char"
	   get_vars_char(h_sta,h_end,h_str)
	 elsif t_var == "byte"
	   get_vars_byte(h_sta,h_end,h_str)
	 elsif t_var == "sint"
	   get_vars_sint(h_sta,h_end,h_str)
	 elsif t_var == "int"
	   get_vars_int(h_sta,h_end,h_str)
	 elsif t_var == "sfloat"
	   get_vars_sfloat(h_sta,h_end,h_str)
	 elsif t_var == "float"
	   get_vars_float(h_sta,h_end,h_str)
	 else
	   raise NetcdfError, "variable type #{t_var} isn't supported in netCDF"
	 end
       end
     else
       raise ArgumentError,"{'start'}=>{ARRAY} or {'index'}=>{ARRAY} is needed"
     end
   end

   alias get simple_get

   def __rubber_expansion( args )
     if (id = args.index(false))  # substitution into id
       # false is incuded
       alen = args.length
       if args.rindex(false) != id
	 raise ArguemntError,"only one rubber dimension is permitted"
       elsif alen > rank+1
	 raise ArgumentError, "too many args"
       end
       ar = ( id!=0 ? args[0..id-1] : [] )
       args = ar + [true]*(rank-alen+1) + args[id+1..-1]
     elsif args.length == 0   # to support empty [], []=
       args = [true]*rank
     end
     args
   end
   private :__rubber_expansion

   def [](*a)
     if a.length == 0
       return self.get
     end
     a = __rubber_expansion(a)
     first = Array.new
     last = Array.new
     stride = Array.new
     set_stride = false
     a.each{|i|
       if(i.is_a?(Fixnum))
	 first.push(i)
	 last.push(i)
	 stride.push(1)
       elsif(i.is_a?(Range))
	 first.push(i.first)
	 last.push(i.exclude_end? ? i.last-1 : i.last)
	 stride.push(1)
       elsif(i.is_a?(Hash))
	 r = (i.to_a[0])[0]
         s = (i.to_a[0])[1]
         if ( !( r.is_a?(Range) ) || ! ( s.is_a?(Integer) ) )
	    raise TypeError, "Hash argument must be {a_Range, step}"
	 end
	 first.push(r.first) 
	 last.push(r.exclude_end? ? r.last-1 : r.last)
	 stride.push(s)
	 set_stride = true
       elsif(i.is_a?(TrueClass))
	 first.push(0)
	 last.push(-1)
	 stride.push(1)
       elsif( i.is_a?(Array) || i.is_a?(NArray))
	 a_new = a.dup
	 at = a.index(i)
	 i = NArray.to_na(i) if i.is_a?(Array)
	 for n in 0..i.length-1
	   a_new[at] = i[n]..i[n]
	   na_tmp = self[*a_new]
	   if n==0 then
	     k = at
	     if at > 0
	       a[0..at-1].each{|x| if x.is_a?(Fixnum) then k -= 1 end}
	     end
	     shape_tmp = na_tmp.shape
	     shape_tmp[k] = i.length
	     na = na_tmp.class.new(na_tmp.typecode,*shape_tmp)
	     index_tmp = Array.new(shape_tmp.length,true)
	   end
	   index_tmp[k] = n..n
	   na[*index_tmp] = na_tmp
	 end
	 return na
       else
	 raise TypeError, "argument must be Fixnum, Range, Hash, TrueClass, Array, or NArray"
       end
     }

     if(set_stride)
       na = self.get({"start"=>first, "end"=>last, "stride"=>stride})
     else
       na = self.get({"start"=>first, "end"=>last})
     end
     shape = na.shape
     (a.length-1).downto(0){ |i|
	 shape.delete_at(i) if a[i].is_a?(Fixnum)
      }
      na.reshape!( *shape )
     na
   end

   def []=(*a)
     val = a.pop
     a = __rubber_expansion(a)
     first = Array.new
     last = Array.new
     stride = Array.new
     set_stride = false
     a.each{|i|
       if(i.is_a?(Fixnum))
	 first.push(i)
	 last.push(i)
	 stride.push(1)
       elsif(i.is_a?(Range))
	 first.push(i.first)
	 last.push(i.exclude_end? ? i.last-1 : i.last)
	 stride.push(1)
       elsif(i.is_a?(Hash))
	 r = (i.to_a[0])[0]
         s = (i.to_a[0])[1]
         if ( !( r.is_a?(Range) ) || ! ( s.is_a?(Integer) ) )
	    raise ArgumentError, "Hash argument must be {first..last, step}"
	 end
	 first.push(r.first) 
	 last.push(r.exclude_end? ? r.last-1 : r.last)
	 stride.push(s)
	 set_stride = true
       elsif(i.is_a?(TrueClass))
	 first.push(0)
	 last.push(-1)
	 stride.push(1)
       elsif(i.is_a?(Array) || i.is_a?(NArray))
	 a_new = a.dup
	 at = a.index(i)
	 i = NArray.to_na(i) if i.is_a?(Array)
	 val = NArray.to_na(val) if val.is_a?(Array)
	 rank_of_subset = a.dup.delete_if{|v| v.is_a?(Fixnum)}.length
	 if val.rank != rank_of_subset
	   raise "rank of the rhs (#{val.rank}) is not equal to the rank "+
                 "of the subset specified by #{a.inspect} (#{rank_of_subset})"
	 end
	 k = at
	 a[0..at-1].each{|x| if x.is_a?(Fixnum) then k -= 1 end}
	 if i.length != val.shape[k]
	   raise "length of the #{k+1}-th dim of rhs is incorrect "+
                 "(#{i.length} for #{val.shape[k]})"
	 end
	 index_tmp = Array.new(val.rank,true) if !val.is_a?(Numeric) #==>Array-like
	 for n in 0..i.length-1
	   a_new[at] = i[n]..i[n]
	   if !val.is_a?(Numeric) then
	     index_tmp[k] = n..n
	     self[*a_new] = val[*index_tmp]
	   else
	     self[*a_new] = val
	   end
	 end
	 return self
       else
	 raise TypeError, "argument must be Fixnum, Range, Hash, TrueClass, Array, or NArray"
       end
     }

     if(set_stride)
	self.put(val, {"start"=>first, "end"=>last, "stride"=>stride})
     else
	self.put(val, {"start"=>first, "end"=>last})
     end
   end

   def inspect
     'NetCDFVar:'+file.path+'?var='+name
   end
   
 end
 
 class NetCDFAtt
   
   def put(val,atttype=nil)
      putraw(val,atttype)
   end
   
   def inspect
     'NetCDFAtt:'+name
   end
 end
 
 class NetCDFDim
   def inspect
     'NetCDFDim:'+name
   end

   def length_ul0
      if unlimited?
	 0
      else
	 length
      end
   end

 end
end