Esempio n. 1
0
def test_spherical_cartesian():

    theta, phi = erfa.c2s([0.0, np.sqrt(2.0), np.sqrt(2.0)])
    np.testing.assert_allclose(theta, np.pi / 2.0)
    np.testing.assert_allclose(phi, np.pi / 4.0)

    theta, phi, r = erfa.p2s([0.0, np.sqrt(2.0), np.sqrt(2.0)])
    np.testing.assert_allclose(theta, np.pi / 2.0)
    np.testing.assert_allclose(phi, np.pi / 4.0)
    np.testing.assert_allclose(r, 2.0)

    pv = np.array(([0.0, np.sqrt(2.0), np.sqrt(2.0)], [1.0, 0.0, 0.0]),
                  dtype=erfa.dt_pv)
    theta, phi, r, td, pd, rd = erfa.pv2s(pv)
    np.testing.assert_allclose(theta, np.pi / 2.0)
    np.testing.assert_allclose(phi, np.pi / 4.0)
    np.testing.assert_allclose(r, 2.0)
    np.testing.assert_allclose(td, -np.sqrt(2.0) / 2.0)
    np.testing.assert_allclose(pd, 0.0)
    np.testing.assert_allclose(rd, 0.0)

    c = erfa.s2c(np.pi / 2.0, np.pi / 4.0)
    np.testing.assert_allclose(
        c,
        [0.0, np.sqrt(2.0) / 2.0, np.sqrt(2.0) / 2.0], atol=1e-14)

    c = erfa.s2p(np.pi / 2.0, np.pi / 4.0, 1.0)
    np.testing.assert_allclose(
        c,
        [0.0, np.sqrt(2.0) / 2.0, np.sqrt(2.0) / 2.0], atol=1e-14)

    pv = erfa.s2pv(np.pi / 2.0, np.pi / 4.0, 2.0, np.sqrt(2.0) / 2.0, 0.0, 0.0)
    np.testing.assert_allclose(
        pv['p'], [0.0, np.sqrt(2.0), np.sqrt(2.0)], atol=1e-14)
    np.testing.assert_allclose(pv['v'], [-1.0, 0.0, 0.0], atol=1e-14)
def epoch_topocentric_coordinates(alpha, delta, parallax, mura, mudec, vrad, t, refepoch, ephem):
    """
    For each observation epoch calculate the topocentric coordinate directions (alpha(t), delta(t)) given
    the astrometric parameters of a source, the observation times, and the ephemeris (in the BCRS) for
    the observer. Also calculate the local plane coordinates xi(t) and eta(t).

    The code uses the Pyhton ERFA routines (https://pyerfa.readthedocs.io/)

    Parameters
    ----------
    
    alpha : float
        Right ascension at reference epoch (radians)
    delta : float
        Declination at reference epoch (radians)
    parallax : float
        Parallax (mas), negative values allowed
    mura : float
        Proper motion in right ascension, including cos(delta) factor (mas/yr)
    mudec : float
        Proper motion in declination (mas/yr)
    vrad : float
        Radial velocity (km/s)
    t : float array
        Observation times (Julian year TCB)
    refepoch : float
        Reference epoch (Julian year TCB)
    ephem : function
        Funtion providing the observer's ephemeris in BCRS at times t (units of AU)
                
    Returns
    -------
    
    alpha, delta, xi, eta : float arrays
        The coordinates directions to the sources for each time t and the corresponsing local plane coordinates (xi,
        eta), referred to the source direction at the reference epoch.
        Units are radians for (alpha, delta) and mas for (xi, eta).
    """
    # Normal triad, defined at the reference epoch.
    p = np.array([-np.sin(alpha), np.cos(alpha), 0.0])
    q = np.array([-np.sin(delta)*np.cos(alpha), -np.sin(delta)*np.sin(alpha), np.cos(delta)])
    r = np.array([np.cos(delta)*np.cos(alpha), np.cos(delta)*np.sin(alpha), np.sin(delta)])

    # Calculate observer's ephemeris.
    bO_bcrs = ephem(t)

    # Unit conversions
    plx = parallax/1000.0
    pmra = mura*_mastorad/np.cos(delta)
    pmdec = mudec*_mastorad

    uO = pmpx(alpha, delta, pmra, pmdec, plx, vrad, t-refepoch, bO_bcrs.T)

    # Local plane coordinates which approximately equal delta_alpha*cos(delta) and delta_delta
    xi = np.dot(p,uO.T)/np.dot(r,uO.T)*_radtomas
    eta = np.dot(q,uO.T)/np.dot(r,uO.T)*_radtomas

    alpha_obs, delta_obs = c2s(uO)

    return alpha_obs, delta_obs, xi, eta
