File: test_celestial_transformations.py

package info (click to toggle)
python-astropy 1.3-8~bpo8%2B2
  • links: PTS, VCS
  • area: main
  • in suites: jessie-backports
  • size: 44,292 kB
  • sloc: ansic: 160,360; python: 137,322; sh: 11,493; lex: 7,638; yacc: 4,956; xml: 1,796; makefile: 474; cpp: 364
file content (263 lines) | stat: -rw-r--r-- 10,474 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# -*- coding: utf-8 -*-
# Licensed under a 3-clause BSD style license - see LICENSE.rst

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import numpy as np

from ... import units as u
from ..distances import Distance
from ..builtin_frames import (ICRS, FK5, FK4, FK4NoETerms, Galactic,
                              Supergalactic, Galactocentric, HCRS, GCRS)
from .. import SkyCoord
from ...tests.helper import (pytest, quantity_allclose as allclose,
                             assert_quantity_allclose as assert_allclose)
from .. import EarthLocation, CartesianRepresentation
from ...time import Time

from ...extern.six.moves import range

# used below in the next parametrized test
m31_sys = [ICRS, FK5, FK4, Galactic]
m31_coo = [(10.6847929, 41.2690650), (10.6847929, 41.2690650), (10.0004738, 40.9952444), (121.1744050, -21.5729360)]
m31_dist = Distance(770, u.kpc)
convert_precision = 1 * u.arcsec
roundtrip_precision = 1e-4 * u.degree
dist_precision = 1e-9 * u.kpc

m31_params = []
for i in range(len(m31_sys)):
    for j in range(len(m31_sys)):
        if i < j:
            m31_params.append((m31_sys[i], m31_sys[j], m31_coo[i], m31_coo[j]))


@pytest.mark.parametrize(('fromsys', 'tosys', 'fromcoo', 'tocoo'), m31_params)
def test_m31_coord_transforms(fromsys, tosys, fromcoo, tocoo):
    """
    This tests a variety of coordinate conversions for the Chandra point-source
    catalog location of M31 from NED.
    """
    coo1 = fromsys(ra=fromcoo[0]*u.deg, dec=fromcoo[1]*u.deg, distance=m31_dist)
    coo2 = coo1.transform_to(tosys)
    if tosys is FK4:
        coo2_prec = coo2.transform_to(FK4(equinox=Time('B1950', scale='utc')))
        assert (coo2_prec.spherical.lon - tocoo[0]*u.deg) < convert_precision  # <1 arcsec
        assert (coo2_prec.spherical.lat - tocoo[1]*u.deg) < convert_precision
    else:
        assert (coo2.spherical.lon - tocoo[0]*u.deg) < convert_precision  # <1 arcsec
        assert (coo2.spherical.lat - tocoo[1]*u.deg) < convert_precision
    assert coo1.distance.unit == u.kpc
    assert coo2.distance.unit == u.kpc
    assert m31_dist.unit == u.kpc
    assert (coo2.distance - m31_dist) < dist_precision

    # check round-tripping
    coo1_2 = coo2.transform_to(fromsys)
    assert (coo1_2.spherical.lon - fromcoo[0]*u.deg) < roundtrip_precision
    assert (coo1_2.spherical.lat - fromcoo[1]*u.deg) < roundtrip_precision
    assert (coo1_2.distance - m31_dist) < dist_precision


def test_precession():
    """
    Ensures that FK4 and FK5 coordinates precess their equinoxes
    """
    j2000 = Time('J2000', scale='utc')
    b1950 = Time('B1950', scale='utc')
    j1975 = Time('J1975', scale='utc')
    b1975 = Time('B1975', scale='utc')

    fk4 = FK4(ra=1*u.radian, dec=0.5*u.radian)
    assert fk4.equinox.byear == b1950.byear
    fk4_2 = fk4.transform_to(FK4(equinox=b1975))
    assert fk4_2.equinox.byear == b1975.byear

    fk5 = FK5(ra=1*u.radian, dec=0.5*u.radian)
    assert fk5.equinox.jyear == j2000.jyear
    fk5_2 = fk5.transform_to(FK4(equinox=j1975))
    assert fk5_2.equinox.jyear == j1975.jyear


