def dayofyear(self): """ Return the day of the year for all the TOAs of this pulsar """ t = Time(self.all_toas.get_mjds(), format="mjd") year = Time(np.floor(t.decimalyear), format="decimalyear") return np.asarray(t.mjd - year.mjd) << u.day
def gcrs_posvel_from_itrf(loc, toas, obsname="obs"): """Return a list of PosVel instances for the observatory at the TOA times. Observatory location should be given in the loc argument as an astropy EarthLocation object. This location will be in the ITRF frame (i.e. co-rotating with the Earth). The optional obsname argument will be used as label in the returned PosVel instance. This routine returns a list of PosVel instances, containing the positions (m) and velocities (m / s) at the times of the toas and referenced to the Earth-centered Inertial (ECI, aka GCRS) coordinates. This routine is basically SOFA's pvtob() [Position and velocity of a terrestrial observing station] with an extra rotation from c2ixys() [Form the celestial to intermediate-frame-of-date matrix given the CIP X,Y and the CIO locator s]. This version uses astropy's internal routines, which use IERS A data rather than the final IERS B values. These do differ, and yield results that are different by ~20 m. """ unpack = False # If the input is a single TOA (i.e. a row from the table), # then put it into a list if type(toas) == table.row.Row: ttoas = Time([toas["mjd"]]) unpack = True elif type(toas) == table.table.Table: ttoas = toas["mjd"] elif isinstance(toas, Time): if toas.isscalar: ttoas = Time([toas]) unpack = True else: ttoas = toas else: if np.isscalar(toas): ttoas = Time([toas], format="mjd") unpack = True else: ttoas = toas t = ttoas pos, vel = loc.get_gcrs_posvel(t) r = PosVel(pos.xyz, vel.xyz, obj=obsname, origin="earth") if unpack: return r[0] else: return r
def fake_year(self): """ Function to support plotting of random models on multiple x-axes. Return the decimal year for all the TOAs of this pulsar """ t = Time(self.fake_toas.get_mjds(), format="mjd") return (t.decimalyear) * u.year
def _get_TDB_ephem(self, t, ephem): """Read the ephem TDB-TT column. This column is provided by DE4XXt version of ephemeris. This function is only for the ground-based observatories """ geo_tdb_tt = get_tdb_tt_ephem_geocenter(t.tt, ephem) # NOTE The earth velocity is need to compute the time correcion from # Topocenter to Geocenter # Since earth velocity is not going to change a lot in 3ms. The # differences between TT and TDB can be ignored. earth_pv = objPosVel_wrt_SSB("earth", t.tdb, ephem) obs_geocenter_pv = gcrs_posvel_from_itrf( self.earth_location_itrf(), t, obsname=self.name ) # NOTE # Moyer (1981) and Murray (1983), with fundamental arguments adapted # from Simon et al. 1994. topo_time_corr = numpy.sum( earth_pv.vel / c.c * obs_geocenter_pv.pos / c.c, axis=0 ) topo_tdb_tt = geo_tdb_tt - topo_time_corr result = Time( t.tt.jd1 - JD_MJD, t.tt.jd2 - topo_tdb_tt.to(u.day).value, format="pulsar_mjd", scale="tdb", location=self.earth_location_itrf(), ) return result
def posvel(self, t, ephem, group=None): if t.isscalar: t = Time([t]) earth_pv = objPosVel_wrt_SSB("earth", t, ephem) obs_geocenter_pv = gcrs_posvel_from_itrf( self.earth_location_itrf(), t, obsname=self.name ) return obs_geocenter_pv + earth_pv
def F0(toa, model): dt = toa.get_mjds(high_precision=True) - np.array( Time(model.PEPOCH.value, format="pulsar_mjd", scale="utc") ) # Can use dt[n].jd1 and jd2 with mpmath here if necessary ph = np.array([x.sec * model.F0.value for x in dt]) return ph
def get_TDBs(self, t, method="default", ephem=None, options=None): """This is a high level function for converting TOAs to TDB time scale. Different method can be applied to obtain the result. Current supported methods are ['default', 'ephemeris'] Parameters ---------- t: astropy.time.Time object The time need for converting toas method: str or callable, optional Method of computing TDB "default" Astropy time.Time object built-in converter, uses FB90. SpacecraftObs will include a topocentric correction term. "ephemeris" JPL ephemeris included TDB-TT correction. Not currently implemented. callable This callable is called with the parameter t as its first parameter; additional keyword arguments can be supplied in the options argument ephem: str, optional The ephemeris to get he TDB-TT correction. Required for the 'ephemeris' method. options: dict or None Options to pass to a custom callable. """ if t.isscalar: t = Time([t]) if t.scale == "tdb": return t # Check the method. This pattern is from numpy minize if callable(method): meth = "_custom" else: meth = method.lower() if options is None: options = {} if meth == "_custom": options = dict(options) return method(t, **options) if meth == "default": return self._get_TDB_default(t, ephem) elif meth == "ephemeris": if ephem is None: raise ValueError( "A ephemeris file should be provided to get" " the TDB-TT corrections." ) return self._get_TDB_ephem(t, ephem) else: raise ValueError("Unknown method '%s'." % method)
def test_normal_day(self): one_mjd = Time(self.normal_days[0], scale="utc") mjds = Time(self.normal_days, scale="utc") # convert to pulsar mjd p_one_mjd = Time(one_mjd, format="pulsar_mjd") p_mjds = Time(mjds, format="pulsar_mjd") assert np.isscalar( p_one_mjd.value), "Pulsar one mjd did not return the right lenght." assert np.isclose( np.modf(p_one_mjd.value)[0], 0.5, atol=1e-14 ), "Pulsar mjd did not give the right fractional day at leapsecond day" assert len(p_mjds) == 2, "Pulsar mjds did not return the right lenght." assert np.all( np.isclose(np.modf(p_mjds.value)[0], 0.5, atol=1e-14) ), "Pulsar mjd did not give the right fractional day at leapsecond day" assert np.all(np.isclose( np.modf(mjds.mjd)[0], 0.5, atol=1e-14)), "Astropy time did not have correct leapsecond setup."
def __init__(self, filename, **kwargs): self.filename = filename log.debug("Loading {0} observatory clock correction file {1}".format( self.format, filename)) mjd, clk, self.header = self.load_tempo2_clock_file(filename) # NOTE Clock correction file has a time far in the future as ending point with warnings.catch_warnings(): warnings.simplefilter("ignore", ErfaWarning) self._time = Time(mjd, format="pulsar_mjd", scale="utc") self._clock = clk * u.s
def change_pepoch(self, new_epoch, toas=None, delay=None): """Move PEPOCH to a new time and change the related paramters. Parameters ---------- new_epoch: float or `astropy.Time` object The new PEPOCH value. toas: `toa` object, optional. If current PEPOCH is not provided, the first pulsar frame toa will be treated as PEPOCH. delay: `numpy.array` object If current PEPOCH is not provided, it is required for computing the first pulsar frame toa. """ if isinstance(new_epoch, Time): new_epoch = Time(new_epoch, scale="tdb", precision=9) else: new_epoch = Time(new_epoch, scale="tdb", format="mjd", precision=9) # make new_epoch a toa for delay calculation. new_epoch_toa = toa.get_TOAs_list([toa.TOA(new_epoch)], ephem=toas.ephem) if self.PEPOCH.value is None: if toas is None or delay is None: raise ValueError( "`PEPOCH` is not in the model, thus, 'toa' and" " 'delay' shoule be givne.") tbl = toas.table phsepoch_ld = (tbl["tdb"][0] - delay[0]).tdb.mjd_long else: phsepoch_ld = self.PEPOCH.quantity.tdb.mjd_long dt = (new_epoch.tdb.mjd_long - phsepoch_ld) * u.day fterms = [0.0 * u.Unit("")] + self.get_spin_terms() # rescale the fterms for n in range(len(fterms) - 1): f_par = getattr(self, "F{}".format(n)) f_par.value = taylor_horner_deriv(dt.to(u.second), fterms, deriv_order=n + 1) self.PEPOCH.value = new_epoch
def __init__(self, filename, obscode=None, **kwargs): self.filename = filename self.obscode = obscode log.debug( "Loading {0} observatory ({1}) clock correction file {2}".format( self.format, obscode, filename)) mjd, clk = self.load_tempo1_clock_file(filename, site=obscode) # NOTE Clock correction file has a time far in the future as ending point # We are swithing off astropy warning only for gps correction. with warnings.catch_warnings(): warnings.simplefilter("ignore", ErfaWarning) try: self._time = Time(mjd, format="pulsar_mjd", scale="utc") except ValueError: log.error("Filename {0}, site {1}: Bad MJD {2}".format( filename, obscode, mjd)) raise self._clock = clk * u.us
def year(self): """ Return the decimal year for all the TOAs of this pulsar """ t = Time(self.all_toas.get_mjds(), format="mjd") return np.asarray(t.decimalyear) << u.year
def main(argv=None): parser = argparse.ArgumentParser( description= "Use PINT to compute H-test and plot Phaseogram from a Fermi FT1 event file." ) parser.add_argument("eventfile", help="Fermi event FITS file name.") parser.add_argument("parfile", help="par file to construct model from") parser.add_argument( "weightcol", help="Column name for event weights (or 'CALC' to compute them)") parser.add_argument("--ft2", help="Path to FT2 file.", default=None) parser.add_argument( "--addphase", help="Write FT1 file with added phase column", default=False, action="store_true", ) parser.add_argument("--plot", help="Show phaseogram plot.", action="store_true", default=False) parser.add_argument("--plotfile", help="Output figure file name (default=None)", default=None) parser.add_argument("--maxMJD", help="Maximum MJD to include in analysis", default=None) parser.add_argument( "--outfile", help="Output figure file name (default is to overwrite input file)", default=None, ) parser.add_argument( "--planets", help="Use planetary Shapiro delay in calculations (default=False)", default=False, action="store_true", ) parser.add_argument("--ephem", help="Planetary ephemeris to use (default=DE421)", default="DE421") args = parser.parse_args(argv) # If outfile is specified, that implies addphase if args.outfile is not None: args.addphase = True # Read in model modelin = pint.models.get_model(args.parfile) if "ELONG" in modelin.params: tc = SkyCoord( modelin.ELONG.quantity, modelin.ELAT.quantity, frame="barycentrictrueecliptic", ) else: tc = SkyCoord(modelin.RAJ.quantity, modelin.DECJ.quantity, frame="icrs") if args.ft2 is not None: # Instantiate FermiObs once so it gets added to the observatory registry FermiObs(name="Fermi", ft2name=args.ft2) # Read event file and return list of TOA objects tl = load_Fermi_TOAs(args.eventfile, weightcolumn=args.weightcol, targetcoord=tc) # Discard events outside of MJD range if args.maxMJD is not None: tlnew = [] print("pre len : ", len(tl)) maxT = Time(float(args.maxMJD), format="mjd") print("maxT : ", maxT) for tt in tl: if tt.mjd < maxT: tlnew.append(tt) tl = tlnew print("post len : ", len(tlnew)) # Now convert to TOAs object and compute TDBs and posvels # For Fermi, we are not including GPS or TT(BIPM) corrections ts = toa.get_TOAs_list( tl, include_gps=False, include_bipm=False, planets=args.planets, ephem=args.ephem, ) ts.filename = args.eventfile print(ts.get_summary()) mjds = ts.get_mjds() print(mjds.min(), mjds.max()) # Compute model phase for each TOA iphss, phss = modelin.phase(ts, abs_phase=True) # ensure all postive phases = np.where(phss < 0.0 * u.cycle, phss + 1.0 * u.cycle, phss) mjds = ts.get_mjds() weights = np.array([w["weight"] for w in ts.table["flags"]]) h = float(hmw(phases, weights)) print("Htest : {0:.2f} ({1:.2f} sigma)".format(h, h2sig(h))) if args.plot: log.info("Making phaseogram plot with {0} photons".format(len(mjds))) phaseogram(mjds, phases, weights, bins=100, plotfile=args.plotfile) if args.addphase: # Read input FITS file (again). # If overwriting, open in 'update' mode if args.outfile is None: hdulist = pyfits.open(args.eventfile, mode="update") else: hdulist = pyfits.open(args.eventfile) event_hdu = hdulist[1] event_hdr = event_hdu.header event_dat = event_hdu.data if len(event_dat) != len(phases): raise RuntimeError( "Mismatch between length of FITS table ({0}) and length of phase array ({1})!" .format(len(event_dat), len(phases))) if "PULSE_PHASE" in event_hdu.columns.names: log.info("Found existing PULSE_PHASE column, overwriting...") # Overwrite values in existing Column event_dat["PULSE_PHASE"] = phases else: # Construct and append new column, preserving HDU header and name log.info("Adding new PULSE_PHASE column.") phasecol = pyfits.ColDefs( [pyfits.Column(name="PULSE_PHASE", format="D", array=phases)]) bt = pyfits.BinTableHDU.from_columns(event_hdu.columns + phasecol, header=event_hdr, name=event_hdu.name) hdulist[1] = bt if args.outfile is None: # Overwrite the existing file log.info("Overwriting existing FITS file " + args.eventfile) hdulist.flush(verbose=True, output_verify="warn") else: # Write to new output file log.info("Writing output FITS file " + args.outfile) hdulist.writeto(args.outfile, overwrite=True, checksum=True, output_verify="warn") return 0
def old_gcrs_posvel_from_itrf(loc, toas, obsname="obs"): """Return a list of PosVel instances for the observatory at the TOA times. Observatory location should be given in the loc argument as an astropy EarthLocation object. This location will be in the ITRF frame (i.e. co-rotating with the Earth). The optional obsname argument will be used as label in the returned PosVel instance. This routine returns a list of PosVel instances, containing the positions (m) and velocities (m / s) at the times of the toas and referenced to the Earth-centered Inertial (ECI, aka GCRS) coordinates. This routine is basically SOFA's pvtob() [Position and velocity of a terrestrial observing station] with an extra rotation from c2ixys() [Form the celestial to intermediate-frame-of-date matrix given the CIP X,Y and the CIO locator s]. """ unpack = False # If the input is a single TOA (i.e. a row from the table), # then put it into a list if type(toas) == table.row.Row: ttoas = Time([toas["mjd"]]) unpack = True elif type(toas) == table.table.Table: ttoas = toas["mjd"] elif isinstance(toas, Time): if toas.isscalar: ttoas = Time([toas]) unpack = True else: ttoas = toas else: if np.isscalar(toas): ttoas = Time([toas], format="mjd") unpack = True else: ttoas = toas N = len(ttoas) if len(ttoas.shape) != 1: raise ValueError("At most one-dimensional array of times possible, " "shape was {}".format(ttoas.shape)) # Get various times from the TOAs as arrays tts = np.asarray([(t.jd1, t.jd2) for t in ttoas.tt]).T ut1s = np.asarray([(t.jd1, t.jd2) for t in ttoas.ut1]).T mjds = np.asarray(ttoas.mjd) iers_b = get_iers_b_up_to_date(mjds.max()) # Get x, y coords of Celestial Intermediate Pole and CIO locator s X, Y, S = erfa.xys00a(*tts) # Get dX and dY from IERS A in arcsec and convert to radians # dX = np.interp(mjds, iers_tab['MJD'], iers_tab['dX_2000A_B']) * asec2rad # dY = np.interp(mjds, iers_tab['MJD'], iers_tab['dY_2000A_B']) * asec2rad # Get dX and dY from IERS B in arcsec and convert to radians dX = np.interp(mjds, iers_b["MJD"].to_value(u.d), iers_b["dX_2000A"].to_value(u.rad)) dY = np.interp(mjds, iers_b["MJD"].to_value(u.d), iers_b["dY_2000A"].to_value(u.rad)) # Get GCRS to CIRS matrices rc2i = erfa.c2ixys(X + dX, Y + dY, S) # Gets the TIO locator s' sp = erfa.sp00(*tts) # Get X and Y from IERS A in arcsec and convert to radians # xp = np.interp(mjds, iers_tab['MJD'], iers_tab['PM_X_B']) * asec2rad # yp = np.interp(mjds, iers_tab['MJD'], iers_tab['PM_Y_B']) * asec2rad # Get X and Y from IERS B in arcsec and convert to radians xp = np.interp(mjds, iers_b["MJD"].to_value(u.d), iers_b["PM_x"].to_value(u.rad)) yp = np.interp(mjds, iers_b["MJD"].to_value(u.d), iers_b["PM_y"].to_value(u.rad)) # Get the polar motion matrices rpm = erfa.pom00(xp, yp, sp) # Observatory geocentric coords in m xyzm = np.array([a.to_value(u.m) for a in loc.geocentric]) x, y, z = np.dot(xyzm, rpm).T # Functions of Earth Rotation Angle theta = erfa.era00(*ut1s) s, c = np.sin(theta), np.cos(theta) sx, cx = s * x, c * x sy, cy = s * y, c * y # Initial positions and velocities iposs = np.asarray([cx - sy, sx + cy, z]).T ivels = np.asarray([OM * (-sx - cy), OM * (cx - sy), np.zeros_like(x)]).T # There is probably a way to do this with np.einsum or something... # and here it is . poss = np.empty((N, 3), dtype=np.float64) vels = np.empty((N, 3), dtype=np.float64) poss = np.einsum("ij,ijk->ik", iposs, rc2i) vels = np.einsum("ij,ijk->ik", ivels, rc2i) r = PosVel(poss.T * u.m, vels.T * u.m / u.s, obj=obsname, origin="earth") if unpack: return r[0] else: return r
def test_times_against_tempo2(): log.setLevel("ERROR") # for nice output info, set the following instead # log.setLevel('INFO') ls = u.def_unit("ls", const.c * 1.0 * u.s) log.info("Reading TOAs into PINT") ts = toa.get_TOAs(datadir + "/testtimes.tim", include_bipm=False, usepickle=False) if log.level < 25: ts.print_summary() ts.table.sort("index") log.info("Calling TEMPO2") # cmd = 'tempo2 -output general2 -f tests/testtimes.par tests/testtimes.tim -s "XXX {clock0} {clock1} {clock2} {clock3} {tt} {t2tb} {telSSB} {telVel} {Ttt}\n"' # cmd = 'tempo2 -output general2 -f ' + datadir+'/testtimes.par ' + datadir + \ # '/testtimes.tim -s "XXX {clock0} {clock1} {clock2} {clock3} {tt} {t2tb} {earth_ssb1} {earth_ssb2} {earth_ssb3} {earth_ssb4} {earth_ssb5} {earth_ssb6} {telEpos} {telEVel} {Ttt}\n"' # args = shlex.split(cmd) # # tout = subprocess.check_output(args) # goodlines = [x for x in tout.split("\n") if x.startswith("XXX")] # # assert(len(goodlines)==len(ts.table)) # t2result = numpy.genfromtxt('datafile/testtimes.par' + '.tempo2_test', names=True, comments = '#') f = open(datadir + "/testtimes.par" + ".tempo2_test") lines = f.readlines() goodlines = lines[1:] # Get the output lines from the TOAs for line, TOA in zip(goodlines, ts.table): assert (len(line.split()) == 19 ), "tempo2 general2 does not support all needed outputs" ( oclk, gps_utc, tai_utc, tt_tai, ttcorr, tt2tb, ep0, ep1, ep2, ev0, ev1, ev2, tp0, tp1, tp2, tv0, tv1, tv2, Ttt, ) = (float(x) for x in line.split()) t2_epv = PosVel( numpy.asarray([ep0, ep1, ep2]) * ls, numpy.asarray([ev0, ev1, ev2]) * ls / u.s, ) t2_opv = PosVel( numpy.asarray([tp0, tp1, tp2]) * ls, numpy.asarray([tv0, tv1, tv2]) * ls / u.s, ) t2_ssb2obs = t2_epv + t2_opv # print time_to_mjd_string(TOA.mjd.tt), line.split()[-1] tempo_tt = Time(line.split()[-1], format="mjd_string", scale="tt") # Ensure that the clock corrections are accurate to better than 0.1 ns assert (math.fabs( (oclk * u.s + gps_utc * u.s - TOA["flags"]["clkcorr"]).to( u.ns).value) < 0.1) log.info("TOA in tt difference is: %.2f ns" % ((TOA["mjd"].tt - tempo_tt.tt).sec * u.s).to(u.ns).value) pint_opv = erfautils.gcrs_posvel_from_itrf(Observatory.get( TOA["obs"]).earth_location_itrf(), TOA, obsname=TOA["obs"]) pint_opv = PosVel(pint_opv.pos, pint_opv.vel) # print " obs T2:", t2_opv.pos.to(u.m).value, t2_opv.vel.to(u.m/u.s) # print " obs PINT:", pint_opv.pos.to(u.m), pint_opv.vel.to(u.m/u.s) dopv = pint_opv - t2_opv dpos = numpy.sqrt(numpy.dot(dopv.pos.to(u.m), dopv.pos.to(u.m))) dvel = numpy.sqrt( numpy.dot(dopv.vel.to(u.mm / u.s), dopv.vel.to(u.mm / u.s))) log.info(" obs diff: %.2f m, %.3f mm/s" % (dpos, dvel)) assert dpos < 2.0 and dvel < 0.02 pint_ssb2obs = PosVel( numpy.asarray(TOA["ssb_obs_pos"]) * u.km, numpy.asarray(TOA["ssb_obs_vel"]) * u.km / u.s, origin="SSB", obj="OBS", ) # print " topo T2:", t2_ssb2obs.pos.to(u.km), t2_ssb2obs.vel.to(u.km/u.s) # print " topo PINT:", pint_ssb2obs.pos.to(u.km), pint_ssb2obs.vel.to(u.km/u.s) dtopo = pint_ssb2obs - t2_ssb2obs dpos = numpy.sqrt(numpy.dot(dtopo.pos.to(u.m), dtopo.pos.to(u.m))) dvel = numpy.sqrt( numpy.dot(dtopo.vel.to(u.mm / u.s), dtopo.vel.to(u.mm / u.s))) log.info(" topo diff: %.2f m, %.3f m/s" % (dpos, dvel)) assert dpos < 2.0 and dvel < 0.02
def setUpClass(cls): os.chdir(datadir) cls.test_obs = ["aro", "ao", "chime", "drao"] cls.test_time = Time(np.linspace(55000, 58000, num=100), scale="utc", format="pulsar_mjd")
def get_TDBs(self, t, method="default", ephem=None, options=None, grp=None): """This is a high level function for converting TOAs to TDB time scale. Different method can be applied to obtain the result. Current supported methods are ['astropy', 'ephemeris'] Parameters ---------- t: astropy.time.Time object The time need for converting toas method: str or callable, optional Method of computing TDB default Astropy time.Time object built-in converter, use FB90. Also uses topocentric correction term if self.tt2tdbmethod is pint. ephemeris JPL ephemeris included TDB-TT correction. ephem: str, optional The ephemeris to get he TDB-TT correction. Required for the 'ephemeris' method. """ if t.isscalar: t = Time([t]) if t.scale == "tdb": return t # Check the method. This pattern is from numpy minize if callable(method): meth = "_custom" else: meth = method.lower() if options is None: options = {} if meth == "_custom": options = dict(options) return method(t, **options) if meth == "default": if self.tt2tdb_mode.lower().startswith("astropy"): log.info("Doing astropy mode TDB conversion") return self._get_TDB_astropy(t) elif self.tt2tdb_mode.lower().startswith("pint"): log.info("Doing PINT mode TDB conversion") if ephem is None: raise ValueError( "A ephemeris file should be provided to get" " the TDB-TT corrections, or use tt2tdb_mode=astropy") return self._get_TDB_PINT(t, ephem, grp) elif meth == "ephemeris": if ephem is None: raise ValueError("A ephemeris file should be provided to get" " the TDB-TT corrections.") return self._get_TDB_ephem(t, ephem) else: raise ValueError("Unknown method '%s'." % method)
def main(argv=None): import argparse parser = argparse.ArgumentParser( description= "Use PINT to compute event phases and make plots of photon event files." ) parser.add_argument( "eventfile", help= "Photon event FITS file name (e.g. from NICER, RXTE, XMM, Chandra).", ) parser.add_argument("parfile", help="par file to construct model from") parser.add_argument("--orbfile", help="Name of orbit file", default=None) parser.add_argument("--maxMJD", help="Maximum MJD to include in analysis", default=None) parser.add_argument("--plotfile", help="Output figure file name (default=None)", default=None) parser.add_argument( "--addphase", help="Write FITS file with added phase column", default=False, action="store_true", ) parser.add_argument( "--addorbphase", help="Write FITS file with added orbital phase column", default=False, action="store_true", ) parser.add_argument( "--absphase", help="Write FITS file with integral portion of pulse phase (ABS_PHASE)", default=False, action="store_true", ) parser.add_argument( "--barytime", help= "Write FITS file with a column containing the barycentric time as double precision MJD.", default=False, action="store_true", ) parser.add_argument( "--outfile", help="Output FITS file name (default=same as eventfile)", default=None, ) parser.add_argument("--ephem", help="Planetary ephemeris to use (default=DE421)", default="DE421") parser.add_argument( "--tdbmethod", help="Method for computing TT to TDB (default=astropy)", default="default", ) parser.add_argument("--plot", help="Show phaseogram plot.", action="store_true", default=False) parser.add_argument( "--use_gps", default=False, action="store_true", help="Apply GPS to UTC clock corrections", ) parser.add_argument( "--use_bipm", default=False, action="store_true", help="Use TT(BIPM) instead of TT(TAI)", ) # parser.add_argument("--fix",help="Apply 1.0 second offset for NICER", action='store_true', default=False) args = parser.parse_args(argv) # If outfile is specified, that implies addphase if args.outfile is not None: args.addphase = True # If plotfile is specified, that implies plot if args.plotfile is not None: args.plot = True # Read event file header to figure out what instrument is is from hdr = pyfits.getheader(args.eventfile, ext=1) log.info("Event file TELESCOPE = {0}, INSTRUMENT = {1}".format( hdr["TELESCOP"], hdr["INSTRUME"])) if hdr["TELESCOP"] == "NICER": # Instantiate NICERObs once so it gets added to the observatory registry if args.orbfile is not None: log.info("Setting up NICER observatory") NICERObs(name="NICER", FPorbname=args.orbfile, tt2tdb_mode="pint") # Read event file and return list of TOA objects try: tl = load_NICER_TOAs(args.eventfile) except KeyError: log.error( "Observatory not recognized. This probably means you need to provide an orbit file or barycenter the event file." ) sys.exit(1) elif hdr["TELESCOP"] == "XTE": # Instantiate RXTEObs once so it gets added to the observatory registry if args.orbfile is not None: # Determine what observatory type is. log.info("Setting up RXTE observatory") RXTEObs(name="RXTE", FPorbname=args.orbfile, tt2tdb_mode="pint") # Read event file and return list of TOA objects tl = load_RXTE_TOAs(args.eventfile) elif hdr["TELESCOP"].startswith("XMM"): # Not loading orbit file here, since that is not yet supported. tl = load_XMM_TOAs(args.eventfile) elif hdr["TELESCOP"].lower().startswith("nustar"): if args.orbfile is not None: log.info("Setting up NuSTAR observatory") NuSTARObs(name="NuSTAR", FPorbname=args.orbfile, tt2tdb_mode="pint") tl = load_NuSTAR_TOAs(args.eventfile) else: log.error( "FITS file not recognized, TELESCOPE = {0}, INSTRUMENT = {1}". format(hdr["TELESCOP"], hdr["INSTRUME"])) sys.exit(1) # Now convert to TOAs object and compute TDBs and posvels if len(tl) == 0: log.error("No TOAs, exiting!") sys.exit(0) # Read in model modelin = pint.models.get_model(args.parfile) use_planets = False if "PLANET_SHAPIRO" in modelin.params: if modelin.PLANET_SHAPIRO.value: use_planets = True if "AbsPhase" not in modelin.components: log.error( "TimingModel does not include AbsPhase component, which is required " "for computing phases. Make sure you have TZR* parameters in your par file!" ) raise ValueError("Model missing AbsPhase component.") if args.addorbphase and (not hasattr(modelin, "binary_model_name")): log.error( "TimingModel does not include a binary model, which is required for " "computing orbital phases. Make sure you have BINARY and associated " "model parameters in your par file!") raise ValueError("Model missing BINARY component.") # Discard events outside of MJD range if args.maxMJD is not None: tlnew = [] print("pre len : ", len(tl)) maxT = Time(float(args.maxMJD), format="mjd") print("maxT : ", maxT) for tt in tl: if tt.mjd < maxT: tlnew.append(tt) tl = tlnew print("post len : ", len(tlnew)) ts = toa.get_TOAs_list( tl, ephem=args.ephem, include_bipm=args.use_bipm, include_gps=args.use_gps, planets=use_planets, tdb_method=args.tdbmethod, ) ts.filename = args.eventfile # if args.fix: # ts.adjust_TOAs(TimeDelta(np.ones(len(ts.table))*-1.0*u.s,scale='tt')) print(ts.get_summary()) mjds = ts.get_mjds() print(mjds.min(), mjds.max()) # Compute model phase for each TOA iphss, phss = modelin.phase(ts, abs_phase=True) # ensure all postive negmask = phss < 0.0 phases = np.where(negmask, phss + 1.0, phss) h = float(hm(phases)) print("Htest : {0:.2f} ({1:.2f} sigma)".format(h, h2sig(h))) if args.plot: phaseogram_binned(mjds, phases, bins=100, plotfile=args.plotfile) # Compute orbital phases for each photon TOA if args.addorbphase: delay = modelin.delay(ts) orbits = modelin.binary_instance.orbits() # These lines are already in orbits.orbit_phase() in binary_orbits.py. # What is the correct syntax is to call this function here? norbits = np.array(np.floor(orbits), dtype=np.long) orbphases = orbits - norbits # fractional phase if args.addphase or args.addorbphase: # Read input FITS file (again). # If overwriting, open in 'update' mode if args.outfile is None: hdulist = pyfits.open(args.eventfile, mode="update") else: hdulist = pyfits.open(args.eventfile) datacol = [] data_to_add = {} if args.addphase: if len(hdulist[1].data) != len(phases): raise RuntimeError( "Mismatch between length of FITS table ({0}) and length of phase array ({1})!" .format(len(hdulist[1].data), len(phases))) data_to_add["PULSE_PHASE"] = [phases, "D"] if args.absphase: data_to_add["ABS_PHASE"] = [iphss - negmask, "K"] if args.barytime: bats = modelin.get_barycentric_toas(ts) data_to_add["BARY_TIME"] = [bats, "D"] if args.addorbphase: if len(hdulist[1].data) != len(orbphases): raise RuntimeError( "Mismatch between length of FITS table ({0}) and length of orbital phase array ({1})!" .format(len(hdulist[1].data), len(orbphases))) data_to_add["ORBIT_PHASE"] = [orbphases, "D"] # End if args.addorbphase for key in data_to_add.keys(): if key in hdulist[1].columns.names: log.info("Found existing %s column, overwriting..." % key) # Overwrite values in existing Column hdulist[1].data[key] = data_to_add[key][0] else: # Construct and append new column, preserving HDU header and name log.info("Adding new %s column." % key) datacol.append( pyfits.ColDefs([ pyfits.Column( name=key, format=data_to_add[key][1], array=data_to_add[key][0], ) ])) if len(datacol) > 0: cols = hdulist[1].columns for c in datacol: cols = cols + c bt = pyfits.BinTableHDU.from_columns(cols, header=hdulist[1].header, name=hdulist[1].name) hdulist[1] = bt if args.outfile is None: # Overwrite the existing file log.info("Overwriting existing FITS file " + args.eventfile) hdulist.flush(verbose=True, output_verify="warn") else: # Write to new output file log.info("Writing output FITS file " + args.outfile) hdulist.writeto(args.outfile, overwrite=True, checksum=True, output_verify="warn")
def main(argv=None): parser = argparse.ArgumentParser( description="PINT tool for command-line barycentering calculations.") parser.add_argument("time", help="MJD (UTC, by default)") parser.add_argument( "--timescale", default="utc", help="Time scale for MJD argument ('utc', 'tt', 'tdb'), default=utc", ) parser.add_argument( "--format", help= ("Format for time argument ('mjd' or any astropy.Time format " "(e.g. 'isot'), see <http://docs.astropy.org/en/stable/time/#time-format>)" ), default="mjd", ) parser.add_argument("--freq", type=float, default=np.inf, help="Frequency to use, MHz") parser.add_argument("--obs", default="Geocenter", help="Observatory code (default = Geocenter)") parser.add_argument("--parfile", help="par file to read model from", default=None) parser.add_argument( "--ra", help="RA to use (e.g. '12h22m33.2s' if not read from par file)") parser.add_argument( "--dec", help="Decl. to use (e.g. '19d21m44.2s' if not read from par file)") parser.add_argument("--dm", help="DM to use (if not read from par file)", type=float, default=0.0) parser.add_argument("--ephem", default="DE421", help="Ephemeris to use") parser.add_argument( "--use_gps", default=False, action="store_true", help="Apply GPS to UTC clock corrections", ) parser.add_argument( "--use_bipm", default=False, action="store_true", help="Use TT(BIPM) instead of TT(TAI)", ) args = parser.parse_args(argv) if args.format in ("mjd", "jd", "unix"): # These formats require conversion from string to long double first fmt = args.format # Never allow format == 'mjd' because it fails when scale is 'utc' # Change 'mjd' to 'pulsar_mjd' to deal with this. if fmt == "mjd": fmt = "pulsar_mjd" t = Time(np.longdouble(args.time), scale=args.timescale, format=fmt, precision=9) print(t) else: t = Time(args.time, scale=args.timescale, format=args.format, precision=9) log.debug(t.iso) t = toa.TOA(t, freq=args.freq, obs=args.obs) # Build TOAs and compute TDBs and positions from ephemeris ts = toa.get_TOAs_list( [t], ephem=args.ephem, include_bipm=args.use_bipm, include_gps=args.use_gps, planets=False, ) if args.parfile is not None: m = pint.models.get_model(args.parfile) else: # Construct model by hand m = pint.models.StandardTimingModel # Should check if 12:13:14.2 syntax is used and support that as well! m.RAJ.quantity = Angle(args.ra) m.DECJ.quantity = Angle(args.dec) m.DM.quantity = args.dm * u.parsec / u.cm**3 tdbtimes = m.get_barycentric_toas(ts) print("{0:.16f}".format(tdbtimes[0].value)) return
def year(self): """ Return the decimal year for all the TOAs of this pulsar """ t = Time(self.selected_toas.get_mjds(), format="mjd") return (t.decimalyear) * u.year