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 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)
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)
Exemplo n.º 5
0
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]))
Exemplo n.º 6
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.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 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'))
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'))
                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
            # length determination stage otherwise.
            if cheb.length is not None:
                try:
                    cheb.calcSegments()
                except ValueError as ve:
                    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", 147, file=log)

            # Write out coefficients.
            cheb.write(coeffFile, residFile, failedFile, append=append)
            append = True
    print("ALL DONE", file=log)

Exemplo n.º 10
0
                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
            # length determination stage otherwise.
            if cheb.length is not None:
                try:
                    cheb.calcSegments()
                except ValueError as ve:
                    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", 147, file=log)

            # Write out coefficients.
            cheb.write(coeffFile, residFile, failedFile, append=append)
            append = True
    print("ALL DONE", file=log)