def testBasics(self): """Test basic functionality of Site """ for long in (54.3, -134.5): for lat in (-23.4, 12.3): for elev in (2789, 6543): site = coordConv.Site(long, lat, elev) self.assertEqual(long, site.meanLong) self.assertEqual(lat, site.meanLat) self.assertEqual(elev, site.elev) self.assertAlmostEqual(long, site.corrLong) self.assertAlmostEqual(lat, site.corrLat) site.setPoleWander(0, 0) self.assertAlmostEqual(long, site.corrLong) self.assertAlmostEqual(lat, site.corrLat) for xArcsec in (-0.3, 0, 0.3): x = xArcsec / 3600.0 for yArcsec in (-0.3, 0, 0.3): y = yArcsec / 3600.0 site.setPoleWander(x, y) # the following is an approximation given in the header of slaPolmo approxCorrLong = long + (x * coordConv.cosd(long) ) - (y * coordConv.sind(long)) approxCorrLat = lat + ( ((x * coordConv.sind(long)) + (y * coordConv.cosd(long))) * coordConv.tand(lat)) self.assertAlmostEqual(approxCorrLong, site.corrLong, 3) self.assertAlmostEqual(approxCorrLat, site.corrLat, 3) siteCopy = coordConv.Site(site) self.assertEqual(repr(site), repr(siteCopy))
def testConvertFrom(self): """Test a few instances of CoordSys.convertFrom on PVTCoords This test assumes that CoordSys.convertFrom works on Coords (tested elsewhere) """ site = coordConv.Site(-105.822616, 32.780988, 2788) fromCoordSys = coordConv.ICRSCoordSys() toCoordSys = coordConv.GalCoordSys() dt = 0.001 def pvtCoordIter(): for equatAng in (0, 71, -123.4): for polarAng in (0, -75, -89.9, 89.9): for equatVel in (0, 0.023): for polarVel in (0, -math.copysign(0.012, polarAng)): for tai in (4889100000.5, 1000.1): equatPVT = coordConv.PVT( equatAng, equatVel, tai) polarPVT = coordConv.PVT( polarAng, polarVel, tai) yield coordConv.PVTCoord(equatPVT, polarPVT) for fromPVTCoord in pvtCoordIter(): tai0 = fromPVTCoord.getTAI() taiPair = [tai0, tai0 + dt] fromCoordPair = [fromPVTCoord.getCoord(t) for t in taiPair] toPVTCoord = toCoordSys.convertFrom(fromCoordSys, fromPVTCoord, site) for fromCoord, tai in itertools.izip(fromCoordPair, taiPair): predToCoord = toCoordSys.convertFrom(fromCoordSys, fromCoord, site, tai) measToCoord = toPVTCoord.getCoord(tai) self.assertAlmostEqual( predToCoord.angularSeparation(measToCoord), 0)
def testLunarVel(self): """Sanity-check lunar tracking velocity This checks for an issue we had with tracking close objects: position was right, but velocity was not. This was because Apparent Geocentric date was not being updated inside the PVTCoord version of CoordSys.convertFrom. """ tai = 4914602887 dt = 0.1 site = coordConv.Site(-105.822616, 32.780988, 2788) geoCoordSys = coordConv.AppGeoCoordSys() topoCoordSys = coordConv.AppTopoCoordSys() geoCoord = coordConv.Coord(0, 75, 82505922) topoPVTList = [] for evalTAI in (tai, tai + dt): geoPVTCoord = coordConv.PVTCoord(geoCoord, geoCoord, evalTAI, 0.01) topoPVTCoord = topoCoordSys.convertFrom(geoCoordSys, geoPVTCoord, site) topoPVTPair = [coordConv.PVT() for i in range(2)] topoPVTCoord.getSphPVT(topoPVTPair[0], topoPVTPair[1]) topoPVTList.append(topoPVTPair) for i in range(2): pvt0 = topoPVTList[0][i] pvt1 = topoPVTList[1][i] coordConv.assertPVTsAlmostEqual(pvt0.copy(pvt1.t), pvt1)
def makeSite(): """Create a realistic site object (for the APO 3.5m)""" site = coordConv.Site(-105.822616, 32.780988, 2.788) site.setPoleWander(0.89e-5, 0.92e-4) site.ut1_tai = -34.782 site.refCoA = 1.2e-2 site.refCoB = -1.3e-5 return site
def testLastFromTAI(self): """Test lastFromTAI This is not a very accurate test because my reference nutc function above is too old. """ site = coordConv.Site(10, 10, 10) # values are not used for ut1_tai in (0, -10.5, 23.3, 900.3): site.ut1_tai = ut1_tai for tai in (4232.89, 20000.32, 56350.03, 74222.9): self.assertAlmostEqual(coordConv.lastFromTAI(tai, site), lastFromTAI(tai, site), places=3)
def testError(self): """Test that constructing with invalid latitude raises an exception """ for long in (54.3, -134.5): for elev in (2789, 6543): for baseLat in (-90, 90): for dLat in (-1, -0.00001, 0, 0.00001, 1): lat = baseLat + dLat if -90 <= lat <= 90: # make sure Site can be constructed coordConv.Site(long, lat, elev) else: # make sure Site construction raises an exception self.assertRaises(Exception, coordConv.Site, long, lat, elev)
def testNullConversion(self): """Test round trip conversion """ site = coordConv.Site(-105.822616, 32.780988, 2788) site.setPoleWander(1.1e-4, -0.5e-4) site.ut1_tai = -2e-8 site.refCoA = 1.2e-2 site.refCoB = -1.3e-5 maxRoundTripErr = 0 for cls in JulianSysList: for date in (1975, 2012): coordSys = cls(date) for equatAng in (100, -45): for polAng in (-20, 25, 89): for dist in (0, 0.01, 1): for pmRA in (0, -3): for pmDec in (0, 5): for radVel in (0, 7): fromCoord = coordConv.Coord( equatAng, polAng, dist, pmRA, pmDec, radVel) fk5Coord = coordSys.toFK5J2000( fromCoord, site) toCoord = coordSys.fromFK5J2000( fk5Coord, site) roundTripErr = toCoord.angularSeparation( fromCoord) maxRoundTripErr = max( roundTripErr, maxRoundTripErr) self.assertLess(roundTripErr, 1e-8) print "maxRoundTripErr for mean and app. geo. coordinate systems =", maxRoundTripErr, "deg" maxRoundTripErr = 0 for cls in AzAltSysList: for date in (4842765000, 4872765000): coordSys = cls(date) for equatAng in (100, -45): for polAng in (0, 25, 89): for dist in (0, 0.01, 1): fromCoord = coordConv.Coord(equatAng, polAng, dist) fk5Coord = coordSys.toFK5J2000(fromCoord, site) toCoord = coordSys.fromFK5J2000(fk5Coord, site) roundTripErr = toCoord.angularSeparation(fromCoord) maxRoundTripErr = max(roundTripErr, maxRoundTripErr) self.assertLess(roundTripErr, 1e-7) print "maxRoundTripErr for app. topo and observed coordinate systems =", maxRoundTripErr, "deg"
def testNoneAndOtherCoordSys(self): """Test that conversions to and from NoneCoordSys and OtherCoordSys fail """ for nullSys in ( coordConv.NoneCoordSys(), coordConv.OtherCoordSys("foo"), ): self.assertFalse(nullSys.canConvert()) site = coordConv.Site(-105.822616, 32.780988, 2788) fromCoord = coordConv.Coord(10, 30) for csysName in FullNameList: otherSys = coordConv.makeCoordSys(csysName, 2001) self.assertRaises(Exception, nullSys.convertFrom, otherSys, fromCoord, site) self.assertRaises(Exception, otherSys.convertFrom, nullSys, fromCoord, site)
def testConvertFromVel(self): """Test velocity of convertFrom """ taiDate = 4889900000.205 site = coordConv.Site(-105.822616, 32.780988, 2788) icrsCoordSys = coordConv.ICRSCoordSys() appTopoCoordSys = coordConv.AppTopoCoordSys() # find ICRS coordinate of a sidereal point on the equator along the meridion appTopoCoord = coordConv.Coord(0, 90 - site.meanLat) icrsCoord = icrsCoordSys.convertFrom(appTopoCoordSys, appTopoCoord, site, taiDate) icrsPVTCoord = coordConv.PVTCoord(icrsCoord, icrsCoord, taiDate, 0.001) appTopoPVTCoord = appTopoCoordSys.convertFrom(icrsCoordSys, icrsPVTCoord, site) equatPVT = coordConv.PVT() polarPVT = coordConv.PVT() appTopoPVTCoord.getSphPVT(equatPVT, polarPVT) self.assertEqual(equatPVT.t, taiDate) self.assertEqual(polarPVT.t, taiDate) equatSpaceVel = equatPVT.vel * coordConv.cosd(polarPVT.pos) self.assertAlmostEqual(polarPVT.vel, 0, places=3) self.assertAlmostEqual(equatSpaceVel, -1 / 240.0, places=3) # 360 deg/day # check round trip of scale and orientation for fromDir in (0, 45): for fromVel in (0, 0.01): fromDirPVT = coordConv.PVT(fromDir, fromVel, taiDate) toDirPVT = coordConv.PVT() fromDir2PVT = coordConv.PVT() at2PVTCoord, scaleChange = appTopoCoordSys.convertFrom( toDirPVT, icrsCoordSys, icrsPVTCoord, fromDirPVT, site) icrs2PVTCoord, scaleChange2 = icrsCoordSys.convertFrom( fromDir2PVT, appTopoCoordSys, at2PVTCoord, toDirPVT, site) self.assertAlmostEqual(scaleChange, 1.0 / scaleChange2, places=7) coordConv.assertPVTsAlmostEqual(fromDirPVT, fromDir2PVT, doWrap=True, velPlaces=6)
compDate = toDate + dataAgeYears appGeoCoordSys = coordConv.AppGeoCoordSys(compDate) appGeoCoord = appGeoCoordSys.convertFrom( fromCoordSys, coord, site) fromCoord = fromCoordSys.convertFrom(appGeoCoordSys, coord, site) angSep = max(refAppGeoCoord.angularSeparation(appGeoCoord), refFromCoord.angularSeparation(fromCoord)) dictKey = (dataAgeSec, ageMult) oldAngSep = errDict.get(dictKey) if oldAngSep is None or angSep > oldAngSep: errDict[dictKey] = angSep errDict = {} site = coordConv.Site(-105.822616, 32.780988, 2.788) for fromCoordSys in (coordConv.ICRSCoordSys(2010), ): for equatAng in (0, 45): for polarAng in (-85, 0, 30, 89): coord = coordConv.Coord(equatAng, polarAng) runOne(fromCoordSys, coord, site, errDict) print "Results (in arcsec) for fromCoordSys=", fromCoordSys.getName( ), fromCoordSys.getDate(), "; coord=", coord.getSphPos() for ageAndMult in sorted(errDict.keys()): print "%s: %0.4f" % (ageAndMult, errDict[ageAndMult] * 3600) # based on these results, 200 seconds gives an error < 0.001 arcseconds, # and it is not so sensitive that it needs to be a constructor parameter # localhost$ tests/checkAppGeoTime.py # Results (in arcsec) for fromCoordSys= icrs 2000.0 ; coord= [False, 44.99999999999999, 29.999999999999996]
def testFile(self): """Test file of coordinate conversions from TCC (data/masscc_out.dat) Known issues: - radVel does not match; the TCC seems to zero radVel if at infinity, but why? Also, the TCC seems to be able to round trip RadVel even if at infinity, but how, if it zeros it when at infinity? Once I resolve this, update the testCoord.py accordingly, as well as this code. - Other problems await at other coordinate systems. """ site = None numErrors = 0 with file(DataFile, "rU") as f: gotSiteData = False startTime = time.time() nTested = 0 for lineInd, line in enumerate(f): line = line.strip() if not line or line.startswith("#"): continue if not gotSiteData: meanLat, meanLong, elevation, ut1_tai, poleX, poleY = [ float(val) for val in line.split() ] site = coordConv.Site(meanLong, meanLat, elevation) site.setPoleWander(poleX, poleY) site.ut1_tai = ut1_tai gotSiteData = True continue dataList = line.split() fromSysCode, fromDate, fromPos1, fromPos2, fromPM1, fromPM2, fromParallax, fromRadVel, fromDir, refCoA, refCoB, \ toSysCode, toDate, refToPos1, refToPos2, refToPM1, refToPM2, refToParallax, refToRadVel, \ refToDir, refScaleChange, refAtInf, refAtPole, isOK, tai, last \ = [cnvFunc(val) for val, cnvFunc in itertools.izip(dataList, CnvList)] if not isOK: print "Skipping line %s: %s; isOK false" % (lineInd + 1, line) if (fromSysCode == 1) and (fromRadVel != 0) and ( fromPM1 == 0) and (fromPM2 == 0): print "Skipping line %s; FK4 with zero PM and nonzero radVel" % ( lineInd + 1, ) continue nTested += 1 fromCoord = coordConv.Coord(fromPos1, fromPos2, fromParallax, fromPM1, fromPM2, fromRadVel) fromPVTCoord = coordConv.PVTCoord(fromCoord, fromCoord, tai, 0.01) fromPVTDir = coordConv.PVT(fromDir, 0, tai) fromCoordSys = getCoordSys(fromSysCode, fromDate, tai) toCoordSys = getCoordSys(toSysCode, toDate, tai) site.refCoA = refCoA site.refCoB = refCoB try: toCoord, toDir, scaleChange = toCoordSys.convertFrom( fromCoordSys, fromCoord, fromDir, site) toPVTDir = coordConv.PVT() toPVTCoord, scaleChange2 = toCoordSys.convertFrom( toPVTDir, fromCoordSys, fromPVTCoord, fromPVTDir, site) except Exception: print "Failed on line %s: %s\n" % (lineInd + 1, line) raise atPole, toPos1, toPos2 = toCoord.getSphPos() toParallax = toCoord.getParallax() atPole, toPM1, toPM2 = toCoord.getPM() toRadVel = toCoord.getRadVel() if toCoord.atInfinity( ): # emulate something the TCC does that I don't think my code can do toRadVel = fromRadVel predList = (toParallax, toPM1, toPM2, toRadVel) refList = (refToParallax, refToPM1, refToPM2, refToRadVel) refToCoord = coordConv.Coord(refToPos1, refToPos2, refToParallax, refToPM1, refToPM2, refToRadVel) try: self.assertEqual(toCoord.atPole(), refAtPole) self.assertEqual(toCoord.atInfinity(), refAtInf) if (fromSysCode > 0) and (toSysCode > 0): atol = 1e-7 elif (fromSysCode < -1) and (toSysCode < -1): atol = 1e-7 else: # the sla_Mappa in the old TCC is giving slightly different answers # thatn the latest slaMappa and that appears to explain a small discrepancy # when converting to/from apparent geocentric coordinates; # the error is most noticeable for the precession/nutation matrix. atol = 1e-3 self.assertLess(toCoord.angularSeparation(refToCoord), atol) self.assertLess( toPVTCoord.getCoord(tai).angularSeparation(refToCoord), atol) maxPxDelta = refToParallax * 1000.0 self.assertAlmostEqual(toParallax, refToParallax, delta=maxPxDelta) self.assertTrue( numpy.allclose(predList[1:], refList[1:], atol=atol)) self.assertAlmostEqual(refToDir, coordConv.wrapNear(toDir, refToDir), places=2) self.assertAlmostEqual(refToDir, coordConv.wrapNear( toPVTDir.getPos(tai), refToDir), places=2) # scale change bears very little resemblance between old and new. # I believe this is a bug in the old TCC, since mean->mean should be 1.0 # and the new code is significantly closer to 1.0 than the old code. # self.assertAlmostEqual(refScaleChange, scaleChange, places=5) self.assertAlmostEqual(scaleChange, scaleChange2, places=5) if (fromSysCode > 0) and (toSysCode > 0): self.assertAlmostEqual(scaleChange, 1.0, places=5) if toCoordSys.getDateType() == coordConv.DateType_TAI: # "to" system uses tai as its time; try various strategies that remove proper motion to the given tai date # test the removePM function (which removes proper motion and radial velocity, but not parallax) zpmFromCoord = fromCoordSys.removePM(fromCoord, tai) if fromCoordSys.getName() != "fk4": # FK4 coordinates have fictitious space motion zpmFromAtPole, zpmFromPM1, zpmFromPM2 = zpmFromCoord.getPM( ) self.assertEqual(fromCoord.atPole(), zpmFromAtPole) self.assertEqual(zpmFromPM1, 0) self.assertEqual(zpmFromPM2, 0) zpmFromRadVel = zpmFromCoord.getRadVel() self.assertEqual(zpmFromRadVel, 0) # zpmFromAtPole, zpmFromPM1, zpmFromPM2 = zpmFromCoord.getPM() # self.assertEqual(fromCoord.atPole(), zpmFromAtPole) # zpmFromRadVel = zpmFromCoord.getRadVel() # self.assertEqual(zpmFromPM1, 0) # self.assertEqual(zpmFromPM2, 0) # self.assertEqual(zpmFromRadVel, 0) zpmToCoord, zpmToDir, zpmScaleChange = toCoordSys.convertFrom( fromCoordSys, zpmFromCoord, fromDir, site) zpmToAtPole, zpmToPos1, zpmToPos2 = zpmToCoord.getSphPos( ) self.assertEqual(atPole, zpmToAtPole) zpmToAtPole, zpmToPM1, zpmToPM2 = zpmToCoord.getPM() self.assertEqual(atPole, zpmToAtPole) zpmToRadVel = zpmToCoord.getRadVel() self.assertAlmostEqual(toDir, zpmToDir, places=2) # why so poor? self.assertAlmostEqual(scaleChange, zpmScaleChange, places=6) self.assertLess(toCoord.angularSeparation(zpmToCoord), 1e-7) self.assertEqual(zpmToPM1, 0) self.assertEqual(zpmToPM2, 0) self.assertEqual(zpmToRadVel, 0) except Exception as e: if ContinueOnError: print print str(e) print "Failed on line %s: %s" % (lineInd + 1, line) print "fromCoordSys=(%s, %s); toCoordSys=(%s, %s)" % ( fromCoordSys.getName(), fromCoordSys.getDate(), toCoordSys.getName(), toCoordSys.getDate()) print "toSphPos= ", toPos1, toPos2 print "refToSphPos=", refToPos1, refToPos2 print "angular sep=", toCoord.angularSeparation( refToCoord) * 3600.0, "arcsec" print "pred parallax, PM and radVel=", predList print "ref parallax, PM and radVel=", refList print "from parallax, PM and radVel=", (fromParallax, fromPM1, fromPM2, fromRadVel) print "from vec pos, vel=", fromCoord.getVecPos( ), fromCoord.getVecPM() print "to vec pos, vel=", toCoord.getVecPos( ), toCoord.getVecPM() if not ContinueOnError: raise numErrors += 1 duration = time.time() - startTime print "Tested %d conversions in %0.2f seconds: %0.0f conversions/second" % \ (nTested, duration, nTested/duration) self.assertEqual(numErrors, 0, "%s errors" % (numErrors, ))