miriad 4.1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +103 -0
- data/Rakefile +82 -0
- data/ext/bug.c +341 -0
- data/ext/dio.c +317 -0
- data/ext/extconf.rb +49 -0
- data/ext/headio.c +835 -0
- data/ext/hio.c +1515 -0
- data/ext/hio.h +48 -0
- data/ext/interface.c +74 -0
- data/ext/io.h +56 -0
- data/ext/key.c +934 -0
- data/ext/maskio.c +398 -0
- data/ext/maxdimc.h.in +9 -0
- data/ext/miriad.h +371 -0
- data/ext/miriad.i +464 -0
- data/ext/miriad_ruby.c +602 -0
- data/ext/miriad_ruby.i +443 -0
- data/ext/miriad_wrap.c +4210 -0
- data/ext/narray_ruby.swg +59 -0
- data/ext/pack.c +639 -0
- data/ext/scrio.c +132 -0
- data/ext/sysdep.h +185 -0
- data/ext/uvio.c +4934 -0
- data/ext/xyio.c +476 -0
- data/ext/xyzio.c +2020 -0
- data/lib/miriad.rb +564 -0
- metadata +93 -0
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
|