Пример #1
0
    def change_dmepoch(self, new_epoch):
        """Change DMEPOCH to a new value and update DM accordingly.

        Parameters
        ----------
        new_epoch: float MJD (in TDB) or `astropy.Time` object
            The new DMEPOCH value.
        """
        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)

        dmterms = [0.0 * u.Unit("")] + self.get_DM_terms()
        if self.DMEPOCH.value is None:
            if any(d.value != 0 for d in dmterms[2:]):
                # Should be ruled out by validate()
                raise ValueError(
                    f"DMEPOCH not set but some DM derivatives are not zero: {dmterms}"
                )
            self.DMEPOCH.value = new_epoch

        dmepoch_ld = self.DMEPOCH.quantity.tdb.mjd_long
        dt = (new_epoch.tdb.mjd_long - dmepoch_ld) * u.day

        for n in range(len(dmterms) - 1):
            cur_deriv = self.DM if n == 0 else getattr(self, "DM{}".format(n))
            cur_deriv.value = taylor_horner_deriv(dt.to(u.yr),
                                                  dmterms,
                                                  deriv_order=n + 1)
        self.DMEPOCH.value = new_epoch
Пример #2
0
    def change_dmepoch(self, new_epoch):
        """Change DMEPOCH to a new value and update DM accordingly.

        Parameters
        ----------
        new_epoch: float MJD (in TDB) or `astropy.Time` object
            The new DMEPOCH value.
        """
        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)

        if self.DMEPOCH.value is None:
            raise ValueError("DMEPOCH is not currently set.")

        dmepoch_ld = self.DMEPOCH.quantity.tdb.mjd_long
        dt = (new_epoch.tdb.mjd_long - dmepoch_ld) * u.day
        dmterms = [0.0 * u.Unit("")] + self.get_DM_terms()

        for n in range(len(dmterms) - 1):
            cur_deriv = self.DM if n == 0 else getattr(self, "DM{}".format(n))
            cur_deriv.value = taylor_horner_deriv(dt.to(u.yr),
                                                  dmterms,
                                                  deriv_order=n + 1)
        self.DMEPOCH.value = new_epoch
Пример #3
0
 def pbdot_orbit(self):
     FBXs = [0*u.Unit(""),]
     ii = 0
     while 'FB' + str(ii) in self.orbit_params:
         FBXs.append(getattr(self, 'FB' + str(ii)))
         ii += 1
     orbit_freq_dot = ut.taylor_horner_deriv(self.tt0, FBXs, 2)
     return -(self.pbprime() ** 2) * orbit_freq_dot
Пример #4
0
 def pbprime(self):
     FBXs = [0*u.Unit(""),]
     ii = 0
     while 'FB' + str(ii) in self.orbit_params:
         FBXs.append(getattr(self, 'FB' + str(ii)))
         ii += 1
     orbit_freq = ut.taylor_horner_deriv(self.tt0, FBXs, 1)
     return 1.0 / orbit_freq
Пример #5
0
 def pbdot_orbit(self):
     FBXs = [0*u.Unit(""),]
     ii = 0
     while 'FB' + str(ii) in self.orbit_params:
         FBXs.append(getattr(self, 'FB' + str(ii)))
         ii += 1
     orbit_freq_dot = ut.taylor_horner_deriv(self.tt0, FBXs, 2)
     return -(self.pbprime() ** 2) * orbit_freq_dot
Пример #6
0
 def pbprime(self):
     FBXs = [0*u.Unit(""),]
     ii = 0
     while 'FB' + str(ii) in self.orbit_params:
         FBXs.append(getattr(self, 'FB' + str(ii)))
         ii += 1
     orbit_freq = ut.taylor_horner_deriv(self.tt0, FBXs, 1)
     return 1.0 / orbit_freq
Пример #7
0
 def d_pbprime_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_FB = ut.taylor_horner_deriv(self.tt0, FBXs, 1) / par.unit
     return -(self.pbprime() ** 2) * d_FB
Пример #8
0
 def d_pbprime_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_FB = ut.taylor_horner_deriv(self.tt0, FBXs, 1) / par.unit
     return -(self.pbprime() ** 2) * d_FB
