def test_process_and_accuracy(self): # Checks that instantiating an observatory and phasing of # topocentric times works. Verifies accuracy to the sub-mus # level by comparison with stored Tempo2 "Fermi plugin" results. modelin = pint.models.get_model(parfile) get_satellite_observatory("Fermi", ft2file) tl = load_Fermi_TOAs(eventfileraw, weightcolumn="PSRJ0030+0451") # ts = toa.TOAs(toalist=tl) ts = toa.get_TOAs_list(tl, include_gps=False, include_bipm=False, planets=False, ephem="DE405") iphss, phss = modelin.phase(ts, abs_phase=True) ph_pint = phss % 1 with fits.open(eventfileraw) as f: ph_tempo2 = f[1].data.field("pulse_phase") dphi = ph_pint - ph_tempo2 dphi[dphi < -0.1] += 1 dphi[dphi > 0.1] -= 1 resids_mus = dphi / modelin.F0.value * 1e6 # if the "2 mus" problem exists, the scatter in these values will # be 4-5 mus, whereas if everything is OK it should be few 100 ns # require range in TOAs to be less than 200ns self.assertTrue((resids_mus.max() - resids_mus.min()) < 0.2) # require absolute phase to be within 500 ns; NB this relies on # GBT clock corrections since the TZR is referenced there self.assertTrue(max(abs(resids_mus)) < 0.5)
def get_TZR_toa(self, toas): """Get the TOAs class for the TZRMJD. We are treating the TZRMJD as a special TOA. Note that any observatory clock corrections will be applied to this TOA, as with any other TOA. This does not affect the value of the TZRMJD parmeter, however. """ if self.tz_cache is not None: # This should also verify that the clkc_info is the same so it is valid. return self.tz_cache else: # NOTE: Using TZRMJD.quantity.jd[1,2] so that the time scale can be properly # set to the TZRSITE default timescale (e.g. UTC for TopoObs and TDB for SSB) TZR_toa = toa.TOA( (self.TZRMJD.quantity.jd1 - 2400000.5, self.TZRMJD.quantity.jd2), obs=self.TZRSITE.value, freq=self.TZRFRQ.quantity, ) clkc_info = toas.clock_corr_info tz = toa.get_TOAs_list( [TZR_toa], include_bipm=clkc_info["include_bipm"], include_gps=clkc_info["include_gps"], ephem=toas.ephem, planets=toas.planets, ) self.tz_cache = tz return tz
def test_generate_polycos(tmpdir, par_file, obs, obsfreq, nspan, ncoeff): output_polyco = tmpdir / "B1855_polyco_round_trip_from_par.dat" mjd_start, mjd_end = 55000.0, 55001.0 model = get_model(str(par_file)) p = Polycos() p.generate_polycos(model, mjd_start, mjd_end, obs, nspan, ncoeff, obsfreq) p.write_polyco_file(output_polyco) q = Polycos() q.read_polyco_file(output_polyco) mjds = np.linspace(mjd_start, mjd_end, 51) t = toa.get_TOAs_list( [toa.TOA(mjd, obs=obs, freq=obsfreq) for mjd in mjds], ephem=model.EPHEM.value) ph1 = p.eval_abs_phase(mjds) ph2 = q.eval_abs_phase(mjds) ph3 = model.phase(t, abs_phase=True) assert np.allclose(ph1.int.value[0], ph3.int.value[0]) assert np.allclose(ph1.frac.value[0], ph3.frac.value[0]) assert np.allclose(ph2.int.value[0], ph3.int.value[0]) assert np.allclose(ph2.frac.value[0], ph3.frac.value[0])
def __call__(self, time): """Create list of TOAs for one or more times. Parameters ---------- time : `~astropy.time.Time` Input time stamps. Returns ------- toas : `~pint.toa.TOAs` Combining all TOAs. """ # local import since we cannot count on PINT being present, # and doing it globally messes up sphinx. from pint import toa if time.scale == 'utc': time = time.replicate(format='pulsar_mjd') freq, _ = np.broadcast_arrays(self.frequency, time.jd1, subok=True) time = time._apply(np.broadcast_to, freq.shape) toa_list = [] for t, f in zip(time.ravel(), freq.ravel()): # This format converting should be done by PINT in the future. toa_entry = toa.TOA(t, obs=self.observatory, freq=f) toa_list.append(toa_entry) toas = toa.get_TOAs_list(toa_list, **self.control_params) toas.shape = time.shape return toas
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 longdouble 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 get_barycentric_correction(orbfile, parfile, dt=5, ephem='DE421'): no = SatelliteObs(name="NuSTAR", FPorbname=orbfile, tt2tdb_mode="pint") with fits.open(orbfile) as hdul: mjdref = high_precision_keyword_read(hdul[1].header, 'MJDREF') mjds = np.arange(no.X.x[1], no.X.x[-2], dt / 86400) mets = (mjds - mjdref) * 86400 obs, scale = 'nustar', "tt" toalist = [None] * len(mjds) for i in range(len(mjds)): # Create TOA list toalist[i] = toa.TOA(mjds[i], obs=obs, scale=scale) if parfile is not None and os.path.exists(parfile): modelin = pint.models.get_model(parfile) else: modelin = get_dummy_parfile_for_position(orbfile) ts = toa.get_TOAs_list( toalist, ephem=ephem, include_bipm=False, include_gps=False, planets=False, tdb_method='default', ) bats = modelin.get_barycentric_toas(ts) return interp1d(mets, (bats.value - mjds) * 86400, assume_sorted=True, bounds_error=False, fill_value='extrapolate', kind='quadratic')
def test_toas_read_list(): x = toa.get_TOAs("test1.tim") toas, commands = toa.read_toa_file("test1.tim") y = toa.get_TOAs_list(toas, commands=commands, filename=x.filename, hashes=x.hashes) assert x == y
def _gen_polyco(self, parfile, MJD_start, segLength = 60.0, ncoeff = 15, \ maxha=12.0, method="TEMPO", numNodes=20, usePINT = True): """ This will be a convenience function to generate polycos and subsequent parameters to replace the values in a PSRFITS file header. The default way to do this will be to use PINT (usePINT = True), with other methods currently unsupported. The input values are: parfile [string] : path to par file used to generate the polycos. The observing frequency, and observatory will come from the par file MJD_start [float] : Start MJD of the polyco. Should start no later than the beginning of the observation segLength [float] : Length in minutes of the range covered by the polycos generated. Default is 60 minutes ncoeff [int] : number of polyco coeffeicients to generate. Default is 15, the same as in the PSRFITS file maxha [float] : max hour angle needed by PINT. Default is 12.0 method [string] : Method PINT uses to generate the polyco. Currently only TEMPO is supported. numNodes [int] : Number of nodes PINT will use to fit the polycos. Must be larger than ncoeff usePINT [bool] : Method used to generate polycos. Currently only PINT is supported. """ if usePINT: # Define dictionary to put parameters into polyco_dict = {'NSPAN': segLength, 'NCOEF': ncoeff} # load parfile to PINT model object m = models.get_model(parfile) # Determine MJD_end based on segLength MJD_end = MJD_start + np.double( make_quant(segLength, 'min').to('day').value) # MJD # Determine obseratory and observing frequency obsFreq = m.TZRFRQ.value # in MHz polyco_dict['REF_FREQ'] = obsFreq obs = m.TZRSITE.value # string polyco_dict['NSITE'] = obs.encode( 'utf-8') # observatory code needs to be in binary # Get pulsar frequency polyco_dict['REF_F0'] = m.F0.value # get the polycos pcs = polycos.Polycos() pcs.generate_polycos(m, MJD_start, MJD_end, obs, segLength, ncoeff, obsFreq, maxha=12.0, method="TEMPO", \ numNodes=20) coeffs = pcs.polycoTable['entry'][-1].coeffs polyco_dict['COEFF'] = coeffs # Now we need to determine the reference MJD, and phase REF_MJD = np.double(pcs.polycoTable['tmid'][-1]) polyco_dict['REF_MJD'] = REF_MJD # Now find the phase difference tmid_toa = toa.get_TOAs_list( [toa.TOA(REF_MJD, obs=obs, freq=obsFreq)]) ref_phase = m.phase(tmid_toa) # Need to force positive value if ref_phase.frac.value[0] < 0.0: ref_frac_phase = 1.0 - abs(ref_phase.frac.value[0]) else: ref_frac_phase = ref_phase.frac.value[0] polyco_dict['REF_PHS'] = ref_frac_phase return polyco_dict else: print("Only PINT is currently supported for generating polycos") raise NotImplementedError()
def test_roundtrip_bary_toa_Tempo2format(self): # Create a barycentric TOA t1time = Time(58534.0, 0.0928602471130208, format="mjd", scale="tdb") t1 = toa.TOA(t1time, obs="Barycenter", freq=0.0) ts = toa.get_TOAs_list([t1], ephem="DE421") ts.write_TOA_file("testbary.tim", format="Tempo2") ts2 = toa.get_TOAs("testbary.tim") print(ts.table, ts2.table) assert np.abs(ts.table["mjd"][0] - ts2.table["mjd"][0]) < 1.0e-15 * u.d assert np.abs(ts.table["tdb"][0] - ts2.table["tdb"][0]) < 1.0e-15 * u.d
def test_roundtrip_topo_toa_TEMPOformat(self): # Create a barycentric TOA t1time = Time(58534.0, 0.0928602471130208, format="mjd", scale="utc") t1 = toa.TOA(t1time, obs="gbt", freq=0.0) ts = toa.get_TOAs_list([t1], ephem="DE421") ts.write_TOA_file("testtopot1.tim", format="TEMPO") ts2 = toa.get_TOAs("testtopot1.tim") print(ts.table, ts2.table) assert ts.table["mjd"][0] - ts2.table["mjd"][0] < 1.0e-15 assert ts.table["tdb"][0] - ts2.table["tdb"][0] < 1.0e-15
def __call__(self, time): """Create list of TOAs for one or more times. Parameters ---------- time : `~astropy.time.Time` Input time stamps. """ toa_list = make_toa_list(time, self.observatory, self.frequency) return toa.get_TOAs_list(toa_list, **self.control_params)
def test_roundtrip_topo_toa_TEMPOformat(tmpdir): # Create a barycentric TOA t1time = Time(58534.0, 0.0928602471130208, format="mjd", scale="utc") t1 = toa.TOA(t1time, obs="gbt", freq=0.0) ts = toa.get_TOAs_list([t1], ephem="DE421") outnm = os.path.join(tmpdir, "testtopot1.tim") ts.write_TOA_file(outnm, format="TEMPO") ts2 = toa.get_TOAs(outnm) assert np.abs(ts.table["mjd"][0] - ts2.table["mjd"][0]) < 1.0e-15 * u.d assert np.abs(ts.table["tdb"][0] - ts2.table["tdb"][0]) < 1.0e-15 * u.d
def get_TZR_toa(self, toas): """ Get the TOAs class for the TZRMJD. We are treating the TZRMJD as a special TOA. """ TZR_toa = toa.TOA(self.TZRMJD.quantity, obs=self.TZRSITE.value, freq=self.TZRFRQ.quantity) clkc_info = toas.clock_corr_info tz = toa.get_TOAs_list([ TZR_toa, ], include_bipm=clkc_info['include_bipm'], include_gps=clkc_info['include_gps'], ephem=toas.ephem, planets=toas.planets) return tz
def get_TZR_toa(self, toas): """Get the TOAs class for the TZRMJD. We are treating the TZRMJD as a special TOA. Note that any observatory clock corrections will be applied to this TOA, as with any other TOA. This does not affect the value of the TZRMJD parmeter, however. """ clkc_info = toas.clock_corr_info # If we have cached the TZR TOA and all the TZR* and clock info has not changed, then don't rebuild it if self.tz_cache is not None: if (self.tz_clkc_info["include_bipm"] == clkc_info["include_bipm"] and self.tz_clkc_info["include_gps"] == clkc_info["include_gps"] and self.tz_planets == toas.planets and self.tz_ephem == toas.ephem and self.tz_hash == hash( (self.TZRMJD.value, self.TZRSITE.value, self.TZRFRQ.value))): return self.tz_cache # Otherwise we have to build the TOA and apply clock corrections # NOTE: Using TZRMJD.quantity.jd[1,2] so that the time scale can be properly # set to the TZRSITE default timescale (e.g. UTC for TopoObs and TDB for SSB) log.debug( "Creating and dealing with the single TZR_toa for absolute phase") TZR_toa = toa.TOA( (self.TZRMJD.quantity.jd1 - 2400000.5, self.TZRMJD.quantity.jd2), obs=self.TZRSITE.value, freq=self.TZRFRQ.quantity, ) tz = toa.get_TOAs_list( [TZR_toa], include_bipm=clkc_info["include_bipm"], include_gps=clkc_info["include_gps"], ephem=toas.ephem, planets=toas.planets, ) log.debug("Done with TZR_toa") self.tz_cache = tz self.tz_hash = hash( (self.TZRMJD.value, self.TZRSITE.value, self.TZRFRQ.value)) self.tz_clkc_info = clkc_info self.tz_planets = toas.planets self.tz_ephem = toas.ephem return tz
def get_TZR_toa(self, toas): """ Get the TOAs class for the TZRMJD. We are treating the TZRMJD as a special TOA. """ # NOTE: Using TZRMJD.quantity.jd[1,2] so that the time scale can be properly # set to the TZRSITE default timescale (e.g. UTC for TopoObs and TDB for SSB) TZR_toa = toa.TOA( (self.TZRMJD.quantity.jd1 - 2400000.5, self.TZRMJD.quantity.jd2), obs=self.TZRSITE.value, freq=self.TZRFRQ.quantity) clkc_info = toas.clock_corr_info tz = toa.get_TOAs_list([ TZR_toa, ], include_bipm=clkc_info['include_bipm'], include_gps=clkc_info['include_gps'], ephem=toas.ephem, planets=toas.planets) return tz
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 = time_to_longdouble(tbl['tdb'][0] - delay[0]) else: phsepoch_ld = time_to_longdouble(self.PEPOCH.quantity) dt = ((time_to_longdouble(new_epoch) - 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 test_commenting_toas(tmpdir): # Create a barycentric TOA t1time = Time(58534.0, 0.0928602471130208, format="mjd", scale="utc") t1 = toa.TOA(t1time, obs="gbt", freq=0.0) t2 = toa.TOA(t1time, obs="gbt", freq=0.0) ts = toa.get_TOAs_list([t1, t2], ephem="DE421") assert ts.ntoas == 2 outnm = os.path.join(tmpdir, "testtopo.tim") ts.write_TOA_file(outnm) ts2 = toa.get_TOAs(outnm) assert ts2.ntoas == 2 # none should be commented ts.table[0]["flags"]["cut"] = "do_not_like" # cut flag ts.table[1]["flags"]["ignore"] = str(1) # ignore flag ts.write_TOA_file(outnm) ts3 = toa.get_TOAs(outnm) # defaut is to not comment assert ts3.ntoas == 2 # none should be commented by default ts.write_TOA_file(outnm, commentflag="cut") ts4 = toa.get_TOAs(outnm) assert ts4.ntoas == 1 # one should be commented ts.write_TOA_file(outnm, commentflag="ignore") ts5 = toa.get_TOAs(outnm) assert ts5.ntoas == 1 # one should be commented
def test_roundtrip_topo_toa_TEMPOformat(self): # Create a barycentric TOA t1time = Time(58534.0, 0.0928602471130208, format="mjd", scale="utc") t1 = toa.TOA(t1time, obs="gbt", freq=0.0) ts = toa.get_TOAs_list([t1], ephem="DE421") ts.write_TOA_file("testtopot1.tim", format="TEMPO") ts2 = toa.get_TOAs("testtopot1.tim") print(ts.table, ts2.table) assert np.abs(ts.table["mjd"][0] - ts2.table["mjd"][0]) < 1.0e-15 * u.d assert np.abs(ts.table["tdb"][0] - ts2.table["tdb"][0]) < 1.0e-15 * u.d # Comment out because TEMPO2 distro doesn't include gmrt2gps.clk so far # def test_roundtrip_gmrt_toa_Tempo2format(self): # if os.getenv("TEMPO2") is None: # pytest.skip("TEMPO2 evnironment variable is not set, can't run this test") # # Create a barycentric TOA # t1time = Time(58534.0, 0.0928602471130208, format="mjd", scale="utc") # t1 = toa.TOA(t1time, obs="gmrt", freq=0.0) # ts = toa.get_TOAs_list([t1], ephem="DE421") # ts.write_TOA_file("testgmrt.tim", format="Tempo2") # ts2 = toa.get_TOAs("testgmrt.tim") # print(ts.table, ts2.table) assert np.abs(ts.table["mjd"][0] - ts2.table["mjd"][0]) < 1.0e-15 * u.d assert np.abs(ts.table["tdb"][0] - ts2.table["tdb"][0]) < 1.0e-15 * u.d
def generate_polycos(self, model, mjdStart, mjdEnd, obs, segLength, ncoeff, obsFreq, maxha, method="TEMPO", numNodes=20): """ Generate the polyco file data file. Parameters --------- model : TimingModel TimingModel for generate the Polycos with parameters setup. mjdStart : float / nump longdouble Start time of polycos in mjd mjdEnd : float / nump longdouble Ending time of polycos in mjd obs : str Observatory code segLength : Length of polyco segement [unit: minutes] ncoeff : number of coefficents obsFreq : observing frequency maxha : Maximum hour angle method : sting optional ['TEMPO','TEMPO2',...] Default TEMPO Method to generate polycos. Now it is only support the TEMPO method. numNodes : int optional. Default 20 Number of nodes for fitting. It can not be less then the number of coefficents. Return --------- A polyco table. """ mjdStart = np.longdouble(mjdStart) * u.day mjdEnd = np.longdouble(mjdEnd) * u.day timeLength = mjdEnd - mjdStart segLength = np.longdouble(segLength) * u.min obsFreq = float(obsFreq) month = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ] # Alocate memery coeffs = np.longdouble(np.zeros(ncoeff)) entryList = [] entryIntvl = np.arange(mjdStart.value, mjdEnd.value, segLength.to('day').value) if entryIntvl[-1] < mjdEnd.value: entryIntvl = np.append(entryIntvl, mjdEnd.value) # Make sure the number of nodes is bigger then number of coeffs. if numNodes < ncoeff: numNodes = ncoeff + 1 # generate the ploynomial coefficents if method == "TEMPO": # Using tempo1 method to create polycos for i in range(len(entryIntvl) - 1): tStart = entryIntvl[i] tStop = entryIntvl[i + 1] nodes = np.linspace(tStart, tStop, numNodes) tmid = ((tStart + tStop) / 2.0) * u.day toaMid = toa.get_TOAs_list([ toa.TOA((np.modf(tmid.value)[1], np.modf(tmid.value)[0]), obs=obs, freq=obsFreq), ]) refPhase = model.phase(toaMid.table) mjdSpan = ((tStop - tStart) * u.day).to('min') # Create node toas(Time sample using TOA class) toaList = [ toa.TOA((np.modf(toaNode)[1], np.modf(toaNode)[0]), obs=obs, freq=obsFreq) for toaNode in nodes ] toas = toa.get_TOAs_list(toaList) ph = model.phase(toas.table) dt = (nodes * u.day - tmid).to('min') # Use constant rdcPhase = ph - refPhase rdcPhase = rdcPhase.int - dt.value * model.F0.value * 60.0 + rdcPhase.frac dtd = dt.value.astype(float) # Trancate to double rdcPhased = rdcPhase.astype(float) coeffs = np.polyfit(dtd, rdcPhased, ncoeff - 1) coeffs = coeffs[::-1] midTime = at.Time(int(tmid.value), np.modf(tmid.value)[0], format='mjd', scale='utc') date, hms = midTime.iso.split() yy, mm, dd = date.split('-') date = dd + '-' + month[int(mm) - 1] + '-' + yy[2:4] hms = hms.replace(':', "") entry = polycoEntry(tmid.value, mjdSpan.to('day').value, refPhase.int, refPhase.frac, model.F0.value, ncoeff, coeffs, obs) entryList.append( (model.PSR.value, date, hms, tmid.value, model.DM.value, 0.0, 0.0, 0.0, obsFreq, entry)) pTable = table.Table(rows=entryList, names=('psr', 'date', 'utc', 'tmid', 'dm', 'dopper', 'logrms', 'binary_phase', 'obsfreq', 'entry'), meta={'name': 'Ployco Data Table'}) self.polycoTable = pTable else: # Reading from an old polycofile pass
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( "--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'].startswith('NuSTAR'): # Not loading orbit file here, since that is not yet supported. 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 # 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 * u.cycle phases = np.where(negmask, phss + 1.0 * u.cycle, 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) 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) 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 * u.cycle, 'K'] if args.barytime: bats = modelin.get_barycentric_toas(ts) data_to_add['BARY_TIME'] = [bats, 'D'] datacol = [] 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 d_phase_d_toa(self, toas, time_intval = 60 ,method = None, num_sample = 20, order = 11): """Return the derivative of phase wrt TOA time_intval: is in seconds method: with finite difference and chebyshev interpolation """ d_phase_d_toa = np.zeros(len(toas)) if method is None or "FDM": # Using finite difference to calculate the derivitve dt = np.longdouble(time_intval)/np.longdouble(num_sample) num_sample = int(num_sample)/2*2+1 for i,singal_toa in enumerate(toas): toa_utc_ld = utils.time_to_longdouble(singal_toa['mjd']) # Resample the toa points domain = (toa_utc_ld-time_intval/2.0,toa_utc_ld+time_intval/2.0) sample = np.linspace(domain[0],domain[1],num_sample) toa_list = [] for sample_time in sample: toa_list.append(toa.TOA((np.modf(sample_time)[1], np.modf(sample_time)[0]),obs = singal_toa['obs'], freq = singal_toa['freq'])) sample_toalist = toa.get_TOAs_list(toa_list) ph = self.phase(sample_toalist.table) p = ph.int-ph.int.min()+ph.frac p = np.array(p,dtype='float64') # Reduce the value of samples in order to use double precision reduce_samepl = np.array((sample-sample.min())*86400.0,dtype = 'float64') dx = np.gradient(reduce_samepl) dp = np.gradient(p-p.mean(),dx) d_phase_d_toa[i] = dp[num_sample/2] if method is "chebyshev": # Using chebyshev interpolation to calculate the for i,singal_toa in enumerate(toas): # Have more sample point around toa toa_utc_ld = utils.time_to_longdouble(singal_toa['mjd']) domain = (toa_utc_ld-time_intval/2.0,toa_utc_ld+time_intval/2.0) sample = np.linspace(domain[0],domain[1],num_sample) toa_list = [] for sample_time in sample: toa_list.append(toa.TOA((np.modf(sample_time)[1], np.modf(sample_time)[0]),obs = singal_toa['obs'], freq = singal_toa['freq'])) sample_toalist = toa.get_TOAs_list(toa_list) # Calculate phase ph = self.phase(sample_toalist.table) p = ph.int-ph.int.min()+ph.frac p = np.array(p,dtype='float64') # reduce the phase value to use double precision reduce_samepl = np.array((sample-sample.min())*86400.0,dtype = 'float64') coeff = np.polynomial.chebyshev.chebfit(reduce_samepl, p,order) dcoeff = np.polynomial.chebyshev.chebder(coeff) dy = np.polynomial.chebyshev.chebval(reduce_samepl,dcoeff) d_phase_d_toa[i] = dy[num_sample/2] return d_phase_d_toa
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): 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("--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 # 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 * u.cycle phases = np.where(negmask, phss + 1.0 * u.cycle, 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) 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) 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*u.cycle,'K'] if args.barytime: bats = modelin.get_barycentric_toas(ts) data_to_add['BARY_TIME'] = [bats,'D'] datacol = [] 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= "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 generate_polycos( self, model, mjdStart, mjdEnd, obs, segLength, ncoeff, obsFreq, maxha=12.0, method="TEMPO", numNodes=20, ): """ Generate the polyco data. Parameters --------- model : TimingModel TimingModel to generate the Polycos with parameters setup. mjdStart : float / nump longdouble Start time of polycos in mjd mjdEnd : float / nump longdouble Ending time of polycos in mjd obs : str Observatory code segLength : float Length of polyco segement [unit: minutes] ncoeff : int number of coefficents obsFreq : float observing frequency [unit: MHz] maxha : float optional. Default 12.0 Maximum hour angle method : string optional ['TEMPO','TEMPO2',...] Default TEMPO Method to generate polycos. Only the TEMPO method is supported for now. numNodes : int optional. Default 20 Number of nodes for fitting. It cannot be less then the number of coefficents. Return --------- A polyco table. """ mjdStart = data2longdouble(mjdStart) * u.day mjdEnd = data2longdouble(mjdEnd) * u.day timeLength = mjdEnd - mjdStart segLength = data2longdouble(segLength) * u.min obsFreq = float(obsFreq) month = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ] # Alocate memery coeffs = data2longdouble(np.zeros(ncoeff)) entryList = [] entryIntvl = np.arange(mjdStart.value, mjdEnd.value, segLength.to("day").value) if entryIntvl[-1] < mjdEnd.value: entryIntvl = np.append(entryIntvl, mjdEnd.value) # Make sure the number of nodes is bigger then number of coeffs. if numNodes < ncoeff: numNodes = ncoeff + 1 # generate the ploynomial coefficents if method == "TEMPO": # Using tempo1 method to create polycos for i in range(len(entryIntvl) - 1): tStart = entryIntvl[i] tStop = entryIntvl[i + 1] nodes = np.linspace(tStart, tStop, numNodes) tmid = ((tStart + tStop) / 2.0) * u.day toaMid = toa.get_TOAs_list([ toa.TOA( (np.modf(tmid.value)[1], np.modf(tmid.value)[0]), obs=obs, freq=obsFreq, ) ]) refPhase = model.phase(toaMid) mjdSpan = ((tStop - tStart) * u.day).to("min") # Create node toas(Time sample using TOA class) toaList = [ toa.TOA( (np.modf(toaNode)[1], np.modf(toaNode)[0]), obs=obs, freq=obsFreq, ) for toaNode in nodes ] toas = toa.get_TOAs_list(toaList) ph = model.phase(toas) dt = (nodes * u.day - tmid).to("min") # Use constant rdcPhase = ph - refPhase rdcPhase = (rdcPhase.int - (dt.value * model.F0.value * 60.0) * u.cycle + rdcPhase.frac) dtd = dt.value.astype(float) # Truncate to double rdcPhased = rdcPhase.astype(float) coeffs = np.polyfit(dtd, rdcPhased, ncoeff - 1) coeffs = coeffs[::-1] midTime = Time(int(tmid.value), np.modf(tmid.value)[0], format="mjd", scale="utc") date, hms = midTime.iso.split() yy, mm, dd = date.split("-") date = dd + "-" + month[int(mm) - 1] + "-" + yy[2:4] hms = hms.replace(":", "") entry = PolycoEntry( tmid.value, mjdSpan.to("day").value, refPhase.int, refPhase.frac, model.F0.value, ncoeff, coeffs, obs, ) entryList.append(( model.PSR.value, date, hms, tmid.value, model.DM.value, 0.0, 0.0, 0.0, mjdSpan.to("day").value, tStart, tStop, obs, obsFreq, entry, )) pTable = table.Table( rows=entryList, names=( "psr", "date", "utc", "tmid", "dm", "doppler", "logrms", "binary_phase", "mjd_span", "t_start", "t_stop", "obs", "obsfreq", "entry", ), meta={"name": "Polyco Data Table"}, ) self.polycoTable = pTable if len(self.polycoTable) == 0: raise ValueError("Zero polycos found for table") else: # Reading from an old polycofile pass
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 main(argv=None): import argparse parser = argparse.ArgumentParser( description= "Use PINT to compute event phases and make plots of photon event files.", formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) 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("--minMJD", help="Minimum MJD to include in analysis", default=None) parser.add_argument("--plotfile", help="Output figure file name", 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") 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( "--log-level", type=str, choices=("TRACE", "DEBUG", "INFO", "WARNING", "ERROR"), default="WARNING", help="Logging level", dest="loglevel", ) # parser.add_argument("--fix",help="Apply 1.0 second offset for NICER", action='store_true', default=False) parser.add_argument( "--polycos", default=False, action="store_true", help= "Use polycos to calculate phases; use when working with very large event files", ) args = parser.parse_args(argv) log.remove() log.add( sys.stderr, level=args.loglevel, colorize=True, format=pint.logging.format, filter=pint.logging.LogFilter(), ) # 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 # set MJD ranges maxmjd = np.inf if (args.maxMJD is None) else float(args.maxMJD) minmjd = 0.0 if (args.minMJD is None) else float(args.minMJD) # 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"])) telescope = hdr["TELESCOP"].lower() # Instantiate observatory once so it gets added to the observatory registry if args.orbfile is not None: log.info(f"Setting up {telescope.upper()} observatory") try: get_satellite_observatory(telescope, args.orbfile) except Exception: log.error( "The orbit file is not recognized. It is likely that this mission is not supported. " "Please barycenter the event file using the official mission tools before processing with PINT" ) # Read event file and return list of TOA objects, if not using polycos if args.polycos == False: try: tl = load_event_TOAs(args.eventfile, telescope, minmjd=minmjd, maxmjd=maxmjd) 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) # 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.") # Use polycos to calculate pulse phases if args.polycos: log.info("Using polycos to get pulse phases.") if args.addorbphase: raise ValueError("Cannot use orbphase with polycos.") # Polycos parameters segLength = 120 # in minutes ncoeff = 10 obsfreq = 0 # Open event file and get start and end mjds hdulist = pyfits.open(args.eventfile) data = hdulist[1].data mjds = read_fits_event_mjds(hdulist[1]) minmjd = min(mjds) maxmjd = max(mjds) # Check if event file is barycentered if hdulist[1].header["TIMESYS"] != "TDB": raise ValueError( "The event file has not been barycentered. Polycos can only be used with barycentered data." ) # Create polycos table log.debug("Generating polycos") telescope_n = "@" p = polycos.Polycos() ptable = p.generate_polycos(modelin, minmjd, maxmjd, telescope_n, segLength, ncoeff, obsfreq) # Calculate phases log.debug("Evaluating polycos") phases = p.eval_phase(mjds) phases[phases < 0] += 1.0 h = float(hm(phases)) print("Htest : {0:.2f} ({1:.2f} sigma)".format(h, h2sig(h))) else: # Normal mode, not polycos 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) phases = phss.value % 1 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=int) 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 = {} # Handle case where minMJD/maxMJD do not exceed length of events mjds_float = read_fits_event_mjds(hdulist[1]) time_mask = np.logical_and((mjds_float > minmjd), (mjds_float < maxmjd)) if args.polycos: time_mask = np.logical_and((mjds_float >= minmjd), (mjds_float <= maxmjd)) if args.addphase: if time_mask.sum() != len(phases): raise RuntimeError( "Mismatch between data selection {0} and length of phase array ({1})!" .format(time_mask.sum(), len(phases))) data_to_add["PULSE_PHASE"] = [phases, "D"] if args.absphase: data_to_add["ABS_PHASE"] = [iphss, "K"] if args.barytime: bats = modelin.get_barycentric_toas(ts) data_to_add["BARY_TIME"] = [bats, "D"] if args.addorbphase: if time_mask.sum() != len(orbphases): raise RuntimeError( "Mismatch between data selection ({0}) and length of orbital phase array ({1})!" .format(time_mask.sum(), 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][time_mask] = data_to_add[key][0] else: # Construct and append new column, preserving HDU header and name log.info("Adding new %s column." % key) new_dat = np.full(time_mask.shape, -1, dtype=data_to_add[key][0].dtype) new_dat[time_mask] = data_to_add[key][0] datacol.append( pyfits.ColDefs([ pyfits.Column(name=key, format=data_to_add[key][1], array=new_dat) ])) 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 generate_polycos( self, model, mjdStart, mjdEnd, obs, segLength, ncoeff, obsFreq, maxha=12.0, method="TEMPO", numNodes=20, ): """ Generate the polyco data. Parameters ---------- model : TimingModel TimingModel to generate the Polycos with parameters setup. mjdStart : float / numpy longdouble Start time of polycos in mjd mjdEnd : float / numpy longdouble Ending time of polycos in mjd obs : str Observatory code segLength : int Length of polyco segement [minutes] ncoeff : int Number of coefficents obsFreq : float Observing frequency [MHz] maxha : float optional. Default 12.0 Maximum hour angle. Only 12.0 is supported for now. method : string optional ["TEMPO", "TEMPO2", ...] Default TEMPO Method to generate polycos. Only the TEMPO method is supported for now. numNodes : int optional. Default 20 Number of nodes for fitting. It cannot be less then the number of coefficents. Return --------- A polyco table. """ mjdStart = data2longdouble(mjdStart) mjdEnd = data2longdouble(mjdEnd) segLength = int(segLength) obsFreq = float(obsFreq) # Use the planetary ephemeris specified in the model, if available. if model.EPHEM.value is not None: ephem = model.EPHEM.value else: log.info( "No ephemeris specified in model, using DE421 to generate polycos" ) ephem = "DE421" if maxha != 12.0: raise ValueError("Maximum hour angle != 12.0 is not supported.") # Make sure the number of nodes is bigger than number of coeffs. if numNodes < ncoeff: numNodes = ncoeff + 1 mjdSpan = data2longdouble(segLength / MIN_PER_DAY) # Generate "nice" MJDs for consistency with what tempo2 does tmids = np.arange( int(mjdStart * 24) * 60, int(mjdEnd * 24) * 60 + segLength, segLength) tmids = data2longdouble(tmids) / MIN_PER_DAY # generate the ploynomial coefficents if method == "TEMPO": entryList = [] # Using tempo1 method to create polycos # If you want to disable the progress bar, add disable=True to the tqdm() call. for tmid in tqdm(tmids): tStart = tmid - mjdSpan / 2 tStop = tmid + mjdSpan / 2 nodes = np.linspace(tStart, tStop, numNodes) toaMid = toa.get_TOAs_list( [ toa.TOA((np.modf(tmid)[1], np.modf(tmid)[0]), obs=obs, freq=obsFreq) ], ephem=ephem, ) refPhase = model.phase(toaMid, abs_phase=True) # Create node toas(Time sample using TOA class) toaList = [ toa.TOA( (np.modf(toaNode)[1], np.modf(toaNode)[0]), obs=obs, freq=obsFreq, ) for toaNode in nodes ] toas = toa.get_TOAs_list(toaList, ephem=ephem) ph = model.phase(toas, abs_phase=True) dt = (nodes - tmid) * MIN_PER_DAY rdcPhase = ph - refPhase rdcPhase = rdcPhase.int - (dt * model.F0.value * 60.0) + rdcPhase.frac dtd = dt.astype(float) # Truncate to double rdcPhased = rdcPhase.astype(float) coeffs = np.polyfit(dtd, rdcPhased, ncoeff - 1)[::-1] date, hms = Time(tmid, format="mjd", scale="utc").iso.split() yy, mm, dd = date.split("-") date = dd + "-" + MONTHS[int(mm) - 1] + "-" + yy[-2:] hms = float(hms.replace(":", "")) entry = PolycoEntry( tmid, segLength, refPhase.int, refPhase.frac, model.F0.value, ncoeff, coeffs, ) entry_dict = OrderedDict() entry_dict["psr"] = model.PSR.value entry_dict["date"] = date entry_dict["utc"] = hms entry_dict["tmid"] = tmid entry_dict["dm"] = model.DM.value entry_dict["doppler"] = 0.0 entry_dict["logrms"] = 0.0 entry_dict["mjd_span"] = segLength entry_dict["t_start"] = entry.tstart entry_dict["t_stop"] = entry.tstop entry_dict["obs"] = obs entry_dict["obsfreq"] = obsFreq if model.is_binary: binphase = model.orbital_phase(toaMid, radians=False)[0] entry_dict["binary_phase"] = binphase b = model.get_components_by_category()["pulsar_system"][0] entry_dict["f_orbit"] = 1 / b.PB.value entry_dict["entry"] = entry entryList.append(entry_dict) pTable = table.Table(entryList, meta={"name": "Polyco Data Table"}) self.polycoTable = pTable if len(self.polycoTable) == 0: raise ValueError("Zero polycos found for table") else: raise NotImplementedError( "Only TEMPO method has been implemented.")
def d_phase_d_toa(self, toas, time_intval=60, method=None, num_sample=20, order=11): """Return the derivative of phase wrt TOA time_intval: is in seconds method: with finite difference and chebyshev interpolation """ d_phase_d_toa = np.zeros(len(toas)) if method is None or "FDM": # Using finite difference to calculate the derivitve dt = np.longdouble(time_intval) / np.longdouble(num_sample) num_sample = int(num_sample) / 2 * 2 + 1 for i, singal_toa in enumerate(toas): toa_utc_ld = utils.time_to_longdouble(singal_toa['mjd']) # Resample the toa points domain = (toa_utc_ld - time_intval / 2.0, toa_utc_ld + time_intval / 2.0) sample = np.linspace(domain[0], domain[1], num_sample) toa_list = [] for sample_time in sample: toa_list.append( toa.TOA( (np.modf(sample_time)[1], np.modf(sample_time)[0]), obs=singal_toa['obs'], freq=singal_toa['freq'])) sample_toalist = toa.get_TOAs_list(toa_list) ph = self.phase(sample_toalist.table) p = ph.int - ph.int.min() + ph.frac p = np.array(p, dtype='float64') # Reduce the value of samples in order to use double precision reduce_samepl = np.array((sample - sample.min()) * 86400.0, dtype='float64') dx = np.gradient(reduce_samepl) dp = np.gradient(p - p.mean(), dx) d_phase_d_toa[i] = dp[num_sample / 2] if method is "chebyshev": # Using chebyshev interpolation to calculate the for i, singal_toa in enumerate(toas): # Have more sample point around toa toa_utc_ld = utils.time_to_longdouble(singal_toa['mjd']) domain = (toa_utc_ld - time_intval / 2.0, toa_utc_ld + time_intval / 2.0) sample = np.linspace(domain[0], domain[1], num_sample) toa_list = [] for sample_time in sample: toa_list.append( toa.TOA( (np.modf(sample_time)[1], np.modf(sample_time)[0]), obs=singal_toa['obs'], freq=singal_toa['freq'])) sample_toalist = toa.get_TOAs_list(toa_list) # Calculate phase ph = self.phase(sample_toalist.table) p = ph.int - ph.int.min() + ph.frac p = np.array(p, dtype='float64') # reduce the phase value to use double precision reduce_samepl = np.array((sample - sample.min()) * 86400.0, dtype='float64') coeff = np.polynomial.chebyshev.chebfit( reduce_samepl, p, order) dcoeff = np.polynomial.chebyshev.chebder(coeff) dy = np.polynomial.chebyshev.chebval(reduce_samepl, dcoeff) d_phase_d_toa[i] = dy[num_sample / 2] return d_phase_d_toa
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("--minMJD", help="Minimum 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 Fermi observatory once so it gets added to the observatory registry get_satellite_observatory("Fermi", args.ft2) # Read event file and return list of TOA objects maxmjd = np.inf if (args.maxMJD is None) else float(args.maxMJD) minmjd = 0.0 if (args.minMJD is None) else float(args.minMJD) tl = load_Fermi_TOAs( args.eventfile, maxmjd=maxmjd, minmjd=minmjd, weightcolumn=args.weightcol, targetcoord=tc, ) # 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) phss %= 1 phases = phss.value 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 event_mjds = read_fits_event_mjds_tuples(event_hdu) mjds_float = np.asarray([r[0] + r[1] for r in event_mjds]) time_mask = np.logical_and((mjds_float > minmjd), (mjds_float < maxmjd)) new_phases = np.full(len(event_dat), -1, dtype=float) new_phases[time_mask] = 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"] = new_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=new_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 generate_polycos(self, model, mjdStart, mjdEnd, obs, segLength, ncoeff, obsFreq, maxha, method = "TEMPO",numNodes = 20): """ Generate the polyco file data file. Parameters --------- model : TimingModel TimingModel for generate the Polycos with parameters setup. mjdStart : float / nump longdouble Start time of polycos in mjd mjdEnd : float / nump longdouble Ending time of polycos in mjd obs : str Observatory code segLength : Length of polyco segement [unit: minutes] ncoeff : number of coefficents obsFreq : observing frequency maxha : Maximum hour angle method : sting optional ['TEMPO','TEMPO2',...] Default TEMPO Method to generate polycos. Now it is only support the TEMPO method. numNodes : int optional. Default 20 Number of nodes for fitting. It can not be less then the number of coefficents. Return --------- A polyco table. """ mjdStart = np.longdouble(mjdStart)*u.day mjdEnd = np.longdouble(mjdEnd)*u.day timeLength = mjdEnd-mjdStart segLength = np.longdouble(segLength)*u.min obsFreq = float(obsFreq) month = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug', 'Sep','Oct','Nov','Dec'] # Alocate memery coeffs = np.longdouble(np.zeros(ncoeff)) entryList = [] entryIntvl = np.arange(mjdStart.value,mjdEnd.value, segLength.to('day').value) if entryIntvl[-1] < mjdEnd.value: entryIntvl = np.append(entryIntvl, mjdEnd.value) # Make sure the number of nodes is bigger then number of coeffs. if numNodes < ncoeff: numNodes = ncoeff+1 # generate the ploynomial coefficents if method == "TEMPO": # Using tempo1 method to create polycos for i in range(len(entryIntvl)-1): tStart = entryIntvl[i] tStop = entryIntvl[i+1] nodes = np.linspace(tStart,tStop,numNodes) tmid = ((tStart+tStop)/2.0)*u.day toaMid = toa.get_TOAs_list([toa.TOA((np.modf(tmid.value)[1], np.modf(tmid.value)[0]),obs = obs, freq = obsFreq),]) refPhase = model.phase(toaMid.table) mjdSpan = ((tStop-tStart)*u.day).to('min') # Create node toas(Time sample using TOA class) toaList = [toa.TOA((np.modf(toaNode)[1], np.modf(toaNode)[0]),obs = obs, freq = obsFreq) for toaNode in nodes] toas = toa.get_TOAs_list(toaList) ph = model.phase(toas.table) dt = (nodes*u.day - tmid).to('min') # Use constant rdcPhase = ph-refPhase rdcPhase = rdcPhase.int-dt.value*model.F0.value*60.0+rdcPhase.frac dtd = dt.value.astype(float) # Trancate to double rdcPhased = rdcPhase.astype(float) coeffs = np.polyfit(dtd,rdcPhased,ncoeff-1) coeffs = coeffs[::-1] midTime = at.Time(int(tmid.value),np.modf(tmid.value)[0], format = 'mjd',scale = 'utc') date,hms = midTime.iso.split() yy,mm,dd = date.split('-') date = dd+'-'+month[int(mm)-1]+'-'+yy[2:4] hms = hms.replace(':',"") entry = polycoEntry(tmid.value,mjdSpan.to('day').value, refPhase.int,refPhase.frac, model.F0.value, ncoeff, coeffs,obs) entryList.append((model.PSR.value, date, hms, tmid.value, model.DM.value,0.0,0.0,0.0,obsFreq,entry)) pTable = table.Table(rows = entryList, names = ('psr','date','utc', 'tmid','dm','dopper','logrms','binary_phase', 'obsfreq','entry'), meta={'name': 'Ployco Data Table'}) self.polycoTable = pTable else: # Reading from an old polycofile pass