source: trunk/python/opacity.py@ 1751

Last change on this file since 1751 was 1726, checked in by Malte Marquarding, 15 years ago

fixed typos

File size: 8.7 KB
Line 
1import os
2import math
3from asap import scantable
4from asap import merge
5from asap import fitter
6from asap import selector
7from asap import rcParams
8from asap._asap import atmosphere
9
10
11class model(object):
12 def _to_pascals(self, val):
13 if val > 2000:
14 return val
15 return val*100
16
17 def __init__(self, temperature=288, pressure=101325., humidity=0.5,
18 elevation=700.):
19 """
20 This class implements opacity/atmospheric brightness temperature model
21 equivalent to the model available in MIRIAD. The actual math is a
22 convertion of the Fortran code written by Bob Sault for MIRIAD.
23 It implements a simple model of the atmosphere and Liebe's model (1985)
24 of the complex refractive index of air.
25
26 The model of the atmosphere is one with an exponential fall-off in
27 the water vapour content (scale height of 1540 m) and a temperature
28 lapse rate of 6.5 mK/m. Otherwise the atmosphere obeys the ideal gas
29 equation and hydrostatic equilibrium.
30
31 Note, the model includes atmospheric lines up to 800 GHz, but was not
32 rigorously tested above 100 GHz and for instruments located at
33 a significant elevation. For high-elevation sites it may be necessary to
34 adjust scale height and lapse rate.
35
36 Parameters:
37 temperature: air temperature at the observatory (K)
38 pressure: air pressure at the sea level if the observatory
39 elevation is set to non-zero value (note, by
40 default is set to 700m) or at the observatory
41 ground level if the elevation is set to 0. (The
42 value is in Pascals or hPa, default 101325 Pa
43 humidity: air humidity at the observatory (fractional),
44 default is 0.5
45 elevation: observatory elevation about sea level (in meters)
46 """
47 self._atm = atmosphere(temp, self._to_pascals(pressure), humidity)
48 self.set_observatory_elevation(elevation)
49
50 def get_opacities(self, freq, elevation=None):
51 """Get the opacity value(s) for the fiven frequency(ies).
52 If no elevation is given the opacities for the zenith are returned.
53 If an elevation is specified refraction is also taken into account.
54 Parameters:
55 freq: a frequency value in Hz, or a list of frequency values.
56 One opacity value per frequency is returned as a scalar
57 or list.
58 elevation: the elevation at which to compute the opacity. If `None`
59 is given (default) the zenith opacity is returned.
60
61
62 """
63 func = None
64 if isinstance(freq, (list, tuple)):
65 if elevation is None:
66 return self._atm.zenith_opacities(freq)
67 else:
68 elevation *= math.pi/180.
69 return self._atm.opacities(freq, elevation)
70 else:
71 if elevation is None:
72 return self._atm.zenith_opacity(freq)
73 else:
74 elevation *= math.pi/180.
75 return self._atm.opacity(freq, elevation)
76
77 def set_weather(self, temperature, pressure, humidity):
78 """Update the model using the given environmental parameters.
79 Parameters:
80 temperature: air temperature at the observatory (K)
81 pressure: air pressure at the sea level if the observatory
82 elevation is set to non-zero value (note, by
83 default is set to 700m) or at the observatory
84 ground level if the elevation is set to 0. (The
85 value is in Pascals or hPa, default 101325 Pa
86 humidity: air humidity at the observatory (fractional),
87 default is 0.5
88 """
89 pressure = self._to_pascals(pressure)
90 self._atm.set_weather(temperature, pressure, humidity)
91
92 def set_observatory_elevation(self, elevation):
93 """Update the model using the given the observatory elevation
94 Parameters:
95 elevation: the elevation at which to compute the opacity. If `None`
96 is given (default) the zenith opacity is returned.
97 """
98 self._atm.set_observatory_elevation(el)
99
100
101def _import_data(data):
102 if not isinstance(data, (list,tuple)):
103 if isinstance(data, scantable):
104 return data
105 elif isinstance(data, str):
106 return scantable(data)
107 tables = []
108 for d in data:
109 if isinstance(d, scantable):
110 tables.append(d)
111 elif isinstance(d, str):
112 if os.path.exists(d):
113 tables.append(scantable(d))
114 else:
115 raise IOError("Data file doesn't exists")
116 else:
117 raise TypeError("data is not a scantable or valid file")
118 return merge(tables)
119
120def skydip(data, averagepol=True, tsky=300., plot=False,
121 temperature=288, pressure=101325., humidity=0.5):
122 """Determine the opacity from a set of 'skydip' obervations.
123 This can be any set of observations over a range of elevations,
124 but will ususally be a dedicated (set of) scan(s).
125 Return a list of 'n' opacities for 'n' IFs. In case of averagepol
126 being 'False' a list of 'n*m' elements where 'm' is the number of
127 polarisations, e.g.
128 nIF = 3, nPol = 2 => [if0pol0, if0pol1, if1pol0, if1pol1, if2pol0, if2pol1]
129
130 The opacity is determined by fitting a first order polynomial to:
131
132
133 Tsys(airmass) = p0 + airmass*p1
134
135 where
136
137 airmass = 1/sin(elevation)
138
139 tau = p1/Tsky
140
141 Parameters:
142 data: a list of file names or scantables or a single
143 file name or scantable.
144 averagepol: Return the average of the opacities for the polarisations
145 This might be useful to set to 'False' if one polarisation
146 is corrupted (Mopra). If set to 'False', an opacity value
147 per polarisation is returned.
148 tksy: The sky temperature (default 300.0K). This might
149 be read from the data in the future.
150 plot: Plot each fit (airmass vs. Tsys). Default is 'False'
151 """
152 rcsave = rcParams['verbose']
153 rcParams['verbose'] = False
154 if plot:
155 from matplotlib import pylab
156 scan = _import_data(data)
157 f = fitter()
158 f.set_function(poly=1)
159 sel = selector()
160 basesel = scan.get_selection()
161 inos = scan.getifnos()
162 pnos = scan.getpolnos()
163 opacities = []
164 om = opacitymodel(temperature, pressure, humidity)
165 for ino in inos:
166 sel.set_ifs(ino)
167 opacity = []
168 fits = []
169 airms = []
170 tsyss = []
171 if plot:
172 pylab.cla()
173 pylab.ioff()
174 pylab.clf()
175 pylab.xlabel("Airmass")
176 pylab.ylabel(r"$T_{sys}$")
177 for pno in pnos:
178 sel.set_polarisations(pno)
179 scan.set_selection(basesel+sel)
180 freq = scan.get_coordinate(0).get_reference_value()/1e9
181 freqstr = "%0.4f GHz" % freq
182 tsys = scan.get_tsys()
183 elev = scan.get_elevation()
184 airmass = [ 1./math.sin(i) for i in elev ]
185 airms.append(airmass)
186 tsyss.append(tsys)
187 f.set_data(airmass, tsys)
188 f.fit()
189 fits.append(f.get_fit())
190 params = f.get_parameters()["params"]
191 opacity.append(params[1]/tsky)
192 if averagepol:
193 opacities.append(sum(opacity)/len(opacity))
194 else:
195 opacities += opacity
196 if plot:
197 colors = ['b','g','k']
198 n = len(airms)
199 for i in range(n):
200 pylab.plot(airms[i], tsyss[i], 'o', color=colors[i])
201 pylab.plot(airms[i], fits[i], '-', color=colors[i])
202 pylab.figtext(0.7,0.3-(i/30.0),
203 r"$\tau_{fit}=%0.2f$" % opacity[i],
204 color=colors[i])
205 if averagepol:
206 pylab.figtext(0.7,0.3-(n/30.0),
207 r"$\tau_{avg}=%0.2f$" % opacities[-1],
208 color='r')
209 n +=1
210 pylab.figtext(0.7,0.3-(n/30.0),
211 r"$\tau_{model}=%0.2f$" % om.get_opacities(freq*1e9),
212 color='grey')
213
214 pylab.title("IF%d : %s" % (ino, freqstr))
215
216 pylab.ion()
217 pylab.draw()
218 raw_input("Hit <return> for next fit...")
219 sel.reset()
220
221 scan.set_selection(basesel)
222 rcParams['verbose'] = rcsave
223 if plot:
224 pylab.close()
225 return opacities
Note: See TracBrowser for help on using the repository browser.