def test_vector_inouts(): """ Tests that ERFA functions working with vectors are correctly consumed and spit out """ # values are from test_erfa.c t_ab function pnat = [-0.76321968546737951, -0.60869453983060384, -0.21676408580639883] v = [2.1044018893653786e-5, -8.9108923304429319e-5, -3.8633714797716569e-5] s = 0.99980921395708788 bm1 = 0.99999999506209258 expected = [ -0.7631631094219556269, -0.6087553082505590832, -0.2167926269368471279 ] res = erfa.ab(pnat, v, s, bm1) assert res.shape == (3, ) np.testing.assert_allclose(res, expected) res2 = erfa.ab([pnat] * 4, v, s, bm1) assert res2.shape == (4, 3) np.testing.assert_allclose(res2, [expected] * 4) # here we stride an array and also do it Fortran-order to make sure # it all still works correctly with non-contig arrays pnata = np.array(pnat) arrin = np.array([pnata, pnata / 2, pnata / 3, pnata / 4, pnata / 5] * 4, order='F') res3 = erfa.ab(arrin[::5], v, s, bm1) assert res3.shape == (4, 3) np.testing.assert_allclose(res3, [expected] * 4)
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
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
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
def get_sun(time): """ Determines the location of the sun at a given time (or times, if the input is an array `~astropy.time.Time` object), in geocentric coordinates. Parameters ---------- time : `~astropy.time.Time` The time(s) at which to compute the location of the sun. Returns ------- newsc : `~astropy.coordinates.SkyCoord` The location of the sun as a `~astropy.coordinates.SkyCoord` in the `~astropy.coordinates.GCRS` frame. Notes ----- The algorithm for determining the sun/earth relative position is based on the simplified version of VSOP2000 that is part of ERFA. Compared to JPL's ephemeris, it should be good to about 4 km (in the Sun-Earth vector) from 1900-2100 C.E., 8 km for the 1800-2200 span, and perhaps 250 km over the 1000-3000. """ earth_pv_helio, earth_pv_bary = erfa.epv00(*get_jd12(time, 'tdb')) # We have to manually do aberration because we're outputting directly into # GCRS earth_p = earth_pv_helio['p'] earth_v = earth_pv_bary['v'] # convert barycentric velocity to units of c, but keep as array for passing in to erfa earth_v /= c.to_value(u.au / u.d) dsun = np.sqrt(np.sum(earth_p**2, axis=-1)) invlorentz = (1 - np.sum(earth_v**2, axis=-1))**0.5 properdir = erfa.ab(earth_p / dsun.reshape(dsun.shape + (1, )), -earth_v, dsun, invlorentz) cartrep = CartesianRepresentation(x=-dsun * properdir[..., 0] * u.AU, y=-dsun * properdir[..., 1] * u.AU, z=-dsun * properdir[..., 2] * u.AU) return SkyCoord(cartrep, frame=GCRS(obstime=time))
def get_sun(time): """ Determines the location of the sun at a given time (or times, if the input is an array `~astropy.time.Time` object), in geocentric coordinates. Parameters ---------- time : `~astropy.time.Time` The time(s) at which to compute the location of the sun. Returns ------- newsc : `~astropy.coordinates.SkyCoord` The location of the sun as a `~astropy.coordinates.SkyCoord` in the `~astropy.coordinates.GCRS` frame. Notes ----- The algorithm for determining the sun/earth relative position is based on the simplified version of VSOP2000 that is part of ERFA. Compared to JPL's ephemeris, it should be good to about 4 km (in the Sun-Earth vector) from 1900-2100 C.E., 8 km for the 1800-2200 span, and perhaps 250 km over the 1000-3000. """ earth_pv_helio, earth_pv_bary = erfa.epv00(*get_jd12(time, 'tdb')) # We have to manually do aberration because we're outputting directly into # GCRS earth_p = earth_pv_helio['p'] earth_v = earth_pv_bary['v'] # convert barycentric velocity to units of c, but keep as array for passing in to erfa earth_v /= c.to_value(u.au/u.d) dsun = np.sqrt(np.sum(earth_p**2, axis=-1)) invlorentz = (1-np.sum(earth_v**2, axis=-1))**0.5 properdir = erfa.ab(earth_p/dsun.reshape(dsun.shape + (1,)), -earth_v, dsun, invlorentz) cartrep = CartesianRepresentation(x=-dsun*properdir[..., 0] * u.AU, y=-dsun*properdir[..., 1] * u.AU, z=-dsun*properdir[..., 2] * u.AU) return SkyCoord(cartrep, frame=GCRS(obstime=time))
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