gentooboontoo-gphys 0.6.1.3 → 1.3.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +5631 -464
  3. data/LICENSE.txt +34 -0
  4. data/README +23 -25
  5. data/bin/gdir_client +25 -7
  6. data/bin/gdir_server +19 -13
  7. data/bin/gpaop +41 -28
  8. data/bin/gpcat +19 -11
  9. data/bin/gpcut +20 -11
  10. data/bin/gpedit +37 -1
  11. data/bin/gplist +5 -4
  12. data/bin/gpmath +21 -14
  13. data/bin/gpmaxmin +9 -7
  14. data/bin/gpprint +15 -11
  15. data/bin/gpvect +217 -96
  16. data/bin/gpview +278 -123
  17. data/bin/grads2nc_with_gphys +11 -6
  18. data/doc/attribute.html +1 -1
  19. data/doc/axis.html +85 -66
  20. data/doc/coordmapping.html +22 -22
  21. data/doc/dclext.html +709 -0
  22. data/doc/derivative/gphys-derivative.html +33 -13
  23. data/doc/derivative/numru-derivative.html +60 -31
  24. data/doc/gdir.html +76 -76
  25. data/doc/gdir_server.html +28 -16
  26. data/doc/ggraph.html +493 -706
  27. data/doc/gpcat.html +28 -11
  28. data/doc/gpcut.html +26 -11
  29. data/doc/gphys.html +195 -71
  30. data/doc/gphys_fft.html +162 -21
  31. data/doc/gphys_grads_io.html +9 -9
  32. data/doc/gphys_grib_io.html +7 -7
  33. data/doc/gphys_io.html +118 -31
  34. data/doc/gphys_io_common.html +1 -1
  35. data/doc/gphys_netcdf_io.html +14 -14
  36. data/doc/gplist.html +6 -5
  37. data/doc/gpmath.html +32 -14
  38. data/doc/gpmaxmin.html +9 -7
  39. data/doc/gpprint.html +14 -11
  40. data/doc/gpview.html +254 -146
  41. data/doc/grads2nc_with_gphys.html +6 -8
  42. data/doc/grads_gridded.html +77 -77
  43. data/doc/grib.html +102 -59
  44. data/doc/grid.html +45 -61
  45. data/doc/index.html +51 -41
  46. data/doc/index.rd +47 -36
  47. data/doc/netcdf_convention.html +39 -39
  48. data/doc/unumeric.html +79 -30
  49. data/doc/update +2 -1
  50. data/doc/varray.html +62 -56
  51. data/doc/varraycomposite.html +3 -3
  52. data/ext/ext_coord.c +209 -0
  53. data/ext/ext_init.c +7 -0
  54. data/ext/extconf.rb +41 -0
  55. data/ext/interpo.c +536 -0
  56. data/ext/multibitIO.c +567 -0
  57. data/lib/numru/dcl_mouse.rb +71 -0
  58. data/lib/numru/dclext.rb +2749 -0
  59. data/lib/numru/derivative.rb +124 -31
  60. data/lib/numru/ganalysis.rb +7 -0
  61. data/lib/numru/ganalysis/covariance.rb +154 -0
  62. data/lib/numru/ganalysis/eof.rb +302 -0
  63. data/lib/numru/ganalysis/histogram.rb +337 -0
  64. data/lib/numru/ganalysis/met.rb +872 -0
  65. data/lib/numru/ganalysis/planet.rb +392 -0
  66. data/lib/numru/ggraph.rb +1709 -2498
  67. data/lib/numru/gphys.rb +7 -1
  68. data/lib/numru/gphys/assoccoords.rb +384 -0
  69. data/lib/numru/gphys/attribute.rb +10 -11
  70. data/lib/numru/gphys/axis.rb +97 -25
  71. data/lib/numru/gphys/coordmapping.rb +2 -2
  72. data/lib/numru/gphys/derivative.rb +117 -46
  73. data/lib/numru/gphys/gphys.rb +595 -31
  74. data/lib/numru/gphys/gphys_fft.rb +365 -13
  75. data/lib/numru/gphys/gphys_grads_io.rb +6 -5
  76. data/lib/numru/gphys/gphys_grib_io.rb +6 -6
  77. data/lib/numru/gphys/gphys_gtool3_io.rb +162 -0
  78. data/lib/numru/gphys/gphys_hdfeos5_io.rb +672 -0
  79. data/lib/numru/gphys/gphys_io.rb +260 -20
  80. data/lib/numru/gphys/gphys_io_common.rb +1 -1
  81. data/lib/numru/gphys/gphys_netcdf_io.rb +111 -40
  82. data/lib/numru/gphys/gphys_nusdas_io.rb +64 -7
  83. data/lib/numru/gphys/grads_gridded.rb +158 -57
  84. data/lib/numru/gphys/grib.rb +205 -157
  85. data/lib/numru/gphys/grib_params.rb +196 -1
  86. data/lib/numru/gphys/grid.rb +214 -83
  87. data/lib/numru/gphys/gtool3.rb +771 -0
  88. data/lib/numru/gphys/interpolate.rb +992 -0
  89. data/lib/numru/gphys/mdstorage.rb +145 -0
  90. data/lib/numru/gphys/narray_ext.rb +34 -0
  91. data/lib/numru/gphys/netcdf_convention.rb +44 -2
  92. data/lib/numru/gphys/subsetmapping.rb +1 -1
  93. data/lib/numru/gphys/unumeric.rb +101 -8
  94. data/lib/numru/gphys/varray.rb +66 -20
  95. data/lib/numru/gphys/varraycomposite.rb +107 -29
  96. data/lib/numru/gphys/varraygrib.rb +70 -8
  97. data/lib/numru/gphys/varraygtool3.rb +226 -0
  98. data/lib/numru/gphys/varrayhdfeos5.rb +451 -0
  99. data/lib/numru/gphys/varraynetcdf.rb +13 -5
  100. data/lib/numru/gphys/version.rb +3 -0
  101. data/sample/druby_cli1.rb +2 -0
  102. data/sample/druby_cli2.rb +0 -6
  103. data/sample/druby_serv2.rb +0 -13
  104. data/sample/ncep_theta_coord.rb +79 -0
  105. data/test/eof_slp.rb +28 -0
  106. data/test/mltbit.dat +0 -0
  107. data/test/test_multibitIO.rb +19 -0
  108. data/testdata/assoc_crds.nc +0 -0
  109. metadata +79 -8
  110. data/lib/numru/dclext_datetime_ax.rb +0 -220
  111. data/lib/numru/vizshot.rb +0 -697
