def test_era_inverse(self): # Check a full forward/inverse cycle dt = datetime(2016, 4, 3, 2, 1, 0) t1 = ctime.datetime_to_unix(dt) era = ctime.unix_to_era(t1) t2 = ctime.era_to_unix(era, t1 - 3600.0) # Should be accurate at the 1 ms level self.assertAlmostEqual(t1, t2, 3) # Check a full forward/inverse cycle over a leap second boundary dt = datetime(2009, 1, 1, 3, 0, 0) t1 = ctime.datetime_to_unix(dt) era = ctime.unix_to_era(t1) t2 = ctime.era_to_unix(era, t1 - 6 * 3600.0) # Should be accurate at the 10 ms level self.assertAlmostEqual(t1, t2, 2)
def test_era_known(self): # Check an ERA calculated by caput.time against one calculated by # http://dc.zah.uni-heidelberg.de/apfs/times/q/form (note the latter # uses UT1, so we have maximum precision of 1s) dt = datetime(2016, 4, 3, 2, 1, 0) t1 = ctime.datetime_to_unix(dt) era1 = ctime.unix_to_era(t1) era2 = 221.0 + (52.0 + 50.828 / 60.0) / 60.0 self.assertAlmostEqual(era1, era2, 3) # Test another one dt = datetime(2001, 2, 3, 4, 5, 6) t1 = ctime.datetime_to_unix(dt) era1 = ctime.unix_to_era(t1) era2 = 194.0 + (40.0 + 11.549 / 60.0) / 60.0 self.assertAlmostEqual(era1, era2, 3)
def sun_coord(unix_time, deg=True): date = ephemeris.ensure_unix(np.atleast_1d(unix_time)) skyfield_time = ephemeris.unix_to_skyfield_time(date) ntime = date.size coord = np.zeros((ntime, 4), dtype=np.float32) planets = skyfield.api.load('de421.bsp') sun = planets['sun'] observer = ephemeris._get_chime().skyfield_obs() apparent = observer.at(skyfield_time).observe(sun).apparent() radec = apparent.radec(epoch=skyfield_time) coord[:, 0] = radec[0].radians coord[:, 1] = radec[1].radians altaz = apparent.altaz() coord[:, 2] = altaz[0].radians coord[:, 3] = altaz[1].radians # Correct RA from equinox to CIRS coords using # the equation of the origins era = np.radians(ctime.unix_to_era(date)) gast = 2 * np.pi * skyfield_time.gast / 24.0 coord[:, 0] = coord[:, 0] + (era - gast) # Convert to hour angle coord[:, 0] = _correct_phase_wrap(coord[:, 0] - np.radians(ephemeris.lsa(date))) if deg: coord = np.degrees(coord) return coord
def parse_ant_logs(cls, logs, return_post_report_params=False): """ Unzip and parse .ANT log file output by nsched for John Galt Telescope observations Parameters ---------- logs : list of strings .ZIP filenames. Each .ZIP archive should include a .ANT file and a .POST_REPORT file. This method unzips the archive, uses `parse_post_report` to read the .POST_REPORT file and extract the CHIME sidereal day corresponding to the DRAO sidereal day, and then reads the lines in the .ANT file to obtain the pointing history of the Galt Telescope during this observation. (The DRAO sidereal day is days since the clock in Ev Sheehan's office at DRAO was reset. This clock is typically only reset every few years, but it does not correspond to any defined date, so the date must be figured out from the .POST_REPORT file, which reports both the DRAO sidereal day and the UTC date and time. Known reset dates: 2017-11-21, 2019-3-10) Returns ------- if output_params == False: ant_data: A dictionary consisting of lists containing the LST, hour angle, RA, and dec (all as Skyfield Angle objects), CHIME sidereal day, and DRAO sidereal day. if output_params == True output_params: dictionary returned by `parse_post_report` and ant_data: described above Files ----- the .ANT and .POST_REPORT files in the input .zip archive are extracted into /tmp/26mlog/<loginname>/ """ from skyfield.positionlib import Angle from caput import time as ctime DRAO_lon = ephemeris.CHIMELONGITUDE * 24.0 / 360.0 def sidlst_to_csd(sid, lst, sid_ref, t_ref): """ Convert an integer DRAO sidereal day and LST to a float CHIME sidereal day Parameters ---------- sid : int DRAO sidereal day lst : float, in hours local sidereal time sid_ref : int DRAO sidereal day at the reference time t_ref t_ref : skyfield time object, Julian days Reference time Returns ------- output : float CHIME sidereal day """ csd_ref = int( ephemeris.csd(ephemeris.datetime_to_unix( t_ref.utc_datetime()))) csd = sid - sid_ref + csd_ref return csd + lst / ephemeris.SIDEREAL_S / 24.0 ant_data_list = [] post_report_list = [] for log in logs: doobs = True filename = log.split("/")[-1] basedir = "/tmp/26mlog/{}/".format(os.getlogin()) basename, extension = filename.split(".") post_report_file = basename + ".POST_REPORT" ant_file = basename + ".ANT" if extension == "zip": try: zipfile.ZipFile(log).extract(post_report_file, path=basedir) except: print( "Failed to extract {} into {}. Moving right along...". format(post_report_file, basedir)) doobs = False try: zipfile.ZipFile(log).extract(ant_file, path=basedir) except: print( "Failed to extract {} into {}. Moving right along...". format(ant_file, basedir)) doobs = False if doobs: try: post_report_params = cls.parse_post_report( basedir + post_report_file) with open(os.path.join(basedir, ant_file), "r") as f: lines = [line for line in f] ant_data = {"sid": np.array([])} lsth = [] lstm = [] lsts = [] hah = [] ham = [] has = [] decd = [] decm = [] decs = [] for l in lines: arr = l.split() try: lst_hms = [float(x) for x in arr[2].split(":")] # do last element first: if this is going to # crash because a line in the log is incomplete, # we don't want it to append to any of the lists decs.append(float(arr[8].replace('"', ""))) decm.append(float(arr[7].replace("'", ""))) decd.append(float(arr[6].replace("D", ""))) has.append(float(arr[5].replace("S", ""))) ham.append(float(arr[4].replace("M", ""))) hah.append(float(arr[3].replace("H", ""))) lsts.append(float(lst_hms[2])) lstm.append(float(lst_hms[1])) lsth.append(float(lst_hms[0])) ant_data["sid"] = np.append( ant_data["sid"], int(arr[1])) except: print("Failed in file {} for line \n{}".format( ant_file, l)) if len(ant_data["sid"]) != len(decs): print("WARNING: mismatch in list lengths.") ant_data["lst"] = Angle(hours=(lsth, lstm, lsts)) ha = Angle(hours=(hah, ham, has)) dec = Angle(degrees=(decd, decm, decs)) ant_data["ha"] = Angle( radians=ha.radians - ephemeris.galt_pointing_model_ha(ha, dec).radians, preference="hours", ) ant_data["dec_cirs"] = Angle( radians=dec.radians - ephemeris.galt_pointing_model_dec(ha, dec).radians, preference="degrees", ) ant_data["csd"] = sidlst_to_csd( np.array(ant_data["sid"]), ant_data["lst"].hours, post_report_params["SID"], post_report_params["start_time"], ) ant_data["t"] = ephemeris.unix_to_skyfield_time( ephemeris.csd_to_unix(ant_data["csd"])) # Correct RA from equinox to CIRS coords (both in radians) era = np.radians( ctime.unix_to_era(ephemeris.ensure_unix( ant_data["t"]))) gast = ant_data["t"].gast * 2 * np.pi / 24.0 ant_data["ra_cirs"] = Angle( radians=ant_data["lst"].radians - ant_data["ha"].radians + (era - gast), preference="hours", ) obs = ephemeris.Star_cirs( ra=ant_data["ra_cirs"], dec=ant_data["dec_cirs"], epoch=ant_data["t"], ) ant_data["ra"] = obs.ra ant_data["dec"] = obs.dec ant_data_list.append(ant_data) post_report_list.append(post_report_params) except: print("Parsing {} failed".format(post_report_file)) if return_post_report_params: return post_report_list, ant_data_list return ant_data