miriad 4.1.0.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/lib/miriad.rb ADDED
@@ -0,0 +1,564 @@
1
+ # The MIRIAD-Ruby package...
2
+ #
3
+ # 1. makes MIRIAD datasets accessible from Ruby by wrapping the MIRIAD UVIO
4
+ # routines.
5
+ #
6
+ # 2. makes Ruby usable with MIRIAD datasets by adding convenience, utility, and
7
+ # astronomy related methods to Ruby classes.
8
+ #
9
+ #--
10
+ #$Id: miriad.rb 901 2008-04-17 22:44:07Z davidm $
11
+ #++
12
+
13
+ require 'rbconfig'
14
+ require 'rubygems'
15
+ require 'date'
16
+ require 'narray'
17
+ miriad_shared_lib = 'miriad.' + Config::CONFIG['DLEXT']
18
+ require miriad_shared_lib
19
+ require 'miriad_ruby_shared_library' if false # Fake out RDoc
20
+ #require 'fftw3'
21
+
22
+ # Add CKMS constant to Math module
23
+ Math::const_set :CKMS, 299792.458 unless Math::const_defined? :CKMS
24
+
25
+ # The MIRIAD package adds angle conversion methods to the Math module
26
+ module Math
27
+ # Convert possibly non-integer degrees +fr+ to [degrees, minutes, seconds]
28
+ # where degrees and minutes are integers.
29
+ def self.d_to_dms(fr)
30
+ sign = fr <=> 0
31
+ fr *= sign
32
+ d = fr.to_i; fr %= 1; fr *= 60
33
+ m = fr.to_i; fr %= 1; fr *= 60
34
+ return d*sign, m, fr
35
+ end
36
+
37
+ # Convert possibly non-integer hours +fr+ to [hours, minutes, seconds]
38
+ # where hours and minutes are integers.
39
+ def self.h_to_hms(fr); d_to_dms(fr); end
40
+
41
+ # Convert degrees, minutes, seconds to possibly non-integer degrees.
42
+ # Missing arguments are assumed to be 0.
43
+ def self.dms_to_d(*args)
44
+ d = 0.to_r
45
+ d += args.shift unless args.empty?
46
+ sign = d <=> 0
47
+ d += args.shift * Rational(sign,60) unless args.empty?
48
+ d += args.shift * Rational(sign,3600) unless args.empty?
49
+ return d
50
+ end
51
+
52
+ # Convert hours, minutes, seconds to possibly non-integer hours.
53
+ # Missing arguments are assumed to be 0.
54
+ def self.hms_to_h(*args); dms_to_d(*args); end
55
+
56
+ # Convert degrees to radians
57
+ def self.d2r(d) d*PI/180; end
58
+ # Convert radians to degrees
59
+ def self.r2d(r) r*180/PI; end
60
+ # Convert hours to radians
61
+ def self.h2r(h) h*PI/12; end
62
+ # Convert radians to hours
63
+ def self.r2h(r) r*12/PI; end
64
+ # Convert degrees to hours
65
+ def self.d2h(d) d/15.0; end
66
+ # Convert hours to degrees
67
+ def self.h2d(h) h*15.0; end
68
+ end
69
+
70
+ # Th MIRIAD package adds angle conversion and angle formatting methods to
71
+ # Numeric class.
72
+ class Numeric
73
+ # Convert +self+ to [degrees, minutes, seconds] where degrees and minutes are
74
+ # integers.
75
+ def to_dms() Math.d_to_dms(self); end
76
+ # Convert +self+ to [hours, minutes, seconds] where hours and minutes are
77
+ # integers.
78
+ alias :to_hms :to_dms
79
+ # Convert +self+ to "##d##m##.###s" format with +prec+ fractional places.
80
+ def to_dmsstr(prec=3)
81
+ width = prec == 0 ? 2 : prec+3
82
+ "%02dd%02dm%0#{width}.#{prec}fs" % to_dms
83
+ end
84
+ # Convert +self+ to "##:##:##.###" format with +prec+ fractional places.
85
+ def to_hmsstr(prec=3)
86
+ width = prec == 0 ? 2 : prec+3
87
+ "%02d:%02d:%0#{width}.#{prec}f" % to_dms
88
+ end
89
+ # Convert +self+ from degrees to radians (i.e. <tt>Math.d2r(self)</tt>).
90
+ def d2r() Math.d2r(self); end
91
+ # Convert +self+ from radians to degrees (i.e. <tt>Math.r2d(self)</tt>).
92
+ def r2d() Math.r2d(self); end
93
+ # Convert +self+ from hours to radians (i.e. <tt>Math.h2r(self)</tt>).
94
+ def h2r() Math.h2r(self); end
95
+ # Convert +self+ from radians to hours (i.e. <tt>Math.r2h(self)</tt>).
96
+ def r2h() Math.r2h(self); end
97
+ # Convert +self+ from degrees to hours (i.e. <tt>Math.d2h(self)</tt>).
98
+ def d2h() Math.d2h(self); end
99
+ # Convert +self+ from hours to degrees (i.e. <tt>Math.h2d(self)</tt>).
100
+ def h2d() Math.h2d(self); end
101
+ end
102
+
103
+ # The MIRIAD package adds angle conversion methods to Array class.
104
+ class Array
105
+ # Convert +self+ from [degrees, minutes, seconds] to degrees.
106
+ # Missing arguments are assumed to be 0.
107
+ def dms_to_d; Math::dms_to_d(*self); end
108
+ # Convert +self+ from [hours, minutes, seconds] to hours.
109
+ # Missing arguments are assumed to be 0.
110
+ alias :hms_to_h :dms_to_d
111
+ end
112
+
113
+ # The MIRIAD package adds angle parsing methods to String class.
114
+ class String
115
+ # Parse a "dd:mm:ss.sss" String to Float degrees.
116
+ # <b>NOT</b> the inverse of Numeric#to_dmsstr (but may become so).
117
+ def dms_to_d; Math::dms_to_d(*split(':').map{|s| s.to_f}); end
118
+ # Parse a "hh:mm:ss.sss" String to Float hours.
119
+ alias :hms_to_h :dms_to_d
120
+ end
121
+
122
+ # The MIRIAD package adds astronomy-related and other utilty methods to
123
+ # the +DateTime+ class.
124
+ class DateTime
125
+
126
+ # The J2000 epoch
127
+ J2000 = civil(2000,1,1,12)
128
+
129
+ # Create a +DateTime+ object from a numeric Astronomical Julian Date.
130
+ def self.ajd(d)
131
+ J2000 + d - J2000.ajd
132
+ end
133
+
134
+ # Besselian year at the time represented by +self+.
135
+ #
136
+ # Adapted from http://hpiers.obspm.fr/eop-pc/models/constants.html
137
+ def by
138
+ 2000+(amjd-51544.5)/365.242189813
139
+ end
140
+
141
+ def ut2_ut1
142
+ # Taken from
143
+ # http://www.iers.org/products/6/11136/orig/bulletina-xx-042.txt
144
+ pi2t=Math::PI*2*(by%1)
145
+ ENV['UT2_UT1'] || 0.022 * Math::sin(pi2t) \
146
+ - 0.012 * Math::cos(pi2t) \
147
+ - 0.006 * Math::sin(2*pi2t) \
148
+ + 0.007 * Math::cos(2*pi2t)
149
+ end
150
+
151
+ # UT1-UTC (unit is seconds) at the time represented by +self+
152
+ #
153
+ # This is an increasingly out-of-date approximation only. Taken from
154
+ # http://www.iers.org/products/6/11136/orig/bulletina-xx-042.txt
155
+ def ut1_utc
156
+ # TODO Get more accurate measurement of this value from usno
157
+ ENV.has_key?('UT1_UTC') ?
158
+ ENV['UT1_UTC'].to_f : -0.2221 - 0.00092 * (amjd - 54399) - ut2_ut1
159
+ end
160
+
161
+ # A +DateTime+ object corresponding to the same time as +self+, but
162
+ # with an offset of 0. Returns +self+ if <tt>self.offset == 0</tt>.
163
+ def to_utc
164
+ (offset == 0) ? self : new_offset(0)
165
+ end
166
+
167
+ # Create a +DateTime+ object from a numeric Astronomical Julian Date.
168
+ def self.utc
169
+ now.to_utc
170
+ end
171
+
172
+ # UT1 (expressed in hours) at the time represented by +self+
173
+ def ut1
174
+ ((amjd % 1) * 24 + ut1_utc/(60*60)) % 24
175
+ end
176
+
177
+ # UT1 (expressed in hours) at the current time.
178
+ def self.ut1
179
+ now.ut1
180
+ end
181
+
182
+ # Greenwich Mean Sidereal Time at the time represented by +self+.
183
+ #
184
+ # Adapted from http://aa.usno.navy.mil/faq/docs/GAST.php
185
+ def gmst
186
+ # The local variables here have been slightly renamed from the reference to
187
+ # be more ruby-esque. Here is the mapping...
188
+ #
189
+ # Local Reference
190
+ # jdut1 JD
191
+ # jd0 JD0
192
+ # h H
193
+ # d D
194
+ # d0 D0
195
+ # t T
196
+
197
+ # The UT Julian date of the time of interest
198
+ jdut1 = ajd + ut1_utc/(24*60*60)
199
+ # Julian date of the previous midnight (0h) UT
200
+ jd0 = (jdut1-0.5).floor + 0.5
201
+ # Hours of UT elapsed since jd0
202
+ h = (jdut1 - jd0) * 24.0
203
+ # Days and fraction of day since J2000 epoch
204
+ d = jdut1 - J2000.ajd
205
+ # Integer days (and a half) since epoch
206
+ d0 = jd0 - J2000.ajd
207
+ # Fractional centuries since epoch
208
+ t = d/36525.0
209
+ # gmst
210
+ (6.697374558 + 0.06570982441908 * d0 + 1.00273790935 * h + 0.000026 * t**2) % 24.0
211
+ end
212
+
213
+ # Equation of the Equinoxes at the time represented by +self+.
214
+ #
215
+ # Adapted from http://aa.usno.navy.mil/faq/docs/GAST.php
216
+ def eqeq
217
+ # The local variables here have been slightly renamed from the reference to
218
+ # be more ruby-esque. Here is the mapping...
219
+ #
220
+ # Local Reference
221
+ # jdut1 JD
222
+ # d D
223
+ # omega Omega (Greek letter)
224
+ # dpsi Delta Psi (Greek letters)
225
+ # eps epsilon (Greek letter)
226
+
227
+ # The UT Julian date of the time of interest
228
+ jdut1 = ajd + ut1_utc/(24*60*60)
229
+ # Days and fraction of day since J2000 epoch
230
+ d = jdut1 - J2000.ajd
231
+ # Longitude of the ascending node of the Moon
232
+ omega = 125.04 - 0.052954 * d
233
+ # Mean Longitude of the Sun
234
+ l = 280.47 + 0.98565 * d
235
+ # Delta psi
236
+ dpsi = -0.000319 * Math.sin(omega.d2r) \
237
+ -0.000024 * Math.sin(2*l.d2r)
238
+ # Obliquity
239
+ eps = 23.4393 - 0.0000004 * d
240
+ # eqeq
241
+ dpsi * Math.cos(eps.d2r)
242
+ end
243
+
244
+ # Greenwich Apparent Sidereal Time at the time represented by +self+.
245
+ def gast
246
+ (gmst + eqeq) % 24.0
247
+ end
248
+
249
+ # Local Mean Sidereal Time in hours at the time represented by
250
+ # +self+. +longitude+ is in degrees.
251
+ def lmst(longitude=0.0)
252
+ (gmst + longitude.d2h) % 24.0
253
+ end
254
+
255
+ # Local Apparent Sidereal Time in hours at the time represented by
256
+ # +self+. +longitude+ is in degrees.
257
+ def last(longitude=0.0)
258
+ (gast + longitude.d2h) % 24.0
259
+ end
260
+ end
261
+
262
+ # A subclass of StandardError raised by wrapped MIRIAD code.
263
+ class MirlibError < StandardError
264
+ end
265
+
266
+ # In addition to the Uvio and Visibility classes, the Miriad module also
267
+ # provides some utility methods.
268
+ module Miriad
269
+
270
+ # The version of mirlib on which this package is based.
271
+ MIRLIB_VERSION = "4.1.0"
272
+
273
+ # Contains Polarization code constants. The values follow the AIPS/FITS
274
+ # conventions.
275
+ module Pol
276
+ # Stokes I
277
+ I = 1
278
+ # Stokes Q
279
+ Q = 2
280
+ # Stokes U
281
+ U = 3
282
+ # Stokes V
283
+ V = 4
284
+ # Circular RR
285
+ RR = -1
286
+ # Circular LL
287
+ LL = -2
288
+ # Circular RL
289
+ RL = -3
290
+ # Circular LR
291
+ LR = -4
292
+ # Linear XX
293
+ XX = -5
294
+ # Linear YY
295
+ YY = -6
296
+ # Linear XY
297
+ XY = -7
298
+ # Linear YX
299
+ YX = -8
300
+ end
301
+
302
+ # Compute the [u,v,w] projection of a baseline with endpoints <tt>xyz1</tt>
303
+ # and <tt>xyz2</tt> in the direction of +obsra+, +obsdec+ (i.e. right
304
+ # ascension and declination in the current epoch) at the local apparent
305
+ # sidereal time +lst+. <tt>xyz1</tt> and <tt>xyz2</tt> are three element
306
+ # arrays containing geocentric coordinates of the baseline endpoints, and
307
+ # +obsra+, +obsdec+, and +lst+ are all in radians
308
+ #
309
+ # The body of this method was transcribed from the MIRIAD source file
310
+ # <tt>uvcal.for</tt>.
311
+ def self.xyz2uvw(xyz1,xyz2,obsra,obsdec,lst)
312
+ x1,y1,z1 = xyz1
313
+ x2,y2,z2 = xyz2
314
+
315
+ ha = lst - obsra
316
+ sinha = Math.sin(ha)
317
+ cosha = Math.cos(ha)
318
+ sind = Math.sin(obsdec)
319
+ cosd = Math.cos(obsdec)
320
+
321
+ bxx = x2 - x1
322
+ byy = y2 - y1
323
+ bzz = z2 - z1
324
+
325
+ u = bxx * sinha + byy * cosha
326
+ v = -(bxx * cosha - byy * sinha)*sind + bzz*cosd
327
+ w = (bxx * cosha - byy * sinha)*cosd + bzz*sind
328
+
329
+ [u,v,w]
330
+ end
331
+
332
+ # Precess from one mean RA,DEC to another.
333
+ #
334
+ # A simple precession routine, to precess from one set of mean
335
+ # equatorial coordinates (RA,DEC), to another at a different epoch.
336
+ # This is accurate to order 0.3 arcsec over 50 years.
337
+ #
338
+ # Reference:
339
+ # Explanatory Supplement to the Astronomical Almanac, 1993. p 105-106.
340
+ #
341
+ # NOTE: This does not take account of atmospheric refraction,
342
+ # nutation, aberration nor gravitational deflection.
343
+ #
344
+ # Input:
345
+ # ra,dec RA,DEC at the from_jd epoch (radians).
346
+ # to_jd Julian day of the new epoch. (defaults to current time)
347
+ # from_jd Julian day of the known epoch. (defaults to J2000)
348
+ #
349
+ # Output:
350
+ # [ra+,dec] Precessed coordinates (radians).
351
+ #
352
+ # The body of this method was transcribed from the miriad source file
353
+ # <tt>ephem.for</tt> originally created by Bob Sault.
354
+ def self.precess(ra, dec, to_jd=DateTime.now.ajd, from_jd=DateTime::J2000.ajd)
355
+ t = (from_jd - 2451545)/36525
356
+ m = Math::PI/180 * (1.2812323 + (0.0003879 + 0.0000101*t)*t)*t
357
+ n = Math::PI/180 * (0.5567530 - (0.0001185 + 0.0000116*t)*t)*t
358
+ rm = ra - 0.5*(m + n*Math.sin(ra)*Math.tan(dec))
359
+ dm = dec - 0.5*n*Math.cos(rm)
360
+ #
361
+ # J2000 coordinates.
362
+ #
363
+ r0 = ra - m - n*Math.sin(rm)*Math.tan(dm)
364
+ d0 = dec - n*Math.cos(rm)
365
+ #
366
+ # Coordinates of the other epoch.
367
+ #
368
+ t = (to_jd - 2451545)/36525
369
+ m = Math::PI/180 * (1.2812323 + (0.0003879 + 0.0000101*t)*t)*t
370
+ n = Math::PI/180 * (0.5567530 - (0.0001185 + 0.0000116*t)*t)*t
371
+ rm = r0 + 0.5*(m + n*Math.sin(r0)*Math.tan(d0))
372
+ dm = d0 - 0.5*n*Math.cos(rm)
373
+
374
+ ra = r0 + m + n*Math.sin(rm)*Math.tan(dm)
375
+ dec = d0 + n*Math.cos(rm)
376
+
377
+ [ra, dec]
378
+ end
379
+
380
+ # Format a MIRIAD baseline number as "A1-A2".
381
+ def self.basstr(baseline)
382
+ baseline = baseline.to_i
383
+ "%d-%d" % basant(baseline)
384
+ end
385
+
386
+ # Convert a MIRIAD baseline number into two antenna numbers.
387
+ def self.basant(baseline)
388
+ baseline = baseline.to_i
389
+ [baseline/256, baseline%256]
390
+ end
391
+
392
+ # Convert two antenna numbers into a MIRIAD baseline number
393
+ def self.antbas(a1,a2)
394
+ a1, a2 = a2, a1 if a2 < a1
395
+ a1.to_i*256 + a2.to_i
396
+ end
397
+
398
+ # Convert two antenna numbers, <tt>a1</tt> and <tt>a2</tt>, into a baseline
399
+ # index (NOT a MIRIAD baseline number) using +n+ as the maximum antenna
400
+ # number.
401
+ def self.basidx(a1,a2,n)
402
+ a1, a2 = a2, a1 if a2 < a1
403
+ return a1 + ((2*n+1)*(a2-a1) - (a2-a1)**2) / 2
404
+ end
405
+
406
+ # Convert a baseline index (NOT a MIRIAD baseline number) +i+ into two
407
+ # antenna numbers using +n+ as the maximum antenna number.
408
+ def self.idxbas(i,n)
409
+ b = -(2*n+1)
410
+ ac = 2*i
411
+ r = Math.sqrt(b**2-4*ac)
412
+ d = (-b-r.floor)/2
413
+ d -= 1 while (a1 = i + (b*d + d**2)/2) < 0
414
+ a2 = a1 + d
415
+ [a1, a2]
416
+ end
417
+
418
+ # The Visibility class holds preamble, visdata, and flags for one integration
419
+ # on one baseline. It also provides convenience methods to query and access
420
+ # these attributes and their sub-attributes.
421
+ class Visibility
422
+ # The MIRIAD preamble
423
+ attr_accessor :preamble
424
+ # The MIRIAD visdata
425
+ attr_accessor :data
426
+ # The MIRIAD flags
427
+ attr_accessor :flags
428
+ # Constructs a new Visibility object containing the given +preamble+,
429
+ # +data+, and +flags+ objects. Not used often. Usually Visibility objects
430
+ # are obtained from Uvio#read.
431
+ def initialize(preamble, data, flags)
432
+ @preamble = preamble
433
+ @data = data
434
+ @flags = flags
435
+ end
436
+ # call-seq: Visibility[preamble, data, flags]
437
+ #
438
+ # Alternate way to contruct a Visibility object.
439
+ def self.[](preamble, data, flags)
440
+ self.new(preamble, data, flags)
441
+ end
442
+ # Returns the [u,v,w] coordinates from the preamble.
443
+ def coord() preamble[0..2]; end
444
+ # Returns the Julian date from the preamble.
445
+ def jd() preamble[3]; end
446
+ # Returns the baseline number from the preamble.
447
+ def baseline() preamble[4].to_i; end
448
+ # Returns a DateTime object corresponding to the Julian date from the
449
+ # preamble.
450
+ def time() DateTime.ajd(jd); end
451
+ # Returns the two antenna numbers corresponding to the baseline number
452
+ # from the preamble.
453
+ def ants() Miriad.basant(baseline); end
454
+ # True if the baseline is an autocorrelation.
455
+ def auto?() a1,a2=Miriad.basant(baseline); a1 == a2; end
456
+ # True if the baseline is a cross correlation.
457
+ def cross?() a1,a2=Miriad.basant(baseline); a1 != a2; end
458
+ ## TODO Make this more robust (i.e. less hard-coded)
459
+ #def lags()
460
+ # i = NArray.int(1024).indgen!(512) % 1024
461
+ # d = data[i]
462
+ # d[0] = 0 # Zero-out the DC channel
463
+ # d -= d.mean # Remove the mean
464
+ # FFTW3.dft(d,1)/1024
465
+ #end
466
+ end
467
+
468
+ # The Uvio class is mostly a SWIG wrapper around the UVIO C routines from
469
+ # MIRIAD. Some convenience methods are added in
470
+ # miriad.rb[link:files/miriad_rb.html].
471
+ class Uvio
472
+ # Calls <tt>putvr(var, data, ?a)</tt>
473
+ def putvra(var,data) putvr(var, data, ?a); end
474
+ # Calls <tt>putvr(var, data, ?i)</tt>
475
+ def putvri(var,data) putvr(var, data, ?i); end
476
+ # Calls <tt>putvr(var, data, ?r)</tt>
477
+ def putvrr(var,data) putvr(var, data, ?r); end
478
+ # Calls <tt>putvr(var, data, ?d)</tt>
479
+ def putvrd(var,data) putvr(var, data, ?d); end
480
+
481
+ # Convenience wrapper around self.new. Self.new may become private, so use
482
+ # this method instead.
483
+ def self.open(name,mode='r')
484
+ raise 'invalid dataset name' if name.nil? or name.empty?
485
+ case mode[0]
486
+ when ?r then
487
+ raise 'invalid dataset given' unless test ?d, name
488
+ when ?w then
489
+ raise 'dataset exists' if test ?d, name
490
+ when ?a then
491
+ raise 'invalid dataset given' unless test ?d, name
492
+ end
493
+
494
+ self.new(name,mode)
495
+ end
496
+
497
+ # call-seq:
498
+ # read() -> uvread(5, nchan, nchan) -> Visibility
499
+ # read(nil) -> uvread(5, nchan, nchan) -> Visibility
500
+ # read(vis) -> uvread(vis.preamble, vis.data, vis.flags) -> Visibility
501
+ # read(*args) -> uvread(*args) -> Visibility
502
+ #
503
+ # Convenience wrapper around uvread. Shortens data and flags if they were
504
+ # passed in longer than necessary. Always returns a Visibility, except at
505
+ # end of file in which case it returns +nil+.
506
+ #
507
+ # See uvread for details.
508
+ #
509
+ # <b>This method should be preferred over uvread. uvread may disappear in
510
+ # future versions!</b>
511
+ def read(*args)
512
+ if args.length == 0 || args[0].nil?
513
+ n, p, d, f = uvread(5,nchan,nchan)
514
+ elsif args.length == 1 && Visibility === args[0]
515
+ n, p, d, f = uvread(args[0].preamble,args[0].data,args[0].flags)
516
+ else
517
+ n, p, d, f = uvread(*args)
518
+ end
519
+
520
+ # Return nil on EOF
521
+ return nil if n == 0
522
+
523
+ # FIXME for Array inputs
524
+ # If nread is different than what was passed in
525
+ if n != d.length
526
+ # Shorten data and flags
527
+ d = d[0...n]
528
+ f = f[0...n]
529
+ end
530
+
531
+ # Return Visibility
532
+ return args[0] if Visibility === args[0]
533
+ Visibility[p,d,f]
534
+ end
535
+
536
+ # call-seq: baseline -> [ant1, ant2]
537
+ #
538
+ # Decodes the value of the +baseline+ uv variable and returns a two element
539
+ # array containing the two antenna numbers.
540
+ def baseline
541
+ bl = getvr('baseline')
542
+ bl = [bl.to_i/256, bl.to_i%256] if bl
543
+ end
544
+
545
+ # Uvio.foo, if foo is not a predefined attribute or method, will return the
546
+ # current value of the MIRIAD UV variable +foo+ or +nil+ if it doesn't
547
+ # (yet) exist.
548
+ #
549
+ # Uvio.foo=bar, if foo= is not a predefined attribute or method, will set
550
+ # the value of the MIRIAD UV variable +foo+ to +bar+. Only valid for
551
+ # datasets opened in write mode. [SETTER FUNCTIONALITY NOT YET
552
+ # IMPLEMENTED!]
553
+ def method_missing(sym,*args)
554
+ val = nil
555
+ var = sym.to_s
556
+ case var
557
+ when /=$/: break
558
+ else val = getvr(var)
559
+ end
560
+ val
561
+ end
562
+ end
563
+
564
+ end