@@ -0,0 +1,145 @@
1
+ require "narray"
2
+
3
+ module NumRu
4
+ class MDStorage
5
+ def initialize(rank=1)
6
+ raise(ArgumentError,"rank must be a positive integer") if !(rank>0)
7
+ @rank = rank
8
+ @shape = []
9
+ rank.times{@shape.push(1)}
10
+ @data = [nil]
11
+ (rank-1).times{
12
+ @data = [@data]
13
+ }
14
+ end
15
+
16
+ attr_reader :rank
17
+
18
+ def shape
19
+ @shape.dup
20
+ end
21
+
22
+ # add a new dimension to the last
23
+ def add_dim
24
+ @rank += 1
25
+ @shape.push(1)
26
+ @data = [@data]
27
+ end
28
+
29
+ # increase the length of a dimension by one
30
+ def extend(dim)
31
+ if dim<0 or dim>=rank
32
+ raise(ArgumentError,"invalid dim (#{dim}): not in #{0..rank-1}")
33
+ end
34
+ yield_at_depth(@data,rank-1-dim){|a|
35
+ a.push( dim==0 ? nil : make_nested_array(shape[0..dim-1]) )
36
+ }
37
+ @shape[dim] += 1
38
+ self
39
+ end
40
+
41
+ # substituion at a position specified with integers (only one element)
42
+ def []=(*args)
43
+ val = args.pop
44
+ raise(ArgumentError,"# of args != rank (#{rank})") if args.length != rank
45
+ x = @data
46
+ (rank-1).downto(1) do |d|
47
+ idx = args[d]
48
+ raise(ArgumentError,"all args must be integers") if !idx.is_a?(Integer)
49
+ len = shape[d]
50
+ idx += len if idx<0
51
+ raise("Too big negative index for dim #{d}: #{idx-len}") if idx<0
52
+ if 0<=idx and idx<len
53
+ x = x[idx]
54
+ elsif idx >= len
55
+ (idx-len+1).times{extend(d)}
56
+ x = x[idx]
57
+ else
58
+ raise(ArgumentError,"invalid specification")
59
+ end
60
+ end
61
+
62
+ idx = args[0]
63
+ len = shape[0]
64
+ idx += len if idx<0
65
+ raise("Too big negative index for dim #{0}: #{idx-len}") if idx<0
66
+ if idx >= len
67
+ (idx-len+1).times{extend(0)}
68
+ end
69
+ x[idx] = val
70
+ end
71
+
72
+ # read from a position specified with integers (only one element)
73
+ def [](*args)
74
+ raise(ArgumentError,"# of args != rank (#{rank})") if args.length != rank
75
+ x = @data
76
+ args.reverse_each do |idx|
77
+ raise(ArgumentError,"all args must be integers") if !idx.is_a?(Integer)
78
+ x = x[idx]
79
+ return(x) if x.nil?
80
+ end
81
+ x
82
+ end
83
+
84
+ def to_na
85
+ NArray.to_na(@data)
86
+ end
87
+
88
+ #############################################
89
+ ## < private methods >
90
+ private
91
+ =begin
92
+ def __rubber_expansion( args )
93
+ if (id = args.index(false)) # substitution into id
94
+ # false is incuded
95
+ alen = args.length
96
+ if args.rindex(false) != id
97
+ raise ArguemntError,"only one rubber dimension is permitted"
98
+ elsif alen > rank+1
99
+ raise ArgumentError, "too many args"
100
+ end
101
+ ar = ( id!=0 ? args[0..id-1] : [] )
102
+ args = ar + [true]*(rank-alen+1) + args[id+1..-1]
103
+ end
104
+ args
105
+ end
106
+ =end
107
+
108
+ # make a neste multi-D Array filled with nil
109
+ def make_nested_array(shape)
110
+ if shape.length == 1
111
+ Array.new(shape[0]) # => [nil,nil,...,nil]
112
+ elsif shape.length > 1 # recursive construction
113
+ (0...shape[-1]).collect{make_nested_array(shape[0..-2])}
114
+ else
115
+ raise ArgumentError, "shape must have 1 or more elements"
116
+ end
117
+ end
118
+
119
+ # call the block at the depth in the nested array
120
+ def yield_at_depth(ary,depth, &blk)
121
+ if depth==0
122
+ blk.call(ary) # call the block
123
+ elsif depth>0
124
+ ary.each{|sub| yield_at_depth(sub,depth-1,&blk)}
125
+ else
126
+ raise ArgumentError, "depth must be >= 0"
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ if $0 == __FILE__
133
+ include NumRu
134
+ a = MDStorage.new(3)
135
+ p a
136
+ p a.extend(2)
137
+ p a.extend(2)
138
+ p a.extend(0)
139
+ a[0,0,0] = 10.9
140
+ a[1,0,-1] = "XX"
141
+ p a, a[0,0,0], a[1,0,-1]
142
+ a[2,0,2] = '###'
143
+ p a
144
+ p a.to_na
145
+ end
@@ -0,0 +1,34 @@
1
+ require "narray"
2
+
3
+ class NArray
4
+
5
+ @@dump_size_limit = -1 # max len to allow dump / no limit if negative
6
+ def self.dump_size_limit=(lmt)
7
+ @@dump_size_limit = lmt
8
+ end
9
+ def self.dump_size_limit
10
+ @@dump_size_limit
11
+ end
12
+
13
+ def self.endian
14
+ NArray[1].to_s[1] == 1 ? :little : :big
15
+ end
16
+
17
+ def _dump(limit)
18
+ if (@@dump_size_limit <= 0) || (size <= @@dump_size_limit)
19
+ Marshal.dump([typecode, shape, NArray.endian, to_s])
20
+ else
21
+ raise "size of the NArray (#{size}) is too large to dump "+
22
+ "(limit: #{DUMP_SIZE_LIMIT})"
23
+ end
24
+ end
25
+
26
+ def self._load(str)
27
+ ary = Marshal.load(str)
28
+ typecode, shape, endian, str = ary
29
+ na = NArray.to_na(str, typecode, *shape)
30
+ na = na.swap_byte unless endian == NArray.endian
31
+ return na
32
+ end
33
+
34
+ end
@@ -167,7 +167,8 @@ module NumRu
167
167
  when /^Wind Profiler/
