def testOffsetDataframe(self): """ Test that we can slice and iterate through an orbits dataframe that has already been sub-selected from another datafram """ orbits0 = Orbits() orbits0.readOrbits(os.path.join(self.testdir, 'test_orbitsNEO.s3m'), skiprows=1) orbitsSub = Orbits() orbitsSub.setOrbits(orbits0.orbits.query('index>1')) self.assertEqual(len(orbitsSub), 6) orbit_slice = orbitsSub[2:6] self.assertEqual(orbit_slice[0], orbitsSub[2]) self.assertEqual(orbit_slice[1], orbitsSub[3]) self.assertEqual(orbit_slice[2], orbitsSub[4]) self.assertEqual(orbit_slice[3], orbitsSub[5]) self.assertEqual(len(orbit_slice), 4) orbit_slice = orbitsSub[1:5:2] self.assertEqual(orbit_slice[0], orbitsSub[1]) self.assertEqual(orbit_slice[1], orbitsSub[3]) self.assertEqual(len(orbit_slice), 2) for ii, oo in enumerate(orbitsSub): self.assertEqual(oo, orbits0[ii+2])
def testOffsetDataframe(self): """ Test that we can slice and iterate through an orbits dataframe that has already been sub-selected from another dataframe. """ orbits0 = Orbits() orbits0.readOrbits(os.path.join(self.testdir, 'test_orbitsNEO.s3m')) orbitsSub = Orbits() orbitsSub.setOrbits(orbits0.orbits.query('index>1')) self.assertEqual(len(orbitsSub), 6) orbit_slice = orbitsSub[2:6] self.assertEqual(orbit_slice[0], orbitsSub[2]) self.assertEqual(orbit_slice[1], orbitsSub[3]) self.assertEqual(orbit_slice[2], orbitsSub[4]) self.assertEqual(orbit_slice[3], orbitsSub[5]) self.assertEqual(len(orbit_slice), 4) orbit_slice = orbitsSub[1:5:2] self.assertEqual(orbit_slice[0], orbitsSub[1]) self.assertEqual(orbit_slice[1], orbitsSub[3]) self.assertEqual(len(orbit_slice), 2) for ii, oo in enumerate(orbitsSub): self.assertEqual(oo, orbits0[ii+2])
def readOrbits(orbitfile): if not os.path.isfile(orbitfile): print("Could not find orbit file %s" % (orbitfile)) orbits = Orbits() orbits.readOrbits(orbitfile) print("Read orbit information from %s" % (orbitfile)) return orbits
def make_orbit_plot(orbitFile, metadata): from lsst.sims.movingObjects import Orbits o = Orbits() o.readOrbits(orbitFile) o.orbits['a'] = o.orbits['q'] / (1 - o.orbits['e']) plt.figure(figsize=(8,8)) ax1 = plt.subplot(2, 1, 1) plt.plot(o.orbits['a'], o.orbits['e'], 'o', markersize=4, alpha=0.7) plt.xlim(0, 4) plt.ylim(0, 1) q = 1.05 a = np.arange(0, 5, .05) e = 1 - q/a plt.plot(a, e, 'k:') Q = 0.95 e = Q/a - 1 plt.plot(a, e, 'k:') plt.ylabel(r'Eccentricity') if metadata.lower() == 'pha': plt.title('PHA orbital distribution', fontsize='larger') else: plt.title('NEO orbital distribution', fontsize='larger') plt.subplot(2, 1, 2, sharex=ax1) plt.plot(o.orbits['a'], o.orbits['inc'], 'o', markersize=4, alpha=0.7) plt.xlim(0, 5) plt.ylim(0, 90) plt.xlabel(r'Semi-major Axis (AU)') plt.ylabel(r'Inclination ($^\circ$)') plt.savefig('%s_orbits.' % orbitFile.rstrip('.des') + figformat, format=figformat)
class TestJPLValues(unittest.TestCase): """Test the oorb generated RA/Dec values against JPL generated RA/Dec 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_csv(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 def tearDown(self): del self.orbits del self.jpl def testRADec(self): # We won't compare Vmag, because this also needs information on trailing losses. times = self.jpl['mjdUTC'].unique() 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.query('mjdUTC == @t').sort_values('objId') # Set the ephems, using the objects seen at this time. suborbits = self.orbits.orbits.query( 'objId in @j.objId').sort_values('objId') subOrbits = Orbits() subOrbits.setOrbits(suborbits) ephems = PyOrbEphemerides() ephems.setOrbits(subOrbits) ephs = ephems.generateEphemerides([t], timeScale='UTC', obscode=807, ephMode='N', ephType='Basic', byObject=False) deltaRA[i] = np.abs(ephs['ra'] - j['ra_deg'].values).max() deltaDec[i] = np.abs(ephs['dec'] - j['dec_deg'].values).max() # Convert to mas deltaRA *= 3600. * 1000. deltaDec *= 3600. * 1000. # Much of the time we're closer than 1mas, but there are a few which hit higher values. print('max JPL errors', np.max(deltaRA), np.max(deltaDec)) print('std JPL errors', np.std(deltaRA), np.std(deltaDec)) self.assertLess(np.max(deltaRA), 25) self.assertLess(np.max(deltaDec), 25) self.assertLess(np.std(deltaRA), 3) self.assertLess(np.std(deltaDec), 3)
def testReadOrbits(self): orbits = Orbits() orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsQ.des')) self.assertEqual(len(orbits), 4) orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsA.des')) self.assertEqual(len(orbits), 4) orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsCAR.des')) self.assertEqual(len(orbits), 1) with self.assertRaises(ValueError): orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsBadMix.des')) with self.assertRaises(ValueError): orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsBad.des'))
class TestRun(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.coeffFile = 'tmpCoeff' self.residFile = 'tmpResid' self.failedFile = 'tmpFailed' def tearDown(self): del self.orbits os.remove(self.coeffFile) os.remove(self.residFile) if os.path.isfile(self.failedFile): os.remove(self.failedFile) 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)
class TestRun(unittest.TestCase): 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')) def tearDown(self): del self.orbits if os.path.exists(self.scratch_dir): shutil.rmtree(self.scratch_dir) 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. with warnings.catch_warnings(): warnings.simplefilter('ignore') cheb.calcSegmentLength(length=10.0) # Run through segments. cheb.calcSegments() self.assertEqual(len(np.unique(cheb.coeffs['objId'])), len(self.orbits)) # Write outputs. coeff_name = os.path.join(self.scratch_dir, 'coeff2.txt') resid_name = os.path.join(self.scratch_dir, 'resid2.txt') failed_name = os.path.join(self.scratch_dir, 'failed2.txt') cheb.write(coeff_name, resid_name, failed_name) # 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)
class TestJPLValues(unittest.TestCase): """Test the oorb generated RA/Dec values against JPL generated RA/Dec 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 def tearDown(self): del self.orbits del self.jpl def testRADec(self): # We won't compare Vmag, because this also needs information on trailing losses. times = self.jpl['mjdUTC'].unique() 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.query('mjdUTC == @t').sort_values('objId') # Set the ephems, using the objects seen at this time. suborbits = self.orbits.orbits.query('objId in @j.objId').sort_values('objId') subOrbits = Orbits() subOrbits.setOrbits(suborbits) ephems = PyOrbEphemerides() ephems.setOrbits(subOrbits) ephs = ephems.generateEphemerides([t], timeScale='UTC', obscode=807, byObject=False) deltaRA[i] = np.abs(ephs['ra'] - j['ra_deg'].as_matrix()).max() deltaDec[i] = np.abs(ephs['dec'] - j['dec_deg'].as_matrix()).max() # Convert to mas deltaRA *= 3600. * 1000. deltaDec *= 3600. * 1000. # Much of the time we're closer than 1mas, but there are a few which hit higher values. 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', np.max(deltaRA), np.max(deltaDec)) print('std JPL errors', np.std(deltaRA), np.std(deltaDec))
def testSlicing(self): """ Test that we can slice a collection of orbits """ orbits = Orbits() orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsNEO.s3m'), skiprows=1) orbit_slice = orbits[2:6] self.assertEqual(orbit_slice[0], orbits[2]) self.assertEqual(orbit_slice[1], orbits[3]) self.assertEqual(orbit_slice[2], orbits[4]) self.assertEqual(orbit_slice[3], orbits[5]) self.assertEqual(len(orbit_slice), 4) orbit_slice = orbits[1:7:2] self.assertEqual(orbit_slice[0], orbits[1]) self.assertEqual(orbit_slice[1], orbits[3]) self.assertEqual(orbit_slice[2], orbits[5]) self.assertEqual(len(orbit_slice), 3)
def testSetSeds(self): """ Test that the self-assignment of SEDs works as expected. """ orbits = Orbits() # Test with a range of a values. a = np.arange(0, 5, .05) orbs = pd.DataFrame(a, columns=['a']) seds = orbits.assignSed(orbs) self.assertEqual(np.unique(seds[np.where(a < 2)]), 'S.dat') self.assertEqual(np.unique(seds[np.where(a > 4)]), 'C.dat') # Test when read a values. orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsA.des')) sedvals = orbits.assignSed(orbits.orbits, randomSeed=42) orbits2 = Orbits() orbits2.readOrbits(os.path.join(self.testdir, 'test_orbitsQ.des')) sedvals2 = orbits2.assignSed(orbits2.orbits, randomSeed=42) np.testing.assert_array_equal(sedvals, sedvals2)
def testSlicing(self): """ Test that we can slice a collection of orbits """ orbits = Orbits() orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsNEO.s3m')) orbit_slice = orbits[2:6] self.assertEqual(orbit_slice[0], orbits[2]) self.assertEqual(orbit_slice[1], orbits[3]) self.assertEqual(orbit_slice[2], orbits[4]) self.assertEqual(orbit_slice[3], orbits[5]) self.assertEqual(len(orbit_slice), 4) orbit_slice = orbits[1:7:2] self.assertEqual(orbit_slice[0], orbits[1]) self.assertEqual(orbit_slice[1], orbits[3]) self.assertEqual(orbit_slice[2], orbits[5]) self.assertEqual(len(orbit_slice), 3)
def readOrbits(orbitfile): """Read the orbits from the orbitfile. Parameters ---------- orbitfile: str Name (and path) of the orbit file. Returns ------- lsst.sims.movingObjects.Orbits The orbit object. """ if not os.path.isfile(orbitfile): logging.critical("Could not find orbit file %s" % (orbitfile)) orbits = Orbits() orbits.readOrbits(orbitfile) logging.info("Read orbit information from %s" % (orbitfile)) return orbits
def testIterationAndIndexing(self): orbits = Orbits() orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsNEO.s3m'), skiprows=1) orbitsSingle = orbits[0] assert_frame_equal(orbitsSingle.orbits, orbits.orbits.query('index==0')) orbitsSingle = orbits[3] assert_frame_equal(orbitsSingle.orbits, orbits.orbits.query('index==3')) # Test iteration through all orbits. for orb, (i, orbi) in zip(orbits, orbits.orbits.iterrows()): self.assertEqual(orb.orbits.objId.values[0], orbi.objId) self.assertTrue(isinstance(orb, Orbits)) self.assertEqual(orb.orbits.index, i) # Test iteration through a subset of orbits. orbitsSub = Orbits() orbitsSub.setOrbits(orbits.orbits.query('index > 4')) for orb, (i, orbi) in zip(orbitsSub, orbitsSub.orbits.iterrows()): self.assertEqual(orb.orbits.objId.values[0], orbi.objId) self.assertTrue(isinstance(orb, Orbits)) self.assertEqual(orb.orbits.index, i)
def testIterationAndIndexing(self): orbits = Orbits() orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsNEO.s3m')) orbitsSingle = orbits[0] assert_frame_equal(orbitsSingle.orbits, orbits.orbits.query('index==0')) orbitsSingle = orbits[3] assert_frame_equal(orbitsSingle.orbits, orbits.orbits.query('index==3')) # Test iteration through all orbits. for orb, (i, orbi) in zip(orbits, orbits.orbits.iterrows()): self.assertEqual(orb.orbits.objId.values[0], orbi.objId) self.assertTrue(isinstance(orb, Orbits)) self.assertEqual(orb.orbits.index, i) # Test iteration through a subset of orbits. orbitsSub = Orbits() orbitsSub.setOrbits(orbits.orbits.query('index > 4')) for orb, (i, orbi) in zip(orbitsSub, orbitsSub.orbits.iterrows()): self.assertEqual(orb.orbits.objId.values[0], orbi.objId) self.assertTrue(isinstance(orb, Orbits)) self.assertEqual(orb.orbits.index, i)
class TestRun(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.coeffFile = 'tmpCoeff' self.residFile = 'tmpResid' self.failedFile = 'tmpFailed' def tearDown(self): del self.orbits os.remove(self.coeffFile) os.remove(self.residFile) if os.path.isfile(self.failedFile): os.remove(self.failedFile) 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)
def testSetOrbits(self): orbits = Orbits() orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsQ.des')) # Test that we can set the orbits using a dataframe. suborbits = orbits.orbits.head(1) newOrbits = Orbits() newOrbits.setOrbits(suborbits) self.assertEqual(len(newOrbits), 1) self.assertEqual(newOrbits.format, 'COM') assert_frame_equal(newOrbits.orbits, suborbits) # Test that we can set the orbits using a Series. for i, sso in suborbits.iterrows(): newOrbits = Orbits() newOrbits.setOrbits(sso) self.assertEqual(len(newOrbits), 1) self.assertEqual(newOrbits.format, 'COM') assert_frame_equal(newOrbits.orbits, suborbits) # Test that we can set the orbits using a numpy array with many objects. numpyorbits = orbits.orbits.to_records(index=False) newOrbits = Orbits() newOrbits.setOrbits(numpyorbits) self.assertEqual(len(newOrbits), len(orbits)) self.assertEqual(newOrbits.format, 'COM') assert_frame_equal(newOrbits.orbits, orbits.orbits) # And test that this works for a single row of the numpy array. onenumpyorbits = numpyorbits[0] newOrbits = Orbits() newOrbits.setOrbits(onenumpyorbits) self.assertEqual(len(newOrbits), 1) self.assertEqual(newOrbits.format, 'COM') assert_frame_equal(newOrbits.orbits, suborbits) # And test that it fails appropriately when columns are not correct. neworbits = pd.DataFrame(orbits.orbits) newcols = neworbits.columns.values.tolist() newcols[0] = 'ssmId' newcols[3] = 'ecc' neworbits.columns = newcols newOrbits = Orbits() with self.assertRaises(ValueError): newOrbits.setOrbits(neworbits)
def testSetOrbits(self): orbits = Orbits() orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsQ.des')) # Test that we can set the orbits using a dataframe. suborbits = orbits.orbits.head(1) newOrbits = Orbits() newOrbits.setOrbits(suborbits) self.assertEqual(len(newOrbits), 1) self.assertEqual(newOrbits.orb_format, 'COM') assert_frame_equal(newOrbits.orbits, suborbits) # Test that we can set the orbits using a Series. for i, sso in suborbits.iterrows(): newOrbits = Orbits() newOrbits.setOrbits(sso) self.assertEqual(len(newOrbits), 1) self.assertEqual(newOrbits.orb_format, 'COM') assert_frame_equal(newOrbits.orbits, suborbits) # Test that we can set the orbits using a numpy array with many objects. numpyorbits = orbits.orbits.to_records(index=False) newOrbits = Orbits() newOrbits.setOrbits(numpyorbits) self.assertEqual(len(newOrbits), len(orbits)) self.assertEqual(newOrbits.orb_format, 'COM') assert_frame_equal(newOrbits.orbits, orbits.orbits) # And test that this works for a single row of the numpy array. onenumpyorbits = numpyorbits[0] newOrbits = Orbits() newOrbits.setOrbits(onenumpyorbits) self.assertEqual(len(newOrbits), 1) self.assertEqual(newOrbits.orb_format, 'COM') assert_frame_equal(newOrbits.orbits, suborbits) # And test that it fails appropriately when columns are not correct. neworbits = pd.DataFrame(orbits.orbits) newcols = neworbits.columns.values.tolist() newcols[0] = 'ssmId' newcols[3] = 'ecc' neworbits.columns = newcols newOrbits = Orbits() with self.assertRaises(ValueError): newOrbits.setOrbits(neworbits)
def testReadOrbits(self): orbits = Orbits() orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsQ.des')) self.assertEqual(len(orbits), 4) orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsA.des')) self.assertEqual(len(orbits), 4) with self.assertRaises(ValueError): orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsBad.des'))
def testEqualNotEqual(self): orbits = Orbits() orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsQ.des')) self.assertEqual(len(orbits), 4) orbits2 = Orbits() orbits2.readOrbits(os.path.join(self.testdir, 'test_orbitsQ.des')) self.assertEqual(orbits, orbits2) orbits3 = Orbits() orbits3.readOrbits(os.path.join(self.testdir, 'test_orbitsA.des')) self.assertNotEqual(orbits, orbits3)
def testEqualNotEqual(self): orbits = Orbits() orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsQ.des')) self.assertEqual(len(orbits), 4) orbits2 = Orbits() orbits2.readOrbits(os.path.join(self.testdir, 'test_orbitsQ.des')) self.assertEqual(orbits, orbits2) orbits3 = Orbits() orbits.readOrbits(os.path.join(self.testdir, 'test_orbitsA.des')) self.assertNotEqual(orbits, orbits3)
if not os.path.isfile(args.orbitFile): print("Could not find orbit file %s" % (args.orbitFile)) if args.orbitFile.lower().endswith('s3m'): skiprows = 1 else: skiprows = 0 # Check that basic information about tSpan or tEnd is available. if args.tEnd is None and args.tSpan is None: print("Must specify at least one of tSpan or tEnd") exit() # Read orbits. orbits = Orbits() orbits.readOrbits(args.orbitFile, skiprows=skiprows) # Pull out only objStart to objEnd, if either of these is specified. if args.objStart is not None or args.objEnd is not None: if args.objStart is None: args.objStart = 0 if args.objEnd is None: args.objEnd = len(orbits) - 1 orbits = orbits[args.objStart:args.objEnd + 1] fileSuffix = 'obj%d_%d' % (args.objStart, args.objEnd) else: fileSuffix = '' if args.nObj is None: nObj = len(orbits) else:
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 TestPyOrbEphemerides(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_orbitsQ.des')) self.orbitsKEP = Orbits() self.orbitsKEP.readOrbits( os.path.join(self.testdir, 'test_orbitsA.des')) self.ephems = PyOrbEphemerides() self.ephems.setOrbits(self.orbits) self.len_ephems_basic = 11 self.len_ephems_full = 34 def tearDown(self): del self.orbits del self.orbitsKEP del self.ephems def testSetOrbits(self): # Test that we can set orbits. self.ephems.setOrbits(self.orbits) # Test that setting with an empty orbit object fails. # (Avoids hard-to-interpret errors from pyoorb). with self.assertRaises(ValueError): emptyOrb = Orbits() empty = pd.DataFrame([], columns=self.orbits.dataCols['KEP']) emptyOrb.setOrbits(empty) self.ephems.setOrbits(emptyOrb) def testConvertToOorbArray(self): # Check that orbital elements are converted. self.ephems._convertToOorbElem(self.orbits.orbits, self.orbits.orb_format) self.assertEqual(len(self.ephems.oorbElem), len(self.orbits)) self.assertEqual(self.ephems.oorbElem[0][7], 2) self.assertEqual(self.ephems.oorbElem[0][9], 3) self.assertEqual(self.ephems.oorbElem[0][1], self.orbits.orbits['q'][0]) # Test that we can convert KEP orbital elements too. self.ephems._convertToOorbElem(self.orbitsKEP.orbits, self.orbitsKEP.orb_format) self.assertEqual(len(self.ephems.oorbElem), len(self.orbitsKEP)) self.assertEqual(self.ephems.oorbElem[0][7], 3) self.assertEqual(self.ephems.oorbElem[0][1], self.orbitsKEP.orbits['a'][0]) def testConvertFromOorbArray(self): # Check that we can convert orbital elements TO oorb format and back # without losing info (except ObjId -- we will lose that unless we use updateOrbits.) self.ephems._convertToOorbElem(self.orbits.orbits, self.orbits.orb_format) newOrbits = Orbits() newOrbits.setOrbits(self.orbits.orbits) newOrbits.updateOrbits(self.ephems.convertFromOorbElem()) self.assertEqual(newOrbits, self.orbits) def testConvertTimes(self): times = np.arange(49353, 49353 + 10, 0.5) ephTimes = self.ephems._convertTimes(times, 'UTC') # Check that shape of ephTimes is correct. (times x 2) self.assertEqual(ephTimes.shape[0], len(times)) self.assertEqual(ephTimes.shape[1], 2) # Check that 'timescale' for ephTimes is correct. self.assertEqual(ephTimes[0][1], 1) ephTimes = self.ephems._convertTimes(times, 'TAI') self.assertEqual(ephTimes[0][1], 4) def testOorbEphemeris(self): self.ephems.setOrbits(self.orbits) times = np.arange(49353, 49353 + 3, 0.25) ephTimes = self.ephems._convertTimes(times) # Basic ephemerides. oorbEphs = self.ephems._generateOorbEphsBasic(ephTimes, obscode=807, ephMode='N') # Check that it returned the right sort of array. self.assertEqual( oorbEphs.shape, (len(self.ephems.oorbElem), len(times), self.len_ephems_basic)) # Full ephemerides oorbEphs = self.ephems._generateOorbEphsFull(ephTimes, obscode=807, ephMode='N') # Check that it returned the right sort of array. self.assertEqual( oorbEphs.shape, (len(self.ephems.oorbElem), len(times), self.len_ephems_full)) def testEphemeris(self): # Calculate and convert ephemerides. self.ephems.setOrbits(self.orbits) times = np.arange(49353, 49353 + 2, 0.3) ephTimes = self.ephems._convertTimes(times) oorbEphs = self.ephems._generateOorbEphsBasic(ephTimes, obscode=807) # Group by object, and check grouping. ephs = self.ephems._convertOorbEphsBasic(oorbEphs, byObject=True) self.assertEqual(len(ephs), len(self.orbits)) # Group by time, and check grouping. oorbEphs = self.ephems._generateOorbEphsBasic(ephTimes, obscode=807) ephs = self.ephems._convertOorbEphsBasic(oorbEphs, byObject=False) self.assertEqual(len(ephs), len(times)) # And test all-wrapped-up method: ephsAll = self.ephems.generateEphemerides(times, obscode=807, ephMode='N', ephType='basic', timeScale='UTC', byObject=False) np.testing.assert_equal(ephsAll, ephs) # Reset ephems to use KEP Orbits, and calculate new ephemerides. self.ephems.setOrbits(self.orbitsKEP) oorbEphs = self.ephems._generateOorbEphsBasic(ephTimes, obscode=807, ephMode='N') ephsKEP = self.ephems._convertOorbEphsBasic(oorbEphs, byObject=True) self.assertEqual(len(ephsKEP), len(self.orbitsKEP)) oorbEphs = self.ephems._generateOorbEphsBasic(ephTimes, obscode=807, ephMode='N') ephsKEP = self.ephems._convertOorbEphsBasic(oorbEphs, byObject=False) self.assertEqual(len(ephsKEP), len(times)) # And test all-wrapped-up method: ephsAllKEP = self.ephems.generateEphemerides(times, obscode=807, ephMode='N', ephType='basic', timeScale='UTC', byObject=False) np.testing.assert_equal(ephsAllKEP, ephsKEP)
class TestPyOrbEphemerides(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_orbitsQ.des')) self.orbitsKEP = Orbits() self.orbitsKEP.readOrbits(os.path.join(self.testdir, 'test_orbitsA.des')) self.ephems = PyOrbEphemerides() def tearDown(self): del self.orbits del self.orbitsKEP del self.ephems def testSetOrbits(self): # Test that we can set orbits. self.ephems.setOrbits(self.orbits) assert_frame_equal(self.ephems.orbitObj.orbits, self.orbits.orbits) # Test that setting with something other than an Orbit object fails. with self.assertRaises(ValueError): self.ephems.setOrbits(self.orbits.orbits) # Test that setting with an empty orbit object fails. # (Avoids hard-to-interpret errors from pyoorb). with self.assertRaises(ValueError): emptyOrb = Orbits() empty = pd.DataFrame([], columns=self.orbits.dataCols['KEP']) emptyOrb.setOrbits(empty) self.ephems.setOrbits(emptyOrb) def testConvertToOorbArray(self): # Check that orbital elements are converted. self.ephems.orbitObj = self.orbits self.ephems._convertToOorbElem() self.assertEqual(len(self.ephems.oorbElem), len(self.orbits)) self.assertEqual(self.ephems.oorbElem[0][7], 2) self.assertEqual(self.ephems.oorbElem[0][9], 3) self.assertEqual(self.ephems.oorbElem[0][1], self.orbits.orbits['q'][0]) # Test that we can convert KEP orbital elements too. self.ephems.orbitObj = self.orbitsKEP self.ephems._convertToOorbElem() self.assertEqual(len(self.ephems.oorbElem), len(self.orbitsKEP)) self.assertEqual(self.ephems.oorbElem[0][7], 3) self.assertEqual(self.ephems.oorbElem[0][1], self.orbitsKEP.orbits['a'][0]) def testConvertFromOorbArray(self): self.ephems.orbitObj = self.orbits self.ephems._convertToOorbElem() newOrbits = self.ephems._convertFromOorbElem(self.ephems.oorbElem) self.assertEqual(newOrbits, self.orbits) def testConvertTimes(self): times = np.arange(49353, 49353 + 10, 0.5) ephTimes = self.ephems._convertTimes(times, 'UTC') # Check that shape of ephTimes is correct. self.assertEqual(ephTimes.shape[0], len(times)) self.assertEqual(ephTimes.shape[1], 2) # Check that 'timescale' for ephTimes is correct. self.assertEqual(ephTimes[0][1], 1) ephTimes = self.ephems._convertTimes(times, 'TAI') self.assertEqual(ephTimes[0][1], 4) def testOorbEphemeris(self): self.ephems.setOrbits(self.orbits) times = np.arange(49353, 49353 + 3, 0.25) ephTimes = self.ephems._convertTimes(times) oorbEphs = self.ephems._generateOorbEphs(ephTimes, obscode=807) # Check that it returned the right sort of array. self.assertEqual(oorbEphs.shape, (len(self.ephems.oorbElem), len(times), 10)) def testEphemeris(self): # Calculate and convert ephemerides. self.ephems.setOrbits(self.orbits) times = np.arange(49353, 49353 + 2, 0.3) ephTimes = self.ephems._convertTimes(times) oorbEphs = self.ephems._generateOorbEphs(ephTimes, obscode=807) # Group by object, and check grouping. ephs = self.ephems._convertOorbEphs(oorbEphs, byObject=True) self.assertEqual(len(ephs), len(self.orbits)) # Group by time, and check grouping. ephs = self.ephems._convertOorbEphs(oorbEphs, byObject=False) self.assertEqual(len(ephs), len(times)) # And test all-wrapped-up method: ephsAll = self.ephems.generateEphemerides(times, obscode=807, timeScale='UTC', byObject=False) np.testing.assert_equal(ephsAll, ephs) # Reset ephems to use KEP Orbits, and calculate new ephemerides. self.ephems.setOrbits(self.orbitsKEP) oorbEphs = self.ephems._generateOorbEphs(ephTimes, obscode=807) ephsKEP = self.ephems._convertOorbEphs(oorbEphs, byObject=True) self.assertEqual(len(ephsKEP), len(self.orbitsKEP)) ephsKEP = self.ephems._convertOorbEphs(oorbEphs, byObject=False) self.assertEqual(len(ephsKEP), len(times)) # Check that ephemerides calculated by each method are almost equal. for column in ephs.dtype.names: np.testing.assert_allclose(ephs[column], ephsKEP[column], rtol=0, atol=1e-7) # And test all-wrapped-up method: ephsAllKEP = self.ephems.generateEphemerides(times, obscode=807, timeScale='UTC', byObject=False) np.testing.assert_equal(ephsAllKEP, ephsKEP) # Check that the wrapped method using KEP elements and the wrapped method using COM elements match. for column in ephsAll.dtype.names: np.testing.assert_allclose(ephsAllKEP[column], ephsAll[column], rtol=0, atol=1e-7)
class TestPyOrbEphemerides(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_orbitsQ.des')) self.orbitsKEP = Orbits() self.orbitsKEP.readOrbits( os.path.join(self.testdir, 'test_orbitsA.des')) self.ephems = PyOrbEphemerides() def tearDown(self): del self.orbits del self.orbitsKEP del self.ephems def testSetOrbits(self): # Test that we can set orbits. self.ephems.setOrbits(self.orbits) assert_frame_equal(self.ephems.orbitObj.orbits, self.orbits.orbits) # Test that setting with something other than an Orbit object fails. with self.assertRaises(ValueError): self.ephems.setOrbits(self.orbits.orbits) # Test that setting with an empty orbit object fails. # (Avoids hard-to-interpret errors from pyoorb). with self.assertRaises(ValueError): emptyOrb = Orbits() empty = pd.DataFrame([], columns=self.orbits.dataCols['KEP']) emptyOrb.setOrbits(empty) self.ephems.setOrbits(emptyOrb) def testConvertToOorbArray(self): # Check that orbital elements are converted. self.ephems.orbitObj = self.orbits self.ephems._convertToOorbElem() self.assertEqual(len(self.ephems.oorbElem), len(self.orbits)) self.assertEqual(self.ephems.oorbElem[0][7], 2) self.assertEqual(self.ephems.oorbElem[0][9], 3) self.assertEqual(self.ephems.oorbElem[0][1], self.orbits.orbits['q'][0]) # Test that we can convert KEP orbital elements too. self.ephems.orbitObj = self.orbitsKEP self.ephems._convertToOorbElem() self.assertEqual(len(self.ephems.oorbElem), len(self.orbitsKEP)) self.assertEqual(self.ephems.oorbElem[0][7], 3) self.assertEqual(self.ephems.oorbElem[0][1], self.orbitsKEP.orbits['a'][0]) def testConvertFromOorbArray(self): self.ephems.orbitObj = self.orbits self.ephems._convertToOorbElem() newOrbits = self.ephems._convertFromOorbElem(self.ephems.oorbElem) self.assertEqual(newOrbits, self.orbits) def testConvertTimes(self): times = np.arange(49353, 49353 + 10, 0.5) ephTimes = self.ephems._convertTimes(times, 'UTC') # Check that shape of ephTimes is correct. self.assertEqual(ephTimes.shape[0], len(times)) self.assertEqual(ephTimes.shape[1], 2) # Check that 'timescale' for ephTimes is correct. self.assertEqual(ephTimes[0][1], 1) ephTimes = self.ephems._convertTimes(times, 'TAI') self.assertEqual(ephTimes[0][1], 4) def testOorbEphemeris(self): self.ephems.setOrbits(self.orbits) times = np.arange(49353, 49353 + 3, 0.25) ephTimes = self.ephems._convertTimes(times) oorbEphs = self.ephems._generateOorbEphs(ephTimes, obscode=807) # Check that it returned the right sort of array. self.assertEqual(oorbEphs.shape, (len(self.ephems.oorbElem), len(times), 10)) def testEphemeris(self): # Calculate and convert ephemerides. self.ephems.setOrbits(self.orbits) times = np.arange(49353, 49353 + 2, 0.3) ephTimes = self.ephems._convertTimes(times) oorbEphs = self.ephems._generateOorbEphs(ephTimes, obscode=807) # Group by object, and check grouping. ephs = self.ephems._convertOorbEphs(oorbEphs, byObject=True) self.assertEqual(len(ephs), len(self.orbits)) # Group by time, and check grouping. ephs = self.ephems._convertOorbEphs(oorbEphs, byObject=False) self.assertEqual(len(ephs), len(times)) # And test all-wrapped-up method: ephsAll = self.ephems.generateEphemerides(times, obscode=807, timeScale='UTC', byObject=False) np.testing.assert_equal(ephsAll, ephs) # Reset ephems to use KEP Orbits, and calculate new ephemerides. self.ephems.setOrbits(self.orbitsKEP) oorbEphs = self.ephems._generateOorbEphs(ephTimes, obscode=807) ephsKEP = self.ephems._convertOorbEphs(oorbEphs, byObject=True) self.assertEqual(len(ephsKEP), len(self.orbitsKEP)) ephsKEP = self.ephems._convertOorbEphs(oorbEphs, byObject=False) self.assertEqual(len(ephsKEP), len(times)) # Check that ephemerides calculated by each method are almost equal. for column in ephs.dtype.names: np.testing.assert_allclose(ephs[column], ephsKEP[column], rtol=0, atol=1e-7) # And test all-wrapped-up method: ephsAllKEP = self.ephems.generateEphemerides(times, obscode=807, timeScale='UTC', byObject=False) np.testing.assert_equal(ephsAllKEP, ephsKEP) # Check that the wrapped method using KEP elements and the wrapped method using COM elements match. for column in ephsAll.dtype.names: np.testing.assert_allclose(ephsAllKEP[column], ephsAll[column], rtol=0, atol=1e-7)
import warnings import numpy as np from lsst.sims.movingObjects import Orbits from itertools import repeat if __name__ == '__main__': parser = argparse.ArgumentParser(description="Add SEDs to a series of orbits.") parser.add_argument("--orbitFile", type=str, default=None, help="File containing the orbits.") parser.add_argument("--outFile", type=str, default=None, help="Output orbit file.") args = parser.parse_args() # Parse orbit file input values. if args.orbitFile is None: print("Must specify orbit file to use.") exit() if not os.path.isfile(args.orbitFile): print("Could not find orbit file %s" % (args.orbitFile)) # Read orbits. This adds SEDs with the default setup automatically. orbits = Orbits() orbits.readOrbits(args.orbitFile) # An alternative method to assign the seds: # sedfilenames = orbits.assignSed(orbits.orbits, randomSeed=None) formatcol = np.array([x for x in repeat(orbits.format, len(orbits.orbits))]) orbits.orbits.insert(1, 'FORMAT', formatcol) orbits.orbits.to_csv(args.outFile, sep=' ', index=False, header=True)
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)
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 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 = '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 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'))