def test_fk5_galactic():
    """
    Check that FK5 -> Galactic gives the same as FK5 -> FK4 -> Galactic.
    """

    fk5 = FK5(ra=1*u.deg, dec=2*u.deg)

    direct = fk5.transform_to(Galactic)
    indirect = fk5.transform_to(FK4).transform_to(Galactic)

    assert direct.separation(indirect).degree < 1.e-10

    direct = fk5.transform_to(Galactic)
    indirect = fk5.transform_to(FK4NoETerms).transform_to(Galactic)

    assert direct.separation(indirect).degree < 1.e-10


def test_galactocentric():
    # when z_sun=0, transformation should be very similar to Galactic
    icrs_coord = ICRS(ra=np.linspace(0, 360, 10)*u.deg,
                      dec=np.linspace(-90, 90, 10)*u.deg,
                      distance=1.*u.kpc)

    g_xyz = icrs_coord.transform_to(Galactic).cartesian.xyz
    gc_xyz = icrs_coord.transform_to(Galactocentric(z_sun=0*u.kpc)).cartesian.xyz
    diff = np.abs(g_xyz - gc_xyz)

    assert allclose(diff[0], 8.3*u.kpc, atol=1E-5*u.kpc)
    assert allclose(diff[1:], 0*u.kpc, atol=1E-5*u.kpc)

    # generate some test coordinates
    g = Galactic(l=[0, 0, 45, 315]*u.deg, b=[-45, 45, 0, 0]*u.deg,
                 distance=[np.sqrt(2)]*4*u.kpc)
    xyz = g.transform_to(Galactocentric(galcen_distance=1.*u.kpc, z_sun=0.*u.pc)).cartesian.xyz
    true_xyz = np.array([[0, 0, -1.], [0, 0, 1], [0, 1, 0], [0, -1, 0]]).T*u.kpc
    assert allclose(xyz.to(u.kpc), true_xyz.to(u.kpc), atol=1E-5*u.kpc)

    # check that ND arrays work

    # from Galactocentric to Galactic
    x = np.linspace(-10., 10., 100) * u.kpc
    y = np.linspace(-10., 10., 100) * u.kpc
    z = np.zeros_like(x)

    g1 = Galactocentric(x=x, y=y, z=z)
    g2 = Galactocentric(x=x.reshape(100, 1, 1), y=y.reshape(100, 1, 1),
                        z=z.reshape(100, 1, 1))

    g1t = g1.transform_to(Galactic)
    g2t = g2.transform_to(Galactic)

    assert_allclose(g1t.cartesian.xyz, g2t.cartesian.xyz[:, :, 0, 0])

    # from Galactic to Galactocentric
    l = np.linspace(15, 30., 100) * u.deg
    b = np.linspace(-10., 10., 100) * u.deg
    d = np.ones_like(l.value) * u.kpc

    g1 = Galactic(l=l, b=b, distance=d)
    g2 = Galactic(l=l.reshape(100, 1, 1), b=b.reshape(100, 1, 1),
                  distance=d.reshape(100, 1, 1))

    g1t = g1.transform_to(Galactocentric)
    g2t = g2.transform_to(Galactocentric)

    np.testing.assert_almost_equal(g1t.cartesian.xyz.value,
                                   g2t.cartesian.xyz.value[:, :, 0, 0])


def test_supergalactic():
    """
    Check Galactic<->Supergalactic and Galactic<->ICRS conversion.
    """
    # Check supergalactic North pole.
    npole = Galactic(l=47.37*u.degree, b=+6.32*u.degree)
    assert allclose(npole.transform_to(Supergalactic).sgb.deg, +90, atol=1e-9)

    # Check the origin of supergalactic longitude.
    lon0 = Supergalactic(sgl=0*u.degree, sgb=0*u.degree)
    lon0_gal = lon0.transform_to(Galactic)
    assert allclose(lon0_gal.l.deg, 137.37, atol=1e-9)
    assert allclose(lon0_gal.b.deg, 0, atol=1e-9)

    # Test Galactic<->ICRS with some positions that appear in Foley et al. 2008
    # (http://adsabs.harvard.edu/abs/2008A%26A...484..143F)

    # GRB 021219
    supergalactic = Supergalactic(sgl=29.91*u.degree, sgb=+73.72*u.degree)
    icrs = SkyCoord('18h50m27s +31d57m17s')
    assert supergalactic.separation(icrs) < 0.005 * u.degree

    # GRB 030320
    supergalactic = Supergalactic(sgl=-174.44*u.degree, sgb=+46.17*u.degree)
    icrs = SkyCoord('17h51m36s -25d18m52s')
    assert supergalactic.separation(icrs) < 0.005 * u.degree