Пример #9
0
    def get_PSR_freq(self, calctype="modelF0"):
        """Return pulsar rotational frequency in Hz.

        Parameters
        ----------
        calctype : {'modelF0', 'numerical', 'taylor'}
            Type of calculation.  If `calctype` == "modelF0", then simply the ``F0``
            parameter from the model.
            If `calctype` == "numerical", then try a numerical derivative
            If `calctype` == "taylor", evaluate the frequency with a Taylor series

        Returns
        -------
        freq : astropy.units.Quantity
            Either the single ``F0`` in the model or the spin frequency at the moment of each TOA.
        """
        assert calctype.lower() in ["modelf0", "taylor", "numerical"]
        if calctype.lower() == "modelf0":
            # TODO this function will be re-write and move to timing model soon.
            # The following is a temproary patch.
            if "Spindown" in self.model.components:
                F0 = self.model.F0.quantity
            elif "P0" in self.model.params:
                F0 = 1.0 / self.model.P0.quantity
            else:
                raise AttributeError("No pulsar spin parameter(e.g., 'F0',"
                                     " 'P0') found.")
            return F0.to(u.Hz)
        elif calctype.lower() == "taylor":
            # see Spindown.spindown_phase
            dt = self.model.get_dt(self.toas, 0)
            # if the model is defined through F0, F1, ...
            if "F0" in self.model.params:
                fterms = [0.0 * u.dimensionless_unscaled
                          ] + self.model.get_spin_terms()

            # otherwise assume P0, PDOT
            else:
                F0 = 1.0 / self.model.P0.quantity
                if "PDOT" in self.model.params:
                    F1 = -self.model.PDOT.quantity / self.model.P0.quantity**2
                else:
                    F1 = 0 * u.Hz / u.s
                fterms = [0.0 * u.dimensionless_unscaled, F0, F1]
            return taylor_horner_deriv(dt, fterms, deriv_order=1).to(u.Hz)
        elif calctype.lower() == "numerical":
            return self.model.d_phase_d_toa(self.toas)
Пример #10
0
    def change_pepoch(self, new_epoch, toas=None, delay=None):
        """Move PEPOCH to a new time and change the related paramters.

        Parameters
        ----------
        new_epoch: float or `astropy.Time` object
            The new PEPOCH value.
        toas: `toa` object, optional.
            If current PEPOCH is not provided, the first pulsar frame toa will
            be treated as PEPOCH.
        delay: `numpy.array` object
            If current PEPOCH is not provided, it is required for computing the
            first pulsar frame toa.
        """
        if isinstance(new_epoch, Time):
            new_epoch = Time(new_epoch, scale="tdb", precision=9)
        else:
            new_epoch = Time(new_epoch, scale="tdb", format="mjd", precision=9)
        # make new_epoch a toa for delay calculation.
        new_epoch_toa = toa.get_TOAs_list([toa.TOA(new_epoch)],
                                          ephem=toas.ephem)

        if self.PEPOCH.value is None:
            if toas is None or delay is None:
                raise ValueError(
                    "`PEPOCH` is not in the model, thus, 'toa' and"
                    " 'delay' shoule be givne.")
            tbl = toas.table
            phsepoch_ld = (tbl["tdb"][0] - delay[0]).tdb.mjd_long
        else:
            phsepoch_ld = self.PEPOCH.quantity.tdb.mjd_long
        dt = (new_epoch.tdb.mjd_long - phsepoch_ld) * u.day
        fterms = [0.0 * u.Unit("")] + self.get_spin_terms()
        # rescale the fterms
        for n in range(len(fterms) - 1):
            f_par = getattr(self, "F{}".format(n))
            f_par.value = taylor_horner_deriv(dt.to(u.second),
                                              fterms,
                                              deriv_order=n + 1)
        self.PEPOCH.value = new_epoch