Esempio n. 3
0
def aticq(ri, di, astrom):
    """
    A slightly modified version of the ERFA function ``eraAticq``.

    ``eraAticq`` performs the transformations between two coordinate systems,
    with the details of the transformation being encoded into the ``astrom`` array.

    The companion function ``eraAtciqz`` is meant to be its inverse. However, this
    is not true for directions close to the Solar centre, since the light deflection
    calculations are numerically unstable and therefore not reversible.

    This version sidesteps that problem by artificially reducing the light deflection
    for directions which are within 90 arcseconds of the Sun's position. This is the
    same approach used by the ERFA functions above, except that they use a threshold of
    9 arcseconds.

    Parameters
    ----------
    ri : float or `~numpy.ndarray`
        right ascension, radians
    di : float or `~numpy.ndarray`
        declination, radians
    astrom : eraASTROM array
        ERFA astrometry context, as produced by, e.g. ``eraApci13`` or ``eraApcs13``

    Returns
    --------
    rc : float or `~numpy.ndarray`
    dc : float or `~numpy.ndarray`
    """
    # RA, Dec to cartesian unit vectors
    pos = erfa.s2c(ri, di)

    # Bias-precession-nutation, giving GCRS proper direction.
    ppr = erfa.trxp(astrom['bpn'], pos)

    # Aberration, giving GCRS natural direction
    d = np.zeros_like(ppr)
    for j in range(2):
        before = norm(ppr - d)
        after = erfa.ab(before, astrom['v'], astrom['em'], astrom['bm1'])
        d = after - before
    pnat = norm(ppr - d)

    # Light deflection by the Sun, giving BCRS coordinate direction
    d = np.zeros_like(pnat)
    for j in range(5):
        before = norm(pnat - d)
        after = erfa.ld(1.0, before, before, astrom['eh'], astrom['em'], 5e-8)
        d = after - before
    pco = norm(pnat - d)

    # ICRS astrometric RA, Dec
    rc, dc = erfa.c2s(pco)
    return erfa.anp(rc), dc
Esempio n. 4
0
 def sun(self):
     '''RA and DEC of the Sun'''
     x, y, z = self.eph[0][0], self.eph[0][1], self.eph[0][2]
     self.distances_from_earth.update(
         {'Sun':math.sqrt(x*x + y*y +z*z)}
         )
     a, d = erfa.c2s((-x, -y, -z))
     a = erfa.anp(a)
     self.RA_DEC.update(
         {'Sun':(a, d)}
         )
Esempio n. 5
0
 def planets(self):
     '''RA and DEC of major planets and EMB'''
     for i in range(8):
         x = self.p94[i][0][0] - self.eph[0][0]
         y = self.p94[i][0][1] - self.eph[0][1]
         z = self.p94[i][0][2] - self.eph[0][2]
         self.distances_from_earth.update(
             {Planet(i+1).name:math.sqrt(x*x + y*y +z*z)}
             )
         a, d = erfa.c2s((x,y,z))
         a = erfa.anp(a)
         self.RA_DEC.update(
             {Planet(i+1).name:(a, d)}
             )
