def test_ensure_unix(self): # Check that ensure_unix is doing its job for both scalar and array # inputs dt = datetime(2016, 4, 3, 2, 1, 0) dt_list = [ datetime(2016, 4, 3, 2, 1, 0), datetime(2016, 4, 3, 2, 1, 0) ] ut = ctime.datetime_to_unix(dt) ut_array = ctime.datetime_to_unix(dt_list) sf = ctime.unix_to_skyfield_time(ut) sf_array = ctime.unix_to_skyfield_time(ut_array) self.assertEqual(ctime.ensure_unix(dt), ut) self.assertEqual(ctime.ensure_unix(ut), ut) self.assertAlmostEqual(ctime.ensure_unix(sf), ut, 3) self.assertTrue((ctime.ensure_unix(dt_list) == ut_array).all()) self.assertTrue((ctime.ensure_unix(ut_array) == ut_array).all()) self.assertTrue( np.allclose(ctime.ensure_unix(sf_array), ut_array, rtol=1e-10, atol=1e-4))
def test_time_precision(self): """Make sure we have ~0.03 ms precision and that we aren't overflowing anything at double precision. This number comes from the precision on Julian date time representations: http://aa.usno.navy.mil/software/novas/USNOAA-TN2011-02.pdf """ delta = 0.001 # Try a 1 ms shift unix_time = time.time() unix_time2 = unix_time + delta tt1 = ctime.unix_to_skyfield_time(unix_time).tt_calendar() tt2 = ctime.unix_to_skyfield_time(unix_time2).tt_calendar() err = abs(tt2[-1] - tt1[-1] - delta) self.assertTrue(err < 4e-5) # Check that it is accurate at the 0.03 ms level.
def test_time_precision(self): """Make sure we have ~0.03 ms precision and that we aren't overflowing anything at double precision. This number comes from the precision on Julian date time representations: http://aa.usno.navy.mil/software/novas/USNOAA-TN2011-02.pdf """ delta = 0.001 # Try a 1 ms shift unix_time = time.time() unix_time2 = unix_time + delta tt1 = ctime.unix_to_skyfield_time(unix_time).tt_calendar() tt2 = ctime.unix_to_skyfield_time(unix_time2).tt_calendar() err = abs(tt2[-1] - tt1[-1] - delta) self.assertTrue( err < 4e-5) # Check that it is accurate at the 0.03 ms level.
def test_array(self): # Do a simple test of transit_RA in an array. Use the fact that the RA # advances predictably to predict the answers from skyfield import earthlib epoch = datetime(2000, 1, 1, 11, 58, 56) # Create an observer at an arbitrary location obs = ctime.Observer(118.3, 36.1) # Calculate LST t = ctime.unix_to_skyfield_time(ctime.datetime_to_unix(epoch)) gst = earthlib.sidereal_time(t) lst = (360.0 * gst / 24.0 + obs.longitude) % 360.0 # Drift rate should be very close to 1 degree/4minutes. # Fetch times calculated by ephem delta_deg = np.arange(20) delta_deg.shape = (5, 4) lst = lst + delta_deg # Calculate RA using transit_RA unix_epoch = ctime.datetime_to_unix(epoch) unix_times = unix_epoch + (delta_deg * 60 * 4 * ctime.SIDEREAL_S) TRA = obs.transit_RA(unix_times) # Compare self.assertTrue(np.allclose(lst, TRA, atol=0.02, rtol=1e-10))
def icrs_to_cirs(ra, dec, epoch, apparent=True): """Convert a set of positions from ICRS to CIRS at a given data. Parameters ---------- ra, dec : float or np.ndarray Positions of source in ICRS coordinates including an optional redshift position. epoch : time_like Time to convert the positions to. Can be any type convertible to a time using `caput.time.ensure_unix`. apparent : bool Calculate the apparent position (includes abberation and deflection). Returns ------- ra_cirs, dec_cirs : float or np.ndarray Arrays of the positions in *CIRS* coordiantes. """ positions = Star(ra=Angle(degrees=ra), dec=Angle(degrees=dec)) epoch = ctime.unix_to_skyfield_time(ctime.ensure_unix(epoch)) earth = ctime.skyfield_wrapper.ephemeris["earth"] positions = earth.at(epoch).observe(positions) if apparent: positions = positions.apparent() ra_cirs, dec_cirs, _ = positions.cirs_radec(epoch) return ra_cirs._degrees, dec_cirs._degrees
def test_ensure_unix(self): # Check that ensure_unix is doing its job for both scalar and array # inputs dt = datetime(2016, 4, 3, 2, 1, 0) dt_list = [datetime(2016, 4, 3, 2, 1, 0), datetime(2016, 4, 3, 2, 1, 0)] ut = ctime.datetime_to_unix(dt) ut_array = ctime.datetime_to_unix(dt_list) sf = ctime.unix_to_skyfield_time(ut) sf_array = ctime.unix_to_skyfield_time(ut_array) self.assertEqual(ctime.ensure_unix(dt), ut) self.assertEqual(ctime.ensure_unix(ut), ut) self.assertAlmostEqual(ctime.ensure_unix(sf), ut, 3) self.assertTrue((ctime.ensure_unix(dt_list) == ut_array).all()) self.assertTrue((ctime.ensure_unix(ut_array) == ut_array).all()) self.assertTrue(np.allclose(ctime.ensure_unix(sf_array), ut_array, rtol=1e-10, atol=1e-4))
def object_coords(body, date=None, deg=False, obs=chime): """Calculates the RA and DEC of the source. Gives the ICRS coordinates if no date is given (=J2000), or if a date is specified gives the CIRS coordinates at that epoch. This also returns the *apparent* position, including abberation and deflection by gravitational lensing. This shifts the positions by up to 20 arcseconds. Parameters ---------- body : skyfield source skyfield.starlib.Star or skyfield.vectorlib.VectorSum or skyfield.jpllib.ChebyshevPosition body representing the source. date : float Unix time at which to determine ra of source If None, use Jan 01 2000. deg : bool Return RA ascension in degrees if True, radians if false (default). obs : `caput.time.Observer` An observer instance to use. If not supplied use `chime`. For many calculations changing from this default will make little difference. Returns ------- ra, dec: float Position of the source. """ if date is None: # No date, get ICRS coords if isinstance(body, skyfield.starlib.Star): ra, dec = body.ra.radians, body.dec.radians else: raise ValueError( "Body is not fixed, cannot calculate coordinates without a date." ) else: # Calculate CIRS position with all corrections date = unix_to_skyfield_time(date) radec = obs.skyfield_obs().at(date).observe( body).apparent().cirs_radec(date) ra, dec = radec[0].radians, radec[1].radians # If requested, convert to degrees if deg: ra = np.degrees(ra) dec = np.degrees(dec) # Return return ra, dec
def _gen_basis(self, times, vis, n, max_za=90.): # make za axis max_sinza = np.sin(np.radians(max_za)) if self.harm_basis: sinza = np.linspace(-max_sinza, max_sinza, 2 * int(2 * np.radians(max_za) / np.pi * n)) else: sinza = np.linspace(-max_sinza, max_sinza, n) za = np.arcsin(sinza) az = np.zeros_like(za) az[:az.shape[0] / 2] = 180. alt = 90. - np.cos(np.radians(az)) * np.degrees(za) self.za = za self.sinza = sinza self._basis = np.zeros((vis.shape[0], vis.shape[1], n), dtype=np.complex64) # make EW grid to integrate over phi = np.linspace(-2 * self._res(), 2 * self._res(), 20) z, p = np.meshgrid(za, phi) self.z, self.p = z, p alt, az = tel2azalt(z, p) # model the EW beam as a sinc ew_beam = cylbeam.fraunhofer_cylinder(lambda x: np.ones_like(x), 20.) ew_beam = ew_beam(p)**2 self.ew_beam = ew_beam # calculate phases within beam phases = np.exp(1j * self._fringe_phase(z, p)) for i, t in enumerate(times): sf_t = unix_to_skyfield_time(t) pix = np.zeros((alt.shape[0], alt.shape[1]), dtype=int) for j in range(alt.shape[0]): for k in range(alt.shape[1]): pos = self.obs.at(sf_t).from_altaz( az_degrees=np.degrees(az[j, k]), alt_degrees=np.degrees(alt[j, k])) gallat, gallon = pos.galactic_latlon()[:2] pix[j, k] = healpy.ang2pix(self.nside, gallon.degrees, gallat.degrees, lonlat=True) if len(phases.shape) > 2: basis = np.sum(self.smoothmap[pix] * ew_beam * phases, axis=1) else: basis = self.smoothmap[pix] * ew_beam * phases if self.harm_basis: # convolve NS slice with basis functions basis = np.dot( basis, np.sin( np.arange(1, n + 1)[np.newaxis, :] * (za[:, np.newaxis] + np.pi / 2))) self._basis[:, i, :] = basis
def test_from_unix_time(self): """Make sure we are properly parsing the unix time. This is as much a test of ephem as our code. See issue #29 on the PyEphem github page. """ unix_time = random.random() * 2e6 dt = datetime.utcfromtimestamp(unix_time) st = ctime.unix_to_skyfield_time(unix_time) new_dt = st.utc_datetime() self.assertEqual(dt.year, new_dt.year) self.assertEqual(dt.month, new_dt.month) self.assertEqual(dt.day, new_dt.day) self.assertEqual(dt.hour, new_dt.hour) self.assertEqual(dt.minute, new_dt.minute) self.assertEqual(dt.second, new_dt.second) self.assertTrue(abs(dt.microsecond - new_dt.microsecond) <= 1000) # Skyfield rounds its output at the millisecond level.
def utc_lst_to_mjd(datestring, lst, obs=chime): """Convert datetime string and LST to corresponding modified Julian Day Parameters ---------- datestring : string Date as YYYYMMDD-AAA, where AAA is one of [UTC, PST, PDT] lst : float Local sidereal time at DRAO (CHIME) in decimal hours obs : caput.Observer object Returns ------- mjd : float Modified Julian Date corresponding to the given time. """ return (unix_to_skyfield_time( obs.lsa_to_unix(lst * 360 / 24, datetime_to_unix( parse_date(datestring)))).tt - 2400000.5)
def test_from_unix_time(self): """Make sure we are properly parsing the unix time. This is as much a test of ephem as our code. See issue #29 on the PyEphem github page. """ unix_time = random.random() * 2e6 dt = datetime.utcfromtimestamp(unix_time) st = ctime.unix_to_skyfield_time(unix_time) new_dt = st.utc_datetime() self.assertEqual(dt.year, new_dt.year) self.assertEqual(dt.month, new_dt.month) self.assertEqual(dt.day, new_dt.day) self.assertEqual(dt.hour, new_dt.hour) self.assertEqual(dt.minute, new_dt.minute) self.assertEqual(dt.second, new_dt.second) self.assertTrue( abs(dt.microsecond - new_dt.microsecond) <= 1000) # Skyfield rounds its output at the millisecond level.
def test_epoch(self): from skyfield import earthlib # At the J2000 epoch, sidereal time and transit RA should be the same. epoch = datetime(2000, 1, 1, 11, 58, 56) # Create an observer at an arbitrary location obs = ctime.Observer(118.3, 36.1) # Calculate the transit_RA unix_epoch = ctime.datetime_to_unix(epoch) TRA = obs.transit_RA(unix_epoch) # Calculate LST t = ctime.unix_to_skyfield_time(unix_epoch) gst = earthlib.sidereal_time(t) lst = (360.0 * gst / 24.0 + obs.longitude) % 360.0 # Tolerance limited by stellar aberation self.assertTrue(np.allclose(lst, TRA, atol=0.01, rtol=1e-10))