168
168
  NetCDF_Convention_Wind_Profiler
169
169
  else
170
- NetCDF_Convention_Users_Guide
170
+ #NetCDF_Convention_Users_Guide
171
+ NetCDF_Convention_CF
171
172
  end
172
173
  end
173
174
  end
@@ -299,8 +300,49 @@ module NumRu
299
300
  nil # no rule for that
300
301
  end
301
302
 
303
+ def assoc_coord_names(data)
304
+ nil # no rule for that
305
+ end
306
+
307
+ end
308
+
309
+ module NetCDF_Convention_CF
310
+ # http://cf-pcmdi.llnl.gov/
311
+
312
+ # < inherit the Users guide convention >
313
+
314
+ module Attribute_Mixin
315
+ include NetCDF_Convention_Users_Guide::Attribute_Mixin
316
+ end # module Attribute_Mixin
317
+ module VArray_Mixin
318
+ include NetCDF_Convention_Users_Guide::VArray_Mixin
319
+ end # module VArray_Mixin
320
+ module_function
321
+ extend NetCDF_Convention_Users_Guide
322
+ public_class_method :aux_var_names, :coord_var_names, :cell_bounds?, :cell_center?
323
+
324
+ ########### original part starts here #################
325
+
326
+ def assoc_coord_names(data)
327
+ if s = data.get_att("coordinates")
328
+ nms = s.split(/ +/)
329
+ case data.file
330
+ when NArray
331
+ fl = data.file[0]
332
+ else
333
+ fl = data.file
334
+ end
335
+ nms.delete_if{|nm| !fl.var(nm)}
336
+ nms.delete_if{|nm| fl.dim_names.include?(nm)}
337
+ nms
338
+ else
339
+ nil
340
+ end
341
+ end
342
+
302
343
  end