Esempio n. 6
0
def atciqz(rc, dc, astrom):
    """
    A slightly modified version of the ERFA function ``eraAtciqz``.

    ``eraAtciqz`` performs the transformations between two coordinate systems,
    with the details of the transformation being encoded into the ``astrom`` array.

    The companion function ``eraAticq`` is meant to be its inverse. However, this
    is not true for directions close to the Solar centre, since the light deflection
    calculations are numerically unstable and therefore not reversible.

    This version sidesteps that problem by artificially reducing the light deflection
    for directions which are within 90 arcseconds of the Sun's position. This is the
    same approach used by the ERFA functions above, except that they use a threshold of
    9 arcseconds.

    Parameters
    ----------
    rc : float or `~numpy.ndarray`
        right ascension, radians
    dc : float or `~numpy.ndarray`
        declination, radians
    astrom : eraASTROM array
        ERFA astrometry context, as produced by, e.g. ``eraApci13`` or ``eraApcs13``

    Returns
    --------
    ri : float or `~numpy.ndarray`
    di : float or `~numpy.ndarray`
    """
    # BCRS coordinate direction (unit vector).
    pco = erfa.s2c(rc, dc)

    # Light deflection by the Sun, giving BCRS natural direction.
    pnat = erfa.ld(1.0, pco, pco, astrom['eh'], astrom['em'], 5e-8)

    # Aberration, giving GCRS proper direction.
    ppr = erfa.ab(pnat, astrom['v'], astrom['em'], astrom['bm1'])

    # Bias-precession-nutation, giving CIRS proper direction.
    # Has no effect if matrix is identity matrix, in which case gives GCRS ppr.
    pi = erfa.rxp(astrom['bpn'], ppr)

    # CIRS (GCRS) RA, Dec
    ri, di = erfa.c2s(pi)
    return erfa.anp(ri), di
Esempio n. 7
0
def atciqz(srepr, astrom):
    """
    A slightly modified version of the ERFA function ``eraAtciqz``.

    ``eraAtciqz`` performs the transformations between two coordinate systems,
    with the details of the transformation being encoded into the ``astrom`` array.

    There are two issues with the version of atciqz in ERFA. Both are associated
    with the handling of light deflection.

    The companion function ``eraAticq`` is meant to be its inverse. However, this
    is not true for directions close to the Solar centre, since the light deflection
    calculations are numerically unstable and therefore not reversible.

    This version sidesteps that problem by artificially reducing the light deflection
    for directions which are within 90 arcseconds of the Sun's position. This is the
    same approach used by the ERFA functions above, except that they use a threshold of
    9 arcseconds.

    In addition, ERFA's atciqz assumes a distant source, so there is no difference between
    the object-Sun vector and the observer-Sun vector. This can lead to errors of up to a
    few arcseconds in the worst case (e.g a Venus transit).

    Parameters
    ----------
    srepr : `~astropy.coordinates.SphericalRepresentation`
        Astrometric ICRS position of object from observer
    astrom : eraASTROM array
        ERFA astrometry context, as produced by, e.g. ``eraApci13`` or ``eraApcs13``

    Returns
    --------
    ri : float or `~numpy.ndarray`
        Right Ascension in radians
    di : float or `~numpy.ndarray`
        Declination in radians
    """
    # ignore parallax effects if no distance, or far away
    srepr_distance = srepr.distance
    ignore_distance = srepr_distance.unit == u.one

    # BCRS coordinate direction (unit vector).
    pco = erfa.s2c(srepr.lon.radian, srepr.lat.radian)

    # Find BCRS direction of Sun to object
    if ignore_distance:
        # No distance to object, assume a long way away
        q = pco
    else:
        # Find BCRS direction of Sun to object.
        # astrom['eh'] and astrom['em'] contain Sun to observer unit vector,
        # and distance, respectively.
        eh = astrom['em'][..., np.newaxis] * astrom['eh']
        # unit vector from Sun to object
        q = eh + srepr_distance[..., np.newaxis].to_value(u.au) * pco
        sundist, q = erfa.pn(q)
        sundist = sundist[..., np.newaxis]
        # calculation above is extremely unstable very close to the sun
        # in these situations, default back to ldsun-style behaviour,
        # since this is reversible and drops to zero within stellar limb
        q = np.where(sundist > 1.0e-10, q, pco)

    # Light deflection by the Sun, giving BCRS natural direction.
    pnat = erfa.ld(1.0, pco, q, astrom['eh'], astrom['em'], 1e-6)

    # Aberration, giving GCRS proper direction.
    ppr = erfa.ab(pnat, astrom['v'], astrom['em'], astrom['bm1'])

    # Bias-precession-nutation, giving CIRS proper direction.
    # Has no effect if matrix is identity matrix, in which case gives GCRS ppr.
    pi = erfa.rxp(astrom['bpn'], ppr)

    # CIRS (GCRS) RA, Dec
    ri, di = erfa.c2s(pi)
    return erfa.anp(ri), di