class TestHCRS():
    """
    Check HCRS<->ICRS coordinate conversions.

    Uses ICRS Solar positions predicted by get_body_barycentric; with `t1` and
    `tarr` as defined below, the ICRS Solar positions were predicted using, e.g.
    coord.ICRS(coord.get_body_barycentric(tarr, 'sun')).
    """
    def setup(self):
        self.t1 = Time("2013-02-02T23:00")
        self.t2 = Time("2013-08-02T23:00")
        self.tarr = Time(["2013-02-02T23:00", "2013-08-02T23:00"])

        self.sun_icrs_scalar = ICRS(ra=244.52984668*u.deg,
                                    dec=-22.36943723*u.deg,
                                    distance=406615.66347377*u.km)
        # array of positions corresponds to times in `tarr`
        self.sun_icrs_arr = ICRS(ra=[244.52989062, 271.40976248]*u.deg,
                                 dec=[-22.36943605, -25.07431079]*u.deg,
                                 distance=[406615.66347377, 375484.13558956]*u.km)

        # corresponding HCRS positions
        self.sun_hcrs_t1 = HCRS(CartesianRepresentation([0.0, 0.0, 0.0] * u.km),
                                obstime=self.t1)
        twod_rep = CartesianRepresentation([[0.0, 0.0], [0.0, 0.0], [0.0, 0.0]] * u.km)
        self.sun_hcrs_tarr = HCRS(twod_rep, obstime=self.tarr)
        self.tolerance = 5*u.km

    def test_from_hcrs(self):
        # test scalar transform
        transformed = self.sun_hcrs_t1.transform_to(ICRS())
        separation = transformed.separation_3d(self.sun_icrs_scalar)
        assert_allclose(separation, 0*u.km, atol=self.tolerance)

        # test non-scalar positions and times
        transformed = self.sun_hcrs_tarr.transform_to(ICRS())
        separation = transformed.separation_3d(self.sun_icrs_arr)
        assert_allclose(separation, 0*u.km, atol=self.tolerance)

    def test_from_icrs(self):
        # scalar positions
        transformed = self.sun_icrs_scalar.transform_to(HCRS(obstime=self.t1))
        separation = transformed.separation_3d(self.sun_hcrs_t1)
        assert_allclose(separation, 0*u.km, atol=self.tolerance)
        # nonscalar positions
        transformed = self.sun_icrs_arr.transform_to(HCRS(obstime=self.tarr))
        separation = transformed.separation_3d(self.sun_hcrs_tarr)
        assert_allclose(separation, 0*u.km, atol=self.tolerance)


class TestHelioBaryCentric():
    """
    Check GCRS<->Heliocentric and Barycentric coordinate conversions.

    Uses the WHT observing site (information grabbed from data/sites.json).
    """
    def setup(self):
        wht = EarthLocation(342.12*u.deg, 28.758333333333333*u.deg, 2327*u.m)
        self.obstime = Time("2013-02-02T23:00")
        self.wht_itrs = wht.get_itrs(obstime=self.obstime)

    def test_heliocentric(self):
        gcrs = self.wht_itrs.transform_to(GCRS(obstime=self.obstime))
        helio = gcrs.transform_to(HCRS(obstime=self.obstime))
        # Check it doesn't change from previous times.
        previous = [-1.02597256e+11, 9.71725820e+10, 4.21268419e+10] * u.m
        assert_allclose(helio.cartesian.xyz, previous)

        # And that it agrees with SLALIB to within 14km
        helio_slalib = [-0.685820296, 0.6495585893, 0.2816005464] * u.au
        assert np.sqrt(((helio.cartesian.xyz -
                         helio_slalib)**2).sum()) < 14. * u.km

    def test_barycentric(self):
        gcrs = self.wht_itrs.transform_to(GCRS(obstime=self.obstime))
        bary = gcrs.transform_to(ICRS())
        previous = [-1.02758958e+11, 9.68331109e+10, 4.19720938e+10] * u.m
        assert_allclose(bary.cartesian.xyz, previous)

        # And that it agrees with SLALIB answer to within 14km
        bary_slalib = [-0.6869012079, 0.6472893646, 0.2805661191] * u.au
        assert np.sqrt(((bary.cartesian.xyz -
                         bary_slalib)**2).sum()) < 14. * u.km