def evalfreq(self, t): """Return the freq at time t, computed with this polyco entry""" dt = (data2longdouble(t) - self.tmid.value) * MIN_PER_DAY s = data2longdouble(0.0) for i in range(1, self.ncoeff): s += data2longdouble(i) * self.coeffs[i] * dt**(i - 1) freq = self.f0 + s / 60.0 return freq
def __init__(self, tmid, mjdspan, rph_int, rph_frac, f0, ncoeff, coeffs): self.tmid = data2longdouble(tmid) * u.day self.mjdspan = data2longdouble(mjdspan / MIN_PER_DAY) * u.day self.tstart = self.tmid - (self.mjdspan / 2) self.tstop = self.tmid + (self.mjdspan / 2) self.f0 = data2longdouble(f0) self.ncoeff = ncoeff self.rphase = Phase(rph_int, rph_frac) self.coeffs = data2longdouble(coeffs)
def evalfreqderiv(self, t): """Return the frequency derivative at time t.""" dt = (data2longdouble(t) - self.tmid.value) * MIN_PER_DAY s = data2longdouble(0.0) for i in range(2, self.ncoeff): # Change to long double s += (data2longdouble(i) * data2longdouble(i - 1) * self.coeffs[i] * dt**(i - 2)) freqd = s / (60.0 * 60.0) return freqd
def evalabsphase(self, t): """Return the phase at time t, computed with this polyco entry""" dt = (data2longdouble(t) - self.tmid.value) * data2longdouble(1440.0) # Compute polynomial by factoring out the dt's phase = Phase(self.coeffs[self.ncoeff - 1]) # Compute phase using two long double for i in range(self.ncoeff - 2, -1, -1): pI = Phase(dt * phase.int) pF = Phase(dt * phase.frac) c = Phase(self.coeffs[i]) phase = pI + pF + c # Add DC term phase += self.rphase + Phase(dt * 60.0 * self.f0) return phase
def eval_spin_freq(self, t): """ Polyco evaluate spin frequency for a time array. Parameters --------- t: numpy.ndarray or a single number. An time array in MJD. Time sample should be in order Returns --------- out: numpy array of long double frequencies in Hz Polyco evaluated spin frequency at time t. FREQ(Hz) = F0 + (1/60)*(COEFF(2) + 2*DT*COEFF(3) + 3*DT^2*COEFF(4) + ...) """ if not isinstance(t, np.ndarray) and not isinstance(t, list): t = np.array([t]) entryIndex = self.find_entry(t) poly_result = data2longdouble(np.zeros(len(t))) dt = (data2longdouble(t) - self.polycoTable[entryIndex]["tmid"]) * MIN_PER_DAY for ii, (tt, eidx) in enumerate(zip(dt, entryIndex)): coeffs = self.polycoTable["entry"][eidx].coeffs coeffs = data2longdouble(range(len(coeffs))) * coeffs coeffs = coeffs[::-1][:-1] poly_result[ii] = np.polyval(coeffs, tt) spinFreq = np.array([ self.polycoTable["entry"][eidx].f0 + poly_result[ii] / data2longdouble(60.0) for ii, eidx in zip(range(len(t)), entryIndex) ]) return spinFreq
def __init__(self, tmid, mjdspan, rphaseInt, rphaseFrac, f0, ncoeff, coeffs, obs): self.tmid = tmid * u.day self.mjdspan = mjdspan * u.day self.tstart = data2longdouble( self.tmid) - data2longdouble(self.mjdspan) / 2.0 self.tstop = data2longdouble( self.tmid) + data2longdouble(self.mjdspan) / 2.0 self.rphase = Phase(rphaseInt, rphaseFrac) self.f0 = data2longdouble(f0) self.ncoeff = ncoeff self.coeffs = data2longdouble(coeffs) self.obs = obs
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 tempo_polyco_table_reader(filename): """Read tempo style polyco file to an astropy table. Tempo style: The polynomial ephemerides are written to file 'polyco.dat'. Entries are listed sequentially within the file. The file format is:: ==== ======= ============================================ Line Columns Item ==== ======= ============================================ 1 1-10 Pulsar Name 11-19 Date (dd-mmm-yy) 20-31 UTC (hhmmss.ss) 32-51 TMID (MJD) 52-72 DM 74-79 Doppler shift due to earth motion (10^-4) 80-86 Log_10 of fit rms residual in periods 2 1-20 Reference Phase (RPHASE) 21-38 Reference rotation frequency (F0) 39-43 Observatory number 44-49 Data span (minutes) 50-54 Number of coefficients 55-75 Observing frequency (MHz) 76-80 Binary phase 3* 1-25 Coefficient 1 (COEFF(1)) 26-50 Coefficient 2 (COEFF(2)) 51-75 Coefficient 3 (COEFF(3)) ==== ======= ============================================ * Subsequent lines have three coefficients each, up to NCOEFF One polyco file could include more then one entry. The pulse phase and frequency at time T are then calculated as:: DT = (T-TMID)*1440 PHASE = RPHASE + DT*60*F0 + COEFF(1) + DT*COEFF(2) + DT^2*COEFF(3) + .... FREQ(Hz) = F0 + (1/60)*(COEFF(2) + 2*DT*COEFF(3) + 3*DT^2*COEFF(4) + ....) Parameters ---------- filename : str Name of the input poloco file. References ---------- http://tempo.sourceforge.net/ref_man_sections/tz-polyco.txt """ entries = [] with open(filename, "r") as f: line = f.readline() while line != "": # First line fields = line.split() psrname = fields[0] date = fields[1] utc = float(fields[2]) tmid = np.longdouble(fields[3]) dm = float(fields[4]) doppler = float(fields[5]) logrms = float(fields[6]) # Second line fields = f.readline().split() refPhaseInt, refPhaseFrac = fields[0].split(".") refPhaseInt = np.longdouble(refPhaseInt) refPhaseFrac = np.longdouble("." + refPhaseFrac) if refPhaseInt < 0: refPhaseFrac = -refPhaseFrac refF0 = np.longdouble(fields[1]) obs = fields[2] mjdspan = int(fields[3]) nCoeff = int(fields[4]) obsfreq = float(fields[5]) try: binary_phase = float(fields[6]) f_orbit = float(fields[7]) is_binary = True except IndexError: is_binary = False # Read coefficients coeffs = [] for i in range(-(nCoeff // -3)): line = f.readline() for c in line.split(): coeffs.append(data2longdouble(c)) coeffs = np.array(coeffs) entry = PolycoEntry(tmid, mjdspan, refPhaseInt, refPhaseFrac, refF0, nCoeff, coeffs) entry_dict = OrderedDict() entry_dict["psr"] = psrname entry_dict["date"] = date entry_dict["utc"] = utc entry_dict["tmid"] = tmid entry_dict["dm"] = dm entry_dict["doppler"] = doppler entry_dict["logrms"] = logrms entry_dict["mjd_span"] = mjdspan entry_dict["t_start"] = entry.tstart entry_dict["t_stop"] = entry.tstop entry_dict["obs"] = obs entry_dict["obsfreq"] = obsfreq if is_binary: entry_dict["binary_phase"] = binary_phase entry_dict["f_orbit"] = f_orbit entry_dict["entry"] = entry entries.append(entry_dict) line = f.readline() pTable = table.Table(entries, meta={"name": "Polyco Data Table"}) return pTable
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 tempo_polyco_table_reader(filename): """Read tempo style polyco file to an astropy table. Tempo style: The polynomial ephemerides are written to file 'polyco.dat'. Entries are listed sequentially within the file. The file format is:: ==== ======= ============================================ Line Columns Item ==== ======= ============================================ 1 1-10 Pulsar Name 11-19 Date (dd-mmm-yy) 20-31 UTC (hhmmss.ss) 32-51 TMID (MJD) 52-72 DM 74-79 Doppler shift due to earth motion (10^-4) 80-86 Log_10 of fit rms residual in periods 2 1-20 Reference Phase (RPHASE) 21-38 Reference rotation frequency (F0) 39-43 Observatory number 44-49 Data span (minutes) 50-54 Number of coefficients 55-75 Observing frequency (MHz) 76-80 Binary phase 3* 1-25 Coefficient 1 (COEFF(1)) 26-50 Coefficient 2 (COEFF(2)) 51-75 Coefficient 3 (COEFF(3)) ==== ======= ============================================ * Subsequent lines have three coefficients each, up to NCOEFF One polyco file could include more then one entrie The pulse phase and frequency at time T are then calculated as:: DT = (T-TMID)*1440 PHASE = RPHASE + DT*60*F0 + COEFF(1) + DT*COEFF(2) + DT^2*COEFF(3) + .... FREQ(Hz) = F0 + (1/60)*(COEFF(2) + 2*DT*COEFF(3) + 3*DT^2*COEFF(4) + ....) Parameters ---------- filename : str Name of the input poloco file. References ---------- http://tempo.sourceforge.net/ref_man_sections/tz-polyco.txt """ f = open(filename, "r") # Read entries to the end of file entries = [] while True: # Read first line line1 = f.readline() if len(line1) == 0: break fields = line1.split() psrname = fields[0].strip() date = fields[1].strip() utc = fields[2] tmid = np.longdouble(fields[3]) dm = float(fields[4]) doppler = float(fields[5]) logrms = float(fields[6]) # Read second line line2 = f.readline() fields = line2.split() refPhaseInt, refPhaseFrac = fields[0].split(".") refPhaseInt = data2longdouble(refPhaseInt) refPhaseFrac = data2longdouble("." + refPhaseFrac) if refPhaseInt < 0: refPhaseFrac = -refPhaseFrac refF0 = data2longdouble(fields[1]) obs = fields[2] mjdSpan = data2longdouble( fields[3]) / MIN_PER_DAY # Here change to constant nCoeff = int(fields[4]) obsfreq = float(fields[5].strip()) try: binaryPhase = data2longdouble(fields[6]) except ValueError: binaryPhase = data2longdouble(0.0) # Read coefficients nCoeffLines = int(np.ceil(nCoeff / 3)) # if nCoeff%3>0: # nCoeffLines += 1 coeffs = [] for i in range(nCoeffLines): line = f.readline() for c in line.split(): coeffs.append(data2longdouble(c)) coeffs = np.array(coeffs) tmid = tmid * u.day mjdspan = mjdSpan * u.day tstart = data2longdouble(tmid) - data2longdouble(mjdspan) / 2.0 tstop = data2longdouble(tmid) + data2longdouble(mjdspan) / 2.0 rphase = Phase(refPhaseInt, refPhaseFrac) refF0 = data2longdouble(refF0) coeffs = data2longdouble(coeffs) entry = PolycoEntry(tmid, mjdspan, refPhaseInt, refPhaseFrac, refF0, nCoeff, coeffs, obs) entries.append(( psrname, date, utc, tmid.value, dm, doppler, logrms, binaryPhase, mjdspan, tstart, tstop, obs, obsfreq, entry, )) entry_list = [] for ii in range(len(entries[0])): entry_list.append([t[ii] for t in entries]) # Construct the polyco data table pTable = table.Table( entry_list, names=( "psr", "date", "utc", "tmid", "dm", "doppler", "logrms", "binary_phase", "mjd_span", "t_start", "t_stop", "obs", "obsfreq", "entry", ), meta={"name": "Polyco Data Table"}, ) pTable["index"] = np.arange(len(entries)) return pTable
def test_data2longdouble_converts_arrays(a): assert_array_equal(data2longdouble(a), np.asarray(a, dtype=np.longdouble))
def test_data2longdouble_accepts_types(d, ld): assert data2longdouble(d) == ld