def load_Fermi_TOAs(ft1name,weightcolumn=None,targetcoord=None,logeref=4.1, logesig=0.5,minweight=0.0, minmjd=0.0, maxmjd=np.inf): ''' TOAlist = load_Fermi_TOAs(ft1name) Read photon event times out of a Fermi FT1 file and return a list of PINT TOA objects. Correctly handles raw FT1 files, or ones processed with gtbary to have barycentered or geocentered TOAs. weightcolumn specifies the FITS column name to read the photon weights from. The special value 'CALC' causes the weights to be computed empirically as in Philippe Bruel's SearchPulsation code. logeref and logesig are parameters for the weight computation and are only used when weightcolumn='CALC'. When weights are loaded, or computed, events are filtered by weight >= minweight ''' import astropy.io.fits as pyfits # Load photon times from FT1 file hdulist = pyfits.open(ft1name) ft1hdr=hdulist[1].header ft1dat=hdulist[1].data # TIMESYS will be 'TT' for unmodified Fermi LAT events (or geocentered), and # 'TDB' for events barycentered with gtbary # TIMEREF will be 'GEOCENTER' for geocentered events, # 'SOLARSYSTEM' for barycentered, # and 'LOCAL' for unmodified events timesys = ft1hdr['TIMESYS'] log.info("TIMESYS {0}".format(timesys)) timeref = ft1hdr['TIMEREF'] log.info("TIMEREF {0}".format(timeref)) # Read time column from FITS file mjds = read_fits_event_mjds_tuples(hdulist[1]) if len(mjds) == 0: log.error('No MJDs read from file!') raise energies = ft1dat.field('ENERGY')*u.MeV if weightcolumn is not None: if weightcolumn == 'CALC': photoncoords = SkyCoord(ft1dat.field('RA')*u.degree,ft1dat.field('DEC')*u.degree,frame='icrs') weights = calc_lat_weights(ft1dat.field('ENERGY'), photoncoords.separation(targetcoord), logeref=logeref, logesig=logesig) else: weights = ft1dat.field(weightcolumn) if minweight > 0.0: idx = np.where(weights>minweight)[0] mjds = mjds[idx] energies = energies[idx] weights = weights[idx] # limit the TOAs to ones in selected MJD range mjds_float = np.array([r[0] + r[1] for r in mjds]) idx = np.logical_and((mjds_float > minmjd),(mjds_float < maxmjd)) mjds = mjds[idx] energies = energies[idx] if weightcolumn is not None: weights = weights[idx] if timesys == 'TDB': log.info("Building barycentered TOAs") if weightcolumn is None: toalist=[toa.TOA(m,obs='Barycenter',scale='tdb',energy=e) for m,e in zip(mjds,energies)] else: toalist=[toa.TOA(m,obs='Barycenter',scale='tdb',energy=e,weight=w) for m,e,w in zip(mjds,energies,weights)] else: if timeref == 'LOCAL': log.info('Building spacecraft local TOAs, with MJDs in range {0} to {1}'.format(mjds[0],mjds[-1])) assert timesys == 'TT' fermiobs = get_observatory('Fermi') try: if weightcolumn is None: toalist=[toa.TOA(m, obs='Fermi', scale='tt',energy=e) for m,e in zip(mjds,energies)] else: toalist=[toa.TOA(m, obs='Fermi', scale='tt',energy=e,weight=w) for m,e,w in zip(mjds,energies,weights)] except KeyError: log.error('Error processing Fermi TOAs. You may have forgotten to specify an FT2 file with --ft2') raise else: log.info("Building geocentered TOAs") if weightcolumn is None: toalist=[toa.TOA(m, obs='Geocenter', scale='tt',energy=e) for m,e in zip(mjds,energies)] else: toalist=[toa.TOA(m, obs='Geocenter', scale='tt',energy=e,weight=w) for m,e,w in zip(mjds,energies,weights)] return toalist
def load_Fermi_TOAs(ft1name, weightcolumn=None, targetcoord=None, logeref=4.1, logesig=0.5, minweight=0.0, minmjd=0.0, maxmjd=np.inf): ''' TOAlist = load_Fermi_TOAs(ft1name) Read photon event times out of a Fermi FT1 file and return a list of PINT TOA objects. Correctly handles raw FT1 files, or ones processed with gtbary to have barycentered or geocentered TOAs. weightcolumn specifies the FITS column name to read the photon weights from. The special value 'CALC' causes the weights to be computed empirically as in Philippe Bruel's SearchPulsation code. logeref and logesig are parameters for the weight computation and are only used when weightcolumn='CALC'. When weights are loaded, or computed, events are filtered by weight >= minweight ''' import astropy.io.fits as pyfits # Load photon times from FT1 file hdulist = pyfits.open(ft1name) ft1hdr = hdulist[1].header ft1dat = hdulist[1].data # TIMESYS will be 'TT' for unmodified Fermi LAT events (or geocentered), and # 'TDB' for events barycentered with gtbary # TIMEREF will be 'GEOCENTER' for geocentered events, # 'SOLARSYSTEM' for barycentered, # and 'LOCAL' for unmodified events timesys = ft1hdr['TIMESYS'] log.info("TIMESYS {0}".format(timesys)) timeref = ft1hdr['TIMEREF'] log.info("TIMEREF {0}".format(timeref)) # Read time column from FITS file mjds = read_fits_event_mjds_tuples(hdulist[1]) if len(mjds) == 0: log.error('No MJDs read from file!') raise energies = ft1dat.field('ENERGY') * u.MeV if weightcolumn is not None: if weightcolumn == 'CALC': photoncoords = SkyCoord(ft1dat.field('RA') * u.degree, ft1dat.field('DEC') * u.degree, frame='icrs') weights = calc_lat_weights(ft1dat.field('ENERGY'), photoncoords.separation(targetcoord), logeref=logeref, logesig=logesig) else: weights = ft1dat.field(weightcolumn) if minweight > 0.0: idx = np.where(weights > minweight)[0] mjds = mjds[idx] energies = energies[idx] weights = weights[idx] # limit the TOAs to ones in selected MJD range mjds_float = np.array([r[0] + r[1] for r in mjds]) idx = np.logical_and((mjds_float > minmjd), (mjds_float < maxmjd)) mjds = mjds[idx] energies = energies[idx] if weightcolumn is not None: weights = weights[idx] if timesys == 'TDB': log.info("Building barycentered TOAs") if weightcolumn is None: toalist = [ toa.TOA(m, obs='Barycenter', scale='tdb', energy=e, error=1.0 * u.us) for m, e in zip(mjds, energies) ] else: toalist = [ toa.TOA(m, obs='Barycenter', scale='tdb', energy=e, weight=w, error=1.0 * u.us) for m, e, w in zip(mjds, energies, weights) ] else: if timeref == 'LOCAL': log.info( 'Building spacecraft local TOAs, with MJDs in range {0} to {1}' .format(mjds[0], mjds[-1])) assert timesys == 'TT' try: fermiobs = get_observatory('Fermi') except KeyError: log.error( 'Fermi observatory not defined. Make sure you have specified an FT2 file!' ) raise try: if weightcolumn is None: toalist = [ toa.TOA(m, obs='Fermi', scale='tt', energy=e, error=1.0 * u.us) for m, e in zip(mjds, energies) ] else: toalist = [ toa.TOA(m, obs='Fermi', scale='tt', energy=e, weight=w, error=1.0 * u.us) for m, e, w in zip(mjds, energies, weights) ] except KeyError: log.error( 'Error processing Fermi TOAs. You may have forgotten to specify an FT2 file with --ft2' ) raise else: log.info("Building geocentered TOAs") if weightcolumn is None: toalist = [ toa.TOA(m, obs='Geocenter', scale='tt', energy=e) for m, e in zip(mjds, energies) ] else: toalist = [ toa.TOA(m, obs='Geocenter', scale='tt', energy=e, weight=w) for m, e, w in zip(mjds, energies, weights) ] return toalist
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 load_fits_TOAs( eventname, mission, weights=None, extension=None, timesys=None, timeref=None, minmjd=-np.inf, maxmjd=np.inf, ): """ Read photon event times out of a FITS file as PINT TOA objects. Correctly handles raw event files, or ones processed with axBary to have barycentered TOAs. Different conditions may apply to different missions. The minmjd/maxmjd parameters can be used to avoid instantiation of TOAs we don't want, which can otherwise be very slow. Parameters ---------- eventname : str File name of the FITS event list mission : str Name of the mission (e.g. RXTE, XMM) weights : array or None The array has to be of the same size as the event list. Overwrites possible weight lists from mission-specific FITS files extension : str FITS extension to read timesys : str, default None Force this time system timeref : str, default None Forse this time reference minmjd : float, default "-infinity" minimum MJD timestamp to return maxmjd : float, default "infinity" maximum MJD timestamp to return Returns ------- toalist : list of TOA objects """ # Load photon times from event file hdulist = pyfits.open(eventname) if mission not in mission_config: log.warning("Mission not recognized. Using generic") mission = "generic" if (extension is not None and isinstance(extension, str) and hdulist[1].name not in extension.split(",")): raise RuntimeError( "First table in FITS file" + "must be {}. Found {}".format(extension, hdulist[1].name)) if isinstance(extension, int) and extension != 1: raise ValueError( "At the moment, only data in the first FITS extension is supported" ) if timesys is None: timesys = _get_timesys(hdulist[1]) if timeref is None: timeref = _get_timeref(hdulist[1]) check_timesys(timesys) check_timeref(timeref) if not mission_config[mission]["allow_local"] and timesys != "TDB": log.error("Raw spacecraft TOAs not yet supported for " + mission) obs, scale = _default_obs_and_scale(mission, timesys, timeref) # Read time column from FITS file mjds = read_fits_event_mjds_tuples(hdulist[1]) new_kwargs = _get_columns_from_fits( hdulist[1], mission_config[mission]["fits_columns"]) hdulist.close() if weights is not None: new_kwargs["weights"] = weights # mask out times/columns outside of mjd range mjds_float = np.asarray([r[0] + r[1] for r in mjds]) idx = (minmjd < mjds_float) & (mjds_float < maxmjd) mjds = mjds[idx] for key in new_kwargs.keys(): new_kwargs[key] = new_kwargs[key][idx] toalist = [None] * len(mjds) kw = {} for i in range(len(mjds)): # Create TOA list for key in new_kwargs.keys(): kw[key] = new_kwargs[key][i] toalist[i] = toa.TOA(mjds[i], obs=obs, scale=scale, **kw) return toalist
def load_Fermi_TOAs( ft1name, weightcolumn=None, targetcoord=None, logeref=4.1, logesig=0.5, minweight=0.0, minmjd=-np.inf, maxmjd=np.inf, fermiobs="Fermi", ): """ toalist = load_Fermi_TOAs(ft1name) Read photon event times out of a Fermi FT1 file and return a list of PINT TOA objects. Correctly handles raw FT1 files, or ones processed with gtbary to have barycentered or geocentered TOAs. Parameters ---------- weightcolumn : str Specifies the FITS column name to read the photon weights from. The special value 'CALC' causes the weights to be computed empirically as in Philippe Bruel's SearchPulsation code. targetcoord : astropy.SkyCoord Source coordinate for weight computation if weightcolumn=='CALC' logeref : float Parameter for the weight computation if weightcolumn=='CALC' logesig : float Parameter for the weight computation if weightcolumn=='CALC' minweight : float If weights are loaded or computed, exclude events with smaller weights. minmjd : float Events with earlier MJDs are excluded. maxmjd : float Events with later MJDs are excluded. fermiobs: str The default observatory name is Fermi, and must have already been registered. The user can specify another name Returns ------- toalist : list A list of TOA objects corresponding to the Fermi events. """ # Load photon times from FT1 file hdulist = fits.open(ft1name) ft1hdr = hdulist[1].header ft1dat = hdulist[1].data # TIMESYS will be 'TT' for unmodified Fermi LAT events (or geocentered), and # 'TDB' for events barycentered with gtbary # TIMEREF will be 'GEOCENTER' for geocentered events, # 'SOLARSYSTEM' for barycentered, # and 'LOCAL' for unmodified events timesys = ft1hdr["TIMESYS"] log.info("TIMESYS {0}".format(timesys)) timeref = ft1hdr["TIMEREF"] log.info("TIMEREF {0}".format(timeref)) # Read time column from FITS file mjds = read_fits_event_mjds_tuples(hdulist[1]) if len(mjds) == 0: log.error("No MJDs read from file!") raise energies = ft1dat.field("ENERGY") * u.MeV if weightcolumn is not None: if weightcolumn == "CALC": photoncoords = SkyCoord( ft1dat.field("RA") * u.degree, ft1dat.field("DEC") * u.degree, frame="icrs", ) weights = calc_lat_weights( ft1dat.field("ENERGY"), photoncoords.separation(targetcoord), logeref=logeref, logesig=logesig, ) else: weights = ft1dat.field(weightcolumn) if minweight > 0.0: idx = np.where(weights > minweight)[0] mjds = mjds[idx] energies = energies[idx] weights = weights[idx] # limit the TOAs to ones in selected MJD range mjds_float = np.asarray([r[0] + r[1] for r in mjds]) idx = (minmjd < mjds_float) & (mjds_float < maxmjd) mjds = mjds[idx] energies = energies[idx] if weightcolumn is not None: weights = weights[idx] if timesys == "TDB": log.info("Building barycentered TOAs") obs = "Barycenter" scale = "tdb" msg = "barycentric" elif (timesys == "TT") and (timeref == "LOCAL"): assert timesys == "TT" try: get_observatory(fermiobs) except KeyError: log.error( "%s observatory not defined. Make sure you have specified an FT2 file!" % fermiobs) raise obs = fermiobs scale = "tt" msg = "spacecraft local" elif (timesys == "TT") and (timeref == "GEOCENTRIC"): obs = "Geocenter" scale = "tt" msg = "geocentric" else: raise ValueError("Unrecognized TIMEREF/TIMESYS.") log.info("Building {0} TOAs, with MJDs in range {1} to {2}".format( msg, mjds[0, 0] + mjds[0, 1], mjds[-1, 0] + mjds[-1, 1])) if weightcolumn is None: toalist = [ toa.TOA(m, obs=obs, scale=scale, energy=str(e.to_value(u.MeV)), error=1.0 * u.us) for m, e in zip(mjds, energies) ] else: toalist = [ toa.TOA( m, obs=obs, scale=scale, energy=str(e.to_value(u.MeV)), weight=str(w), error=1.0 * u.us, ) for m, e, w in zip(mjds, energies, weights) ] return toalist
def load_fits_TOAs( eventname, mission, weights=None, extension=None, timesys=None, timeref=None ): """ Read photon event times out of a FITS file as PINT TOA objects. Correctly handles raw event files, or ones processed with axBary to have barycentered TOAs. Different conditions may apply to different missions. Parameters ---------- eventname : str File name of the FITS event list mission : str Name of the mission (e.g. RXTE, XMM) weights : array or None The array has to be of the same size as the event list. Overwrites possible weight lists from mission-specific FITS files extension : str FITS extension to read timesys : str, default None Force this time system timeref : str, default None Forse this time reference Returns ------- toalist : list of TOA objects """ # Load photon times from event file hdulist = pyfits.open(eventname) if extension is not None and hdulist[1].name not in extension.split(","): raise RuntimeError( "First table in FITS file" + "must be {}. Found {}".format(extension, hdulist[1].name) ) if timesys is None: timesys = _get_timesys(hdulist[1]) if timeref is None: timeref = _get_timeref(hdulist[1]) check_timesys(timesys) check_timeref(timeref) if not mission_config[mission]["allow_local"] and timesys != "TDB": log.error("Raw spacecraft TOAs not yet supported for " + mission) obs, scale = _default_obs_and_scale(mission, timesys, timeref) # Read time column from FITS file mjds = read_fits_event_mjds_tuples(hdulist[1]) new_kwargs = _get_columns_from_fits( hdulist[1], mission_config[mission]["fits_columns"] ) hdulist.close() if weights is not None: new_kwargs["weights"] = weights toalist = [None] * len(mjds) kw = {} for i in range(len(mjds)): # Create TOA list for key in new_kwargs.keys(): kw[key] = new_kwargs[key][i] toalist[i] = toa.TOA(mjds[i], obs=obs, scale=scale, **kw) return toalist