Passed
Pull Request — master (#2033)
by
unknown
02:19
created

gammapy.data.pointing.FixedPointingInfo.time_ref()   A

Complexity

Conditions 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
# Licensed under a 3-clause BSD style license - see LICENSE.rst
2
from scipy.interpolate import interp1d
3
from astropy.version import version as astropy_version
4
from astropy.utils import lazyproperty
5
from astropy.units import Quantity
6
from astropy.table import Table
7
from astropy.coordinates import SkyCoord, AltAz, CartesianRepresentation
8
from ..utils.scripts import make_path
9
from ..utils.time import time_ref_from_dict
10
from ..utils.fits import earth_location_from_dict
11
12
__all__ = [
13
    "FixedPointingInfo",
14
    "PointingInfo",
15
]
16
17
18
class FixedPointingInfo:
19
    """IACT array pointing info.
20
21
    Data format specification: :ref:`gadf:iact-pnt`
22
23
    Parameters
24
    ----------
25
    meta : `~astropy.table.Table.meta`
26
        Meta header info from Table on pointing
27
28
    Examples
29
    --------
30
    >>> from gammapy.data import PointingInfo
31
    >>> path = '$GAMMAPY_DATA/tests/hess_event_list.fits'
32
    >>> pointing_info = PointingInfo.read(path)
33
    >>> print(pointing_info)
34
    """
35
36
    def __init__(self, meta):
37
        self.meta = meta
38
39
    @classmethod
40
    def read(cls, filename, hdu="EVENTS"):
41
        """Read pointing information table from file to obtain the metadata.
42
43
        Parameters
44
        ----------
45
        filename : str
46
            File name
47
        hdu : int or str
48
            HDU number or name
49
50
        Returns
51
        -------
52
        pointing_info : `PointingInfo`
53
            Pointing info object
54
        """
55
        filename = make_path(filename)
56
        table = Table.read(str(filename), hdu=hdu)
57
        return cls(meta=table.meta)
58
59
    @lazyproperty
60
    def location(self):
61
        """Observatory location (`~astropy.coordinates.EarthLocation`)."""
62
        return earth_location_from_dict(self.meta)
63
64
    @lazyproperty
65
    def time_ref(self):
66
        """Time reference (`~astropy.time.Time`)"""
67
        return time_ref_from_dict(self.meta)
68
69
    @lazyproperty
70
    def time_start(self):
71
        """Start time (`~astropy.time.Time`)"""
72
        t_start = Quantity(self.meta['TSTART'], "second")
73
        return self.time_ref + t_start
74
75
    @lazyproperty
76
    def time_stop(self):
77
        """Stop time (`~astropy.time.Time`)"""
78
        t_stop = Quantity(self.meta['TSTOP'], "second")
79
        return self.time_ref + t_stop
80
81
    @lazyproperty
82
    def obstime(self):
83
        """Average observation time for the observation (`~astropy.time.Time`)"""
84
        return self.time_start + self.duration / 2
85
86
    @lazyproperty
87
    def duration(self):
88
        """Pointing duration (`~astropy.time.TimeDelta`).
89
90
        The time difference between the TSTART and TSTOP.
91
        """
92
        return self.time_stop - self.time_start
93
94
    @lazyproperty
95
    def radec(self):
96
        """RA / DEC pointing postion from table
97
        (`~astropy.coordinates.SkyCoord`)"""
98
        ra = self.meta["RA_PNT"]
99
        dec = self.meta["DEC_PNT"]
100
        return SkyCoord(ra, dec, unit="deg", frame="icrs")
101
102
    @lazyproperty
103
    def altaz_frame(self):
104
        """ALT / AZ frame (`~astropy.coordinates.AltAz`)."""
105
        return AltAz(obstime=self.obstime, location=self.location)
106
107
    @lazyproperty
108
    def altaz(self):
109
        """ALT / AZ pointing position computed from RA / DEC
110
        (`~astropy.coordinates.SkyCoord`)"""
111
        return self.radec.transform_to(self.altaz_frame)
112
113
114
class PointingInfo:
115
    """IACT array pointing info.
116
117
    Data format specification: :ref:`gadf:iact-pnt`
118
119
    Parameters
120
    ----------
121
    table : `~astropy.table.Table`
122
        Table (with meta header info) on pointing
123
124
    Examples
125
    --------
126
    >>> from gammapy.data import PointingInfo
127
    >>> pointing_info = PointingInfo.read('$GAMMAPY_DATA/tests/hess_event_list.fits')
128
    >>> print(pointing_info)
129
    """
130
131
    def __init__(self, table):
132
        self.table = table
133
134
    @classmethod
135
    def read(cls, filename, hdu="POINTING"):
136
        """Read `PointingInfo` table from file.
137
138
        Parameters
139
        ----------
140
        filename : str
141
            File name
142
        hdu : int or str
143
            HDU number or name
144
145
        Returns
146
        -------
147
        pointing_info : `PointingInfo`
148
            Pointing info object
149
        """
150
        filename = make_path(filename)
151
        table = Table.read(str(filename), hdu=hdu)
152
        return cls(table=table)
153
154
    def __str__(self):
155
        ss = "Pointing info:\n\n"
156
        ss += "Location:     {}\n".format(self.location.geodetic)
157
        m = self.table.meta
158
        ss += "MJDREFI, MJDREFF, TIMESYS = {}\n".format(
159
            (m["MJDREFI"], m["MJDREFF"], m["TIMESYS"])
160
        )
161
        ss += "Time ref:     {}\n".format(self.time_ref.fits)
162
        ss += "Time ref:     {} MJD (TT)\n".format(self.time_ref.mjd)
163
        sec = self.duration.to("second").value
164
        hour = self.duration.to("hour").value
165
        ss += "Duration:     {} sec = {} hours\n".format(sec, hour)
166
        ss += "Table length: {}\n".format(len(self.table))
167
168
        ss += "\nSTART:\n" + self._str_for_index(0) + "\n"
169
        ss += "\nEND:\n" + self._str_for_index(-1) + "\n"
170
171
        return ss
172
173
    def _str_for_index(self, idx):
174
        """Information for one point in the pointing table."""
175
        ss = "Time:  {}\n".format(self.time[idx].fits)
176
        ss += "Time:  {} MJD (TT)\n".format(self.time[idx].mjd)
177
        ss += "RADEC: {} deg\n".format(self.radec[idx].to_string())
178
        ss += "ALTAZ: {} deg\n".format(self.altaz[idx].to_string())
179
        return ss
180
181
    @lazyproperty
182
    def location(self):
183
        """Observatory location (`~astropy.coordinates.EarthLocation`)."""
184
        return earth_location_from_dict(self.table.meta)
185
186
    @lazyproperty
187
    def time_ref(self):
188
        """Time reference (`~astropy.time.Time`)"""
189
        return time_ref_from_dict(self.table.meta)
190
191
    @lazyproperty
192
    def duration(self):
193
        """Pointing table duration (`~astropy.time.TimeDelta`).
194
195
        The time difference between the first and last entry.
196
        """
197
        return self.time[-1] - self.time[0]
198
199
    @lazyproperty
200
    def time(self):
201
        """Time array (`~astropy.time.Time`)"""
202
        met = Quantity(self.table["TIME"].astype("float64"), "second")
203
        time = self.time_ref + met
204
        return time.tt
205
206
    @lazyproperty
207
    def radec(self):
208
        """RA / DEC position from table (`~astropy.coordinates.SkyCoord`)"""
209
        lon = self.table["RA_PNT"]
210
        lat = self.table["DEC_PNT"]
211
        return SkyCoord(lon, lat, unit="deg", frame="icrs")
212
213
    @lazyproperty
214
    def altaz_frame(self):
215
        """ALT / AZ frame (`~astropy.coordinates.AltAz`)."""
216
        return AltAz(obstime=self.time, location=self.location)
217
218
    @lazyproperty
219
    def altaz(self):
220
        """ALT / AZ position computed from RA / DEC (`~astropy.coordinates.SkyCoord`)"""
221
        return self.radec.transform_to(self.altaz_frame)
222
223
    @lazyproperty
224
    def altaz_from_table(self):
225
        """ALT / AZ position from table (`~astropy.coordinates.SkyCoord`)"""
226
        lon = self.table["AZ_PNT"]
227
        lat = self.table["ALT_PNT"]
228
        return SkyCoord(lon, lat, unit="deg", frame=self.altaz_frame)
229
230
    def altaz_interpolate(self, time):
231
        """Interpolate pointing for a given time."""
232
        t_new = time.mjd
233
        t = self.time.mjd
234
        xyz = self.altaz.cartesian
235
        x_new = interp1d(t, xyz.x)(t_new)
236
        y_new = interp1d(t, xyz.y)(t_new)
237
        z_new = interp1d(t, xyz.z)(t_new)
238
        xyz_new = CartesianRepresentation(x_new, y_new, z_new)
239
        altaz_frame = AltAz(obstime=time, location=self.location)
240
241
        # FIXME: an API change in Astropy in 3.1 broke this
242
        # See https://github.com/gammapy/gammapy/pull/1906
243
        if astropy_version >= "3.1":
244
            kwargs = {"representation_type": "unitspherical"}
245
        else:
246
            kwargs = {"representation": "unitspherical"}
247
248
        return SkyCoord(xyz_new, frame=altaz_frame, unit="deg", **kwargs)
249