303
344
 
345
+
304
346
  module NetCDF_Convention_Wind_Profiler
305
347
  # Wind Profiler Convention
306
348
  # http://www.kurasc.kyoto-u.ac.jp/radar-group/wind_profiler_conventions/
@@ -316,7 +358,7 @@ module NumRu
316
358
  ########################
317
359
  module_function
318
360
  extend NetCDF_Convention_Users_Guide
319
- public_class_method :cell_bounds?, :cell_center?
361
+ public_class_method :cell_bounds?, :cell_center?, :assoc_coord_names
320
362
 
321
363
  def to_s
322
364
  "Wind Profiler (http://www.kurasc.kyoto-u.ac.jp/radar-group/wind_profiler_conventions/)"
@@ -231,7 +231,7 @@ module NumRu
231
231
  idxary = @index_array[mida]
232
232
  if idxary.length==1
233
233
  fst = idxary[0]
234
- len = step = 1
234
+ len = stp = 1
235
235
  slicer = __make_regular_slicer((scl=mapping.collapsed),fst,len,stp)
236
236
  SubsetMapping1D.new0.initialize_regular(slicer,scl,fst,len,stp)
237
237
  else
@@ -187,29 +187,88 @@ module NumRu
187
187
  new(val, uni)
188
188
  end
189
189
 
190
+ @@supported_calendars = [nil,"gregorian", "standard", "proleptic_gregorian",
191
+ "noleap", "365_day", "360_day"]
192
+
193
+ def self::supported_calendar?(cal)
194
+ @@supported_calendars.include?(cal)
195
+ end
196
+
197
+ def self::supported_calendars
198
+ @@supported_calendars.dup
199
+ end
200
+
190
201
  # * date (Date or DateTime)
191
202
  # * units (Units or String) : units of the UNumeric to be created
192
- def self::from_date(date, units)
203
+ def self::from_date(date, units, calendar=nil)
193
204
  sunits = units.to_s
194
205
  /(.*) *since *(.*)/ =~ sunits
195
206
  if (!$1 or !$2)
196
207
  raise("Units mismatch. Requires time units that includes 'since'")
197
208
  end
198
209
  tun = Units[$1]
199
- since = DateTime.parse($2)
210
+ since = DateTime.parse(UNumeric::before_date_parse($2))
200
211
  if( tun =~ Units['months since 0001-01-01'] )
201
212
  year0,mon0 = since.year,since.mon
202
213
  year,mon = date.year,date.mon
203
214
  time = Units['months'].convert((year*12+mon)-(year0*12+mon0), tun)
204
215
  elsif( tun =~ Units['days since 0001-01-01'] )