Пример #11
0
    def change_binary_epoch(self, new_epoch):
        """Change the epoch for this binary model.

        T0 will be changed to the periapsis time closest to the supplied epoch,
        and the argument of periapsis (OM), eccentricity (ECC), and projected
        semimajor axis (A1 or X) will be updated according to the specified
        OMDOT, EDOT, and A1DOT or XDOT, if present.

        Note that derivatives of binary orbital frequency higher than the first
        (FB2, FB3, etc.) are ignored in computing the new T0, even if present in
        the model. If high-precision results are necessary, especially for models
        containing higher derivatives of orbital frequency, consider re-fitting
        the model to a set of TOAs. The use of :func:`pint.toa.make_fake_toas`
        and the :class:`pint.fitter.Fitter` option ``track_mode="use_pulse_number"``
        can make this extremely simple.

        Parameters
        ----------
        new_epoch: float MJD (in TDB) or `astropy.Time` object
            The new epoch value.
        """
        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)

        try:
            self.FB2.quantity
            log.warning(
                "Ignoring orbital frequency derivatives higher than FB1"
                "in computing new T0"
            )
        except AttributeError:
            pass

        # Get PB and PBDOT from model
        if self.PB.quantity is not None:
            PB = self.PB.quantity
            if self.PBDOT.quantity is not None:
                PBDOT = self.PBDOT.quantity
            else:
                PBDOT = 0.0 * u.Unit("")
        else:
            PB = 1.0 / self.FB0.quantity
            try:
                PBDOT = -self.FB1.quantity / self.FB0.quantity ** 2
            except AttributeError:
                PBDOT = 0.0 * u.Unit("")

        # Find closest periapsis time and reassign T0
        t0_ld = self.T0.quantity.tdb.mjd_long
        dt = (new_epoch.tdb.mjd_long - t0_ld) * u.day
        d_orbits = dt / PB - PBDOT * dt ** 2 / (2.0 * PB ** 2)
        n_orbits = np.round(d_orbits.to(u.Unit("")))
        dt_integer_orbits = PB * n_orbits + PB * PBDOT * n_orbits ** 2 / 2.0
        self.T0.quantity = self.T0.quantity + dt_integer_orbits

        # Update PB or FB0, FB1, etc.
        if isinstance(self.binary_instance.orbits_cls, bo.OrbitPB):
            dPB = PBDOT * dt_integer_orbits
            self.PB.quantity = self.PB.quantity + dPB
        else:
            fbterms = [
                getattr(self, k).quantity
                for k in self.get_prefix_mapping("FB").values()
            ]
            fbterms = [0.0 * u.Unit("")] + fbterms

            for n in range(len(fbterms) - 1):
                cur_deriv = getattr(self, "FB{}".format(n))
                cur_deriv.value = taylor_horner_deriv(
                    dt.to(u.s), fbterms, deriv_order=n + 1
                )

        # Update ECC, OM, and A1
        dECC = self.EDOT.quantity * dt_integer_orbits
        self.ECC.quantity = self.ECC.quantity + dECC
        dOM = self.OMDOT.quantity * dt_integer_orbits
        self.OM.quantity = self.OM.quantity + dOM
        dA1 = self.A1DOT.quantity * dt_integer_orbits
        self.A1.quantity = self.A1.quantity + dA1
Пример #12
0
 def pbdot_orbit(self):
     """Reported value of PBDOT."""
     orbit_freq_dot = taylor_horner_deriv(self.tt0, self._FBXs(), 2)
     return -(self.pbprime()**2) * orbit_freq_dot
Пример #13
0
 def pbprime(self):
     """Derivative of binary period with respect to time."""
     orbit_freq = taylor_horner_deriv(self.tt0, self._FBXs(), 1)
     return 1.0 / orbit_freq
Пример #14
0
def test_taylor_horner_equals_deriv(x, coeffs):
    assert_allclose(taylor_horner(x, coeffs),
                    taylor_horner_deriv(x, coeffs, 0))
Пример #15
0
 def d_spindown_phase_d_delay(self, toas, delay):
     dt = self.get_dt(toas, delay)
     fterms = [0.0] + self.get_spin_terms()
     d_pphs_d_delay = taylor_horner_deriv(dt.to(u.second), fterms)
     return -d_pphs_d_delay.to(1 / u.second)
