def setUp(self): # Read orbits. self.orbits = Orbits() self.jplDir = os.path.join(getPackageDir('sims_movingObjects'), 'tests/jpl_testdata') self.orbits.readOrbits(os.path.join(self.jplDir, 'S0_n747.des'), skiprows=1) # Read JPL ephems. self.jpl = pd.read_table(os.path.join(self.jplDir, '807_n747.txt'), delim_whitespace=True) # Add times in TAI and UTC, because. t = Time(self.jpl['epoch_mjd'], format='mjd', scale='utc') self.jpl['mjdTAI'] = t.tai.mjd self.jpl['mjdUTC'] = t.utc.mjd self.jpl = self.jpl.to_records(index=False) # Generate interpolation coefficients for the time period in the JPL catalog. self.scratch_dir = tempfile.mkdtemp(dir=ROOT, prefix='TestJPLValues-') self.coeffFile = os.path.join(self.scratch_dir, 'test_coeffs') self.residFile = os.path.join(self.scratch_dir, 'test_resids') self.failedFile = os.path.join(self.scratch_dir, 'test_failed') tStart = self.jpl['mjdTAI'].min() - 0.2 tEnd = self.jpl['mjdTAI'].max() + 0.2 - self.jpl['mjdTAI'].min() self.chebyFits = ChebyFits(self.orbits, tStart, tEnd, ngran=64, skyTolerance=2.5, nDecimal=14, obscode=807) self.chebyFits.calcSegmentLength() self.chebyFits.calcSegments() self.chebyFits.write(self.coeffFile, self.residFile, self.failedFile, append=False) self.coeffKeys = ['objId', 'tStart', 'tEnd', 'ra', 'dec', 'geo_dist', 'vmag', 'elongation'] self.chebyValues = ChebyValues() self.chebyValues.readCoefficients(self.coeffFile)
def testRunThrough(self): # Set up chebyshev fitter. tStart = self.orbits.orbits.epoch.iloc[0] interval = 30 cheb = ChebyFits(self.orbits, tStart, interval, ngran=64, skyTolerance=2.5, nDecimal=10) # Set granularity. Use an value that will be too long, to trigger recursion below. cheb.calcSegmentLength(length=10.0) # Run through segments. cheb.calcSegments() self.assertEqual(len(np.unique(cheb.coeffs['objId'])), len(self.orbits)) # Write outputs. cheb.write(self.coeffFile, self.residFile, self.failedFile) # Test that the segments for each individual object fit together start/end. for k in cheb.coeffs: cheb.coeffs[k] = np.array(cheb.coeffs[k]) for objId in np.unique(cheb.coeffs['objId']): condition = (cheb.coeffs['objId'] == objId) te_prev = tStart for ts, te in zip(cheb.coeffs['tStart'][condition], cheb.coeffs['tEnd'][condition]): # Test that the start of the current interval = the end of the previous interval. self.assertEqual(te_prev, ts) te_prev = te # Test that the end of the last interval is equal to the end of the total interval self.assertEqual(te, tStart + interval)
def setUp(self): self.testdir = os.path.join(getPackageDir('sims_movingObjects'), 'tests/orbits_testdata') self.orbits = Orbits() self.orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsMBA.s3m'), skiprows=1) self.cheb = ChebyFits(self.orbits, 54800, 30, ngran=64, skyTolerance=2.5, nDecimal=10, nCoeff_position=14) self.assertEqual(self.cheb.ngran, 64)
def setUp(self): self.testdir = os.path.join(getPackageDir('sims_movingObjects'), 'tests/orbits_testdata') self.scratch_dir = tempfile.mkdtemp(dir=ROOT, prefix='TestChebyFits-') self.orbits = Orbits() self.orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsMBA.s3m')) self.cheb = ChebyFits(self.orbits, 54800, 30, ngran=64, skyTolerance=2.5, nDecimal=10, nCoeff_position=14) self.assertEqual(self.cheb.ngran, 64)
def setUp(self): self.testdir = 'orbits_testdata' self.orbits = Orbits() self.orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsMBA.s3m'), skiprows=1) self.cheb = ChebyFits(self.orbits, 54800, 54830, ngran=64, skyTolerance=2.5, nDecimal=2, nCoeff_position=14) self.assertEqual(self.cheb.ngran, 64)
def setUp(self): # Read orbits. self.orbits = Orbits() self.orbits.readOrbits('jpl_testdata/S0_n747.des', skiprows=1) # Read JPL ephems. self.jpl = pd.read_table('jpl_testdata/807_n747.txt', delim_whitespace=True) # Add times in TAI and UTC, because. t = Time(self.jpl['epoch_mjd'], format='mjd', scale='utc') self.jpl['mjdTAI'] = t.tai.mjd self.jpl['mjdUTC'] = t.utc.mjd self.jpl = self.jpl.to_records(index=False) # Generate interpolation coefficients for the time period in the JPL catalog. self.coeffFile = 'test_coeffs' self.residFile = 'test_resids' self.failedFile = 'test_failed' tStart = self.jpl['mjdTAI'].min() - 0.2 tEnd = np.max([self.jpl['mjdTAI'].max() + 0.2, tStart + 1]) self.chebyFits = ChebyFits(self.orbits, tStart, tEnd, ngran=64, skyTolerance=2.5, nDecimal=14, nCoeff_position=14, obscode=807) self.chebyFits.calcSegmentLength() self.chebyFits.calcSegments() self.chebyFits.write(self.coeffFile, self.residFile, self.failedFile, append=False) self.coeffKeys = ['objId', 'tStart', 'tEnd', 'ra', 'dec', 'delta', 'vmag', 'elongation'] self.chebyValues = ChebyValues() self.chebyValues.readCoefficients(self.coeffFile)
def setUp(self): self.testdatadir = os.path.join(getPackageDir('sims_movingObjects'), 'tests/orbits_testdata') self.coeffFile = 'test_coeffs' self.residFile = 'test_resids' self.failedFile = 'test_failed' self.orbits = Orbits() self.orbits.readOrbits(os.path.join(self.testdatadir, 'test_orbitsNEO.s3m'), skiprows=1) self.pyephems = PyOrbEphemerides(os.path.join(os.getenv('OORB_DATA'), 'DE405.dat')) self.pyephems.setOrbits(self.orbits) self.tStart = self.orbits.orbits.epoch.iloc[0] self.interval = 15 self.nCoeffs = 14 self.nDecimal = 13 self.chebyFits = ChebyFits(self.orbits, self.tStart, self.interval, ngran=64, skyTolerance=2.5, nDecimal=self.nDecimal, nCoeff_position=self.nCoeffs, obscode=807, timeScale='TAI') self.setLength = 0.5 self.chebyFits.calcSegmentLength(length=self.setLength) self.chebyFits.calcSegments() self.chebyFits.write(self.coeffFile, self.residFile, self.failedFile, append=False) self.coeffKeys = ['objId', 'tStart', 'tEnd', 'ra', 'dec', 'delta', 'vmag', 'elongation']
def testSetSegmentLength(self): # Expect MBAs with standard ngran and tolerance to have length ~2.0 days. self.cheb.calcSegmentLength() self.assertAlmostEqual(self.cheb.length, 2.0) # Test that we can set it to other values which fit into the 30 day window. self.cheb.calcSegmentLength(length=1.5) self.assertEqual(self.cheb.length, 1.5) # Test that we if we try to set it to a value which does not fit into the 30 day window, # that the actual value used is different - and smaller. self.cheb.calcSegmentLength(length=1.9) self.assertTrue(self.cheb.length < 1.9) # Test that we get a warning about the residuals if we try to set the length to be too long. with warnings.catch_warnings(record=True) as w: self.cheb.calcSegmentLength(length=5.0) self.assertTrue(len(w), 1) # Now check granularity works for other orbit types (which would have other standard lengths). # Check for multiple orbit types. for orbitFile in (['test_orbitsMBA.s3m', 'test_orbitsOuter.s3m', 'test_orbitsNEO.s3m']): self.orbits.readOrbits(os.path.join(self.testdir, orbitFile), skiprows=1) tStart = self.orbits.orbits['epoch'].iloc[0] cheb = ChebyFits(self.orbits, tStart, tStart + 30, ngran=64, nDecimal=2) # And that we should converge for a variety of other tolerances. for skyTolerance in (2.5, 5.0, 10.0, 100.0, 1000.0, 20000.0): cheb.skyTolerance = skyTolerance cheb.calcSegmentLength() pos_resid, ratio = cheb._testResiduals(cheb.length) self.assertTrue(pos_resid < skyTolerance) self.assertEqual((cheb.length * 100) % 1, 0) #print 'final', orbitFile, skyTolerance, pos_resid, cheb.length, ratio # And check for challenging 'impactors'. for orbitFile in (['test_orbitsImpactors.s3m']): self.orbits.readOrbits(os.path.join(self.testdir, orbitFile), skiprows=1) tStart = self.orbits.orbits['epoch'].iloc[0] cheb = ChebyFits(self.orbits, tStart, tStart + 30, ngran=64, nDecimal=10) # And that we should converge for a variety of other tolerances. for skyTolerance in (2.5, 10.0, 100.0): cheb.skyTolerance = skyTolerance cheb.calcSegmentLength() pos_resid, ratio = cheb._testResiduals(cheb.length) self.assertTrue(pos_resid < skyTolerance)
def setUp(self): self.testdatadir = 'orbits_testdata' self.coeffFile = 'test_coeffs' self.residFile = 'test_resids' self.failedFile = 'test_failed' self.orbits = Orbits() self.orbits.readOrbits(os.path.join(self.testdatadir, 'test_orbitsNEO.s3m'), skiprows=1) self.pyephems = PyOrbEphemerides(os.path.join(os.getenv('OORB_DATA'), 'DE405.dat')) self.pyephems.setOrbits(self.orbits) self.tStart = self.orbits.orbits.epoch.iloc[0] self.interval = 15 self.nCoeffs = 14 self.chebyFits = ChebyFits(self.orbits, self.tStart, self.tStart+self.interval, ngran=64, skyTolerance=2.5, nDecimal=2, nCoeff_position=self.nCoeffs, obscode=807) self.setLength = 0.5 self.chebyFits.calcSegmentLength(length=self.setLength) self.chebyFits.calcSegments() self.chebyFits.write(self.coeffFile, self.residFile, self.failedFile, append=False) self.coeffKeys = ['objId', 'tStart', 'tEnd', 'ra', 'dec', 'delta', 'vmag', 'elongation']
def testRunThrough(self): # Set up chebyshev fitter. tStart = self.orbits.orbits.epoch.iloc[0] interval = 30 cheb = ChebyFits(self.orbits, tStart, tStart + interval, ngran=64, skyTolerance=2.5, nDecimal=2) # Set granularity. Use an value that will be too long, to trigger recursion below. cheb.calcSegmentLength(length=10.0) # Run through segments. cheb.calcSegments() self.assertEqual(len(np.unique(cheb.coeffs['objId'])), len(self.orbits)) # Write outputs. cheb.write(self.coeffFile, self.residFile, self.failedFile) # Test that the segments for each individual object fit together start/end. for k in cheb.coeffs: cheb.coeffs[k] = np.array(cheb.coeffs[k]) for objId in np.unique(cheb.coeffs['objId']): condition = (cheb.coeffs['objId'] == objId) te_prev = tStart for ts, te in zip(cheb.coeffs['tStart'][condition], cheb.coeffs['tEnd'][condition]): # Test that the start of the current interval = the end of the previous interval. self.assertEqual(te_prev, ts) te_prev = te # Test that the end of the last interval is equal to the end of the total interval self.assertEqual(te, tStart + interval)
# Set output file names. timestring = '%.2f_%.2f' % (t, t + tSpan) coeffFile = '__'.join([fileRoot, 'coeffs', timestring, fileSuffix]).rstrip('_') residFile = '__'.join([fileRoot, 'resids', timestring, fileSuffix]).rstrip('_') failedFile = '__'.join([fileRoot, 'failed', timestring, fileSuffix]).rstrip('_') # Cycle through nObj at a time, to fit and write data files. append = False for n in range(0, len(orbits), nObj): subset = orbits.orbits[n:n + nObj] subsetOrbits = Orbits() subsetOrbits.setOrbits(subset) # Fit chebyshev polynomials. print("Working on objects %d to %d in timespan %f to %f" % (n, n + nObj, t, t + tSpan), file=log) cheb = ChebyFits(subsetOrbits, t, tSpan, skyTolerance=args.skyTol, nDecimal=args.nDecimal, nCoeff_position=args.nCoeff, ngran=64, nCoeff_vmag=9, nCoeff_delta=5, nCoeff_elongation=6, obscode=807, timeScale='TAI') try: cheb.calcSegmentLength(length=args.length) except ValueError as ve: cheb.length = None for objId in subsetOrbits.orbits['objId'].as_matrix(): cheb.failed.append((objId, tStart, tEnd)) warnings.showwarning("Objid %s to %s (n %d to %d), segment %f to %f - error: %s" % (subsetOrbits.orbits.objId.iloc[0], subsetOrbits.orbits.objId.iloc[-1], n, n + nObj, t, t + tSpan, ve.message), UserWarning, "generateCoefficients.py", 132, file=log) # Put this in a separate try/except block, because errors here can mask errors in the previous
class TestChebyValues(unittest.TestCase): def setUp(self): self.testdatadir = 'orbits_testdata' self.coeffFile = 'test_coeffs' self.residFile = 'test_resids' self.failedFile = 'test_failed' self.orbits = Orbits() self.orbits.readOrbits(os.path.join(self.testdatadir, 'test_orbitsNEO.s3m'), skiprows=1) self.pyephems = PyOrbEphemerides(os.path.join(os.getenv('OORB_DATA'), 'DE405.dat')) self.pyephems.setOrbits(self.orbits) self.tStart = self.orbits.orbits.epoch.iloc[0] self.interval = 15 self.nCoeffs = 14 self.chebyFits = ChebyFits(self.orbits, self.tStart, self.tStart+self.interval, ngran=64, skyTolerance=2.5, nDecimal=2, nCoeff_position=self.nCoeffs, obscode=807) self.setLength = 0.5 self.chebyFits.calcSegmentLength(length=self.setLength) self.chebyFits.calcSegments() self.chebyFits.write(self.coeffFile, self.residFile, self.failedFile, append=False) self.coeffKeys = ['objId', 'tStart', 'tEnd', 'ra', 'dec', 'delta', 'vmag', 'elongation'] def tearDown(self): del self.orbits del self.chebyFits os.remove(self.coeffFile) os.remove(self.residFile) if os.path.isfile(self.failedFile): os.remove(self.failedFile) def testSetCoeff(self): # Test setting coefficients directly from chebyFits outputs. chebyValues = ChebyValues() chebyValues.setCoefficients(self.chebyFits) for k in self.coeffKeys: self.assertTrue(k in chebyValues.coeffs) self.assertTrue(isinstance(chebyValues.coeffs[k], np.ndarray)) self.assertEqual(len(np.unique(chebyValues.coeffs['objId'])), len(self.orbits)) # This will only be true for carefully selected length/orbit type, where subdivision did not occur. # For the test MBAs, a len=1day will work. For the test NEOs, a len=0.25 day will work (with 2.5mas skyTol). #self.assertEqual(len(chebyValues.coeffs['tStart']), (self.interval / self.setLength) * len(self.orbits)) self.assertEqual(len(chebyValues.coeffs['ra'][0]), self.nCoeffs) self.assertTrue('meanRA' in chebyValues.coeffs) self.assertTrue('meanDec' in chebyValues.coeffs) def testReadCoeffs(self): # Test reading the coefficients from disk. chebyValues = ChebyValues() chebyValues.readCoefficients(self.coeffFile) chebyValues2 = ChebyValues() chebyValues2.setCoefficients(self.chebyFits) for k in chebyValues.coeffs: if k == 'objId': # Can't test strings with np.test.assert_almost_equal. np.testing.assert_equal(chebyValues.coeffs[k], chebyValues2.coeffs[k]) else: # All of these will only be accurate to 2 less decimal places than they are # print out with in chebyFits. Since vmag, delta and elongation only use 7 # decimal places, this means we can test to 5 decimal places for those. np.testing.assert_almost_equal(chebyValues.coeffs[k], chebyValues2.coeffs[k], decimal=5) def testGetEphemerides(self): # Test that getEphemerides works and is accurate. chebyValues = ChebyValues() #chebyValues.setCoefficients(self.chebyFits) chebyValues.readCoefficients(self.coeffFile) time = self.tStart + self.interval / 2.0 # Test for all objects. ephemerides = chebyValues.getEphemerides(time) pyephemerides = self.pyephems.generateEphemerides(time, obscode=807, timeScale='TAI', byObject=False) # RA and Dec should agree to 2.5mas (skyTolerance above) pos_residuals = np.sqrt((ephemerides['ra'] - pyephemerides['ra'][0]) ** 2 + (ephemerides['dec'] - pyephemerides['dec'][0]) ** 2) pos_residuals *= 3600.0 * 1000.0 self.assertTrue(np.max(pos_residuals) <= 2.5) # Let's just look at the max residuals in all quantities. for k in ('ra', 'dec', 'dradt', 'ddecdt', 'delta'): resids = np.abs(ephemerides[k] - pyephemerides[k][0]) print 'max diff ', k, np.max(resids) resids = np.abs(ephemerides['elongation'] - pyephemerides['solarelon'][0]) print 'max diff elongation', np.max(resids) resids = np.abs(ephemerides['vmag'] - pyephemerides['magV'][0]) print 'max diff vmag', np.max(resids) # Test this for a subset of the objects. objIds = self.orbits.orbits.objId.head(3).as_matrix() ephemerides = chebyValues.getEphemerides(time, objIds) self.assertEqual(len(ephemerides['ra']), 3)
class TestJPLValues(unittest.TestCase): # Test the interpolation-generated RA/Dec values against JPL generated RA/Dec values. # The resulting errors should be similar to the errors reported from testEphemerides when testing against JPL values. def setUp(self): # Read orbits. self.orbits = Orbits() self.orbits.readOrbits('jpl_testdata/S0_n747.des', skiprows=1) # Read JPL ephems. self.jpl = pd.read_table('jpl_testdata/807_n747.txt', delim_whitespace=True) # Add times in TAI and UTC, because. t = Time(self.jpl['epoch_mjd'], format='mjd', scale='utc') self.jpl['mjdTAI'] = t.tai.mjd self.jpl['mjdUTC'] = t.utc.mjd self.jpl = self.jpl.to_records(index=False) # Generate interpolation coefficients for the time period in the JPL catalog. self.coeffFile = 'test_coeffs' self.residFile = 'test_resids' self.failedFile = 'test_failed' tStart = self.jpl['mjdTAI'].min() - 0.2 tEnd = np.max([self.jpl['mjdTAI'].max() + 0.2, tStart + 1]) self.chebyFits = ChebyFits(self.orbits, tStart, tEnd, ngran=64, skyTolerance=2.5, nDecimal=14, nCoeff_position=14, obscode=807) self.chebyFits.calcSegmentLength() self.chebyFits.calcSegments() self.chebyFits.write(self.coeffFile, self.residFile, self.failedFile, append=False) self.coeffKeys = ['objId', 'tStart', 'tEnd', 'ra', 'dec', 'delta', 'vmag', 'elongation'] self.chebyValues = ChebyValues() self.chebyValues.readCoefficients(self.coeffFile) def tearDown(self): del self.orbits del self.jpl os.remove(self.coeffFile) os.remove(self.residFile) if os.path.isfile(self.failedFile): os.remove(self.failedFile) def testRADec(self): # We won't compare Vmag, because this also needs information on trailing losses. times = np.unique(self.jpl['mjdTAI']) deltaObjId = np.zeros(len(times), bool) deltaRA = np.zeros(len(times), float) deltaDec = np.zeros(len(times), float) for i, t in enumerate(times): # Find the JPL objIds visible at this time. j = self.jpl[np.where(self.jpl['mjdTAI'] == t)] ephs = self.chebyValues.getEphemerides(t, j['objId']) ephorder = np.argsort(ephs['objId']) dRA = np.abs(ephs['ra'][ephorder] - j['ra_deg']) * 3600.0 * 1000.0 dDec = np.abs(ephs['dec'][ephorder] - j['dec_deg']) * 3600.0 * 1000.0 deltaRA[i] = dRA.max() deltaDec[i] = dDec.max() # Should be (given OOrb direct prediction): # Much of the time we're closer than 1mas, but there are a few which hit higher values. # This is consistent with the errors/values reported by oorb directly in testEphemerides. self.assertTrue(np.max(deltaRA) < 18) self.assertTrue(np.max(deltaDec) < 6) self.assertTrue(np.std(deltaRA) < 2) self.assertTrue(np.std(deltaDec) < 1) print 'max JPL errors', deltaRA.max(), deltaDec.max() print 'std of JPL errors', np.std(deltaRA), np.std(deltaDec)
class TestChebyValues(unittest.TestCase): def setUp(self): self.testdatadir = os.path.join(getPackageDir('sims_movingObjects'), 'tests/orbits_testdata') self.scratch_dir = tempfile.mkdtemp(dir=ROOT, prefix='TestChebyValues-') self.coeffFile = os.path.join(self.scratch_dir, 'test_coeffs') self.residFile = os.path.join(self.scratch_dir, 'test_resids') self.failedFile = os.path.join(self.scratch_dir, 'test_failed') self.orbits = Orbits() self.orbits.readOrbits(os.path.join(self.testdatadir, 'test_orbitsNEO.s3m'), skiprows=1) self.pyephems = PyOrbEphemerides(os.path.join(os.getenv('OORB_DATA'), 'DE405.dat')) self.pyephems.setOrbits(self.orbits) self.tStart = self.orbits.orbits.epoch.iloc[0] self.interval = 30 self.nCoeffs = 14 self.nDecimal = 13 self.chebyFits = ChebyFits(self.orbits, self.tStart, self.interval, ngran=64, skyTolerance=2.5, nDecimal=self.nDecimal, nCoeff_position=self.nCoeffs, obscode=807, timeScale='TAI') self.setLength = 0.5 self.chebyFits.calcSegmentLength(length=self.setLength) self.chebyFits.calcSegments() self.chebyFits.write(self.coeffFile, self.residFile, self.failedFile, append=False) self.coeffKeys = ['objId', 'tStart', 'tEnd', 'ra', 'dec', 'geo_dist', 'vmag', 'elongation'] def tearDown(self): del self.orbits del self.chebyFits if os.path.exists(self.scratch_dir): shutil.rmtree(self.scratch_dir) def testSetCoeff(self): # Test setting coefficients directly from chebyFits outputs. chebyValues = ChebyValues() chebyValues.setCoefficients(self.chebyFits) for k in self.coeffKeys: self.assertTrue(k in chebyValues.coeffs) self.assertTrue(isinstance(chebyValues.coeffs[k], np.ndarray)) self.assertEqual(len(np.unique(chebyValues.coeffs['objId'])), len(self.orbits)) # This will only be true for carefully selected length/orbit type, where subdivision did not occur. # For the test MBAs, a len=1day will work. # For the test NEOs, a len=0.25 day will work (with 2.5mas skyTol). # self.assertEqual(len(chebyValues.coeffs['tStart']), # (self.interval / self.setLength) * len(self.orbits)) self.assertEqual(len(chebyValues.coeffs['ra'][0]), self.nCoeffs) self.assertTrue('meanRA' in chebyValues.coeffs) self.assertTrue('meanDec' in chebyValues.coeffs) def testReadCoeffs(self): # Test reading the coefficients from disk. chebyValues = ChebyValues() chebyValues.readCoefficients(self.coeffFile) chebyValues2 = ChebyValues() chebyValues2.setCoefficients(self.chebyFits) for k in chebyValues.coeffs: if k == 'objId': # Can't test strings with np.test.assert_almost_equal. np.testing.assert_equal(chebyValues.coeffs[k], chebyValues2.coeffs[k]) else: # All of these will only be accurate to 2 less decimal places than they are # print out with in chebyFits. Since vmag, delta and elongation only use 7 # decimal places, this means we can test to 5 decimal places for those. np.testing.assert_allclose(chebyValues.coeffs[k], chebyValues2.coeffs[k], rtol=0, atol=1e-5) def testGetEphemerides(self): # Test that getEphemerides works and is accurate. chebyValues = ChebyValues() chebyValues.readCoefficients(self.coeffFile) # Multiple times, all objects, all within interval. tstep = self.interval/10.0 time = np.arange(self.tStart, self.tStart + self.interval, tstep) # Test for a single time, but all the objects. ephemerides = chebyValues.getEphemerides(time) pyephemerides = self.pyephems.generateEphemerides(time, obscode=807, timeScale='TAI', byObject=True) # RA and Dec should agree to 2.5mas (skyTolerance above) pos_residuals = np.sqrt((ephemerides['ra'] - pyephemerides['ra']) ** 2 + ((ephemerides['dec'] - pyephemerides['dec']) * np.cos(np.radians(ephemerides['dec']))) ** 2) pos_residuals *= 3600.0 * 1000.0 # Let's just look at the max residuals in all quantities. for k in ('ra', 'dec', 'dradt', 'ddecdt', 'geo_dist'): resids = np.abs(ephemerides[k] - pyephemerides[k]) if k != 'geo_dist': resids *= 3600.0 * 1000.0 print('max diff', k, np.max(resids)) resids = np.abs(ephemerides['elongation'] - pyephemerides['solarelon']) print('max diff elongation', np.max(resids)) resids = np.abs(ephemerides['vmag'] - pyephemerides['magV']) print('max diff vmag', np.max(resids)) self.assertLessEqual(np.max(pos_residuals), 2.5) # Test for single time, but for a subset of the objects. objIds = self.orbits.orbits.objId.head(3).as_matrix() ephemerides = chebyValues.getEphemerides(time, objIds) self.assertEqual(len(ephemerides['ra']), 3) # Test for time outside of segment range. ephemerides = chebyValues.getEphemerides(self.tStart + self.interval * 2, objIds, extrapolate=False) self.assertTrue(np.isnan(ephemerides['ra'][0]), msg='Expected Nan for out of range ephemeris, got %.2e' %(ephemerides['ra'][0]))
class TestChebyFits(unittest.TestCase): def setUp(self): self.testdir = os.path.join(getPackageDir('sims_movingObjects'), 'tests/orbits_testdata') self.orbits = Orbits() self.orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsMBA.s3m'), skiprows=1) self.cheb = ChebyFits(self.orbits, 54800, 30, ngran=64, skyTolerance=2.5, nDecimal=10, nCoeff_position=14) self.assertEqual(self.cheb.ngran, 64) def tearDown(self): del self.orbits del self.cheb @classmethod def tearDownClass(cls): os.remove('tmpCoeff') os.remove('tmpResids') if os.path.isfile('tmpFailed'): os.remove('tmpFailed') def testPrecomputeMultipliers(self): # Precompute multipliers is done as an automatic step in __init__. # After setting up self.cheb, these multipliers should all exist. for key in self.cheb.nCoeff: self.assertTrue(key in self.cheb.multipliers) def testSetSegmentLength(self): # Expect MBAs with standard ngran and tolerance to have length ~2.0 days. self.cheb.calcSegmentLength() self.assertAlmostEqual(self.cheb.length, 2.0) # Test that we can set it to other values which fit into the 30 day window. self.cheb.calcSegmentLength(length=1.5) self.assertEqual(self.cheb.length, 1.5) # Test that we if we try to set it to a value which does not fit into the 30 day window, # that the actual value used is different - and smaller. self.cheb.calcSegmentLength(length=1.9) self.assertTrue(self.cheb.length < 1.9) # Test that we get a warning about the residuals if we try to set the length to be too long. with warnings.catch_warnings(record=True) as w: self.cheb.calcSegmentLength(length=5.0) self.assertTrue(len(w), 1) # Now check granularity works for other orbit types (which would have other standard lengths). # Check for multiple orbit types. for orbitFile in ([ 'test_orbitsMBA.s3m', 'test_orbitsOuter.s3m', 'test_orbitsNEO.s3m' ]): self.orbits.readOrbits(os.path.join(self.testdir, orbitFile), skiprows=1) tStart = self.orbits.orbits['epoch'].iloc[0] cheb = ChebyFits(self.orbits, tStart, 30, ngran=64, nDecimal=2) # And that we should converge for a variety of other tolerances. for skyTolerance in (2.5, 5.0, 10.0, 100.0, 1000.0, 20000.0): cheb.skyTolerance = skyTolerance cheb.calcSegmentLength() pos_resid, ratio = cheb._testResiduals(cheb.length) self.assertTrue(pos_resid < skyTolerance) self.assertEqual((cheb.length * 100) % 1, 0) # print('final', orbitFile, skyTolerance, pos_resid, cheb.length, ratio) # And check for challenging 'impactors'. for orbitFile in (['test_orbitsImpactors.s3m']): self.orbits.readOrbits(os.path.join(self.testdir, orbitFile), skiprows=1) tStart = self.orbits.orbits['epoch'].iloc[0] cheb = ChebyFits(self.orbits, tStart, 30, ngran=64, nDecimal=10) # And that we should converge for a variety of other tolerances. for skyTolerance in (2.5, 10.0, 100.0): cheb.skyTolerance = skyTolerance cheb.calcSegmentLength() pos_resid, ratio = cheb._testResiduals(cheb.length) self.assertTrue(pos_resid < skyTolerance) # print('final', orbitFile, skyTolerance, pos_resid, cheb.length, ratio) def testSegments(self): # Test that we can create segments. self.cheb.calcSegmentLength(length=1.0) times = self.cheb.makeAllTimes() self.cheb.generateEphemerides(times, verbose=False) self.cheb.calcSegments() # We expect calculated coefficients to have the following keys: coeffKeys = [ 'objId', 'tStart', 'tEnd', 'ra', 'dec', 'delta', 'vmag', 'elongation' ] for k in coeffKeys: self.assertTrue(k in self.cheb.coeffs.keys()) # And in this case, we had a 30 day timespan with 1 day segments # (one day segments should be more than enough to meet 2.5mas tolerance, so not subdivided) self.assertEqual(len(self.cheb.coeffs['tStart']), 30 * len(self.orbits)) # And we used 14 coefficients for ra and dec. self.assertEqual(len(self.cheb.coeffs['ra'][0]), 14) self.assertEqual(len(self.cheb.coeffs['dec'][0]), 14) def testWrite(self): # Test that we can write the output to files. self.cheb.calcSegmentLength() self.cheb.generateEphemerides(self.cheb.makeAllTimes()) self.cheb.calcSegments() self.cheb.write('tmpCoeff', 'tmpResids', 'tmpFailed') self.assertTrue(os.path.isfile('tmpCoeff')) self.assertTrue(os.path.isfile('tmpResids'))
class TestJPLValues(unittest.TestCase): # Test the interpolation-generated RA/Dec values against JPL generated RA/Dec values. # The resulting errors should be similar to the errors reported # from testEphemerides when testing against JPL values. def setUp(self): # Read orbits. self.orbits = Orbits() self.jplDir = os.path.join(getPackageDir('sims_movingObjects'), 'tests/jpl_testdata') self.orbits.readOrbits(os.path.join(self.jplDir, 'S0_n747.des'), skiprows=1) # Read JPL ephems. self.jpl = pd.read_table(os.path.join(self.jplDir, '807_n747.txt'), delim_whitespace=True) # Add times in TAI and UTC, because. t = Time(self.jpl['epoch_mjd'], format='mjd', scale='utc') self.jpl['mjdTAI'] = t.tai.mjd self.jpl['mjdUTC'] = t.utc.mjd self.jpl = self.jpl.to_records(index=False) # Generate interpolation coefficients for the time period in the JPL catalog. self.scratch_dir = tempfile.mkdtemp(dir=ROOT, prefix='TestJPLValues-') self.coeffFile = os.path.join(self.scratch_dir, 'test_coeffs') self.residFile = os.path.join(self.scratch_dir, 'test_resids') self.failedFile = os.path.join(self.scratch_dir, 'test_failed') tStart = self.jpl['mjdTAI'].min() - 0.2 tEnd = self.jpl['mjdTAI'].max() + 0.2 - self.jpl['mjdTAI'].min() self.chebyFits = ChebyFits(self.orbits, tStart, tEnd, ngran=64, skyTolerance=2.5, nDecimal=14, obscode=807) self.chebyFits.calcSegmentLength() self.chebyFits.calcSegments() self.chebyFits.write(self.coeffFile, self.residFile, self.failedFile, append=False) self.coeffKeys = ['objId', 'tStart', 'tEnd', 'ra', 'dec', 'geo_dist', 'vmag', 'elongation'] self.chebyValues = ChebyValues() self.chebyValues.readCoefficients(self.coeffFile) def tearDown(self): del self.orbits del self.jpl if os.path.exists(self.scratch_dir): shutil.rmtree(self.scratch_dir) def testRADec(self): # We won't compare Vmag, because this also needs information on trailing losses. times = np.unique(self.jpl['mjdTAI']) deltaRA = np.zeros(len(times), float) deltaDec = np.zeros(len(times), float) for i, t in enumerate(times): # Find the JPL objIds visible at this time. j = self.jpl[np.where(self.jpl['mjdTAI'] == t)] ephs = self.chebyValues.getEphemerides(t, j['objId']) ephorder = np.argsort(ephs['objId']) # Sometimes I've had to reorder both, sometimes just the ephs. ?? jorder = np.argsort(j['objId']) jorder = np.arange(0, len(jorder)) dRA = np.abs(ephs['ra'][ephorder][:,0] - j['ra_deg'][jorder]) * 3600.0 * 1000.0 dDec = np.abs(ephs['dec'][ephorder][:,0] - j['dec_deg'][jorder]) * 3600.0 * 1000.0 deltaRA[i] = dRA.max() deltaDec[i] = dDec.max() if deltaRA[i] > 18: print(j['objId'], ephs['objId']) print(j['ra_deg']) print(ephs['ra']) print(j['dec_deg']) print(ephs['dec']) # Should be (given OOrb direct prediction): # Much of the time we're closer than 1mas, but there are a few which hit higher values. # This is consistent with the errors/values reported by oorb directly in testEphemerides. print('max JPL errors', deltaRA.max(), deltaDec.max()) print('std of JPL errors', np.std(deltaRA), np.std(deltaDec)) self.assertLess(np.max(deltaRA), 25) self.assertLess(np.max(deltaDec), 10) self.assertLess(np.std(deltaRA), 3) self.assertLess(np.std(deltaDec), 2)
def testSetSegmentLength(self): # Expect MBAs with standard ngran and tolerance to have length ~2.0 days. self.cheb.calcSegmentLength() self.assertAlmostEqual(self.cheb.length, 2.0) # Test that we can set it to other values which fit into the 30 day window. self.cheb.calcSegmentLength(length=1.5) self.assertEqual(self.cheb.length, 1.5) # Test that we if we try to set it to a value which does not fit into the 30 day window, # that the actual value used is different - and smaller. self.cheb.calcSegmentLength(length=1.9) self.assertTrue(self.cheb.length < 1.9) # Test that we get a warning about the residuals if we try to set the length to be too long. with warnings.catch_warnings(record=True) as w: self.cheb.calcSegmentLength(length=5.0) self.assertTrue(len(w), 1) # Now check granularity works for other orbit types (which would have other standard lengths). # Check for multiple orbit types. for orbitFile in ([ 'test_orbitsMBA.s3m', 'test_orbitsOuter.s3m', 'test_orbitsNEO.s3m' ]): self.orbits.readOrbits(os.path.join(self.testdir, orbitFile), skiprows=1) tStart = self.orbits.orbits['epoch'].iloc[0] cheb = ChebyFits(self.orbits, tStart, 30, ngran=64, nDecimal=2) # And that we should converge for a variety of other tolerances. for skyTolerance in (2.5, 5.0, 10.0, 100.0, 1000.0, 20000.0): cheb.skyTolerance = skyTolerance cheb.calcSegmentLength() pos_resid, ratio = cheb._testResiduals(cheb.length) self.assertTrue(pos_resid < skyTolerance) self.assertEqual((cheb.length * 100) % 1, 0) # print('final', orbitFile, skyTolerance, pos_resid, cheb.length, ratio) # And check for challenging 'impactors'. for orbitFile in (['test_orbitsImpactors.s3m']): self.orbits.readOrbits(os.path.join(self.testdir, orbitFile), skiprows=1) tStart = self.orbits.orbits['epoch'].iloc[0] cheb = ChebyFits(self.orbits, tStart, 30, ngran=64, nDecimal=10) # And that we should converge for a variety of other tolerances. for skyTolerance in (2.5, 10.0, 100.0): cheb.skyTolerance = skyTolerance cheb.calcSegmentLength() pos_resid, ratio = cheb._testResiduals(cheb.length) self.assertTrue(pos_resid < skyTolerance)
class TestChebyFits(unittest.TestCase): def setUp(self): self.testdir = 'orbits_testdata' self.orbits = Orbits() self.orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsMBA.s3m'), skiprows=1) self.cheb = ChebyFits(self.orbits, 54800, 54830, ngran=64, skyTolerance=2.5, nDecimal=2, nCoeff_position=14) self.assertEqual(self.cheb.ngran, 64) def tearDown(self): del self.orbits del self.cheb @classmethod def tearDownClass(cls): os.remove('tmpCoeff') os.remove('tmpResids') if os.path.isfile('tmpFailed'): os.remove('tmpFailed') def testPrecomputeMultipliers(self): # Precompute multipliers is done as an automatic step in __init__. # After setting up self.cheb, these multipliers should all exist. for key in self.cheb.nCoeff: self.assertTrue(key in self.cheb.multipliers) def testSetSegmentLength(self): # Expect MBAs with standard ngran and tolerance to have length ~2.0 days. self.cheb.calcSegmentLength() self.assertAlmostEqual(self.cheb.length, 2.0) # Test that we can set it to other values which fit into the 30 day window. self.cheb.calcSegmentLength(length=1.5) self.assertEqual(self.cheb.length, 1.5) # Test that we if we try to set it to a value which does not fit into the 30 day window, # that the actual value used is different - and smaller. self.cheb.calcSegmentLength(length=1.9) self.assertTrue(self.cheb.length < 1.9) # Test that we get a warning about the residuals if we try to set the length to be too long. with warnings.catch_warnings(record=True) as w: self.cheb.calcSegmentLength(length=5.0) self.assertTrue(len(w), 1) # Now check granularity works for other orbit types (which would have other standard lengths). # Check for multiple orbit types. for orbitFile in (['test_orbitsMBA.s3m', 'test_orbitsOuter.s3m', 'test_orbitsNEO.s3m']): self.orbits.readOrbits(os.path.join(self.testdir, orbitFile), skiprows=1) tStart = self.orbits.orbits['epoch'].iloc[0] cheb = ChebyFits(self.orbits, tStart, tStart + 30, ngran=64, nDecimal=2) # And that we should converge for a variety of other tolerances. for skyTolerance in (2.5, 5.0, 10.0, 100.0, 1000.0, 20000.0): cheb.skyTolerance = skyTolerance cheb.calcSegmentLength() pos_resid, ratio = cheb._testResiduals(cheb.length) self.assertTrue(pos_resid < skyTolerance) self.assertEqual((cheb.length * 100) % 1, 0) #print 'final', orbitFile, skyTolerance, pos_resid, cheb.length, ratio # And check for challenging 'impactors'. for orbitFile in (['test_orbitsImpactors.s3m']): self.orbits.readOrbits(os.path.join(self.testdir, orbitFile), skiprows=1) tStart = self.orbits.orbits['epoch'].iloc[0] cheb = ChebyFits(self.orbits, tStart, tStart + 30, ngran=64, nDecimal=10) # And that we should converge for a variety of other tolerances. for skyTolerance in (2.5, 10.0, 100.0): cheb.skyTolerance = skyTolerance cheb.calcSegmentLength() pos_resid, ratio = cheb._testResiduals(cheb.length) self.assertTrue(pos_resid < skyTolerance) #print 'final', orbitFile, skyTolerance, pos_resid, cheb.length, ratio def testSegments(self): # Test that we can create segments. self.cheb.calcSegmentLength(length=1.0) times = self.cheb.getAllTimes() self.cheb.generateEphemerides(times, verbose=False) self.cheb.calcSegments() # We expect calculated coefficients to have the following keys: coeffKeys = ['objId', 'tStart', 'tEnd', 'ra', 'dec', 'delta', 'vmag', 'elongation'] for k in coeffKeys: self.assertTrue(k in self.cheb.coeffs.keys()) # And in this case, we had a 30 day timespan with 1 day segments # (one day segments should be more than enough to meet 2.5mas tolerance, so not subdivided) self.assertEqual(len(self.cheb.coeffs['tStart']), 30*len(self.orbits)) # And we used 14 coefficients for ra and dec. self.assertEqual(len(self.cheb.coeffs['ra'][0]), 14) self.assertEqual(len(self.cheb.coeffs['dec'][0]), 14) def testWrite(self): # Test that we can write the output to files. self.cheb.calcSegmentLength() self.cheb.generateEphemerides(self.cheb.getAllTimes()) self.cheb.calcSegments() self.cheb.write('tmpCoeff', 'tmpResids', 'tmpFailed') self.assertTrue(os.path.isfile('tmpCoeff')) self.assertTrue(os.path.isfile('tmpResids'))