205
- time = Units['days'].convert( date-since, tun )
216
+ case calendar
217
+ when nil, "gregorian", "standard"
218
+ time = Units['days'].convert( date-since, tun )
219
+ when "proleptic_gregorian"
220
+ since = DateTime.parse(UNumeric::before_date_parse($2),false,Date::GREGORIAN)
221
+ time = Units['days'].convert( date-since, tun )
222
+ when "noleap", "365_day"
223
+ since_yday = since - DateTime.new(since.year,1,1) # day number of year (0..364)
224
+ since_yday = since_yday - 1 if( since.leap? && since.mon > 2 )
225
+ date_yday = date - DateTime.new(date.year,1,1)
226
+ if( date.leap? )
227
+ if date_yday >= 60.0 # after Mar1
228
+ date_yday = date_yday - 1
229
+ elsif date_yday >= 59.0 # Feb29
230
+ raise("Feb.29 is specified, but calendar is #{calendar}.")
231
+ end
232
+ end
233
+ days = (date.year - since.year)*365 + (date_yday - since_yday)
234
+ time = Units['days'].convert( days, tun )
235
+ when "360_day" # does not work perfectly
236
+ if date.day == 31
237
+ raise("day=31 is specified, but calendar is #{calendar}.")
238
+ end
239
+ if date.is_a?(DateTime)
240
+ date_hour,date_min,date_sec = date.hour,date.min,date.sec
241
+ else
242
+ date_hour,date_min,date_sec = 0,0,0
243
+ end
244
+ days = (date.year-since.year)*360 + (date.mon-since.mon)*30 +
245
+ (date.day-since.day) + Rational(date_hour-since.hour,24) +
246
+ Rational(date_min-since.min,1440) + Rational(date_sec-since.sec,86400)
247
+ time = Units['days'].convert( days.to_f, tun )
248
+ else
249
+ #raise("Unrecognized calendar: #{calendar}")
250
+ return nil
251
+ end
206
252
  else
207
- raise("Unrecognized time units #{tun.to_s} -- may be a BUG?")
253
+ #raise("Unrecognized time units #{tun.to_s}")
254
+ return nil
208
255
  end
209
256
  time = time.to_f
210
257
  UNumeric[time, units]
211
258
  end
212
259
 
260
+
261
+ # Always interpret y \d\d as 00\d\d and y \d as 000\d
262
+ # (Date in Ruby 1.9 interprets them as 20\d\d etc.)
263
+ def self::before_date_parse(str)
264
+ if /^\d\d-\d/ =~ str
265
+ str = "00"+str
266
+ elsif /^\d-\d/ =~ str
267
+ str = "00"+str
268
+ end
269
+ str
270
+ end
271
+
213
272
  def val; @val; end
214
273
 
215
274
  def units; @uni; end
@@ -250,7 +309,7 @@ module NumRu
250
309
 
251
310
  # * eps_sec : Magic epsilon to prevent the round-off of DateTime [seconds].
252
311
  # Recommended value is 0.1.
253
- def to_datetime(eps_sec=0.0)
312
+ def to_datetime(eps_sec=0.0,calendar=nil)
254
313
  time = self.val
255
314
  sunits = self.units.to_s
256
315
  /(.*) *since *(.*)/ =~ sunits
@@ -258,13 +317,47 @@ module NumRu
258
317
  raise("Units mismatch. Requires time units that includes 'since'")
259
318
  end
260
319
  tun = Units[$1]
261
- since = DateTime.parse($2)
320
+ sincestr = $2.sub(/(^\d{1,2}-\d+-\d)/,'00\1')
321
+ #^ correction for Ruby 1.9 to prevent 1- or 2-digit years
322
+ # (e.g. 1, 02) to be interpreted as in 2000's (e.g., 2001, 2002)
323
+ since = DateTime.parse(UNumeric::before_date_parse(sincestr))
262
324
  if( tun =~ Units['months since 0001-01-01'] )
263
325
  datetime = since >> tun.convert( time, Units['months'] )
264
326
  elsif( tun =~ Units['days since 0001-01-01'] )
