source: branches/alma/python/opacity.py @ 1770

Last change on this file since 1770 was 1770, checked in by Kana Sugimoto, 14 years ago

New Development: Yes

JIRA Issue: No (to merge the alma branch to trunk)

Ready for Test: No

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s): single dish package

Description: merged changes in trunk after ASAP3.0.0 release (r1752-1768)


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(temperature, self._to_pascals(pressure),
48                               humidity)
49        self.set_observatory_elevation(elevation)
50
51    def get_opacities(self, freq, elevation=None):
52        """Get the opacity value(s) for the fiven frequency(ies).
53        If no elevation is given the opacities for the zenith are returned.
54        If an elevation is specified refraction is also taken into account.
55        Parameters:
56            freq:       a frequency value in Hz, or a list of frequency values.
57                        One opacity value per frequency is returned as a scalar
58                        or list.
59            elevation:  the elevation at which to compute the opacity. If `None`
60                        is given (default) the zenith opacity is returned.
61
62
63        """
64        func = None
65        if isinstance(freq, (list, tuple)):
66            if elevation is None:
67                return self._atm.zenith_opacities(freq)
68            else:
69                elevation *= math.pi/180.
70                return self._atm.opacities(freq, elevation)
71        else:
72            if elevation is None:
73                return self._atm.zenith_opacity(freq)
74            else:
75                elevation *= math.pi/180.
76                return self._atm.opacity(freq, elevation)
77
78    def set_weather(self, temperature, pressure, humidity):
79        """Update the model using the given environmental parameters.
80        Parameters:
81            temperature:    air temperature at the observatory (K)
82            pressure:       air pressure at the sea level if the observatory
83                            elevation is set to non-zero value (note, by
84                            default is set to 700m) or at the observatory
85                            ground level if the elevation is set to 0. (The
86                            value is in Pascals or hPa, default 101325 Pa
87            humidity:       air humidity at the observatory (fractional),
88                            default is 0.5
89        """
90        pressure = self._to_pascals(pressure)
91        self._atm.set_weather(temperature, pressure, humidity)
92
93    def set_observatory_elevation(self, elevation):
94        """Update the model using the given the observatory elevation
95        Parameters:
96            elevation:  the elevation at which to compute the opacity. If `None`
97                        is given (default) the zenith opacity is returned.
98        """
99        self._atm.set_observatory_elevation(elevation)
100
101
102def _import_data(data):
103    if not isinstance(data, (list,tuple)):
104        if isinstance(data, scantable):
105            return data
106        elif isinstance(data, str):
107            return scantable(data)
108    tables = []
109    for d in data:
110        if isinstance(d, scantable):
111            tables.append(d)
112        elif isinstance(d, str):
113            if os.path.exists(d):
114                tables.append(scantable(d))
115            else:
116                raise IOError("Data file doesn't exists")
117        else:
118            raise TypeError("data is not a scantable or valid file")
119    return merge(tables)
120
121def skydip(data, averagepol=True, tsky=300., plot=False,
122           temperature=288, pressure=101325., humidity=0.5):
123    """Determine the opacity from a set of 'skydip' obervations.
124    This can be any set of observations over a range of elevations,
125    but will ususally be a dedicated (set of) scan(s).
126    Return a list of 'n' opacities for 'n' IFs. In case of averagepol
127    being 'False' a list of 'n*m' elements where 'm' is the number of
128    polarisations, e.g.
129    nIF = 3, nPol = 2 => [if0pol0, if0pol1, if1pol0, if1pol1, if2pol0, if2pol1]
130
131    The opacity is determined by fitting a first order polynomial to:
132
133
134        Tsys(airmass) = p0 + airmass*p1
135
136    where
137
138        airmass = 1/sin(elevation)
139
140        tau =  p1/Tsky
141
142    Parameters:
143        data:       a list of file names or scantables or a single
144                    file name or scantable.
145        averagepol: Return the average of the opacities for the polarisations
146                    This might be useful to set to 'False' if one polarisation
147                    is corrupted (Mopra). If set to 'False', an opacity value
148                    per polarisation is returned.
149        tksy:       The sky temperature (default 300.0K). This might
150                    be read from the data in the future.
151        plot:       Plot each fit (airmass vs. Tsys). Default is 'False'
152    """
153    rcsave = rcParams['verbose']
154    rcParams['verbose'] = False
155    if plot:
156        from matplotlib import pylab
157    scan = _import_data(data)
158    f = fitter()
159    f.set_function(poly=1)
160    sel = selector()
161    basesel = scan.get_selection()
162    inos = scan.getifnos()
163    pnos = scan.getpolnos()
164    opacities = []
165    om = model(temperature, pressure, humidity)
166    for ino in inos:
167        sel.set_ifs(ino)
168        opacity = []
169        fits = []
170        airms = []
171        tsyss = []
172        if plot:
173            pylab.cla()
174            pylab.ioff()
175            pylab.clf()
176            pylab.xlabel("Airmass")
177            pylab.ylabel(r"$T_{sys}$")
178        for pno in pnos:
179            sel.set_polarisations(pno)
180            scan.set_selection(basesel+sel)
181            freq = scan.get_coordinate(0).get_reference_value()/1e9
182            freqstr = "%0.4f GHz" % freq
183            tsys = scan.get_tsys()
184            elev = scan.get_elevation()
185            airmass = [ 1./math.sin(i) for i in elev ]
186            airms.append(airmass)
187            tsyss.append(tsys)
188            f.set_data(airmass, tsys)
189            f.fit()
190            fits.append(f.get_fit())
191            params = f.get_parameters()["params"]
192            opacity.append(params[1]/tsky)
193        if averagepol:
194            opacities.append(sum(opacity)/len(opacity))
195        else:
196            opacities += opacity
197        if plot:
198            colors = ['b','g','k']
199            n = len(airms)
200            for i in range(n):
201                pylab.plot(airms[i], tsyss[i], 'o', color=colors[i])
202                pylab.plot(airms[i], fits[i], '-', color=colors[i])
203                pylab.figtext(0.7,0.3-(i/30.0),
204                                  r"$\tau_{fit}=%0.2f$" % opacity[i],
205                                  color=colors[i])
206            if averagepol:
207                pylab.figtext(0.7,0.3-(n/30.0),
208                                  r"$\tau_{avg}=%0.2f$" % opacities[-1],
209                                  color='r')
210                n +=1
211            pylab.figtext(0.7,0.3-(n/30.0),
212                          r"$\tau_{model}=%0.2f$" % om.get_opacities(freq*1e9),
213                          color='grey')
214
215            pylab.title("IF%d : %s" % (ino, freqstr))
216
217            pylab.ion()
218            pylab.draw()
219            raw_input("Hit <return> for next fit...")
220        sel.reset()
221
222    scan.set_selection(basesel)
223    rcParams['verbose'] = rcsave
224    if plot:
225        pylab.close()
226    return opacities
Note: See TracBrowser for help on using the repository browser.