def testWrap(self): for wrap in (-1000, -10, -1, 0, 1, 10, 1000): for offset in (-360, -180, -90, 0, 90, 180, 270, 360): for epsMult in (-3, -2, -1, 0, 1, 2, 3): ang = offset + (wrap * 360) ang += ang * DoubleEpsilon * epsMult sinAng = sind(ang) cosAng = cosd(ang) pvt = PVT(ang, ang, 35.0) # pick anything for vel and time posAng = wrapPos(ang) self.assertGreaterEqual(posAng, 0.0) self.assertLess(posAng, 360.0) # prove that posAng and ang are the same angle # sin and cos are a sanity check on wrapCtr self.assertAlmostEqual(wrapCtr(posAng - ang), 0) self.assertAlmostEqual(sind(posAng), sinAng) self.assertAlmostEqual(cosd(posAng), cosAng) posPvt = wrapPos(pvt) self.assertEqual(posPvt.pos, posAng) self.assertEqual(posPvt.vel, pvt.vel) self.assertEqual(posPvt.t, pvt.t) ctrAng = wrapCtr(ang) self.assertGreaterEqual(ctrAng, -180.0) self.assertLess(ctrAng, 180.0) # prove that ctrAng and ang are the same angle self.assertAlmostEqual(wrapCtr(ctrAng - ang), 0) self.assertAlmostEqual(sind(ctrAng), sinAng) self.assertAlmostEqual(cosd(ctrAng), cosAng) ctrPvt = wrapCtr(pvt) self.assertEqual(ctrPvt.pos, ctrAng) self.assertEqual(ctrPvt.vel, pvt.vel) self.assertEqual(ctrPvt.t, pvt.t) for refAngBase in (-180, 0, 180, 360): for refEpsMult in (-3, -2, -1, 0, 1, 2, 3): refAng = refAngBase refAng += refAng * refEpsMult * DoubleEpsilon nearAng = wrapNear(ang, refAng) self.assertGreaterEqual(nearAng - refAng, -180) self.assertLess(nearAng - refAng, 180) # prove that nearAng and ang are the same angle self.assertAlmostEqual(wrapCtr(nearAng - ang), 0) self.assertAlmostEqual(sind(nearAng), sinAng) self.assertAlmostEqual(cosd(nearAng), cosAng)
def gmstFromUT1(ut1): """Convert from universal time (MJD) to Greenwich mean sidereal time, in degrees Based on Pat Wallace's GMST, whose comments follow: The IAU 1982 expression (see page S15 of 1984 Astronomical Almanac) is used, but rearranged to reduce rounding errors. This expression is always described as giving the GMST at 0 hours UT. In fact, it gives the difference between the GMST and the UT, which happens to equal the GMST (modulo 24 hours) at 0 hours UT each day. In this routine, the entire UT is used directly as the argument for the standard formula, and the fractional part of the UT is added separately; note that the factor 1.0027379... does not appear. See also the routine GMSTA, which delivers better numerical precision by accepting the UT date and time as separate arguments. P.T.Wallace Starlink 14 September 1995 History: 2002-20-12 ROwen Removed an extra + sign that was doing nothing. Thanks to pychecker. """ # convert date to Julian centuries since J2000 jc = (ut1 - coordConv.MJDJ2000) / 36525.0 return coordConv.wrapPos( (math.fmod(ut1, 1.0) * 360.0) # fraction of day of UT1, in degrees + (24110.54841 + (8640184.812866 + (0.093104 - (6.2e-6 * jc)) * jc) * jc) * 0.0041666666666666666)
def gmstFromUT1(ut1): """Convert from universal time (MJD) to Greenwich mean sidereal time, in degrees Based on Pat Wallace's GMST, whose comments follow: The IAU 1982 expression (see page S15 of 1984 Astronomical Almanac) is used, but rearranged to reduce rounding errors. This expression is always described as giving the GMST at 0 hours UT. In fact, it gives the difference between the GMST and the UT, which happens to equal the GMST (modulo 24 hours) at 0 hours UT each day. In this routine, the entire UT is used directly as the argument for the standard formula, and the fractional part of the UT is added separately; note that the factor 1.0027379... does not appear. See also the routine GMSTA, which delivers better numerical precision by accepting the UT date and time as separate arguments. P.T.Wallace Starlink 14 September 1995 History: 2002-20-12 ROwen Removed an extra + sign that was doing nothing. Thanks to pychecker. """ # convert date to Julian centuries since J2000 jc= (ut1 - coordConv.MJDJ2000) / 36525.0 return coordConv.wrapPos ( (math.fmod(ut1, 1.0) * 360.0) # fraction of day of UT1, in degrees + (24110.54841 + (8640184.812866 + (0.093104-(6.2e-6*jc))*jc)*jc)*0.0041666666666666666)
def lastFromTAI(tai, site): ut1Days = (tai + site.ut1_tai) / coordConv.SecPerDay gmst = gmstFromUT1(ut1Days) # compute apparent - mean sidereal time, in degrees ttDays = (tai + coordConv.TT_TAI) / coordConv.SecPerDay appMinusMean = eqeqx(ttDays) / coordConv.RadPerDeg # compute local apparent sideral time, in degrees, in range [0, 360) return coordConv.wrapPos(gmst + site.corrLong + appMinusMean)
def lastFromTAI(tai, site): ut1Days = (tai + site.ut1_tai) / coordConv.SecPerDay gmst = gmstFromUT1(ut1Days) # compute apparent - mean sidereal time, in degrees ttDays = (tai + coordConv.TT_TAI) / coordConv.SecPerDay; appMinusMean = eqeqx(ttDays) / coordConv.RadPerDeg; # compute local apparent sideral time, in degrees, in range [0, 360) return coordConv.wrapPos(gmst + site.corrLong + appMinusMean);
def testBasics(self): """Check sph -> vec and back again for points not at the pole The round trip test relies on the fact that the internal representation of a coord is vector, so simply retrieving the sph info again suffices to test a round trip. Warning: the test of vector velocity is poor because the code is copied from the C++. However, two other tests will help: - Convert a coordinate system to itself with two different dates of observation and check that the expected amount of spatial motion occurs - Compare coordinate conversion results to the old TCC """ for equatAng in (0, 71, -123.4): for polarAng in (0, -75, -89.999999, 89.999999): for parallax in (0, MinParallax / 0.9000001, MinParallax / 0.8999999, 5): for equatPM in (4,): # (0, 4): for polarPM in (-7,): # (0, -7): for radVel in (0, -34): coord = Coord(equatAng, polarAng, parallax, equatPM, polarPM, radVel) self.assertFalse(coord.atPole()) self.assertEqual(coord.atInfinity(), parallax < MinParallax / 0.9) # check vector position vecPos = coord.getVecPos() dist = coord.getDistance() self.assertAlmostEqual(numpy.linalg.norm(vecPos), dist, 2) predVecPos = ( dist * cosd(polarAng) * cosd(equatAng), dist * cosd(polarAng) * sind(equatAng), dist * sind(polarAng), ) self.assertTrue(numpy.allclose(predVecPos, vecPos)) # check vector proper motion vecPM = coord.getVecPM() RadPerYear_per_ArcsecPerCentury = RadPerDeg / (ArcsecPerDeg * 100.0) SecPerYear = SecPerDay * DaysPerYear AUPerYear_per_KmPerSec = SecPerYear / KmPerAU sinEquat = sind(equatAng) cosEquat = cosd(equatAng) sinPolar = sind(polarAng) cosPolar = cosd(polarAng) # change units of proper motion from arcsec/century to au/year pmAUPerYear1 = equatPM * dist * RadPerYear_per_ArcsecPerCentury pmAUPerYear2 = polarPM * dist * RadPerYear_per_ArcsecPerCentury # change units of radial velocity from km/sec to au/year radVelAUPerYear = radVel * AUPerYear_per_KmPerSec predVecPM = ( - (pmAUPerYear2 * sinPolar * cosEquat) - (pmAUPerYear1 * cosPolar * sinEquat) + (radVelAUPerYear * cosPolar * cosEquat), - (pmAUPerYear2 * sinPolar * sinEquat) + (pmAUPerYear1 * cosPolar * cosEquat) + (radVelAUPerYear * cosPolar * sinEquat), + (pmAUPerYear2 * cosPolar) + (radVelAUPerYear * sinPolar), ) self.assertTrue(numpy.allclose(predVecPM, vecPM)) # check round trip atPole, destEquatAng, destPolarAng = coord.getSphPos() self.assertAlmostEqual(wrapPos(equatAng), destEquatAng) self.assertAlmostEqual(polarAng, destPolarAng) destParallax = coord.getParallax() predParallax = 0 if coord.atInfinity() else parallax self.assertAlmostEqual(predParallax, destParallax) atPole, destEquatPM, destPolarPM = coord.getPM() self.assertAlmostEqual(equatPM, destEquatPM, 6) self.assertAlmostEqual(polarPM, destPolarPM, 6) destRadVel = coord.getRadVel() self.assertAlmostEqual(radVel, destRadVel) coordCopy = Coord(coord) self.assertEqual(repr(coord), repr(coordCopy))
def testBasics(self): """Check sph -> vec and back again for points not at the pole The round trip test relies on the fact that the internal representation of a coord is vector, so simply retrieving the sph info again suffices to test a round trip. Warning: the test of vector velocity is poor because the code is copied from the C++. However, two other tests will help: - Convert a coordinate system to itself with two different dates of observation and check that the expected amount of spatial motion occurs - Compare coordinate conversion results to the old TCC """ for equatAng in (0, 71, -123.4): for polarAng in (0, -75, -89.999999, 89.999999): for parallax in (0, MinParallax / 0.9000001, MinParallax / 0.8999999, 5): for equatPM in (4, ): # (0, 4): for polarPM in (-7, ): # (0, -7): for radVel in (0, -34): coord = Coord(equatAng, polarAng, parallax, equatPM, polarPM, radVel) self.assertFalse(coord.atPole()) self.assertEqual(coord.atInfinity(), parallax < MinParallax / 0.9) # check vector position vecPos = coord.getVecPos() dist = coord.getDistance() self.assertAlmostEqual( numpy.linalg.norm(vecPos), dist, 2) predVecPos = ( dist * cosd(polarAng) * cosd(equatAng), dist * cosd(polarAng) * sind(equatAng), dist * sind(polarAng), ) self.assertTrue( numpy.allclose(predVecPos, vecPos)) # check vector proper motion vecPM = coord.getVecPM() RadPerYear_per_ArcsecPerCentury = RadPerDeg / ( ArcsecPerDeg * 100.0) SecPerYear = SecPerDay * DaysPerYear AUPerYear_per_KmPerSec = SecPerYear / KmPerAU sinEquat = sind(equatAng) cosEquat = cosd(equatAng) sinPolar = sind(polarAng) cosPolar = cosd(polarAng) # change units of proper motion from arcsec/century to au/year pmAUPerYear1 = equatPM * dist * RadPerYear_per_ArcsecPerCentury pmAUPerYear2 = polarPM * dist * RadPerYear_per_ArcsecPerCentury # change units of radial velocity from km/sec to au/year radVelAUPerYear = radVel * AUPerYear_per_KmPerSec predVecPM = ( -(pmAUPerYear2 * sinPolar * cosEquat) - (pmAUPerYear1 * cosPolar * sinEquat) + (radVelAUPerYear * cosPolar * cosEquat), -(pmAUPerYear2 * sinPolar * sinEquat) + (pmAUPerYear1 * cosPolar * cosEquat) + (radVelAUPerYear * cosPolar * sinEquat), +(pmAUPerYear2 * cosPolar) + (radVelAUPerYear * sinPolar), ) self.assertTrue( numpy.allclose(predVecPM, vecPM)) # check round trip atPole, destEquatAng, destPolarAng = coord.getSphPos( ) self.assertAlmostEqual(wrapPos(equatAng), destEquatAng) self.assertAlmostEqual(polarAng, destPolarAng) destParallax = coord.getParallax() predParallax = 0 if coord.atInfinity( ) else parallax self.assertAlmostEqual(predParallax, destParallax) atPole, destEquatPM, destPolarPM = coord.getPM( ) self.assertAlmostEqual(equatPM, destEquatPM, 6) self.assertAlmostEqual(polarPM, destPolarPM, 6) destRadVel = coord.getRadVel() self.assertAlmostEqual(radVel, destRadVel) coordCopy = Coord(coord) self.assertEqual(repr(coord), repr(coordCopy))