265
- datetime = since + tun.convert( time, Units['days'] )
327
+ case calendar
328
+ when nil, "gregorian", "standard"
329
+ # default: Julian calendar before 1582-10-15, Gregorian calendar afterward
330
+ datetime = since + tun.convert( time, Units['days'] )
331
+ when "proleptic_gregorian"
332
+ # Gregorian calendar extended to the past
333
+ since = DateTime.parse(UNumeric::before_date_parse(sincestr),false,Date::GREGORIAN)
334
+ datetime = since + tun.convert( time, Units['days'] )
335
+ when "noleap", "365_day"
336
+ since_yday = since - DateTime.new(since.year,1,1) # day number of year (0..364)
337
+ since_yday = since_yday - 1 if( since.leap? && since.mon > 2 )
338
+ days = since_yday + tun.convert( time, Units['days'] )
339
+ year = since.year + (days/365).to_i
340
+ date_yday = days%365 # day number of year (0..364)
341
+ datetime = DateTime.new(year,1,1) + date_yday
342
+ datetime = datetime + 1 if( datetime.leap? && date_yday >= 59 )
343
+ when "360_day" # does not work perfectly
344
+ since_day = since - DateTime.new(since.year,since.mon,1)
345
+ days = (since.mon-1)*30 + since_day + tun.convert( time, Units['days'] )
346
+ year = since.year + (days/360).to_i
347
+ mon = ((days%360)/30).to_i + 1
348
+ datetime = DateTime.new(year,mon,1) + days%30 # Feb29->Mar1,Feb30->Mar2
349
+ #datetime = DateTime.new(year,mon,days%30 + 1) # stops if Feb29,Feb30
350
+ if datetime.mon != mon # Feb29,Feb30
351
+ $stderr.print("cannot convert #{year}-#{mon}-#{(days%30+1).to_i} to DateTime instance\n")
352
+ return nil
353
+ end
354
+ else
355
+ #raise("Unrecognized calendar: #{calendar}")
356
+ return nil
357
+ end
266
358
  else
267
- raise("Unrecognized time units #{tun.to_s} -- may be a BUG?")
359
+ #raise("Unrecognized time units #{tun.to_s}")
360
+ return nil
268
361
  end
269
362
  if eps_sec != 0.0
270
363
  datetime = datetime + eps_sec/8.64e4
@@ -263,6 +263,12 @@ NOMENCLATURE
263
263
  * Float if the modulo is defined
264
264
  * nil if modulo is not found
265
265
 
266
+ ---axis_cyclic_extendible?
267
+ (meaningful only if self is a coordinate variable.)
268
+ Returns true if self is cyclic and it is suitable to exend
269
+ cyclically (having the distance between both ends
270
+ equal to (modulo - dx), where dx is the mean increment).
271
+
266
272
  ---coerce(other)
267
273
  For Numeric operators. (If you do not know it, see a manual or book of Ruby)
268
274
 
@@ -325,7 +331,7 @@ These methods returns a NArray (not a VArray).
325
331
  when nil
326
332
  @attr = NumRu::Attribute.new
327
333
  else
328
- raise TypeErroor, "#{attr.class} is unsupported for the 2nd arg"
334
+ raise TypeError, "#{attr.class} is unsupported for the 2nd arg"
329
335
  end
330
336
  end
331
337
 
@@ -409,11 +415,7 @@ These methods returns a NArray (not a VArray).
409
415
  end
410
416
 
411
417
  def ntype
412
- if !@mapping
413
- __ntype(@ary)
414
- else
415
- __ntype(@varray.ary)
416
- end
418
+ __ntype(typecode)
417
419
  end
418
420
 
419
421
  def name=(nm)
@@ -446,7 +448,7 @@ These methods returns a NArray (not a VArray).
446
448
  if @mapping
447
449
  @varray.file
448
450
  else
449
- raise nil
451
+ return nil
450
452
  end
451
453
  end
452
454
 
@@ -545,7 +547,14 @@ These methods returns a NArray (not a VArray).
545
547
  end
546
548
  myunits = self.units
547
549
  if myunits != to
548
- gp = myunits.convert2(self, to)
550
+ if calendar = self.get_att("calendar")
551
+ date0 = UNumeric.new(0,myunits).to_datetime
552
+ un0 = UNumeric.from_date(date0,to,calendar)
553
+ offset = un0.to_f
554
+ gp = self + offset
555
+ else
556
+ gp = myunits.convert2(self, to)
557
+ end
549
558
  gp.units = to
550
559
  gp
551
560
  else
@@ -625,7 +634,7 @@ These methods returns a NArray (not a VArray).
625
634
  when /circular/i
626
635
  true
627
636
  when nil # 'topology' not defined
