def test_taylor_horner_basic(): """Check basic calculation against schoolbook formula.""" assert taylor_horner(2.0, [10]) == 10 assert taylor_horner(2.0, [10, 3]) == 10 + 3 * 2.0 assert taylor_horner(2.0, [10, 3, 4]) == 10 + 3 * 2.0 + 4 * 2.0**2 / 2.0 assert taylor_horner( 2.0, [10, 3, 4, 12 ]) == 10 + 3 * 2.0 + 4 * 2.0**2 / 2.0 + 12 * 2.0**3 / (3.0 * 2.0)
def d_dm_d_DMs( self, toas, param_name, acc_delay=None): # NOTE we should have a better name for this.) """ Derivatives of DM wrt the DM taylor expansion parameters. """ tbl = toas.table try: bfreq = self.barycentric_radio_freq(toas) except AttributeError: warn("Using topocentric frequency for dedispersion!") bfreq = tbl["freq"] par = getattr(self, param_name) unit = par.units if param_name == "DM": order = 0 else: pn, idxf, idxv = split_prefixed_name(param_name) order = idxv dms = self.get_DM_terms() dm_terms = np.longdouble(np.zeros(len(dms))) dm_terms[order] = np.longdouble(1.0) if self.DMEPOCH.value is None: DMEPOCH = tbl["tdbld"][0] else: DMEPOCH = self.DMEPOCH.value dt = (tbl["tdbld"] - DMEPOCH) * u.day dt_value = (dt.to(u.yr)).value d_dm_d_dm_param = taylor_horner(dt_value, dm_terms) * (self.DM.units / par.units) return d_dm_d_dm_param
def d_dm_d_DMs( self, toas, param_name, acc_delay=None): # NOTE we should have a better name for this.) """Derivatives of DM wrt the DM taylor expansion parameters.""" par = getattr(self, param_name) if param_name == "DM": order = 0 else: pn, idxf, idxv = split_prefixed_name(param_name) order = idxv dms = self.get_DM_terms() dm_terms = np.longdouble(np.zeros(len(dms))) dm_terms[order] = np.longdouble(1.0) if self.DMEPOCH.value is None: if any(t.value != 0 for t in dms[1:]): # Should be ruled out by validate() raise ValueError( f"DMEPOCH is not set but {param_name} is not zero") DMEPOCH = 0 else: DMEPOCH = self.DMEPOCH.value dt = (toas["tdbld"] - DMEPOCH) * u.day dt_value = (dt.to(u.yr)).value d_dm_d_dm_param = taylor_horner(dt_value, dm_terms) * (self.DM.units / par.units) return d_dm_d_dm_param
def orbits(self): FBXs = [0*u.Unit(""),] ii = 0 while 'FB' + str(ii) in self.orbit_params: FBXs.append(getattr(self, 'FB' + str(ii))) ii += 1 orbits = ut.taylor_horner(self.tt0, FBXs) return orbits.decompose()
def d_orbits_d_FBX(self, FBX): par = getattr(self, FBX) ii = 0 FBXs = [0*u.Unit(""),] while 'FB' + str(ii) in self.orbit_params: if 'FB' + str(ii) != FBX: FBXs.append(0.0 * getattr(self, 'FB' + str(ii)).unit) else: FBXs.append(1.0 * getattr(self, 'FB' + str(ii)).unit) ii += 1 d_orbits = ut.taylor_horner(self.tt0, FBXs) / par.unit return d_orbits.decompose()*2*np.pi*u.rad
def d_phase_d_F(self, toas, param, delay): """Calculate the derivative wrt to an spin term.""" par = getattr(self, param) unit = par.units pn, idxf, idxv = split_prefixed_name(param) order = idxv + 1 fterms = [0.0 * u.Unit("")] + self.get_spin_terms() # make the choosen fterms 1 others 0 fterms = [ft * numpy.longdouble(0.0) / unit for ft in fterms] fterms[order] += numpy.longdouble(1.0) dt = self.get_dt(toas, delay) d_pphs_d_f = taylor_horner(dt.to(u.second), fterms) return d_pphs_d_f.to(1 / unit)
def base_dm(self, toas): tbl = toas.table dm = np.zeros(len(tbl)) dm_terms = self.get_DM_terms() if self.DMEPOCH.value is None: DMEPOCH = tbl["tdbld"][0] else: DMEPOCH = self.DMEPOCH.value dt = (tbl["tdbld"] - DMEPOCH) * u.day dt_value = (dt.to(u.yr)).value dm_terms_value = [d.value for d in dm_terms] dm = taylor_horner(dt_value, dm_terms_value) return dm * self.DM.units
def spindown_phase(self, toas, delay): """Spindown phase function. delay is the time delay from the TOA to time of pulse emission at the pulsar, in seconds. This routine should implement Eq 120 of the Tempo2 Paper II (2006, MNRAS 372, 1549) returns an array of phases in long double """ dt = self.get_dt(toas, delay) # Add the [0.0] because that is the constant phase term fterms = [0.0 * u.dimensionless_unscaled] + self.get_spin_terms() phs = taylor_horner(dt.to(u.second), fterms) return phs.to(u.dimensionless_unscaled)
def base_dm(self, toas): tbl = toas.table dm = np.zeros(len(tbl)) dm_terms = self.get_DM_terms() if any(t.value != 0 for t in dm_terms[1:]): DMEPOCH = self.DMEPOCH.value try: dt = (tbl["tdbld"] - DMEPOCH) * u.day except TypeError as e: raise ValueError( "DMEPOCH not set but some derivatives are not zero: {dm_terms}" ) from e dt_value = dt.to_value(u.yr) else: dt_value = np.zeros(len(toas), dtype=np.longdouble) dm_terms_value = [d.value for d in dm_terms] dm = taylor_horner(dt_value, dm_terms_value) return dm * self.DM.units
def base_dm(self, toas): dm = np.zeros(len(toas)) dm_terms = self.get_DM_terms() if any(t.value != 0 for t in dm_terms[1:]): DMEPOCH = self.DMEPOCH.value if DMEPOCH is None: # Should be ruled out by validate() raise ValueError( f"DMEPOCH not set but some derivatives are not zero: {dm_terms}" ) else: dt = (toas["tdbld"] - DMEPOCH) * u.day dt_value = dt.to_value(u.yr) else: dt_value = np.zeros(len(toas), dtype=np.longdouble) dm_terms_value = [d.value for d in dm_terms] dm = taylor_horner(dt_value, dm_terms_value) return dm * self.DM.units
def piecewise_phase(self, toas, delay): """Glitch phase function. delay is the time delay from the TOA to time of pulse emission at the pulsar, in seconds. returns an array of phases in long double """ phs = u.Quantity(np.zeros(toas.ntoas, dtype=np.longdouble)) glepnames = [x for x in self.params if x.startswith("PWEP_")] for glepnm in glepnames: glep = getattr(self, glepnm) idx = glep.index # dPH = getattr(self, "PWPH_%d" % idx).quantity # dF0 = getattr(self, "PWF0_%d" % idx).quantity # dF1 = getattr(self, "PWF1_%d" % idx).quantity # dF2 = getattr(self, "PWF2_%d" % idx).quantity dt, affected = self.get_dt_and_affected(toas, delay, glepnm) # fterms = [dPH, dF0, dF1, dF2] fterms = self.get_spin_terms(idx) phs[affected] += taylor_horner(dt.to(u.second), fterms) return phs.to(u.dimensionless_unscaled)
def d_phase_d_F(self, toas, param, delay): """Calculate the derivative wrt to an spin term.""" par = getattr(self, param) unit = par.units pn, idxf, idxv = split_prefixed_name(param) if param.startswith("PWF"): order = split_prefixed_name(param[:4])[2] + 1 else: order = 0 # order = idxv + 1 fterms = self.get_spin_terms(idxv) # make the choosen fterms 1 others 0 fterms = [ft * np.longdouble(0.0) / unit for ft in fterms] fterms[order] += np.longdouble(1.0) glepnm = f"PWEP_{idxf}" res = u.Quantity(np.zeros(toas.ntoas, dtype=np.longdouble)) * (1 / unit) dt, affected = self.get_dt_and_affected(toas, delay, glepnm) d_pphs_d_f = taylor_horner(dt.to(u.second), fterms) res[affected] = d_pphs_d_f.to(1 / unit) return res
def test_taylor_horner_equals_deriv(x, coeffs): assert_allclose(taylor_horner(x, coeffs), taylor_horner_deriv(x, coeffs, 0))
def orbits(self): """Orbital phase (number of orbits since T0).""" orbits = taylor_horner(self.tt0, self._FBXs()) return orbits.decompose()
def test_taylor_horner_units_ok(x, result, n): coeffs = [result / x**i for i in range(n + 1)] taylor_horner(x, coeffs) + result
def f(x): return taylor_horner(x, coeffs)