Пример #16
0
 def d_spindown_phase_d_delay(self, toas, delay):
     dt = self.get_dt(toas, delay)
     fterms = [0.0] + self.get_spin_terms()
     with u.set_enabled_equivalencies(dimensionless_cycles):
         d_pphs_d_delay = taylor_horner_deriv(dt.to(u.second), fterms)
         return -d_pphs_d_delay.to(u.cycle / u.second)
Пример #17
0
    def change_binary_epoch(self, new_epoch):
        """Change the epoch for this binary model.

        TASC will be changed to the epoch of the ascending node closest to the
        supplied epoch, and the Laplace parameters (EPS1, EPS2) and projected
        semimajor axis (A1 or X) will be updated according to the specified
        EPS1DOT, EPS2DOT, and A1DOT or XDOT, if present.

        Note that derivatives of binary orbital frequency higher than the first
        (FB2, FB3, etc.) are ignored in computing the new T0, even if present in
        the model. If high-precision results are necessary, especially for models
        containing higher derivatives of orbital frequency, consider re-fitting
        the model to a set of TOAs.

        Parameters
        ----------
        new_epoch: float MJD (in TDB) or `astropy.Time` object
            The new epoch value.
        """
        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)

        try:
            FB2 = self.FB2.quantity
            log.warning(
                "Ignoring orbital frequency derivatives higher than FB1"
                "in computing new TASC")
        except AttributeError:
            pass

        # Get PB and PBDOT from model
        if self.PB.quantity is not None:
            PB = self.PB.quantity
            if self.PBDOT.quantity is not None:
                PBDOT = self.PBDOT.quantity
            else:
                PBDOT = 0.0 * u.Unit("")
        else:
            PB = 1.0 / self.FB0.quantity
            try:
                PBDOT = -self.FB1.quantity / self.FB0.quantity**2
            except AttributeError:
                PBDOT = 0.0 * u.Unit("")

        # Find closest periapsis time and reassign T0
        tasc_ld = self.TASC.quantity.tdb.mjd_long
        dt = (new_epoch.tdb.mjd_long - tasc_ld) * u.day
        d_orbits = dt / PB - PBDOT * dt**2 / (2.0 * PB**2)
        n_orbits = np.round(d_orbits.to(u.Unit("")))
        dt_integer_orbits = PB * n_orbits + PB * PBDOT * n_orbits**2 / 2.0
        self.TASC.quantity = self.TASC.quantity + dt_integer_orbits

        # Update PB or FB0, FB1, etc.
        if isinstance(self.binary_instance.orbits_cls, bo.OrbitPB):
            dPB = PBDOT * dt_integer_orbits
            self.PB.quantity = self.PB.quantity + dPB
        else:
            fbterms = [
                getattr(self, k).quantity
                for k in self.get_prefix_mapping("FB").values()
            ]
            fbterms = [0.0 * u.Unit("")] + fbterms

            for n in range(len(fbterms) - 1):
                cur_deriv = getattr(self, "FB{}".format(n))
                cur_deriv.value = taylor_horner_deriv(dt.to(u.s),
                                                      fbterms,
                                                      deriv_order=n + 1)

        # Update EPS1, EPS2, and A1
        if self.EPS1DOT.quantity is not None:
            dEPS1 = self.EPS1DOT.quantity * dt_integer_orbits
            self.EPS1.quantity = self.EPS1.quantity + dEPS1
        if self.EPS2DOT.quantity is not None:
            dEPS2 = self.EPS2DOT.quantity * dt_integer_orbits
            self.EPS2.quantity = self.EPS2.quantity + dEPS2
        if self.A1DOT.quantity is not None:
            dA1 = self.A1DOT.quantity * dt_integer_orbits
            self.A1.quantity = self.A1.quantity + dA1
Пример #18
0
def test_taylor_horner_deriv(x, coeffs, order):
    def f(x):
        return taylor_horner(x, coeffs)

    df = Derivative(f, n=order)
    assert_allclose(df(x), taylor_horner_deriv(x, coeffs, order), atol=1e-11)