628
- if attr['units'] == 'degrees_east'
637
+ if /degrees?_east/ =~ attr['units']
629
638
  true # special treatment a common convention for the earth
630
639
  else
631
640
  nil # not defined --> nil
@@ -645,15 +654,34 @@ These methods returns a NArray (not a VArray).
645
654
  else
646
655
  attval[0]
647
656
  end
648
- else
649
- if attr['units'] == 'degrees_east'
650
- 360.0 # special treatment a common convention for the earth
651
- else
652
- nil # not defined --> nil
653
- end
657
+ elsif /degrees?_east/ =~ attr['units']
658
+ 360.0 # special treatment: a common convention for the earth
659
+ elsif (tp = attr['topology']) and (/circular/i =~ tp)
660
+ un = Units[attr['units']]
661
+ if un == Units['degrees']
662
+ 360.0
663
+ elsif un == Units['radian']
664
+ 2*Math::PI
665
+ else
666
+ nil # cannot guess --> nil
667
+ end
668
+ else
669
+ nil # not defined --> nil
654
670
  end
655
671
  end
656
672
 
673
+ def axis_cyclic_extendible?
674
+ modulo = axis_modulo
675
+ return false if !modulo
676
+ v = val
677
+ width = (v[-1] - v[0]).abs
678
+ dx = width / (length-1)
679
+ eps = 1e-4
680
+ modulo = modulo.abs
681
+ extendible = ( ((width+dx) - modulo).abs < eps*modulo )
682
+ return extendible
683
+ end
684
+
657
685
  ### < NArray methods > ###
658
686
 
659
687
  ## ToDo: implement units handling
@@ -778,7 +806,7 @@ These methods returns a NArray (not a VArray).
778
806
  ary = NArrayMiss.to_nam(vl)#{f}(vr)
779
807
  end
780
808
  va = VArray.new( ary, self.attr_copy, self.name )
781
- va.units= self.units#{f}(other.units)
809
+ va.units= self.units#{f}(other.units) if "#{f}" != "**"
782
810
  va
783
811
  when Numeric, NArray, NArrayMiss, Array
784
812
  vl = self.val
@@ -789,7 +817,7 @@ These methods returns a NArray (not a VArray).
789
817
  ary = NArrayMiss.to_nam(vl)#{f}(vr)
790
818
  end
791
819
  va = VArray.new( ary, self.attr_copy, self.name )
792
- if "#{f}" == "**"
820
+ if "#{f}" == "**" && other.is_a?(Numeric)
793
821
  va.units= self.units#{f}(other)
794
822
  end
795
823
  va
@@ -966,6 +994,15 @@ These methods returns a NArray (not a VArray).
966
994
 
967
995
  alias shape_current shape
968
996
 
997
+ ## < marshal dump/load >
998
+ def marshal_dump
999
+ [@name, @mapping, @varray, @ary, @attr]
1000
+ end
1001
+
1002
+ def marshal_load(ary)
1003
+ @name, @mapping, @varray, @ary, @attr = *ary
1004
+ end
1005
+
969
1006
  ## < private methods >
970
1007
  private
971
1008
  def __rubber_expansion( args )
@@ -998,8 +1035,8 @@ These methods returns a NArray (not a VArray).
998
1035
  end
999
1036
  narray
1000
1037
  end
1001
- def __ntype(na)
1002
- case na.typecode
1038
+ def __ntype(typecode)
1039
+ case typecode
1003
1040
  when NArray::BYTE
1004
1041
  "byte"
1005
1042
  when NArray::SINT
@@ -1072,8 +1109,17 @@ if $0 == __FILE__
1072
1109
 
1073
1110
  p '*axis conventions*'
1074
1111
  p vx = VArray.new( NArray.int(6).indgen!, nil, 'x' )
1075
- vx.set_att('topology','circular')
1112
+
1113
+ vx.put_att("topology","circular")
1076
1114
  vx.set_att('modulo',[360.0])
1077
1115
  vx.set_att('positive','down')
1078
1116
  p vx.axis_draw_positive, vx.axis_cyclic?, vx.axis_modulo
1117
+
1118
+ p ' cyclic extendible:'
1119
+ p vx.axis_cyclic_extendible?
1120
+ vx.set_att('modulo',[6.0])
1121
+ p vx.axis_cyclic_extendible?
1122
+
1123
+ p '*typecode*'
1124
+ p vx.typecode, vx[0..1].typecode
1079
1125
  end