From 2376d4613948112fcfd4a32d464494e9e546bdad Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Tue, 18 Jul 2023 09:52:28 +0200 Subject: [PATCH 001/195] Correction to docstring for pbprime functions --- src/pint/models/stand_alone_psr_binaries/binary_orbits.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py index 7ee4f6b81..3a1d60bbb 100644 --- a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py +++ b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py @@ -29,7 +29,7 @@ def orbit_phase(self): return (orbits - norbits) * 2 * np.pi * u.rad def pbprime(self): - """Derivative of binary period with respect to time.""" + """Instantaneous binary period as a function of time.""" raise NotImplementedError def pbdot_orbit(self): @@ -105,7 +105,7 @@ def orbits(self): ).decompose() def pbprime(self): - """Derivative of binary period with respect to time.""" + """Instantaneous binary period as a function of time.""" return self.PB + self.PBDOT * self.tt0 def pbdot_orbit(self): @@ -186,7 +186,7 @@ def orbits(self): return orbits.decompose() def pbprime(self): - """Derivative of binary period with respect to time.""" + """Instantaneous binary period as a function of time.""" orbit_freq = taylor_horner_deriv(self.tt0, self._FBXs(), 1) return 1.0 / orbit_freq From d6635a635e14b856ae68612f9c6292940b9a2a6c Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Mon, 17 Jul 2023 16:42:40 +0200 Subject: [PATCH 002/195] Starting to add ORBWAVES model --- src/pint/models/pulsar_binary.py | 60 ++++++ .../stand_alone_psr_binaries/binary_orbits.py | 189 ++++++++++++++++++ 2 files changed, 249 insertions(+) diff --git a/src/pint/models/pulsar_binary.py b/src/pint/models/pulsar_binary.py index 5e32079ad..36afff3e3 100644 --- a/src/pint/models/pulsar_binary.py +++ b/src/pint/models/pulsar_binary.py @@ -179,6 +179,43 @@ def __init__(self): long_double=True, ) ) + + self.add_param( + prefixParameter( + name="ORBWAVEC0", + value=None, + units="s", + description="Amplitude of cosine wave in Tasc-shift function", + aliases=["ORBWAVEC"], + description_template=self.ORBWAVE_description, + type_match="float", + long_double=True, + ) + ) + + self.add_param( + prefixParameter( + name="ORBWAVES0", + value=None, + units="s", + description="Amplitude of sine wave in Tasc-shift function", + aliases=["ORBWAVES"], + description_template=self.ORBWAVE_description, + type_match="float", + long_double=True, + ) + ) + + self.add_param( + floatParameter( + name="ORBWAVEOM", + units="rad/s", + description="Amplitude of cosine wave in Tasc-shift function", + long_double=True + ) + ) + + self.internal_params = [] self.warn_default_params = ["ECC", "OM"] # Set up delay function @@ -188,8 +225,10 @@ def setup(self): super().setup() for bpar in self.params: self.register_deriv_funcs(self.d_binary_delay_d_xxxx, bpar) + print(bpar) # Setup the model isinstance self.binary_instance = self.binary_model_class() + # Setup the FBX orbits if FB is set. # TODO this should use a smarter way to set up orbit. FBX_mapping = self.get_prefix_mapping_component("FB") @@ -202,6 +241,24 @@ def setup(self): self.binary_instance.orbits_cls = bo.OrbitFBX( self.binary_instance, list(FBXs.keys()) ) + + ORBWAVES_mapping = self.get_prefix_mapping_component("ORBWAVES") + ORBWAVES = {ows: getattr(self, ows).quantity for ows in ORBWAVES_mapping.values()} + ORBWAVEC_mapping = self.get_prefix_mapping_component("ORBWAVEC") + ORBWAVEC = {owc: getattr(self, owc).quantity for owc in ORBWAVEC_mapping.values()} + if any(v is not None for v in ORBWAVES.values()): + self.binary_instance.add_binary_params("ORBWAVEOM",self.ORBWAVEOM.value) + + for ow_name,ow_value in ORBWAVES.items(): + print(ow_name,ow_value) + self.binary_instance.add_binary_params(ow_name,ow_value) + for ow_name,ow_value in ORBWAVEC.items(): + print(ow_name,ow_value) + self.binary_instance.add_binary_params(ow_name,ow_value) + self.binary_instance.orbits_cls = bo.OrbitWaves( + self.binary_instance, ["PB","TASC","ORBWAVEOM"] + list(ORBWAVES.keys()) + list(ORBWAVEC.keys()) + ) + # Note: if we are happy to use these to show alternate parameterizations then this can be uncommented # # remove the PB parameterization, replace with functions @@ -465,6 +522,9 @@ def FBX_unit(self, n): def FBX_description(self, n): return "%dth time derivative of frequency of orbit" % n + def ORBWAVE_description(self, n): + return "%dth cosine wave in Fourier series model of Tasc shifts" % n + def change_binary_epoch(self, new_epoch): """Change the epoch for this binary model. diff --git a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py index 3a1d60bbb..4d0ae2b85 100644 --- a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py +++ b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py @@ -2,6 +2,7 @@ import astropy.units as u import numpy as np +import matplotlib.pyplot as plt from pint.utils import taylor_horner, taylor_horner_deriv @@ -237,3 +238,191 @@ def d_pbprime_d_par(self, par): if re.match(r"FB\d+", par) is not None else np.zeros(len(self.tt0)) * u.second / par_obj.unit ) + +class OrbitWaves(Orbit): + """ Orbit with orbital phase variations described by a Fourier series""" + + def __init__(self, parent, orbit_params=["PB","TASC","ORBWAVEOM","ORBWAVEC0","ORBWAVES0"]): + super().__init__("orbitWaves", parent, orbit_params) + # add the rest of FBX parameters. + Cindices = set() + Sindices = set() + + nc = 0 + ns = 0 + for k in self.binary_params: + if re.match(r"ORBWAVEC\d+", k) is not None and k not in self.orbit_params: + self.orbit_params += [k] + Cindices.add(int(k[8:])) + nc += 1 + if re.match(r"ORBWAVES\d+", k) is not None and k not in self.orbit_params: + self.orbit_params += [k] + Sindices.add(int(k[7:])) + ns += 1 + + if (Cindices != set(range(len(Cindices))) + or Sindices != set(range(len(Sindices)))): + raise ValueError( + f"Orbwave Indices must be 0 up to some number k without gaps " + f"but are {indices}." + ) + + if nc != ns: + raise ValueError( + f"Must have equal number of sine/cosine ORBWAVE pairs " + f"but have {ns} and {nc}." + ) + + self.nwaves = ns + + def _ORBWAVEs(self): + + ii = 0 + while f"ORBWAVEC{ii}" in self.orbit_params: + ii += 1 + self.nwaves = ii + + ORBWAVEs = np.zeros((self.nwaves,2)) * u.Unit("s") + + for ii in range(self.nwaves): + ORBWAVEs[ii,0] = getattr(self,f"ORBWAVEC{ii}") + ORBWAVEs[ii,1] = getattr(self,f"ORBWAVES{ii}") + + return ORBWAVEs + + def _Tascshift(self): + + waveamps = self._ORBWAVEs() + OM = self.ORBWAVEOM.to("radian/second") + + nh = np.arange(self.nwaves) + 1 + Cwaves = waveamps[:,0,None] * np.cos(OM * nh[:,None] * self.tt0[None,:]) + Swaves = waveamps[:,1,None] * np.sin(OM * nh[:,None] * self.tt0[None,:]) + + dTasc = np.sum(Cwaves + Swaves,axis=0) + + return dTasc + + def _dTascshift_dt(self): + + waveamps = self._ORBWAVEs() + OM = self.ORBWAVEOM.to("radian/second") + + nh = np.arange(self.nwaves) + 1 + Cwaves = -OM * nh[:,None] * waveamps[:,0,None] * np.sin(OM * nh[:,None] * self.tt0[None,:]) + Swaves = OM * nh[:,None] * waveamps[:,1,None] * np.cos(OM * nh[:,None] * self.tt0[None,:]) + + dTascshift_dt = np.sum(Cwaves + Swaves,axis=0) + + return dTascshift_dt.to(u.Unit(""),equivalencies=u.dimensionless_angles()) + + def _d2Tascshift_dt2(self): + + waveamps = self._ORBWAVEs() + OM = self.ORBWAVEOM.to("radian/second") + + nh = np.arange(self.nwaves) + 1 + Cwaves = -(OM * nh[:,None]) ** 2 * waveamps[:,0,None] * np.cos(OM * nh[:,None] * self.tt0[None,:]) + Swaves = -(OM * nh[:,None]) ** 2 * waveamps[:,1,None] * np.sin(OM * nh[:,None] * self.tt0[None,:]) + + d2Tascshift_dt2 = np.sum(Cwaves + Swaves,axis=0) + + return d2Tascshift_dt2.to(u.Unit("1/s"),equivalencies=u.dimensionless_angles()) + + def orbits(self): + + PB = self.PB.to("second") + orbits = self.tt0 / PB + + # If TASC occurs "early", then accumulated orbital phase is larger, + # hence -ve sign here + dphi = -self._Tascshift() / PB + + """Orbital phase (number of orbits since T0).""" + + orbits += dphi + return orbits.decompose() + + def pbprime(self): + """Derivative of binary period with respect to time.""" + PB = self.PB.to("second") + FB0 = 1.0/PB + + FB0_shift = -self._dTascshift_dt() / PB + + return 1.0 / (FB0 + FB0_shift).decompose() + + def pbdot_orbit(self): + """Reported value of PBDOT.""" + PB = self.PB.to("second") + FB1 = -self._d2Tascshift_dt2() / PB + + return -(self.pbprime() ** 2) * FB1 + + def d_orbits_d_TASC(self): + + PB = self.PB.to("second") + return -(1 / PB).decompose() + + def d_orbits_d_PB(self): + + PB = self.PB.to("second") + return -(self.tt0 / PB ** 2).decompose() + + def d_orbits_d_orbwave(self,par): + + OM = self.ORBWAVEOM.to("radian/second") + nh = int(par[8:]) + + return ( + np.cos(OM * nh * self.tt0) + if par[7] == C + else np.sin(OM * nh * self.tt0) + ) + + def d_pbprime_d_PB(self): + + PB = self.PB.to("second") + FB0 = 1.0/PB + + FB0_shift = -self._dTascshift_dt() / PB + + FB0_prime = FB0 + FB0_shift + + return (1.0/FB0_prime ** 2 / PB ** 2).decompose() + + def d_pbprime_d_orbwave(self,par): + + OM = self.ORBWAVEOM.to("radian/second") + PB = self.PB.to("second") + FB0 = 1.0/PB + FB0_shift = -self._dTascshift_dt() / PB + + FB0_prime = FB0 + FB0_shift + + nh = int(par[8:]) + if par[7] == "C": + dFB0_shift_dorbwave = -OM * nh * np.sin(OM * nh * self.tt0) / PB + else: + dFB0_shift_dorbwave = OM * nh * np.cos(OM * nh * self.tt0) / PB + + return 1.0/FB0_prime ** 2 * dFB0_shift_dorbwave + + def d_orbits_d_par(self, par): + + return ( + self.d_orbits_d_orbwave(par) + if re.match(r"ORBWAVE[CS]\d+", par) is not None + else super().d_orbits_d_par(par) + ) + + def d_pbprime_d_par(self, par): + par_obj = getattr(self, par) + return ( + self.d_pbprime_d_orbwave(par) + if re.match(r"ORBWAVE[CS]\d+", par) is not None + else np.zeros(len(self.tt0)) * u.second / par_obj.unit + ) + + + From b06328ce64ff6154f6ece96bbd20724811fbd8a8 Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Tue, 18 Jul 2023 12:02:18 +0200 Subject: [PATCH 003/195] Fixing units in ORBWAVE derivative functions --- .../stand_alone_psr_binaries/binary_orbits.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py index 4d0ae2b85..9d7eb770e 100644 --- a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py +++ b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py @@ -362,23 +362,24 @@ def pbdot_orbit(self): def d_orbits_d_TASC(self): PB = self.PB.to("second") - return -(1 / PB).decompose() + return -(1 / PB).decompose() * 2 * np.pi * u.rad def d_orbits_d_PB(self): PB = self.PB.to("second") - return -(self.tt0 / PB ** 2).decompose() + return -(self.tt0 / PB ** 2).decompose() * 2 * np.pi * u.rad def d_orbits_d_orbwave(self,par): OM = self.ORBWAVEOM.to("radian/second") + PB = self.PB.to("second") nh = int(par[8:]) return ( - np.cos(OM * nh * self.tt0) - if par[7] == C - else np.sin(OM * nh * self.tt0) - ) + -np.cos(OM * nh * self.tt0) + if par[7] == "C" + else -np.sin(OM * nh * self.tt0) + ) * 2 * np.pi * u.rad / PB def d_pbprime_d_PB(self): @@ -406,7 +407,9 @@ def d_pbprime_d_orbwave(self,par): else: dFB0_shift_dorbwave = OM * nh * np.cos(OM * nh * self.tt0) / PB - return 1.0/FB0_prime ** 2 * dFB0_shift_dorbwave + return ( + 1.0/FB0_prime ** 2 * dFB0_shift_dorbwave + ).to("d/s",equivalencies=u.dimensionless_angles()) def d_orbits_d_par(self, par): From 0266e856d5fe01111965b744fdb28d7d04fcd9b4 Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Wed, 26 Jul 2023 21:13:23 +0200 Subject: [PATCH 004/195] Added ORBWAVE_EPOCH parameter; changed units of ORBWAVEs to orbits, instead of seconds. --- src/pint/models/pulsar_binary.py | 55 ++++-- .../stand_alone_psr_binaries/binary_orbits.py | 185 +++++++++++------- 2 files changed, 154 insertions(+), 86 deletions(-) diff --git a/src/pint/models/pulsar_binary.py b/src/pint/models/pulsar_binary.py index 36afff3e3..a6d731160 100644 --- a/src/pint/models/pulsar_binary.py +++ b/src/pint/models/pulsar_binary.py @@ -184,7 +184,7 @@ def __init__(self): prefixParameter( name="ORBWAVEC0", value=None, - units="s", + units="", description="Amplitude of cosine wave in Tasc-shift function", aliases=["ORBWAVEC"], description_template=self.ORBWAVE_description, @@ -197,7 +197,7 @@ def __init__(self): prefixParameter( name="ORBWAVES0", value=None, - units="s", + units="", description="Amplitude of sine wave in Tasc-shift function", aliases=["ORBWAVES"], description_template=self.ORBWAVE_description, @@ -208,14 +208,20 @@ def __init__(self): self.add_param( floatParameter( - name="ORBWAVEOM", + name="ORBWAVE_OM", units="rad/s", description="Amplitude of cosine wave in Tasc-shift function", - long_double=True + long_double=True, + ) + ) + self.add_param( + MJDParameter( + name="ORBWAVE_EPOCH", + description="Reference epoch for ORBWAVEs model", + time_scale="tdb", ) ) - self.internal_params = [] self.warn_default_params = ["ECC", "OM"] # Set up delay function @@ -225,7 +231,6 @@ def setup(self): super().setup() for bpar in self.params: self.register_deriv_funcs(self.d_binary_delay_d_xxxx, bpar) - print(bpar) # Setup the model isinstance self.binary_instance = self.binary_model_class() @@ -243,22 +248,36 @@ def setup(self): ) ORBWAVES_mapping = self.get_prefix_mapping_component("ORBWAVES") - ORBWAVES = {ows: getattr(self, ows).quantity for ows in ORBWAVES_mapping.values()} + ORBWAVES = { + ows: getattr(self, ows).quantity for ows in ORBWAVES_mapping.values() + } ORBWAVEC_mapping = self.get_prefix_mapping_component("ORBWAVEC") - ORBWAVEC = {owc: getattr(self, owc).quantity for owc in ORBWAVEC_mapping.values()} + ORBWAVEC = { + owc: getattr(self, owc).quantity for owc in ORBWAVEC_mapping.values() + } if any(v is not None for v in ORBWAVES.values()): - self.binary_instance.add_binary_params("ORBWAVEOM",self.ORBWAVEOM.value) - - for ow_name,ow_value in ORBWAVES.items(): - print(ow_name,ow_value) - self.binary_instance.add_binary_params(ow_name,ow_value) - for ow_name,ow_value in ORBWAVEC.items(): - print(ow_name,ow_value) - self.binary_instance.add_binary_params(ow_name,ow_value) + self.binary_instance.add_binary_params("ORBWAVE_OM", self.ORBWAVE_OM.value) + self.binary_instance.add_binary_params( + "ORBWAVE_EPOCH", self.ORBWAVE_EPOCH.value + ) + + ii = 0 + while f"ORBWAVES{ii}" in ORBWAVES.keys(): + self.binary_instance.add_binary_params( + f"ORBWAVES{ii}", ORBWAVES[f"ORBWAVES{ii}"] + ) + self.binary_instance.add_binary_params( + f"ORBWAVEC{ii}", ORBWAVEC[f"ORBWAVEC{ii}"] + ) + ii += 1 + self.binary_instance.orbits_cls = bo.OrbitWaves( - self.binary_instance, ["PB","TASC","ORBWAVEOM"] + list(ORBWAVES.keys()) + list(ORBWAVEC.keys()) + self.binary_instance, + ["PB", "TASC", "ORBWAVE_OM", "ORBWAVE_EPOCH"] + + list(ORBWAVES.keys()) + + list(ORBWAVEC.keys()), ) - + # Note: if we are happy to use these to show alternate parameterizations then this can be uncommented # # remove the PB parameterization, replace with functions diff --git a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py index 9d7eb770e..ff8a17ffb 100644 --- a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py +++ b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py @@ -239,10 +239,22 @@ def d_pbprime_d_par(self, par): else np.zeros(len(self.tt0)) * u.second / par_obj.unit ) -class OrbitWaves(Orbit): - """ Orbit with orbital phase variations described by a Fourier series""" - def __init__(self, parent, orbit_params=["PB","TASC","ORBWAVEOM","ORBWAVEC0","ORBWAVES0"]): +class OrbitWaves(Orbit): + """Orbit with orbital phase variations described by a Fourier series""" + + def __init__( + self, + parent, + orbit_params=[ + "PB", + "TASC", + "ORBWAVE_OM", + "ORBWAVE_EPOCH", + "ORBWAVEC0", + "ORBWAVES0", + ], + ): super().__init__("orbitWaves", parent, orbit_params) # add the rest of FBX parameters. Cindices = set() @@ -257,11 +269,12 @@ def __init__(self, parent, orbit_params=["PB","TASC","ORBWAVEOM","ORBWAVEC0","OR nc += 1 if re.match(r"ORBWAVES\d+", k) is not None and k not in self.orbit_params: self.orbit_params += [k] - Sindices.add(int(k[7:])) + Sindices.add(int(k[8:])) ns += 1 - - if (Cindices != set(range(len(Cindices))) - or Sindices != set(range(len(Sindices)))): + + if Cindices != set(range(len(Cindices))) or Sindices != set( + range(len(Sindices)) + ): raise ValueError( f"Orbwave Indices must be 0 up to some number k without gaps " f"but are {indices}." @@ -282,52 +295,84 @@ def _ORBWAVEs(self): ii += 1 self.nwaves = ii - ORBWAVEs = np.zeros((self.nwaves,2)) * u.Unit("s") + ORBWAVEs = np.zeros((self.nwaves, 2)) * u.Unit("") for ii in range(self.nwaves): - ORBWAVEs[ii,0] = getattr(self,f"ORBWAVEC{ii}") - ORBWAVEs[ii,1] = getattr(self,f"ORBWAVES{ii}") + ORBWAVEs[ii, 0] = getattr(self, f"ORBWAVEC{ii}") + ORBWAVEs[ii, 1] = getattr(self, f"ORBWAVES{ii}") return ORBWAVEs - def _Tascshift(self): + def _tw(self): + + t = self.t + if not hasattr(self.t, "unit") or self.t.unit is None: + t = self.t * u.day + tw = t - self.ORBWAVE_EPOCH.value * u.d + return tw + + def _deltaPhi(self): + + tw = self._tw() waveamps = self._ORBWAVEs() - OM = self.ORBWAVEOM.to("radian/second") - + OM = self.ORBWAVE_OM.to("radian/second") + nh = np.arange(self.nwaves) + 1 - Cwaves = waveamps[:,0,None] * np.cos(OM * nh[:,None] * self.tt0[None,:]) - Swaves = waveamps[:,1,None] * np.sin(OM * nh[:,None] * self.tt0[None,:]) + Cwaves = waveamps[:, 0, None] * np.cos(OM * nh[:, None] * tw[None, :]) + Swaves = waveamps[:, 1, None] * np.sin(OM * nh[:, None] * tw[None, :]) - dTasc = np.sum(Cwaves + Swaves,axis=0) + delta_Phi = np.sum(Cwaves + Swaves, axis=0) - return dTasc + return delta_Phi - def _dTascshift_dt(self): + def _d_deltaPhi_dt(self): + tw = self._tw() waveamps = self._ORBWAVEs() - OM = self.ORBWAVEOM.to("radian/second") - + OM = self.ORBWAVE_OM.to("radian/second") + nh = np.arange(self.nwaves) + 1 - Cwaves = -OM * nh[:,None] * waveamps[:,0,None] * np.sin(OM * nh[:,None] * self.tt0[None,:]) - Swaves = OM * nh[:,None] * waveamps[:,1,None] * np.cos(OM * nh[:,None] * self.tt0[None,:]) + Cwaves = ( + -OM + * nh[:, None] + * waveamps[:, 0, None] + * np.sin(OM * nh[:, None] * tw[None, :]) + ) + Swaves = ( + OM + * nh[:, None] + * waveamps[:, 1, None] + * np.cos(OM * nh[:, None] * tw[None, :]) + ) - dTascshift_dt = np.sum(Cwaves + Swaves,axis=0) + d_deltaPhi_dt = np.sum(Cwaves + Swaves, axis=0) - return dTascshift_dt.to(u.Unit(""),equivalencies=u.dimensionless_angles()) + return d_deltaPhi_dt.to(u.Unit("1/s"), equivalencies=u.dimensionless_angles()) - def _d2Tascshift_dt2(self): + def _d2_deltaPhi_dt2(self): + tw = self._tw() waveamps = self._ORBWAVEs() - OM = self.ORBWAVEOM.to("radian/second") - + OM = self.ORBWAVE_OM.to("radian/second") + nh = np.arange(self.nwaves) + 1 - Cwaves = -(OM * nh[:,None]) ** 2 * waveamps[:,0,None] * np.cos(OM * nh[:,None] * self.tt0[None,:]) - Swaves = -(OM * nh[:,None]) ** 2 * waveamps[:,1,None] * np.sin(OM * nh[:,None] * self.tt0[None,:]) + Cwaves = ( + -((OM * nh[:, None]) ** 2) + * waveamps[:, 0, None] + * np.cos(OM * nh[:, None] * tw[None, :]) + ) + Swaves = ( + -((OM * nh[:, None]) ** 2) + * waveamps[:, 1, None] + * np.sin(OM * nh[:, None] * tw[None, :]) + ) - d2Tascshift_dt2 = np.sum(Cwaves + Swaves,axis=0) + d2_deltaPhi_dt2 = np.sum(Cwaves + Swaves, axis=0) - return d2Tascshift_dt2.to(u.Unit("1/s"),equivalencies=u.dimensionless_angles()) + return d2_deltaPhi_dt2.to( + u.Unit("1/s^2"), equivalencies=u.dimensionless_angles() + ) def orbits(self): @@ -336,7 +381,7 @@ def orbits(self): # If TASC occurs "early", then accumulated orbital phase is larger, # hence -ve sign here - dphi = -self._Tascshift() / PB + dphi = self._deltaPhi() """Orbital phase (number of orbits since T0).""" @@ -344,73 +389,75 @@ def orbits(self): return orbits.decompose() def pbprime(self): - """Derivative of binary period with respect to time.""" + """Instantaneous binary period as a function of time.""" PB = self.PB.to("second") - FB0 = 1.0/PB + FB0 = 1.0 / PB + + FB0_shift = self._d_deltaPhi_dt() - FB0_shift = -self._dTascshift_dt() / PB - return 1.0 / (FB0 + FB0_shift).decompose() def pbdot_orbit(self): """Reported value of PBDOT.""" - PB = self.PB.to("second") - FB1 = -self._d2Tascshift_dt2() / PB - + FB1 = self._d2_deltaPhi_dt2() + return -(self.pbprime() ** 2) * FB1 def d_orbits_d_TASC(self): PB = self.PB.to("second") - return -(1 / PB).decompose() * 2 * np.pi * u.rad + return -(1 / PB) * 2 * np.pi * u.rad def d_orbits_d_PB(self): PB = self.PB.to("second") - return -(self.tt0 / PB ** 2).decompose() * 2 * np.pi * u.rad + return -(self.tt0 / PB**2).decompose() * 2 * np.pi * u.rad - def d_orbits_d_orbwave(self,par): + def d_orbits_d_orbwave(self, par): - OM = self.ORBWAVEOM.to("radian/second") - PB = self.PB.to("second") + print("d_orbits_d_orbwave", par) + tw = self._tw() + WOM = self.ORBWAVE_OM.to("radian/second") nh = int(par[8:]) return ( - -np.cos(OM * nh * self.tt0) - if par[7] == "C" - else -np.sin(OM * nh * self.tt0) - ) * 2 * np.pi * u.rad / PB + (np.cos(WOM * nh * tw) if par[7] == "C" else np.sin(WOM * nh * tw)) + * 2 + * np.pi + * u.rad + ) def d_pbprime_d_PB(self): PB = self.PB.to("second") - FB0 = 1.0/PB + FB0 = 1.0 / PB - FB0_shift = -self._dTascshift_dt() / PB + FB0_shift = self._d_deltaPhi_dt() FB0_prime = FB0 + FB0_shift - - return (1.0/FB0_prime ** 2 / PB ** 2).decompose() - def d_pbprime_d_orbwave(self,par): + return (1.0 / ((FB0_prime * PB) ** 2)).decompose() - OM = self.ORBWAVEOM.to("radian/second") + def d_pbprime_d_orbwave(self, par): + + tw = self._tw() + WOM = self.ORBWAVE_OM.to("radian/second") PB = self.PB.to("second") - FB0 = 1.0/PB - FB0_shift = -self._dTascshift_dt() / PB + FB0 = 1.0 / PB + FB0_shift = self._d_deltaPhi_dt() FB0_prime = FB0 + FB0_shift nh = int(par[8:]) if par[7] == "C": - dFB0_shift_dorbwave = -OM * nh * np.sin(OM * nh * self.tt0) / PB + d_deltaFB0_d_orbwave = -WOM * nh * np.sin(WOM * nh * tw) else: - dFB0_shift_dorbwave = OM * nh * np.cos(OM * nh * self.tt0) / PB + d_deltaFB0_d_orbwave = WOM * nh * np.cos(WOM * nh * tw) + + return (-1.0 / FB0_prime**2 * d_deltaFB0_d_orbwave).to( + "d", equivalencies=u.dimensionless_angles() + ) - return ( - 1.0/FB0_prime ** 2 * dFB0_shift_dorbwave - ).to("d/s",equivalencies=u.dimensionless_angles()) - def d_orbits_d_par(self, par): return ( @@ -421,11 +468,13 @@ def d_orbits_d_par(self, par): def d_pbprime_d_par(self, par): par_obj = getattr(self, par) - return ( - self.d_pbprime_d_orbwave(par) - if re.match(r"ORBWAVE[CS]\d+", par) is not None - else np.zeros(len(self.tt0)) * u.second / par_obj.unit - ) + if re.match(r"ORBWAVE[CS]\d+", par) is not None: + return self.d_pbprime_d_orbwave(par) - + elif par == "PB": + return self.d_pbprime_d_PB() + + # TASC, or other parameters, don't affect PB prime + else: + return np.zeros(len(self.tt0)) * u.second / par_obj.unit From 1d25d7ec5961c7c7b64ffb549bc01513eab4ba61 Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Fri, 15 Dec 2023 14:25:45 +0100 Subject: [PATCH 005/195] Tidying up comments in new ORBWAVES code --- src/pint/models/pulsar_binary.py | 69 ++++++++++--------- .../stand_alone_psr_binaries/binary_orbits.py | 10 +-- 2 files changed, 39 insertions(+), 40 deletions(-) diff --git a/src/pint/models/pulsar_binary.py b/src/pint/models/pulsar_binary.py index 150df16ce..becc3f995 100644 --- a/src/pint/models/pulsar_binary.py +++ b/src/pint/models/pulsar_binary.py @@ -1,3 +1,4 @@ + """Support for independent binary models. This module if for wrapping standalone binary models so that they work @@ -189,7 +190,7 @@ def __init__(self): units="", description="Amplitude of cosine wave in Tasc-shift function", aliases=["ORBWAVEC"], - description_template=self.ORBWAVE_description, + description_template=self.ORBWAVEC_description, type_match="float", long_double=True, ) @@ -202,7 +203,7 @@ def __init__(self): units="", description="Amplitude of sine wave in Tasc-shift function", aliases=["ORBWAVES"], - description_template=self.ORBWAVE_description, + description_template=self.ORBWAVES_description, type_match="float", long_double=True, ) @@ -212,7 +213,7 @@ def __init__(self): floatParameter( name="ORBWAVE_OM", units="rad/s", - description="Amplitude of cosine wave in Tasc-shift function", + description="Base frequency for ORBWAVEs model", long_double=True, ) ) @@ -249,6 +250,34 @@ def setup(self): self.binary_instance, list(FBXs.keys()) ) + # Note: if we are happy to use these to show alternate parameterizations then this can be uncommented + + # # remove the PB parameterization, replace with functions + # self.remove_param("PB") + # self.remove_param("PBDOT") + # self.add_param( + # funcParameter( + # name="PB", + # units=u.day, + # description="Orbital period", + # long_double=True, + # params=("FB0",), + # func=_p_to_f, + # ) + # ) + # self.add_param( + # funcParameter( + # name="PBDOT", + # units=u.day / u.day, + # description="Orbital period derivative respect to time", + # unit_scale=True, + # scale_factor=1e-12, + # scale_threshold=1e-7, + # params=("FB0", "FB1"), + # func=_pdot_to_fdot, + # ) + # ) + ORBWAVES_mapping = self.get_prefix_mapping_component("ORBWAVES") ORBWAVES = { ows: getattr(self, ows).quantity for ows in ORBWAVES_mapping.values() @@ -280,33 +309,6 @@ def setup(self): + list(ORBWAVEC.keys()), ) - # Note: if we are happy to use these to show alternate parameterizations then this can be uncommented - - # # remove the PB parameterization, replace with functions - # self.remove_param("PB") - # self.remove_param("PBDOT") - # self.add_param( - # funcParameter( - # name="PB", - # units=u.day, - # description="Orbital period", - # long_double=True, - # params=("FB0",), - # func=_p_to_f, - # ) - # ) - # self.add_param( - # funcParameter( - # name="PBDOT", - # units=u.day / u.day, - # description="Orbital period derivative respect to time", - # unit_scale=True, - # scale_factor=1e-12, - # scale_threshold=1e-7, - # params=("FB0", "FB1"), - # func=_pdot_to_fdot, - # ) - # ) # Note: if we are happy to use these to show alternate parameterizations then this can be uncommented # else: # # remove the FB parameterization, replace with functions @@ -543,8 +545,11 @@ def FBX_unit(self, n): def FBX_description(self, n): return "%dth time derivative of frequency of orbit" % n - def ORBWAVE_description(self, n): - return "%dth cosine wave in Fourier series model of Tasc shifts" % n + def ORBWAVES_description(self, n): + return "Coefficient of the %dth sine wave in Fourier series model of Tasc variations" % n + + def ORBWAVEC_description(self, n): + return "Coefficient of the %dth cosine wave in Fourier series model of Tasc variations" % n def change_binary_epoch(self, new_epoch): """Change the epoch for this binary model. diff --git a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py index ff8a17ffb..63273fa44 100644 --- a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py +++ b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py @@ -2,7 +2,6 @@ import astropy.units as u import numpy as np -import matplotlib.pyplot as plt from pint.utils import taylor_horner, taylor_horner_deriv @@ -256,7 +255,7 @@ def __init__( ], ): super().__init__("orbitWaves", parent, orbit_params) - # add the rest of FBX parameters. + Cindices = set() Sindices = set() @@ -375,16 +374,12 @@ def _d2_deltaPhi_dt2(self): ) def orbits(self): - + """Orbital phase (number of orbits since TASC).""" PB = self.PB.to("second") orbits = self.tt0 / PB - # If TASC occurs "early", then accumulated orbital phase is larger, - # hence -ve sign here dphi = self._deltaPhi() - """Orbital phase (number of orbits since T0).""" - orbits += dphi return orbits.decompose() @@ -415,7 +410,6 @@ def d_orbits_d_PB(self): def d_orbits_d_orbwave(self, par): - print("d_orbits_d_orbwave", par) tw = self._tw() WOM = self.ORBWAVE_OM.to("radian/second") nh = int(par[8:]) From 48d85edb2e4e79de229314b3eeaa63453281d770 Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Thu, 18 Jan 2024 13:09:46 +0100 Subject: [PATCH 006/195] Correcting harmonic number in orbwave derivatives --- src/pint/models/stand_alone_psr_binaries/binary_orbits.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py index 63273fa44..460e9041c 100644 --- a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py +++ b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py @@ -412,7 +412,7 @@ def d_orbits_d_orbwave(self, par): tw = self._tw() WOM = self.ORBWAVE_OM.to("radian/second") - nh = int(par[8:]) + nh = int(par[8:]) + 1 return ( (np.cos(WOM * nh * tw) if par[7] == "C" else np.sin(WOM * nh * tw)) @@ -442,7 +442,7 @@ def d_pbprime_d_orbwave(self, par): FB0_prime = FB0 + FB0_shift - nh = int(par[8:]) + nh = int(par[8:]) + 1 if par[7] == "C": d_deltaFB0_d_orbwave = -WOM * nh * np.sin(WOM * nh * tw) else: From f2e08b0e31333ebc4427451e81eff0eb9db0d670 Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Thu, 18 Jan 2024 15:44:33 +0100 Subject: [PATCH 007/195] Running black on files changed by orbwaves additions. --- src/pint/models/pulsar_binary.py | 11 ++++++++--- .../models/stand_alone_psr_binaries/binary_orbits.py | 11 ----------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/pint/models/pulsar_binary.py b/src/pint/models/pulsar_binary.py index becc3f995..6aa7672ac 100644 --- a/src/pint/models/pulsar_binary.py +++ b/src/pint/models/pulsar_binary.py @@ -1,4 +1,3 @@ - """Support for independent binary models. This module if for wrapping standalone binary models so that they work @@ -546,10 +545,16 @@ def FBX_description(self, n): return "%dth time derivative of frequency of orbit" % n def ORBWAVES_description(self, n): - return "Coefficient of the %dth sine wave in Fourier series model of Tasc variations" % n + return ( + "Coefficient of the %dth sine wave in Fourier series model of Tasc variations" + % n + ) def ORBWAVEC_description(self, n): - return "Coefficient of the %dth cosine wave in Fourier series model of Tasc variations" % n + return ( + "Coefficient of the %dth cosine wave in Fourier series model of Tasc variations" + % n + ) def change_binary_epoch(self, new_epoch): """Change the epoch for this binary model. diff --git a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py index 460e9041c..bfa3a4dbc 100644 --- a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py +++ b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py @@ -288,7 +288,6 @@ def __init__( self.nwaves = ns def _ORBWAVEs(self): - ii = 0 while f"ORBWAVEC{ii}" in self.orbit_params: ii += 1 @@ -303,7 +302,6 @@ def _ORBWAVEs(self): return ORBWAVEs def _tw(self): - t = self.t if not hasattr(self.t, "unit") or self.t.unit is None: t = self.t * u.day @@ -312,7 +310,6 @@ def _tw(self): return tw def _deltaPhi(self): - tw = self._tw() waveamps = self._ORBWAVEs() OM = self.ORBWAVE_OM.to("radian/second") @@ -326,7 +323,6 @@ def _deltaPhi(self): return delta_Phi def _d_deltaPhi_dt(self): - tw = self._tw() waveamps = self._ORBWAVEs() OM = self.ORBWAVE_OM.to("radian/second") @@ -350,7 +346,6 @@ def _d_deltaPhi_dt(self): return d_deltaPhi_dt.to(u.Unit("1/s"), equivalencies=u.dimensionless_angles()) def _d2_deltaPhi_dt2(self): - tw = self._tw() waveamps = self._ORBWAVEs() OM = self.ORBWAVE_OM.to("radian/second") @@ -399,17 +394,14 @@ def pbdot_orbit(self): return -(self.pbprime() ** 2) * FB1 def d_orbits_d_TASC(self): - PB = self.PB.to("second") return -(1 / PB) * 2 * np.pi * u.rad def d_orbits_d_PB(self): - PB = self.PB.to("second") return -(self.tt0 / PB**2).decompose() * 2 * np.pi * u.rad def d_orbits_d_orbwave(self, par): - tw = self._tw() WOM = self.ORBWAVE_OM.to("radian/second") nh = int(par[8:]) + 1 @@ -422,7 +414,6 @@ def d_orbits_d_orbwave(self, par): ) def d_pbprime_d_PB(self): - PB = self.PB.to("second") FB0 = 1.0 / PB @@ -433,7 +424,6 @@ def d_pbprime_d_PB(self): return (1.0 / ((FB0_prime * PB) ** 2)).decompose() def d_pbprime_d_orbwave(self, par): - tw = self._tw() WOM = self.ORBWAVE_OM.to("radian/second") PB = self.PB.to("second") @@ -453,7 +443,6 @@ def d_pbprime_d_orbwave(self, par): ) def d_orbits_d_par(self, par): - return ( self.d_orbits_d_orbwave(par) if re.match(r"ORBWAVE[CS]\d+", par) is not None From 7a44f8b2262d8bea0669e559808c5ed926898237 Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Thu, 18 Jan 2024 15:46:21 +0100 Subject: [PATCH 008/195] Removing some unnecessary whitespace changes --- src/pint/models/pulsar_binary.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pint/models/pulsar_binary.py b/src/pint/models/pulsar_binary.py index 6aa7672ac..53c071afe 100644 --- a/src/pint/models/pulsar_binary.py +++ b/src/pint/models/pulsar_binary.py @@ -235,7 +235,6 @@ def setup(self): self.register_deriv_funcs(self.d_binary_delay_d_xxxx, bpar) # Setup the model isinstance self.binary_instance = self.binary_model_class() - # Setup the FBX orbits if FB is set. # TODO this should use a smarter way to set up orbit. FBX_mapping = self.get_prefix_mapping_component("FB") @@ -248,7 +247,6 @@ def setup(self): self.binary_instance.orbits_cls = bo.OrbitFBX( self.binary_instance, list(FBXs.keys()) ) - # Note: if we are happy to use these to show alternate parameterizations then this can be uncommented # # remove the PB parameterization, replace with functions From a305ae0760bda5940bbad2d6f22dcfdd3861f23e Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Mon, 3 Jun 2024 12:02:12 +0200 Subject: [PATCH 009/195] ChromaticCMX stub --- src/pint/models/chromatic_model.py | 414 ++++++++++++++++++++++++++++ src/pint/models/dispersion_model.py | 2 +- 2 files changed, 415 insertions(+), 1 deletion(-) diff --git a/src/pint/models/chromatic_model.py b/src/pint/models/chromatic_model.py index 83583a5e9..5fab08926 100644 --- a/src/pint/models/chromatic_model.py +++ b/src/pint/models/chromatic_model.py @@ -300,3 +300,417 @@ def change_cmepoch(self, new_epoch): dt.to(u.yr), cmterms, deriv_order=n + 1 ) self.CMEPOCH.value = new_epoch + + +class ChromaticCMX(Chromatic): + """This class provides a CMX model - piecewise-constant chromatic variations. + + This model lets the user specify time ranges and fit for a different + CMX value in each time range. + + Parameters supported: + + .. paramtable:: + :class: pint.models.dispersion_model.DispersionDMX + """ + + register = True + category = "dispersion_dmx" + + def __init__(self): + super().__init__() + + # DMX is for info output right now + # @abhisrkckl: What exactly is the use of this parameter? + self.add_param( + floatParameter( + name="DMX", + units="pc cm^-3", + value=0.0, + description="Dispersion measure", + convert_tcb2tdb=False, + ) + ) + + self.add_DMX_range(None, None, dmx=0, frozen=False, index=1) + + self.dm_value_funcs += [self.dmx_dm] + self.set_special_params(["DMX_0001", "DMXR1_0001", "DMXR2_0001"]) + self.delay_funcs_component += [self.DMX_dispersion_delay] + + def add_DMX_range(self, mjd_start, mjd_end, index=None, dmx=0, frozen=True): + """Add DMX range to a dispersion model with specified start/end MJDs and DMX. + + Parameters + ---------- + + mjd_start : float or astropy.quantity.Quantity or astropy.time.Time + MJD for beginning of DMX event. + mjd_end : float or astropy.quantity.Quantity or astropy.time.Time + MJD for end of DMX event. + index : int, None + Integer label for DMX event. If None, will increment largest used index by 1. + dmx : float or astropy.quantity.Quantity + Change in DM during DMX event. + frozen : bool + Indicates whether DMX will be fit. + + Returns + ------- + + index : int + Index that has been assigned to new DMX event. + + """ + + #### Setting up the DMX title convention. If index is None, want to increment the current max DMX index by 1. + if index is None: + dct = self.get_prefix_mapping_component("DMX_") + index = np.max(list(dct.keys())) + 1 + i = f"{int(index):04d}" + + if mjd_end is not None and mjd_start is not None: + if mjd_end < mjd_start: + raise ValueError("Starting MJD is greater than ending MJD.") + elif mjd_start != mjd_end: + raise ValueError("Only one MJD bound is set.") + + if int(index) in self.get_prefix_mapping_component("DMX_"): + raise ValueError( + f"Index '{index}' is already in use in this model. Please choose another." + ) + + if isinstance(dmx, u.quantity.Quantity): + dmx = dmx.to_value(u.pc / u.cm**3) + if isinstance(mjd_start, Time): + mjd_start = mjd_start.mjd + elif isinstance(mjd_start, u.quantity.Quantity): + mjd_start = mjd_start.value + if isinstance(mjd_end, Time): + mjd_end = mjd_end.mjd + elif isinstance(mjd_end, u.quantity.Quantity): + mjd_end = mjd_end.value + self.add_param( + prefixParameter( + name=f"DMX_{i}", + units="pc cm^-3", + value=dmx, + description="Dispersion measure variation", + parameter_type="float", + frozen=frozen, + tcb2tdb_scale_factor=DMconst, + ) + ) + self.add_param( + prefixParameter( + name=f"DMXR1_{i}", + units="MJD", + description="Beginning of DMX interval", + parameter_type="MJD", + time_scale="utc", + value=mjd_start, + tcb2tdb_scale_factor=u.Quantity(1), + ) + ) + self.add_param( + prefixParameter( + name=f"DMXR2_{i}", + units="MJD", + description="End of DMX interval", + parameter_type="MJD", + time_scale="utc", + value=mjd_end, + tcb2tdb_scale_factor=u.Quantity(1), + ) + ) + self.setup() + self.validate() + return index + + def add_DMX_ranges(self, mjd_starts, mjd_ends, indices=None, dmxs=0, frozens=True): + """Add DMX ranges to a dispersion model with specified start/end MJDs and DMXs. + + Parameters + ---------- + + mjd_starts : iterable of float or astropy.quantity.Quantity or astropy.time.Time + MJD for beginning of DMX event. + mjd_end : iterable of float or astropy.quantity.Quantity or astropy.time.Time + MJD for end of DMX event. + indices : iterable of int, None + Integer label for DMX event. If None, will increment largest used index by 1. + dmxs : iterable of float or astropy.quantity.Quantity, or float or astropy.quantity.Quantity + Change in DM during DMX event. + frozens : iterable of bool or bool + Indicates whether DMX will be fit. + + Returns + ------- + + indices : list + Indices that has been assigned to new DMX events + + """ + if len(mjd_starts) != len(mjd_ends): + raise ValueError( + f"Number of mjd_start values {len(mjd_starts)} must match number of mjd_end values {len(mjd_ends)}" + ) + if indices is None: + indices = [None] * len(mjd_starts) + dmxs = np.atleast_1d(dmxs) + if len(dmxs) == 1: + dmxs = np.repeat(dmxs, len(mjd_starts)) + if len(dmxs) != len(mjd_starts): + raise ValueError( + f"Number of mjd_start values {len(mjd_starts)} must match number of dmx values {len(dmxs)}" + ) + frozens = np.atleast_1d(frozens) + if len(frozens) == 1: + frozens = np.repeat(frozens, len(mjd_starts)) + if len(frozens) != len(mjd_starts): + raise ValueError( + f"Number of mjd_start values {len(mjd_starts)} must match number of frozen values {len(frozens)}" + ) + + #### Setting up the DMX title convention. If index is None, want to increment the current max DMX index by 1. + dct = self.get_prefix_mapping_component("DMX_") + last_index = np.max(list(dct.keys())) + added_indices = [] + for mjd_start, mjd_end, index, dmx, frozen in zip( + mjd_starts, mjd_ends, indices, dmxs, frozens + ): + if index is None: + index = last_index + 1 + last_index += 1 + elif index in list(dct.keys()): + raise ValueError( + f"Attempting to insert DMX_{index:04d} but it already exists" + ) + added_indices.append(index) + i = f"{int(index):04d}" + + if mjd_end is not None and mjd_start is not None: + if mjd_end < mjd_start: + raise ValueError("Starting MJD is greater than ending MJD.") + elif mjd_start != mjd_end: + raise ValueError("Only one MJD bound is set.") + if int(index) in dct: + raise ValueError( + f"Index '{index}' is already in use in this model. Please choose another." + ) + if isinstance(dmx, u.quantity.Quantity): + dmx = dmx.to_value(u.pc / u.cm**3) + if isinstance(mjd_start, Time): + mjd_start = mjd_start.mjd + elif isinstance(mjd_start, u.quantity.Quantity): + mjd_start = mjd_start.value + if isinstance(mjd_end, Time): + mjd_end = mjd_end.mjd + elif isinstance(mjd_end, u.quantity.Quantity): + mjd_end = mjd_end.value + log.trace(f"Adding DMX_{i} from MJD {mjd_start} to MJD {mjd_end}") + self.add_param( + prefixParameter( + name=f"DMX_{i}", + units="pc cm^-3", + value=dmx, + description="Dispersion measure variation", + parameter_type="float", + frozen=frozen, + tcb2tdb_scale_factor=DMconst, + ) + ) + self.add_param( + prefixParameter( + name=f"DMXR1_{i}", + units="MJD", + description="Beginning of DMX interval", + parameter_type="MJD", + time_scale="utc", + value=mjd_start, + tcb2tdb_scale_factor=u.Quantity(1), + ) + ) + self.add_param( + prefixParameter( + name=f"DMXR2_{i}", + units="MJD", + description="End of DMX interval", + parameter_type="MJD", + time_scale="utc", + value=mjd_end, + tcb2tdb_scale_factor=u.Quantity(1), + ) + ) + self.setup() + self.validate() + return added_indices + + def remove_DMX_range(self, index): + """Removes all DMX parameters associated with a given index/list of indices. + + Parameters + ---------- + + index : float, int, list, np.ndarray + Number or list/array of numbers corresponding to DMX indices to be removed from model. + """ + + if isinstance(index, (int, float, np.int64)): + indices = [index] + elif isinstance(index, (list, set, np.ndarray)): + indices = index + else: + raise TypeError( + f"index must be a float, int, set, list, or array - not {type(index)}" + ) + for index in indices: + index_rf = f"{int(index):04d}" + for prefix in ["DMX_", "DMXR1_", "DMXR2_"]: + self.remove_param(prefix + index_rf) + self.validate() + + def get_indices(self): + """Returns an array of integers corresponding to DMX parameters. + + Returns + ------- + inds : np.ndarray + Array of DMX indices in model. + """ + inds = [int(p.split("_")[-1]) for p in self.params if "DMX_" in p] + return np.array(inds) + + def setup(self): + super().setup() + # Get DMX mapping. + # Register the DMX derivatives + for prefix_par in self.get_params_of_type("prefixParameter"): + if prefix_par.startswith("DMX_"): + self.register_deriv_funcs(self.d_delay_d_dmparam, prefix_par) + self.register_dm_deriv_funcs(self.d_dm_d_DMX, prefix_par) + + def validate(self): + """Validate the DMX parameters.""" + super().validate() + DMX_mapping = self.get_prefix_mapping_component("DMX_") + DMXR1_mapping = self.get_prefix_mapping_component("DMXR1_") + DMXR2_mapping = self.get_prefix_mapping_component("DMXR2_") + if DMX_mapping.keys() != DMXR1_mapping.keys(): + # FIXME: report mismatch + raise ValueError( + "DMX_ parameters do not " + "match DMXR1_ parameters. " + "Please check your prefixed parameters." + ) + if DMX_mapping.keys() != DMXR2_mapping.keys(): + raise ValueError( + "DMX_ parameters do not " + "match DMXR2_ parameters. " + "Please check your prefixed parameters." + ) + r1 = np.zeros(len(DMX_mapping)) + r2 = np.zeros(len(DMX_mapping)) + indices = np.zeros(len(DMX_mapping), dtype=np.int32) + for j, index in enumerate(DMX_mapping): + if ( + getattr(self, f"DMXR1_{index:04d}").quantity is not None + and getattr(self, f"DMXR2_{index:04d}").quantity is not None + ): + r1[j] = getattr(self, f"DMXR1_{index:04d}").quantity.mjd + r2[j] = getattr(self, f"DMXR2_{index:04d}").quantity.mjd + indices[j] = index + for j, index in enumerate(DMXR1_mapping): + if np.any((r1[j] > r1) & (r1[j] < r2)): + k = np.where((r1[j] > r1) & (r1[j] < r2))[0] + for kk in k.flatten(): + log.warning( + f"Start of DMX_{index:04d} ({r1[j]}-{r2[j]}) overlaps with DMX_{indices[kk]:04d} ({r1[kk]}-{r2[kk]})" + ) + if np.any((r2[j] > r1) & (r2[j] < r2)): + k = np.where((r2[j] > r1) & (r2[j] < r2))[0] + for kk in k.flatten(): + log.warning( + f"End of DMX_{index:04d} ({r1[j]}-{r2[j]}) overlaps with DMX_{indices[kk]:04d} ({r1[kk]}-{r2[kk]})" + ) + + def validate_toas(self, toas): + DMX_mapping = self.get_prefix_mapping_component("DMX_") + DMXR1_mapping = self.get_prefix_mapping_component("DMXR1_") + DMXR2_mapping = self.get_prefix_mapping_component("DMXR2_") + bad_parameters = [] + for k in DMXR1_mapping.keys(): + if self._parent[DMX_mapping[k]].frozen: + continue + b = self._parent[DMXR1_mapping[k]].quantity.mjd * u.d + e = self._parent[DMXR2_mapping[k]].quantity.mjd * u.d + mjds = toas.get_mjds() + n = np.sum((b <= mjds) & (mjds < e)) + if n == 0: + bad_parameters.append(DMX_mapping[k]) + if bad_parameters: + raise MissingTOAs(bad_parameters) + + def dmx_dm(self, toas): + condition = {} + tbl = toas.table + if not hasattr(self, "dmx_toas_selector"): + self.dmx_toas_selector = TOASelect(is_range=True) + DMX_mapping = self.get_prefix_mapping_component("DMX_") + DMXR1_mapping = self.get_prefix_mapping_component("DMXR1_") + DMXR2_mapping = self.get_prefix_mapping_component("DMXR2_") + for epoch_ind in DMX_mapping.keys(): + r1 = getattr(self, DMXR1_mapping[epoch_ind]).quantity + r2 = getattr(self, DMXR2_mapping[epoch_ind]).quantity + condition[DMX_mapping[epoch_ind]] = (r1.mjd, r2.mjd) + select_idx = self.dmx_toas_selector.get_select_index( + condition, tbl["mjd_float"] + ) + # Get DMX delays + dm = np.zeros(len(tbl)) * self._parent.DM.units + for k, v in select_idx.items(): + dm[v] += getattr(self, k).quantity + return dm + + def DMX_dispersion_delay(self, toas, acc_delay=None): + """This is a wrapper function for interacting with the TimingModel class""" + return self.dispersion_type_delay(toas) + + def d_dm_d_DMX(self, toas, param_name, acc_delay=None): + condition = {} + tbl = toas.table + if not hasattr(self, "dmx_toas_selector"): + self.dmx_toas_selector = TOASelect(is_range=True) + param = getattr(self, param_name) + dmx_index = param.index + DMXR1_mapping = self.get_prefix_mapping_component("DMXR1_") + DMXR2_mapping = self.get_prefix_mapping_component("DMXR2_") + r1 = getattr(self, DMXR1_mapping[dmx_index]).quantity + r2 = getattr(self, DMXR2_mapping[dmx_index]).quantity + condition = {param_name: (r1.mjd, r2.mjd)} + select_idx = self.dmx_toas_selector.get_select_index( + condition, tbl["mjd_float"] + ) + + try: + bfreq = self._parent.barycentric_radio_freq(toas) + except AttributeError: + warn("Using topocentric frequency for dedispersion!") + bfreq = tbl["freq"] + dmx = np.zeros(len(tbl)) + for k, v in select_idx.items(): + dmx[v] = 1.0 + return dmx * (u.pc / u.cm**3) / (u.pc / u.cm**3) + + def print_par(self, format="pint"): + result = "" + DMX_mapping = self.get_prefix_mapping_component("DMX_") + DMXR1_mapping = self.get_prefix_mapping_component("DMXR1_") + DMXR2_mapping = self.get_prefix_mapping_component("DMXR2_") + result += getattr(self, "DMX").as_parfile_line(format=format) + sorted_list = sorted(DMX_mapping.keys()) + for ii in sorted_list: + result += getattr(self, DMX_mapping[ii]).as_parfile_line(format=format) + result += getattr(self, DMXR1_mapping[ii]).as_parfile_line(format=format) + result += getattr(self, DMXR2_mapping[ii]).as_parfile_line(format=format) + return result diff --git a/src/pint/models/dispersion_model.py b/src/pint/models/dispersion_model.py index e5317b06c..9ddd06ed7 100644 --- a/src/pint/models/dispersion_model.py +++ b/src/pint/models/dispersion_model.py @@ -308,7 +308,7 @@ def change_dmepoch(self, new_epoch): class DispersionDMX(Dispersion): - """This class provides a DMX model - multiple DM values. + """This class provides a DMX model - piecewise-constant DM variations. This model lets the user specify time ranges and fit for a different DM value in each time range. From 2142369383ad760e3cc183bb8d3e111f21c4a9d2 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Mon, 3 Jun 2024 13:04:26 +0200 Subject: [PATCH 010/195] cmx --- src/pint/models/chromatic_model.py | 287 ++++++++++++++-------------- src/pint/models/dispersion_model.py | 2 +- 2 files changed, 140 insertions(+), 149 deletions(-) diff --git a/src/pint/models/chromatic_model.py b/src/pint/models/chromatic_model.py index 5fab08926..3a0d4f40c 100644 --- a/src/pint/models/chromatic_model.py +++ b/src/pint/models/chromatic_model.py @@ -2,11 +2,13 @@ from warnings import warn import numpy as np import astropy.units as u -from pint.models.timing_model import DelayComponent, MissingParameter +from pint.models.timing_model import DelayComponent, MissingParameter, MissingTOAs from pint.models.parameter import floatParameter, prefixParameter, MJDParameter +from pint.toa_select import TOASelect from pint.utils import split_prefixed_name, taylor_horner, taylor_horner_deriv from pint import DMconst from astropy.time import Time +from loguru import logger as log cmu = u.pc / u.cm**3 / u.MHz**2 @@ -311,61 +313,49 @@ class ChromaticCMX(Chromatic): Parameters supported: .. paramtable:: - :class: pint.models.dispersion_model.DispersionDMX + :class: pint.models.chromatic_model.ChromaticCMX """ register = True - category = "dispersion_dmx" + category = "chromatic_cmx" def __init__(self): super().__init__() - # DMX is for info output right now - # @abhisrkckl: What exactly is the use of this parameter? - self.add_param( - floatParameter( - name="DMX", - units="pc cm^-3", - value=0.0, - description="Dispersion measure", - convert_tcb2tdb=False, - ) - ) + self.add_CMX_range(None, None, cmx=0, frozen=False, index=1) - self.add_DMX_range(None, None, dmx=0, frozen=False, index=1) + self.cm_value_funcs += [self.cmx_cm] + self.set_special_params(["CMX_0001", "CMXR1_0001", "CMXR2_0001"]) + self.delay_funcs_component += [self.CMX_chromatic_delay] - self.dm_value_funcs += [self.dmx_dm] - self.set_special_params(["DMX_0001", "DMXR1_0001", "DMXR2_0001"]) - self.delay_funcs_component += [self.DMX_dispersion_delay] - - def add_DMX_range(self, mjd_start, mjd_end, index=None, dmx=0, frozen=True): - """Add DMX range to a dispersion model with specified start/end MJDs and DMX. + def add_CMX_range(self, mjd_start, mjd_end, index=None, cmx=0, frozen=True): + """Add CMX range to a chromatic model with specified start/end MJDs and CMX value. Parameters ---------- mjd_start : float or astropy.quantity.Quantity or astropy.time.Time - MJD for beginning of DMX event. + MJD for beginning of CMX event. mjd_end : float or astropy.quantity.Quantity or astropy.time.Time - MJD for end of DMX event. + MJD for end of CMX event. index : int, None - Integer label for DMX event. If None, will increment largest used index by 1. - dmx : float or astropy.quantity.Quantity - Change in DM during DMX event. + Integer label for CMX event. If None, will increment largest used index by 1. + cmx : float or astropy.quantity.Quantity + Change in CM during CMX event. frozen : bool - Indicates whether DMX will be fit. + Indicates whether CMX will be fit. Returns ------- index : int - Index that has been assigned to new DMX event. + Index that has been assigned to new CMX event. """ - #### Setting up the DMX title convention. If index is None, want to increment the current max DMX index by 1. + #### Setting up the CMX title convention. If index is None, want to increment the current max CMX index by 1. if index is None: - dct = self.get_prefix_mapping_component("DMX_") + dct = self.get_prefix_mapping_component("CMX_") index = np.max(list(dct.keys())) + 1 i = f"{int(index):04d}" @@ -375,13 +365,14 @@ def add_DMX_range(self, mjd_start, mjd_end, index=None, dmx=0, frozen=True): elif mjd_start != mjd_end: raise ValueError("Only one MJD bound is set.") - if int(index) in self.get_prefix_mapping_component("DMX_"): + if int(index) in self.get_prefix_mapping_component("CMX_"): raise ValueError( f"Index '{index}' is already in use in this model. Please choose another." ) - if isinstance(dmx, u.quantity.Quantity): - dmx = dmx.to_value(u.pc / u.cm**3) + if isinstance(cmx, u.quantity.Quantity): + cmx = cmx.to_value(cmu) + if isinstance(mjd_start, Time): mjd_start = mjd_start.mjd elif isinstance(mjd_start, u.quantity.Quantity): @@ -392,63 +383,63 @@ def add_DMX_range(self, mjd_start, mjd_end, index=None, dmx=0, frozen=True): mjd_end = mjd_end.value self.add_param( prefixParameter( - name=f"DMX_{i}", - units="pc cm^-3", - value=dmx, + name=f"CMX_{i}", + units=cmu, + value=cmx, description="Dispersion measure variation", parameter_type="float", frozen=frozen, - tcb2tdb_scale_factor=DMconst, + convert_tcb2tdb=False, ) ) self.add_param( prefixParameter( - name=f"DMXR1_{i}", + name=f"CMXR1_{i}", units="MJD", - description="Beginning of DMX interval", + description="Beginning of CMX interval", parameter_type="MJD", time_scale="utc", value=mjd_start, - tcb2tdb_scale_factor=u.Quantity(1), + convert_tcb2tdb=False, ) ) self.add_param( prefixParameter( - name=f"DMXR2_{i}", + name=f"CMXR2_{i}", units="MJD", - description="End of DMX interval", + description="End of CMX interval", parameter_type="MJD", time_scale="utc", value=mjd_end, - tcb2tdb_scale_factor=u.Quantity(1), + convert_tcb2tdb=False, ) ) self.setup() self.validate() return index - def add_DMX_ranges(self, mjd_starts, mjd_ends, indices=None, dmxs=0, frozens=True): - """Add DMX ranges to a dispersion model with specified start/end MJDs and DMXs. + def add_CMX_ranges(self, mjd_starts, mjd_ends, indices=None, cmxs=0, frozens=True): + """Add CMX ranges to a dispersion model with specified start/end MJDs and CMXs. Parameters ---------- mjd_starts : iterable of float or astropy.quantity.Quantity or astropy.time.Time - MJD for beginning of DMX event. + MJD for beginning of CMX event. mjd_end : iterable of float or astropy.quantity.Quantity or astropy.time.Time - MJD for end of DMX event. + MJD for end of CMX event. indices : iterable of int, None - Integer label for DMX event. If None, will increment largest used index by 1. - dmxs : iterable of float or astropy.quantity.Quantity, or float or astropy.quantity.Quantity - Change in DM during DMX event. + Integer label for CMX event. If None, will increment largest used index by 1. + cmxs : iterable of float or astropy.quantity.Quantity, or float or astropy.quantity.Quantity + Change in CM during CMX event. frozens : iterable of bool or bool - Indicates whether DMX will be fit. + Indicates whether CMX will be fit. Returns ------- indices : list - Indices that has been assigned to new DMX events + Indices that has been assigned to new CMX events """ if len(mjd_starts) != len(mjd_ends): @@ -457,12 +448,12 @@ def add_DMX_ranges(self, mjd_starts, mjd_ends, indices=None, dmxs=0, frozens=Tru ) if indices is None: indices = [None] * len(mjd_starts) - dmxs = np.atleast_1d(dmxs) - if len(dmxs) == 1: - dmxs = np.repeat(dmxs, len(mjd_starts)) - if len(dmxs) != len(mjd_starts): + cmxs = np.atleast_1d(cmxs) + if len(cmxs) == 1: + cmxs = np.repeat(cmxs, len(mjd_starts)) + if len(cmxs) != len(mjd_starts): raise ValueError( - f"Number of mjd_start values {len(mjd_starts)} must match number of dmx values {len(dmxs)}" + f"Number of mjd_start values {len(mjd_starts)} must match number of cmx values {len(cmxs)}" ) frozens = np.atleast_1d(frozens) if len(frozens) == 1: @@ -472,19 +463,19 @@ def add_DMX_ranges(self, mjd_starts, mjd_ends, indices=None, dmxs=0, frozens=Tru f"Number of mjd_start values {len(mjd_starts)} must match number of frozen values {len(frozens)}" ) - #### Setting up the DMX title convention. If index is None, want to increment the current max DMX index by 1. - dct = self.get_prefix_mapping_component("DMX_") + #### Setting up the CMX title convention. If index is None, want to increment the current max CMX index by 1. + dct = self.get_prefix_mapping_component("CMX_") last_index = np.max(list(dct.keys())) added_indices = [] - for mjd_start, mjd_end, index, dmx, frozen in zip( - mjd_starts, mjd_ends, indices, dmxs, frozens + for mjd_start, mjd_end, index, cmx, frozen in zip( + mjd_starts, mjd_ends, indices, cmxs, frozens ): if index is None: index = last_index + 1 last_index += 1 elif index in list(dct.keys()): raise ValueError( - f"Attempting to insert DMX_{index:04d} but it already exists" + f"Attempting to insert CMX_{index:04d} but it already exists" ) added_indices.append(index) i = f"{int(index):04d}" @@ -498,8 +489,8 @@ def add_DMX_ranges(self, mjd_starts, mjd_ends, indices=None, dmxs=0, frozens=Tru raise ValueError( f"Index '{index}' is already in use in this model. Please choose another." ) - if isinstance(dmx, u.quantity.Quantity): - dmx = dmx.to_value(u.pc / u.cm**3) + if isinstance(cmx, u.quantity.Quantity): + cmx = cmx.to_value(u.pc / u.cm**3) if isinstance(mjd_start, Time): mjd_start = mjd_start.mjd elif isinstance(mjd_start, u.quantity.Quantity): @@ -508,52 +499,52 @@ def add_DMX_ranges(self, mjd_starts, mjd_ends, indices=None, dmxs=0, frozens=Tru mjd_end = mjd_end.mjd elif isinstance(mjd_end, u.quantity.Quantity): mjd_end = mjd_end.value - log.trace(f"Adding DMX_{i} from MJD {mjd_start} to MJD {mjd_end}") + log.trace(f"Adding CMX_{i} from MJD {mjd_start} to MJD {mjd_end}") self.add_param( prefixParameter( - name=f"DMX_{i}", - units="pc cm^-3", - value=dmx, + name=f"CMX_{i}", + units=cmu, + value=cmx, description="Dispersion measure variation", parameter_type="float", frozen=frozen, - tcb2tdb_scale_factor=DMconst, + convert_tcb2tdb=False, ) ) self.add_param( prefixParameter( - name=f"DMXR1_{i}", + name=f"CMXR1_{i}", units="MJD", - description="Beginning of DMX interval", + description="Beginning of CMX interval", parameter_type="MJD", time_scale="utc", value=mjd_start, - tcb2tdb_scale_factor=u.Quantity(1), + convert_tcb2tdb=False, ) ) self.add_param( prefixParameter( - name=f"DMXR2_{i}", + name=f"CMXR2_{i}", units="MJD", - description="End of DMX interval", + description="End of CMX interval", parameter_type="MJD", time_scale="utc", value=mjd_end, - tcb2tdb_scale_factor=u.Quantity(1), + convert_tcb2tdb=False, ) ) self.setup() self.validate() return added_indices - def remove_DMX_range(self, index): - """Removes all DMX parameters associated with a given index/list of indices. + def remove_CMX_range(self, index): + """Removes all CMX parameters associated with a given index/list of indices. Parameters ---------- index : float, int, list, np.ndarray - Number or list/array of numbers corresponding to DMX indices to be removed from model. + Number or list/array of numbers corresponding to CMX indices to be removed from model. """ if isinstance(index, (int, float, np.int64)): @@ -566,129 +557,129 @@ def remove_DMX_range(self, index): ) for index in indices: index_rf = f"{int(index):04d}" - for prefix in ["DMX_", "DMXR1_", "DMXR2_"]: + for prefix in ["CMX_", "CMXR1_", "CMXR2_"]: self.remove_param(prefix + index_rf) self.validate() def get_indices(self): - """Returns an array of integers corresponding to DMX parameters. + """Returns an array of integers corresponding to CMX parameters. Returns ------- inds : np.ndarray - Array of DMX indices in model. + Array of CMX indices in model. """ - inds = [int(p.split("_")[-1]) for p in self.params if "DMX_" in p] + inds = [int(p.split("_")[-1]) for p in self.params if "CMX_" in p] return np.array(inds) def setup(self): super().setup() - # Get DMX mapping. - # Register the DMX derivatives + # Get CMX mapping. + # Register the CMX derivatives for prefix_par in self.get_params_of_type("prefixParameter"): - if prefix_par.startswith("DMX_"): + if prefix_par.startswith("CMX_"): self.register_deriv_funcs(self.d_delay_d_dmparam, prefix_par) - self.register_dm_deriv_funcs(self.d_dm_d_DMX, prefix_par) + self.register_dm_deriv_funcs(self.d_dm_d_CMX, prefix_par) def validate(self): - """Validate the DMX parameters.""" + """Validate the CMX parameters.""" super().validate() - DMX_mapping = self.get_prefix_mapping_component("DMX_") - DMXR1_mapping = self.get_prefix_mapping_component("DMXR1_") - DMXR2_mapping = self.get_prefix_mapping_component("DMXR2_") - if DMX_mapping.keys() != DMXR1_mapping.keys(): + CMX_mapping = self.get_prefix_mapping_component("CMX_") + CMXR1_mapping = self.get_prefix_mapping_component("CMXR1_") + CMXR2_mapping = self.get_prefix_mapping_component("CMXR2_") + if CMX_mapping.keys() != CMXR1_mapping.keys(): # FIXME: report mismatch raise ValueError( - "DMX_ parameters do not " - "match DMXR1_ parameters. " + "CMX_ parameters do not " + "match CMXR1_ parameters. " "Please check your prefixed parameters." ) - if DMX_mapping.keys() != DMXR2_mapping.keys(): + if CMX_mapping.keys() != CMXR2_mapping.keys(): raise ValueError( - "DMX_ parameters do not " - "match DMXR2_ parameters. " + "CMX_ parameters do not " + "match CMXR2_ parameters. " "Please check your prefixed parameters." ) - r1 = np.zeros(len(DMX_mapping)) - r2 = np.zeros(len(DMX_mapping)) - indices = np.zeros(len(DMX_mapping), dtype=np.int32) - for j, index in enumerate(DMX_mapping): + r1 = np.zeros(len(CMX_mapping)) + r2 = np.zeros(len(CMX_mapping)) + indices = np.zeros(len(CMX_mapping), dtype=np.int32) + for j, index in enumerate(CMX_mapping): if ( - getattr(self, f"DMXR1_{index:04d}").quantity is not None - and getattr(self, f"DMXR2_{index:04d}").quantity is not None + getattr(self, f"CMXR1_{index:04d}").quantity is not None + and getattr(self, f"CMXR2_{index:04d}").quantity is not None ): - r1[j] = getattr(self, f"DMXR1_{index:04d}").quantity.mjd - r2[j] = getattr(self, f"DMXR2_{index:04d}").quantity.mjd + r1[j] = getattr(self, f"CMXR1_{index:04d}").quantity.mjd + r2[j] = getattr(self, f"CMXR2_{index:04d}").quantity.mjd indices[j] = index - for j, index in enumerate(DMXR1_mapping): + for j, index in enumerate(CMXR1_mapping): if np.any((r1[j] > r1) & (r1[j] < r2)): k = np.where((r1[j] > r1) & (r1[j] < r2))[0] for kk in k.flatten(): log.warning( - f"Start of DMX_{index:04d} ({r1[j]}-{r2[j]}) overlaps with DMX_{indices[kk]:04d} ({r1[kk]}-{r2[kk]})" + f"Start of CMX_{index:04d} ({r1[j]}-{r2[j]}) overlaps with CMX_{indices[kk]:04d} ({r1[kk]}-{r2[kk]})" ) if np.any((r2[j] > r1) & (r2[j] < r2)): k = np.where((r2[j] > r1) & (r2[j] < r2))[0] for kk in k.flatten(): log.warning( - f"End of DMX_{index:04d} ({r1[j]}-{r2[j]}) overlaps with DMX_{indices[kk]:04d} ({r1[kk]}-{r2[kk]})" + f"End of CMX_{index:04d} ({r1[j]}-{r2[j]}) overlaps with CMX_{indices[kk]:04d} ({r1[kk]}-{r2[kk]})" ) def validate_toas(self, toas): - DMX_mapping = self.get_prefix_mapping_component("DMX_") - DMXR1_mapping = self.get_prefix_mapping_component("DMXR1_") - DMXR2_mapping = self.get_prefix_mapping_component("DMXR2_") + CMX_mapping = self.get_prefix_mapping_component("CMX_") + CMXR1_mapping = self.get_prefix_mapping_component("CMXR1_") + CMXR2_mapping = self.get_prefix_mapping_component("CMXR2_") bad_parameters = [] - for k in DMXR1_mapping.keys(): - if self._parent[DMX_mapping[k]].frozen: + for k in CMXR1_mapping.keys(): + if self._parent[CMX_mapping[k]].frozen: continue - b = self._parent[DMXR1_mapping[k]].quantity.mjd * u.d - e = self._parent[DMXR2_mapping[k]].quantity.mjd * u.d + b = self._parent[CMXR1_mapping[k]].quantity.mjd * u.d + e = self._parent[CMXR2_mapping[k]].quantity.mjd * u.d mjds = toas.get_mjds() n = np.sum((b <= mjds) & (mjds < e)) if n == 0: - bad_parameters.append(DMX_mapping[k]) + bad_parameters.append(CMX_mapping[k]) if bad_parameters: raise MissingTOAs(bad_parameters) - def dmx_dm(self, toas): + def cmx_dm(self, toas): condition = {} tbl = toas.table - if not hasattr(self, "dmx_toas_selector"): - self.dmx_toas_selector = TOASelect(is_range=True) - DMX_mapping = self.get_prefix_mapping_component("DMX_") - DMXR1_mapping = self.get_prefix_mapping_component("DMXR1_") - DMXR2_mapping = self.get_prefix_mapping_component("DMXR2_") - for epoch_ind in DMX_mapping.keys(): - r1 = getattr(self, DMXR1_mapping[epoch_ind]).quantity - r2 = getattr(self, DMXR2_mapping[epoch_ind]).quantity - condition[DMX_mapping[epoch_ind]] = (r1.mjd, r2.mjd) - select_idx = self.dmx_toas_selector.get_select_index( + if not hasattr(self, "cmx_toas_selector"): + self.cmx_toas_selector = TOASelect(is_range=True) + CMX_mapping = self.get_prefix_mapping_component("CMX_") + CMXR1_mapping = self.get_prefix_mapping_component("CMXR1_") + CMXR2_mapping = self.get_prefix_mapping_component("CMXR2_") + for epoch_ind in CMX_mapping.keys(): + r1 = getattr(self, CMXR1_mapping[epoch_ind]).quantity + r2 = getattr(self, CMXR2_mapping[epoch_ind]).quantity + condition[CMX_mapping[epoch_ind]] = (r1.mjd, r2.mjd) + select_idx = self.cmx_toas_selector.get_select_index( condition, tbl["mjd_float"] ) - # Get DMX delays + # Get CMX delays dm = np.zeros(len(tbl)) * self._parent.DM.units for k, v in select_idx.items(): dm[v] += getattr(self, k).quantity return dm - def DMX_dispersion_delay(self, toas, acc_delay=None): + def CMX_dispersion_delay(self, toas, acc_delay=None): """This is a wrapper function for interacting with the TimingModel class""" return self.dispersion_type_delay(toas) - def d_dm_d_DMX(self, toas, param_name, acc_delay=None): + def d_dm_d_CMX(self, toas, param_name, acc_delay=None): condition = {} tbl = toas.table - if not hasattr(self, "dmx_toas_selector"): - self.dmx_toas_selector = TOASelect(is_range=True) + if not hasattr(self, "cmx_toas_selector"): + self.cmx_toas_selector = TOASelect(is_range=True) param = getattr(self, param_name) - dmx_index = param.index - DMXR1_mapping = self.get_prefix_mapping_component("DMXR1_") - DMXR2_mapping = self.get_prefix_mapping_component("DMXR2_") - r1 = getattr(self, DMXR1_mapping[dmx_index]).quantity - r2 = getattr(self, DMXR2_mapping[dmx_index]).quantity + cmx_index = param.index + CMXR1_mapping = self.get_prefix_mapping_component("CMXR1_") + CMXR2_mapping = self.get_prefix_mapping_component("CMXR2_") + r1 = getattr(self, CMXR1_mapping[cmx_index]).quantity + r2 = getattr(self, CMXR2_mapping[cmx_index]).quantity condition = {param_name: (r1.mjd, r2.mjd)} - select_idx = self.dmx_toas_selector.get_select_index( + select_idx = self.cmx_toas_selector.get_select_index( condition, tbl["mjd_float"] ) @@ -697,20 +688,20 @@ def d_dm_d_DMX(self, toas, param_name, acc_delay=None): except AttributeError: warn("Using topocentric frequency for dedispersion!") bfreq = tbl["freq"] - dmx = np.zeros(len(tbl)) + cmx = np.zeros(len(tbl)) for k, v in select_idx.items(): - dmx[v] = 1.0 - return dmx * (u.pc / u.cm**3) / (u.pc / u.cm**3) + cmx[v] = 1.0 + return cmx * (u.pc / u.cm**3) / (u.pc / u.cm**3) def print_par(self, format="pint"): result = "" - DMX_mapping = self.get_prefix_mapping_component("DMX_") - DMXR1_mapping = self.get_prefix_mapping_component("DMXR1_") - DMXR2_mapping = self.get_prefix_mapping_component("DMXR2_") - result += getattr(self, "DMX").as_parfile_line(format=format) - sorted_list = sorted(DMX_mapping.keys()) + CMX_mapping = self.get_prefix_mapping_component("CMX_") + CMXR1_mapping = self.get_prefix_mapping_component("CMXR1_") + CMXR2_mapping = self.get_prefix_mapping_component("CMXR2_") + result += getattr(self, "CMX").as_parfile_line(format=format) + sorted_list = sorted(CMX_mapping.keys()) for ii in sorted_list: - result += getattr(self, DMX_mapping[ii]).as_parfile_line(format=format) - result += getattr(self, DMXR1_mapping[ii]).as_parfile_line(format=format) - result += getattr(self, DMXR2_mapping[ii]).as_parfile_line(format=format) + result += getattr(self, CMX_mapping[ii]).as_parfile_line(format=format) + result += getattr(self, CMXR1_mapping[ii]).as_parfile_line(format=format) + result += getattr(self, CMXR2_mapping[ii]).as_parfile_line(format=format) return result diff --git a/src/pint/models/dispersion_model.py b/src/pint/models/dispersion_model.py index 9ddd06ed7..61f68dd93 100644 --- a/src/pint/models/dispersion_model.py +++ b/src/pint/models/dispersion_model.py @@ -344,7 +344,7 @@ def __init__(self): self.delay_funcs_component += [self.DMX_dispersion_delay] def add_DMX_range(self, mjd_start, mjd_end, index=None, dmx=0, frozen=True): - """Add DMX range to a dispersion model with specified start/end MJDs and DMX. + """Add DMX range to a dispersion model with specified start/end MJDs and DMX value. Parameters ---------- From cc6830b5e0c8dfcf4cbc983ad578f52616e710c8 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 2 Jul 2024 09:44:51 +0200 Subject: [PATCH 011/195] fix cmx --- CHANGELOG-unreleased.md | 1 + src/pint/models/chromatic_model.py | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 2899b99f8..36c201efc 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -10,5 +10,6 @@ the released changes. ## Unreleased ### Changed ### Added +- Piecewise-constant model for chromatic variations (CMX) ### Fixed ### Removed diff --git a/src/pint/models/chromatic_model.py b/src/pint/models/chromatic_model.py index 799440637..c7cf6854f 100644 --- a/src/pint/models/chromatic_model.py +++ b/src/pint/models/chromatic_model.py @@ -578,8 +578,8 @@ def setup(self): # Register the CMX derivatives for prefix_par in self.get_params_of_type("prefixParameter"): if prefix_par.startswith("CMX_"): - self.register_deriv_funcs(self.d_delay_d_dmparam, prefix_par) - self.register_dm_deriv_funcs(self.d_dm_d_CMX, prefix_par) + self.register_deriv_funcs(self.d_delay_d_cmparam, prefix_par) + self.register_cm_deriv_funcs(self.d_cm_d_CMX, prefix_par) def validate(self): """Validate the CMX parameters.""" @@ -642,7 +642,7 @@ def validate_toas(self, toas): if bad_parameters: raise MissingTOAs(bad_parameters) - def cmx_dm(self, toas): + def cmx_cm(self, toas): condition = {} tbl = toas.table if not hasattr(self, "cmx_toas_selector"): @@ -658,16 +658,16 @@ def cmx_dm(self, toas): condition, tbl["mjd_float"] ) # Get CMX delays - dm = np.zeros(len(tbl)) * self._parent.DM.units + cm = np.zeros(len(tbl)) * self._parent.CM.units for k, v in select_idx.items(): - dm[v] += getattr(self, k).quantity - return dm + cm[v] += getattr(self, k).quantity + return cm - def CMX_dispersion_delay(self, toas, acc_delay=None): + def CMX_chromatic_delay(self, toas, acc_delay=None): """This is a wrapper function for interacting with the TimingModel class""" return self.dispersion_type_delay(toas) - def d_dm_d_CMX(self, toas, param_name, acc_delay=None): + def d_cm_d_CMX(self, toas, param_name, acc_delay=None): condition = {} tbl = toas.table if not hasattr(self, "cmx_toas_selector"): From ea598df27d5aed0e12179c593fa794526836c12d Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 2 Jul 2024 09:59:04 +0200 Subject: [PATCH 012/195] parallel tox --- .github/workflows/ci_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 65f603dba..d508187d9 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -77,7 +77,7 @@ jobs: python -c "import pip; print(f'pip {pip.__version__}')" python -c "import tox; print(f'tox {tox.__version__}')" - name: Run tests - run: tox -e ${{ matrix.tox_env }} + run: tox -p auto -e ${{ matrix.tox_env }} - name: Upload coverage to codecov if: "endsWith(matrix.tox_env, '-cov')" uses: codecov/codecov-action@v2 From 37866df3e7ba67f96023ecd0110f4f8edd7b2618 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 2 Jul 2024 10:12:45 +0200 Subject: [PATCH 013/195] pytest -p auto --- .github/workflows/ci_test.yml | 2 +- tox.ini | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index d508187d9..65f603dba 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -77,7 +77,7 @@ jobs: python -c "import pip; print(f'pip {pip.__version__}')" python -c "import tox; print(f'tox {tox.__version__}')" - name: Run tests - run: tox -p auto -e ${{ matrix.tox_env }} + run: tox -e ${{ matrix.tox_env }} - name: Upload coverage to codecov if: "endsWith(matrix.tox_env, '-cov')" uses: codecov/codecov-action@v2 diff --git a/tox.ini b/tox.ini index bc9b94cf6..bc5c5bb5d 100644 --- a/tox.ini +++ b/tox.ini @@ -33,6 +33,7 @@ passenv = deps = pytest + pytest-xdist cov: coverage cov: pytest-cov cov: pytest-remotedata @@ -42,8 +43,8 @@ deps = setuptools commands = pip freeze - !cov: pytest - cov: pytest -v --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} + !cov: pytest -p auto + cov: pytest -p auto -v --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} cov: coverage xml -o {toxinidir}/coverage.xml depends = @@ -70,6 +71,7 @@ deps = matplotlib==3.2.0 scipy==1.4.1 pytest + pytest-xdist coverage hypothesis<=6.72.0 commands = {posargs:pytest} From ae40390d798c86bfae0b6cde72557e19e0cd7b62 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 2 Jul 2024 10:14:36 +0200 Subject: [PATCH 014/195] -n --- tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index bc5c5bb5d..0f5cad571 100644 --- a/tox.ini +++ b/tox.ini @@ -43,8 +43,8 @@ deps = setuptools commands = pip freeze - !cov: pytest -p auto - cov: pytest -p auto -v --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} + !cov: pytest -n auto + cov: pytest -n auto -v --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} cov: coverage xml -o {toxinidir}/coverage.xml depends = From 2dbbf265faec4b5b677b1a28a2250020a1361cc8 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 2 Jul 2024 10:18:01 +0200 Subject: [PATCH 015/195] oldestdeps --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 0f5cad571..86d4e27a3 100644 --- a/tox.ini +++ b/tox.ini @@ -74,7 +74,7 @@ deps = pytest-xdist coverage hypothesis<=6.72.0 -commands = {posargs:pytest} +commands = {posargs:pytest -n auto} [testenv:report] skip_install = true From 4d072d21e212f0115bdd1a93bfbcfb6855705caa Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 2 Jul 2024 10:36:32 +0200 Subject: [PATCH 016/195] test_noisefit --- tests/test_noisefit.py | 55 +++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/tests/test_noisefit.py b/tests/test_noisefit.py index 16e7cdc31..69f652cec 100644 --- a/tests/test_noisefit.py +++ b/tests/test_noisefit.py @@ -6,27 +6,38 @@ from io import StringIO import numpy as np +import pytest -par = """ - ELAT 1.3 1 - ELONG 2.5 1 - F0 100 1 - F1 1e-13 1 - PEPOCH 55000 - EPHEM DE440 - EFAC mjd 50000 53000 2 1 - EQUAD mjd 53000 55000 0.8 1 -""" -m = get_model(StringIO(par)) -t = make_fake_toas_uniform(50000, 55000, 200, m, add_noise=True) +@pytest.fixture +def model_and_toas_1(): + par = """ + ELAT 1.3 1 + ELONG 2.5 1 + F0 100 1 + F1 1e-13 1 + PEPOCH 55000 + EPHEM DE440 + EFAC mjd 50000 53000 2 1 + EQUAD mjd 53000 55000 0.8 1 + """ -m2, t2 = get_model_and_toas( - datadir / "ecorr_fit_test.par", datadir / "ecorr_fit_test.tim" -) + m = get_model(StringIO(par)) + t = make_fake_toas_uniform(50000, 55000, 200, m, add_noise=True) + return m, t + + +@pytest.fixture +def model_and_toas_2(): + return get_model_and_toas( + datadir / "ecorr_fit_test.par", datadir / "ecorr_fit_test.tim" + ) + + +def test_white_noise_fit(model_and_toas_1): + m, t = model_and_toas_1 -def test_white_noise_fit(): assert m.EFAC1.uncertainty_value == 0 and m.EQUAD1.uncertainty_value == 0 ftr = DownhillWLSFitter(t, m) @@ -47,7 +58,9 @@ def test_white_noise_fit(): ) -def test_white_noise_refit(): +def test_white_noise_refit(model_and_toas_1): + m, t = model_and_toas_1 + ftr = DownhillWLSFitter(t, m) ftr.model.EFAC1.value = 1.5 @@ -67,7 +80,9 @@ def test_white_noise_refit(): ) -def test_ecorr_fit(): +def test_ecorr_fit(model_and_toas_2): + m2, t2 = model_and_toas_2 + ftr = DownhillGLSFitter(t2, m2) ftr.fit_toas() @@ -79,7 +94,9 @@ def test_ecorr_fit(): ) -def test_ecorr_refit(): +def test_ecorr_refit(model_and_toas_2): + m2, t2 = model_and_toas_2 + ftr = DownhillGLSFitter(t2, m2) ftr.model.ECORR1.value = 0.75 From f0781b299c494b0860c1815e2565322862200e77 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 2 Jul 2024 10:42:22 +0200 Subject: [PATCH 017/195] CHANGELOG --- CHANGELOG-unreleased.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 2899b99f8..bf668fc9c 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -9,6 +9,7 @@ the released changes. ## Unreleased ### Changed +- Run CI tests in parallel ### Added ### Fixed ### Removed From fb3c6f1f7cc01f03bed325caf3385961abc74f59 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 2 Jul 2024 10:48:09 +0200 Subject: [PATCH 018/195] test_publish --- tests/test_publish.py | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/tests/test_publish.py b/tests/test_publish.py index f8663ff3d..cab74adb1 100644 --- a/tests/test_publish.py +++ b/tests/test_publish.py @@ -5,24 +5,37 @@ from pint.scripts import pintpublish import os -data_NGC6440E = get_model_and_toas(datadir / "NGC6440E.par", datadir / "NGC6440E.tim") +@pytest.fixture +def data_NGC6440E(): + return get_model_and_toas(datadir / "NGC6440E.par", datadir / "NGC6440E.tim") -def test_NGC6440E(): + +@pytest.fixture +def data_J0613m0200_NANOGrav_9yv1(): + return get_model_and_toas( + datadir / "J0613-0200_NANOGrav_9yv1.gls.par", + datadir / "J0613-0200_NANOGrav_9yv1.tim", + ) + + +@pytest.fixture +def data_J1614m2230_NANOGrav_12yv3_wb(): + return get_model_and_toas( + datadir / "J1614-2230_NANOGrav_12yv3.wb.gls.par", + datadir / "J1614-2230_NANOGrav_12yv3.wb.tim", + ) + + +def test_NGC6440E(data_NGC6440E): m, t = data_NGC6440E output = publish(m, t) assert "1748-2021E" in output assert "DE421" in output -data_J0613m0200_NANOGrav_9yv1 = get_model_and_toas( - datadir / "J0613-0200_NANOGrav_9yv1.gls.par", - datadir / "J0613-0200_NANOGrav_9yv1.tim", -) - - @pytest.mark.parametrize("full", [True, False]) -def test_J0613m0200_NANOGrav_9yv1(full): +def test_J0613m0200_NANOGrav_9yv1(data_J0613m0200_NANOGrav_9yv1, full): m, t = data_J0613m0200_NANOGrav_9yv1 output = publish( m, t, include_dmx=full, include_fd=full, include_noise=full, include_jumps=full @@ -39,14 +52,8 @@ def test_J0613m0200_NANOGrav_9yv1(full): assert not full or "RNAMP" in output -data_J1614m2230_NANOGrav_12yv3_wb = get_model_and_toas( - datadir / "J1614-2230_NANOGrav_12yv3.wb.gls.par", - datadir / "J1614-2230_NANOGrav_12yv3.wb.tim", -) - - @pytest.mark.parametrize("full", [True, False]) -def test_J1614m2230_NANOGrav_12yv3_wb(full): +def test_J1614m2230_NANOGrav_12yv3_wb(data_J1614m2230_NANOGrav_12yv3_wb, full): m, t = data_J1614m2230_NANOGrav_12yv3_wb output = publish( m, t, include_dmx=full, include_fd=full, include_noise=full, include_jumps=full From a510a3ce80edc3c8ca4a39d68f5759434e5efb96 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 2 Jul 2024 12:02:42 +0200 Subject: [PATCH 019/195] test_timing_model --- tests/test_timing_model.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/test_timing_model.py b/tests/test_timing_model.py index 2cd37645c..5c9456757 100644 --- a/tests/test_timing_model.py +++ b/tests/test_timing_model.py @@ -42,9 +42,6 @@ def timfile_nojumps(): return get_TOAs(os.path.join(datadir, "NGC6440E.tim")) -len_timfile_nojumps = len(get_TOAs(os.path.join(datadir, "NGC6440E.tim"))) - - class TestModelBuilding: def setup_method(self): self.parfile = os.path.join(datadir, "J0437-4715.par") From 8ed1af7bf2d6b93d09966d4535158b50d5a04ee0 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 2 Jul 2024 15:55:13 +0200 Subject: [PATCH 020/195] -- --- tests/test_toa_shuffle.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/test_toa_shuffle.py b/tests/test_toa_shuffle.py index 2d757c09b..cf97b8ce1 100644 --- a/tests/test_toa_shuffle.py +++ b/tests/test_toa_shuffle.py @@ -18,12 +18,6 @@ import pint.residuals from pint.models import get_model -shuffletoas = """FORMAT 1 -test 1234.0 54321 0 pks -test2 888 59055 0 meerkat -test3 350 59000 0 gbt -""" - class TOAOrderSetup: parfile = os.path.join(datadir, "NGC6440E.par") @@ -95,6 +89,11 @@ def test_resorting_toas_chi2_match(sortkey): class TOALineOrderSetup: + shuffletoas = """FORMAT 1 + test 1234.0 54321 0 pks + test2 888 59055 0 meerkat + test3 350 59000 0 gbt + """ timfile = io.StringIO(shuffletoas) t = toa.get_TOAs(timfile) timfile.seek(0) From 119b749f52af64f65b934ce2dd1bd06b257740af Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 2 Jul 2024 16:24:44 +0200 Subject: [PATCH 021/195] not verbose --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 86d4e27a3..6fa6a9a7c 100644 --- a/tox.ini +++ b/tox.ini @@ -44,7 +44,7 @@ deps = commands = pip freeze !cov: pytest -n auto - cov: pytest -n auto -v --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} + cov: pytest -n auto --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} cov: coverage xml -o {toxinidir}/coverage.xml depends = From ff809fac154b63396634dd13c9e11e411c540c51 Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Mon, 12 Aug 2024 10:56:16 +0200 Subject: [PATCH 022/195] Fixes in orbwave initialisation --- src/pint/models/pulsar_binary.py | 15 ++++------ .../stand_alone_psr_binaries/binary_orbits.py | 29 +++++++++---------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/src/pint/models/pulsar_binary.py b/src/pint/models/pulsar_binary.py index 53c071afe..5ae8442ce 100644 --- a/src/pint/models/pulsar_binary.py +++ b/src/pint/models/pulsar_binary.py @@ -283,21 +283,18 @@ def setup(self): ORBWAVEC = { owc: getattr(self, owc).quantity for owc in ORBWAVEC_mapping.values() } + if any(v is not None for v in ORBWAVES.values()): self.binary_instance.add_binary_params("ORBWAVE_OM", self.ORBWAVE_OM.value) self.binary_instance.add_binary_params( "ORBWAVE_EPOCH", self.ORBWAVE_EPOCH.value ) - ii = 0 - while f"ORBWAVES{ii}" in ORBWAVES.keys(): - self.binary_instance.add_binary_params( - f"ORBWAVES{ii}", ORBWAVES[f"ORBWAVES{ii}"] - ) - self.binary_instance.add_binary_params( - f"ORBWAVEC{ii}", ORBWAVEC[f"ORBWAVEC{ii}"] - ) - ii += 1 + for k in ORBWAVES.keys(): + self.binary_instance.add_binary_params(k, ORBWAVES[k]) + + for k in ORBWAVEC.keys(): + self.binary_instance.add_binary_params(k, ORBWAVEC[k]) self.binary_instance.orbits_cls = bo.OrbitWaves( self.binary_instance, diff --git a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py index bfa3a4dbc..fc4ca7037 100644 --- a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py +++ b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py @@ -261,13 +261,16 @@ def __init__( nc = 0 ns = 0 + for k in self.binary_params: - if re.match(r"ORBWAVEC\d+", k) is not None and k not in self.orbit_params: - self.orbit_params += [k] + if re.match(r"ORBWAVEC\d+", k) is not None: + if k not in self.orbit_params: + self.orbit_params += [k] Cindices.add(int(k[8:])) nc += 1 - if re.match(r"ORBWAVES\d+", k) is not None and k not in self.orbit_params: - self.orbit_params += [k] + if re.match(r"ORBWAVES\d+", k) is not None: + if k not in self.orbit_params: + self.orbit_params += [k] Sindices.add(int(k[8:])) ns += 1 @@ -275,8 +278,8 @@ def __init__( range(len(Sindices)) ): raise ValueError( - f"Orbwave Indices must be 0 up to some number k without gaps " - f"but are {indices}." + f"Orbwave indices must be 0 up to some number k without gaps " + f"but are {Cindices} and {Sindices}." ) if nc != ns: @@ -285,14 +288,12 @@ def __init__( f"but have {ns} and {nc}." ) + if self.ORBWAVEC0 is None or self.ORBWAVES0 is None: + raise ValueError("The ORBWAVEC0 or ORBWAVES0 parameter is unset") + self.nwaves = ns def _ORBWAVEs(self): - ii = 0 - while f"ORBWAVEC{ii}" in self.orbit_params: - ii += 1 - self.nwaves = ii - ORBWAVEs = np.zeros((self.nwaves, 2)) * u.Unit("") for ii in range(self.nwaves): @@ -302,11 +303,7 @@ def _ORBWAVEs(self): return ORBWAVEs def _tw(self): - t = self.t - if not hasattr(self.t, "unit") or self.t.unit is None: - t = self.t * u.day - - tw = t - self.ORBWAVE_EPOCH.value * u.d + tw = self.t - self.ORBWAVE_EPOCH.value * u.d return tw def _deltaPhi(self): From 36f3ca8879bf8886bba08cbfc75bd6f19eecfd14 Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Mon, 12 Aug 2024 11:58:37 +0200 Subject: [PATCH 023/195] Added new tcb2tdb conversion scale factors for ORBWAVES parameters --- src/pint/models/pulsar_binary.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pint/models/pulsar_binary.py b/src/pint/models/pulsar_binary.py index a2ac804c5..db71db7a8 100644 --- a/src/pint/models/pulsar_binary.py +++ b/src/pint/models/pulsar_binary.py @@ -214,6 +214,7 @@ def __init__(self): description_template=self.ORBWAVEC_description, type_match="float", long_double=True, + tcb2tdb_scale_factor=u.Quantity(1), ) ) @@ -227,6 +228,7 @@ def __init__(self): description_template=self.ORBWAVES_description, type_match="float", long_double=True, + tcb2tdb_scale_factor=u.Quantity(1), ) ) @@ -236,6 +238,7 @@ def __init__(self): units="rad/s", description="Base frequency for ORBWAVEs model", long_double=True, + tcb2tdb_scale_factor=u.Quantity(1), ) ) self.add_param( @@ -243,6 +246,7 @@ def __init__(self): name="ORBWAVE_EPOCH", description="Reference epoch for ORBWAVEs model", time_scale="tdb", + tcb2tdb_scale_factor=u.Quantity(1), ) ) From 6847b71722dee0ff65f8b695bb9213b664e2b08a Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Mon, 12 Aug 2024 12:03:24 +0200 Subject: [PATCH 024/195] Adding tests for ORBWAVEs functions --- tests/datafile/J1048+2339_3PC_fake.tim | 107 ++++++++++++++++++ tests/datafile/J1048+2339_orbwaves.par | 48 ++++++++ .../datafile/J1048+2339_orbwaves_invalid1.par | 46 ++++++++ .../datafile/J1048+2339_orbwaves_invalid2.par | 47 ++++++++ .../datafile/J1048+2339_orbwaves_invalid3.par | 47 ++++++++ tests/test_orbwaves.py | 44 +++++++ 6 files changed, 339 insertions(+) create mode 100644 tests/datafile/J1048+2339_3PC_fake.tim create mode 100644 tests/datafile/J1048+2339_orbwaves.par create mode 100644 tests/datafile/J1048+2339_orbwaves_invalid1.par create mode 100644 tests/datafile/J1048+2339_orbwaves_invalid2.par create mode 100644 tests/datafile/J1048+2339_orbwaves_invalid3.par create mode 100644 tests/test_orbwaves.py diff --git a/tests/datafile/J1048+2339_3PC_fake.tim b/tests/datafile/J1048+2339_3PC_fake.tim new file mode 100644 index 000000000..33d3f61b0 --- /dev/null +++ b/tests/datafile/J1048+2339_3PC_fake.tim @@ -0,0 +1,107 @@ +FORMAT 1 +C Created: 2024-01-17T17:35:49.743600 +C PINT_version: 0.9.8+44.g1d25d7ec.dirty +C User: cclark +C Host: HNB775 +C OS: macOS-11.7.10-x86_64-i386-64bit +C Python: 3.11.0 | packaged by conda-forge | (main, Jan 15 2023, 05:44:48) [Clang 14.0.6 ] +fake 1400.000000 56499.6542924265793634 20.000 arecibo -pn -14556992621.0 +fake 1400.000000 56515.4714585239121180 20.000 arecibo -pn -14264065295.0 +fake 1400.000000 56530.1658492425925694 20.000 arecibo -pn -13991925153.0 +fake 1400.000000 56552.8508442386096066 20.000 arecibo -pn -13571785893.0 +fake 1400.000000 56573.1875466751208218 20.000 arecibo -pn -13195126377.0 +fake 1400.000000 56566.0911291819698843 20.000 arecibo -pn -13326561640.0 +fake 1400.000000 56570.6109755583843172 20.000 arecibo -pn -13242848100.0 +fake 1400.000000 56593.0993371540435069 20.000 arecibo -pn -12826327673.0 +fake 1400.000000 56597.6169268134667246 20.000 arecibo -pn -12742653507.0 +fake 1400.000000 56584.9166539062826851 20.000 arecibo -pn -12977884987.0 +fake 1400.000000 56628.4981058130401389 20.000 arecibo -pn -12170671808.0 +fake 1400.000000 56629.6491682273526967 20.000 arecibo -pn -12149352121.0 +fake 1400.000000 56631.3948759159077430 20.000 arecibo -pn -12117018055.0 +fake 1400.000000 56647.7043342506005207 20.000 arecibo -pn -11814934720.0 +fake 1400.000000 56664.0323435136898380 20.000 arecibo -pn -11512511204.0 +fake 1400.000000 56662.6202116121144444 20.000 arecibo -pn -11538666096.0 +fake 1400.000000 56672.5319303522428934 20.000 arecibo -pn -11355086157.0 +fake 1400.000000 56684.7216506798818518 20.000 arecibo -pn -11129317426.0 +fake 1400.000000 56707.5113283280297106 20.000 arecibo -pn -10707235585.0 +fake 1400.000000 56718.1584645803764815 20.000 arecibo -pn -10510047952.0 +fake 1400.000000 56724.6996789532842129 20.000 arecibo -pn -10388904838.0 +fake 1400.000000 56736.8561543310538079 20.000 arecibo -pn -10163771090.0 +fake 1400.000000 56742.9772745043780441 20.000 arecibo -pn -10050411113.0 +fake 1400.000000 56744.8663333106221991 20.000 arecibo -pn -10015427356.0 +fake 1400.000000 56768.2681409742178935 20.000 arecibo -pn -9582048339.0 +fake 1400.000000 56772.0303959887401968 20.000 arecibo -pn -9512376009.0 +fake 1400.000000 56791.3104227062363658 20.000 arecibo -pn -9155336606.0 +fake 1400.000000 56797.7828604962445255 20.000 arecibo -pn -9035476833.0 +fake 1400.000000 56828.4317284397404398 20.000 arecibo -pn -8467904208.0 +fake 1400.000000 56812.0591817380739699 20.000 arecibo -pn -8771100758.0 +fake 1400.000000 56815.4905032654365741 20.000 arecibo -pn -8707557734.0 +fake 1400.000000 56841.7902342958811921 20.000 arecibo -pn -8220521613.0 +fake 1400.000000 56837.2661549845360417 20.000 arecibo -pn -8304302163.0 +fake 1400.000000 56848.5214910022805440 20.000 arecibo -pn -8095865857.0 +fake 1400.000000 56883.4384623373841320 20.000 arecibo -pn -7449224561.0 +fake 1400.000000 56880.8078014433801619 20.000 arecibo -pn -7497943625.0 +fake 1400.000000 56863.8792153396387384 20.000 arecibo -pn -7811454003.0 +fake 1400.000000 56888.1516839050684954 20.000 arecibo -pn -7361935924.0 +fake 1400.000000 56900.3285856223282407 20.000 arecibo -pn -7136417053.0 +fake 1400.000000 56926.5954650101420255 20.000 arecibo -pn -6649934542.0 +fake 1400.000000 56940.6035905419990163 20.000 arecibo -pn -6390485783.0 +fake 1400.000000 56936.8112658763676505 20.000 arecibo -pn -6460725217.0 +fake 1400.000000 56952.1893387214877662 20.000 arecibo -pn -6175898993.0 +fake 1400.000000 56955.1061180325763079 20.000 arecibo -pn -6121875452.0 +fake 1400.000000 56955.3718469374112500 20.000 arecibo -pn -6116953617.0 +fake 1400.000000 56980.1841145056263194 20.000 arecibo -pn -5657382463.0 +fake 1400.000000 56999.6866740820557408 20.000 arecibo -pn -5296155314.0 +fake 1400.000000 57003.1191636566178009 20.000 arecibo -pn -5232578657.0 +fake 1400.000000 57008.9625675219576159 20.000 arecibo -pn -5124347386.0 +fake 1400.000000 57039.6211866433689237 20.000 arecibo -pn -4556497914.0 +fake 1400.000000 57035.2024855226981944 20.000 arecibo -pn -4638338817.0 +fake 1400.000000 57030.6871973368739236 20.000 arecibo -pn -4721968796.0 +fake 1400.000000 57061.5047784739957523 20.000 arecibo -pn -4151190878.0 +fake 1400.000000 57057.6151107016963889 20.000 arecibo -pn -4223230403.0 +fake 1400.000000 57077.0368741394684028 20.000 arecibo -pn -3863528613.0 +fake 1400.000000 57070.3456692022659491 20.000 arecibo -pn -3987452131.0 +fake 1400.000000 57110.1177331390579977 20.000 arecibo -pn -3250878928.0 +fake 1400.000000 57112.4934863738438657 20.000 arecibo -pn -3206881410.0 +fake 1400.000000 57113.2766723567323727 20.000 arecibo -pn -3192377388.0 +fake 1400.000000 57134.0700569265716551 20.000 arecibo -pn -2807304956.0 +fake 1400.000000 57146.6515469834735648 20.000 arecibo -pn -2574312382.0 +fake 1400.000000 57149.7566600342336226 20.000 arecibo -pn -2516810137.0 +fake 1400.000000 57165.2526190755023611 20.000 arecibo -pn -2229847804.0 +fake 1400.000000 57187.2688830774209259 20.000 arecibo -pn -1822139031.0 +fake 1400.000000 57190.6849732852207292 20.000 arecibo -pn -1758877503.0 +fake 1400.000000 57187.9589681610874190 20.000 arecibo -pn -1809359372.0 +fake 1400.000000 57200.3717603740499769 20.000 arecibo -pn -1579491245.0 +fake 1400.000000 57210.6059847836613542 20.000 arecibo -pn -1389965223.0 +fake 1400.000000 57227.0308377842580208 20.000 arecibo -pn -1085791426.0 +fake 1400.000000 57236.8596851869279052 20.000 arecibo -pn -903767168.0 +fake 1400.000000 57261.2487812880531366 20.000 arecibo -pn -452083881.0 +fake 1400.000000 57260.4442328007430556 20.000 arecibo -pn -466984383.0 +fake 1400.000000 57268.5769349500900232 20.000 arecibo -pn -316363616.0 +fake 1400.000000 57279.9979853937153241 20.000 arecibo -pn -104838855.0 +fake 1400.000000 57295.6360907784355671 20.000 arecibo -pn 184795178.0 +fake 1400.000000 57301.3161497624851158 20.000 arecibo -pn 289996962.0 +fake 1400.000000 57317.2132137646926157 20.000 arecibo -pn 584435547.0 +fake 1400.000000 57305.1445115133814120 20.000 arecibo -pn 360903928.0 +fake 1400.000000 57331.7799537955628588 20.000 arecibo -pn 854238088.0 +fake 1400.000000 57329.0529708326988542 20.000 arecibo -pn 803729018.0 +fake 1400.000000 57337.5205917926200810 20.000 arecibo -pn 960566046.0 +fake 1400.000000 57365.2644749378174190 20.000 arecibo -pn 1474439290.0 +fake 1400.000000 57357.4298283792541783 20.000 arecibo -pn 1329325411.0 +fake 1400.000000 57373.5424751155939351 20.000 arecibo -pn 1627764289.0 +fake 1400.000000 57388.6568674133486228 20.000 arecibo -pn 1907710417.0 +fake 1400.000000 57393.9312912733891782 20.000 arecibo -pn 2005401471.0 +fake 1400.000000 57410.9067652986654399 20.000 arecibo -pn 2319811514.0 +fake 1400.000000 57421.2851809244780440 20.000 arecibo -pn 2512030434.0 +fake 1400.000000 57432.9383376233199190 20.000 arecibo -pn 2727855790.0 +fake 1400.000000 57439.2307955621883102 20.000 arecibo -pn 2844394914.0 +fake 1400.000000 57465.9557426709758101 20.000 arecibo -pn 3339339546.0 +fake 1400.000000 57473.2128096176505093 20.000 arecibo -pn 3473736409.0 +fake 1400.000000 57469.1446187069599884 20.000 arecibo -pn 3398395700.0 +fake 1400.000000 57473.7402821754510069 20.000 arecibo -pn 3483504941.0 +fake 1400.000000 57494.4992201782944907 20.000 arecibo -pn 3867941489.0 +fake 1400.000000 57516.7439985751001505 20.000 arecibo -pn 4279885696.0 +fake 1400.000000 57498.9767069652037038 20.000 arecibo -pn 3950859181.0 +fake 1400.000000 57540.7899028004051968 20.000 arecibo -pn 4725180159.0 +fake 1400.000000 57518.1608066433601852 20.000 arecibo -pn 4306123159.0 +fake 1400.000000 57539.6812402803568286 20.000 arecibo -pn 4704649696.0 diff --git a/tests/datafile/J1048+2339_orbwaves.par b/tests/datafile/J1048+2339_orbwaves.par new file mode 100644 index 000000000..a1f230cd8 --- /dev/null +++ b/tests/datafile/J1048+2339_orbwaves.par @@ -0,0 +1,48 @@ +PSR J1048+2339 +RAJ 10:48:43.41835421 1 0.00007631 +DECJ 23:39:53.4043452 1 0.0020013 +PMRA -18.7000 +PMDEC -9.4000 +POSEPOCH 56700.0000 +F0 214.3547853411294852 1 0.0000000000170721 +F1 -1.381753144359e-15 1 1.531201039458e-18 +PEPOCH 57285.000000 +START 56508.798 +FINISH 57548.936 +#DM 16.654332 +DMEPOCH 56700.0000 +SOLARN0 10.00 +EPHEM DE421 +CLK TT(BIPM2021) +UNITS TDB +TIMEEPH FB90 +T2CMETHOD IAU2000B +CORRECT_TROPOSPHERE N +PLANET_SHAPIRO N +DILATEFREQ N +NTOA 104 +TRES 8.84 +TZRMJD 57285.65854990785506 +TZRFRQ 326.988 +TZRSITE 3 +NITS 1 +BINARY ELL1 +A1 0.836120368 1 0.000003165 +EPS1 0 +EPS2 0 +# ATNF DM info (from drc+16): +DM 16.6544 0.0001 +ORBWAVE_OM 3.495788643739122e-08 +ORBWAVE_EPOCH 57028.867 +TASC 56637.61958641038 1 +PB 0.250506696660119 1 +ORBWAVEC0 0.01359122306797746 1 +ORBWAVES0 -0.1138721359160273 1 +ORBWAVEC1 -0.009093465738757574 1 +ORBWAVES1 0.03712548529066605 1 +ORBWAVEC2 0.00414066930830874 1 +ORBWAVES2 -0.011358879259751396 1 +ORBWAVEC3 -0.001400204000025873 1 +ORBWAVES3 0.002749601047126059 1 +ORBWAVEC4 0.00019385501703957642 1 +ORBWAVES4 -0.00028698933945954427 1 \ No newline at end of file diff --git a/tests/datafile/J1048+2339_orbwaves_invalid1.par b/tests/datafile/J1048+2339_orbwaves_invalid1.par new file mode 100644 index 000000000..acc571819 --- /dev/null +++ b/tests/datafile/J1048+2339_orbwaves_invalid1.par @@ -0,0 +1,46 @@ +PSR J1048+2339 +RAJ 10:48:43.41835421 1 0.00007631 +DECJ 23:39:53.4043452 1 0.0020013 +PMRA -18.7000 +PMDEC -9.4000 +POSEPOCH 56700.0000 +F0 214.3547853411294852 1 0.0000000000170721 +F1 -1.381753144359e-15 1 1.531201039458e-18 +PEPOCH 57285.000000 +START 56508.798 +FINISH 57548.936 +#DM 16.654332 +DMEPOCH 56700.0000 +SOLARN0 10.00 +EPHEM DE421 +CLK TT(BIPM2021) +UNITS TDB +TIMEEPH FB90 +T2CMETHOD IAU2000B +CORRECT_TROPOSPHERE N +PLANET_SHAPIRO N +DILATEFREQ N +NTOA 104 +TRES 8.84 +TZRMJD 57285.65854990785506 +TZRFRQ 326.988 +TZRSITE 3 +NITS 1 +BINARY ELL1 +A1 0.836120368 1 0.000003165 +EPS1 0 +EPS2 0 +# ATNF DM info (from drc+16): +DM 16.6544 0.0001 +ORBWAVE_OM 3.495788643739122e-08 +ORBWAVE_EPOCH 57028.867 +TASC 56637.61958641038 1 +PB 0.250506696660119 1 +ORBWAVEC1 -0.009093465738757574 1 +ORBWAVES1 0.03712548529066605 1 +ORBWAVEC2 0.00414066930830874 1 +ORBWAVES2 -0.011358879259751396 1 +ORBWAVEC3 -0.001400204000025873 1 +ORBWAVES3 0.002749601047126059 1 +ORBWAVEC4 0.00019385501703957642 1 +ORBWAVES4 -0.00028698933945954427 1 \ No newline at end of file diff --git a/tests/datafile/J1048+2339_orbwaves_invalid2.par b/tests/datafile/J1048+2339_orbwaves_invalid2.par new file mode 100644 index 000000000..bca3bd853 --- /dev/null +++ b/tests/datafile/J1048+2339_orbwaves_invalid2.par @@ -0,0 +1,47 @@ +PSR J1048+2339 +RAJ 10:48:43.41835421 1 0.00007631 +DECJ 23:39:53.4043452 1 0.0020013 +PMRA -18.7000 +PMDEC -9.4000 +POSEPOCH 56700.0000 +F0 214.3547853411294852 1 0.0000000000170721 +F1 -1.381753144359e-15 1 1.531201039458e-18 +PEPOCH 57285.000000 +START 56508.798 +FINISH 57548.936 +#DM 16.654332 +DMEPOCH 56700.0000 +SOLARN0 10.00 +EPHEM DE421 +CLK TT(BIPM2021) +UNITS TDB +TIMEEPH FB90 +T2CMETHOD IAU2000B +CORRECT_TROPOSPHERE N +PLANET_SHAPIRO N +DILATEFREQ N +NTOA 104 +TRES 8.84 +TZRMJD 57285.65854990785506 +TZRFRQ 326.988 +TZRSITE 3 +NITS 1 +BINARY ELL1 +A1 0.836120368 1 0.000003165 +EPS1 0 +EPS2 0 +# ATNF DM info (from drc+16): +DM 16.6544 0.0001 +ORBWAVE_OM 3.495788643739122e-08 +ORBWAVE_EPOCH 57028.867 +TASC 56637.61958641038 1 +PB 0.250506696660119 1 +ORBWAVEC0 0.01359122306797746 1 +ORBWAVES0 -0.1138721359160273 1 +ORBWAVEC1 -0.009093465738757574 1 +ORBWAVES1 0.03712548529066605 1 +ORBWAVEC2 0.00414066930830874 1 +ORBWAVES2 -0.011358879259751396 1 +ORBWAVES3 0.002749601047126059 1 +ORBWAVEC4 0.00019385501703957642 1 +ORBWAVES4 -0.00028698933945954427 1 \ No newline at end of file diff --git a/tests/datafile/J1048+2339_orbwaves_invalid3.par b/tests/datafile/J1048+2339_orbwaves_invalid3.par new file mode 100644 index 000000000..6eb0b2ed1 --- /dev/null +++ b/tests/datafile/J1048+2339_orbwaves_invalid3.par @@ -0,0 +1,47 @@ +PSR J1048+2339 +RAJ 10:48:43.41835421 1 0.00007631 +DECJ 23:39:53.4043452 1 0.0020013 +PMRA -18.7000 +PMDEC -9.4000 +POSEPOCH 56700.0000 +F0 214.3547853411294852 1 0.0000000000170721 +F1 -1.381753144359e-15 1 1.531201039458e-18 +PEPOCH 57285.000000 +START 56508.798 +FINISH 57548.936 +#DM 16.654332 +DMEPOCH 56700.0000 +SOLARN0 10.00 +EPHEM DE421 +CLK TT(BIPM2021) +UNITS TDB +TIMEEPH FB90 +T2CMETHOD IAU2000B +CORRECT_TROPOSPHERE N +PLANET_SHAPIRO N +DILATEFREQ N +NTOA 104 +TRES 8.84 +TZRMJD 57285.65854990785506 +TZRFRQ 326.988 +TZRSITE 3 +NITS 1 +BINARY ELL1 +A1 0.836120368 1 0.000003165 +EPS1 0 +EPS2 0 +# ATNF DM info (from drc+16): +DM 16.6544 0.0001 +ORBWAVE_OM 3.495788643739122e-08 +ORBWAVE_EPOCH 57028.867 +TASC 56637.61958641038 1 +PB 0.250506696660119 1 +ORBWAVEC0 0.01359122306797746 1 +ORBWAVES0 -0.1138721359160273 1 +ORBWAVEC1 -0.009093465738757574 1 +ORBWAVES1 0.03712548529066605 1 +ORBWAVEC2 0.00414066930830874 1 +ORBWAVES2 -0.011358879259751396 1 +ORBWAVEC3 -0.001400204000025873 1 +ORBWAVES3 0.002749601047126059 1 +ORBWAVEC4 0.00019385501703957642 1 diff --git a/tests/test_orbwaves.py b/tests/test_orbwaves.py new file mode 100644 index 000000000..96dcf0f94 --- /dev/null +++ b/tests/test_orbwaves.py @@ -0,0 +1,44 @@ +import os +import astropy.units as u +import pytest + +import pint.models as tm +from pint import fitter, toa, simulation +from pinttestdata import datadir +import pint.models.parameter as param +from pint import ls +from pint.models import get_model, get_model_and_toas + + +def test_orbwaves_fit(): + m, t = get_model_and_toas( + os.path.join(datadir, "J1048+2339_orbwaves.par"), + os.path.join(datadir, "J1048+2339_3PC_fake.tim"), + ) + + f = fitter.WLSFitter(toas=t, model=m) + + rms = f.resids.rms_weighted().to_value("us") + + assert rms > 29.2 and rms < 29.3 + + f.fit_toas() + rms = f.resids.rms_weighted().to_value("us") + + assert rms > 21.1 and rms < 21.2 + + +def test_invalid_parfiles(): + with pytest.raises(Exception): + m1 = get_model(os.path.join(datadir, "J1048+2339_orbwaves_invalid1.par")) + + with pytest.raises(Exception): + m2 = get_model(os.path.join(datadir, "J1048+2339_orbwaves_invalid2.par")) + + with pytest.raises(Exception): + m3 = get_model(os.path.join(datadir, "J1048+2339_orbwaves_invalid3.par")) + + +if __name__ == "__main__": + test_orbwaves_fit() + test_invalid_parfiles() From 28a65a96596f6ab80689c4d70e15e60d10612a32 Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Mon, 12 Aug 2024 14:25:41 +0200 Subject: [PATCH 025/195] Add invalid ORBWAVEs parameters to exception list for parfile tests --- tests/test_all_component_and_model_builder.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/test_all_component_and_model_builder.py b/tests/test_all_component_and_model_builder.py index 8dab2f33a..adbf688a6 100644 --- a/tests/test_all_component_and_model_builder.py +++ b/tests/test_all_component_and_model_builder.py @@ -448,7 +448,13 @@ def __init__(self): del Component.component_types["SubsetModel2"] -bad_trouble = ["J1923+2515_NANOGrav_9yv1.gls.par", "J1744-1134.basic.ecliptic.par"] +bad_trouble = [ + "J1923+2515_NANOGrav_9yv1.gls.par", + "J1744-1134.basic.ecliptic.par", + "J1048+2339_orbwaves_invalid1.par", + "J1048+2339_orbwaves_invalid2.par", + "J1048+2339_orbwaves_invalid3.par", +] # Test all the parameters. From 8bee2c66a2a8a441397fe33d68ba5552f1b93909 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 13 Aug 2024 10:43:48 +0200 Subject: [PATCH 026/195] rerun --- tox.ini | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tox.ini b/tox.ini index dce11bda3..53134d7dd 100644 --- a/tox.ini +++ b/tox.ini @@ -18,7 +18,8 @@ envlist = skip_missing_interpreters = True [tool:pytest] -# pytest docs seem to say that this section should be called just pytest, not tool:pytest; is it working? +# pytest docs seem to say that this section should be called just pytest, +# not tool:pytest; is it working? testpaths = tests addopts = --cov-report=term-missing @@ -34,6 +35,7 @@ passenv = deps = pytest pytest-xdist + pytest-rerunfailures cov: coverage cov: pytest-cov cov: pytest-remotedata @@ -43,8 +45,8 @@ deps = setuptools commands = pip freeze - !cov: pytest -n auto - cov: pytest -n auto --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} + !cov: pytest -n auto --reruns 5 + cov: pytest -n auto --reruns 5 --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} cov: coverage xml -o {toxinidir}/coverage.xml depends = @@ -72,9 +74,10 @@ deps = scipy==1.4.1 pytest pytest-xdist + pytest-rerunfailures coverage hypothesis<=6.72.0 -commands = {posargs:pytest -n auto} +commands = {posargs:pytest -n auto --reruns 5} [testenv:report] skip_install = true From e6db751bed4f74e1cdb62226f26c864cb284ad42 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 13 Aug 2024 10:50:28 +0200 Subject: [PATCH 027/195] CHANGELOG --- CHANGELOG-unreleased.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 1ee8b6ed6..89f18dc9f 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -11,7 +11,7 @@ the released changes. ### Changed - Moved the events -> TOAs and photon weights code into the function `load_events_weights` within `event_optimize`. - Updated the `maxMJD` argument in `event_optimize` to default to the current mjd -- Run CI tests in parallel +- Run CI tests in parallel, re-run failed tests - `maskParameter.__repr__()` output now includes the frozen attribute. - Changed default value of `FDJUMPLOG` to `Y` - Bumped `black` version to 24.x From 558058078ebeec76dad1e75f831948b39888f634 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 13 Aug 2024 10:51:05 +0200 Subject: [PATCH 028/195] CHANGELOG --- CHANGELOG-unreleased.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 89f18dc9f..7cfe0c486 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -11,7 +11,7 @@ the released changes. ### Changed - Moved the events -> TOAs and photon weights code into the function `load_events_weights` within `event_optimize`. - Updated the `maxMJD` argument in `event_optimize` to default to the current mjd -- Run CI tests in parallel, re-run failed tests +- Run CI tests in parallel, re-run failed tests (for intermittent failures due to random chance) - `maskParameter.__repr__()` output now includes the frozen attribute. - Changed default value of `FDJUMPLOG` to `Y` - Bumped `black` version to 24.x From b659ac4adbdc81beaf0145c9995f6ed916a8324e Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 13 Aug 2024 11:00:09 +0200 Subject: [PATCH 029/195] oversubscribe --- requirements_dev.txt | 2 ++ tox.ini | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/requirements_dev.txt b/requirements_dev.txt index a00511840..d210e4854 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -12,6 +12,8 @@ wheel>=0.29.0 pytest>=4.3 pytest-cov>=2.7.1 pytest-runner>=5.1 +pytest-xdist +pytest-rerunfailures flake8>=3.7 pep8-naming>=0.8.2 flake8-docstrings>=1.4 diff --git a/tox.ini b/tox.ini index 53134d7dd..bba6c8f7d 100644 --- a/tox.ini +++ b/tox.ini @@ -45,8 +45,8 @@ deps = setuptools commands = pip freeze - !cov: pytest -n auto --reruns 5 - cov: pytest -n auto --reruns 5 --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} + !cov: pytest -n 6 --reruns 5 + cov: pytest -n 6 --reruns 5 --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} cov: coverage xml -o {toxinidir}/coverage.xml depends = @@ -77,7 +77,7 @@ deps = pytest-rerunfailures coverage hypothesis<=6.72.0 -commands = {posargs:pytest -n auto --reruns 5} +commands = {posargs:pytest -n 6 --reruns 5} [testenv:report] skip_install = true From 0ca156d1f77f3fd90f2b39e32b290d1aa135805d Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 13 Aug 2024 11:14:11 +0200 Subject: [PATCH 030/195] test_toa_shuffle --- tests/test_toa_shuffle.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/tests/test_toa_shuffle.py b/tests/test_toa_shuffle.py index cf97b8ce1..cd7bd1b3c 100644 --- a/tests/test_toa_shuffle.py +++ b/tests/test_toa_shuffle.py @@ -23,22 +23,17 @@ class TOAOrderSetup: parfile = os.path.join(datadir, "NGC6440E.par") model = get_model(parfile) # fake a multi-telescope, multi-frequency data-set and make sure the results don't depend on TOA order - fakes = [ + t = ( simulation.make_fake_toas_uniform( 55000, 55500, 30, model=model, freq=1400 * u.MHz, obs="ao" - ), - simulation.make_fake_toas_uniform( + ) + + simulation.make_fake_toas_uniform( 55010, 55500, 40, model=model, freq=800 * u.MHz, obs="gbt" - ), - simulation.make_fake_toas_uniform( + ) + + simulation.make_fake_toas_uniform( 55020, 55500, 50, model=model, freq=2000 * u.MHz, obs="@" - ), - ] - f = io.StringIO() - for t in fakes: - t.write_TOA_file(f) - f.seek(0) - t = toa.get_TOAs(f) + ) + ) r = pint.residuals.Residuals(t, model, subtract_mean=False) @classmethod From 2e01c6642846cf83c8d0d0da755adc6f7616591c Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Wed, 14 Aug 2024 14:40:08 +0200 Subject: [PATCH 031/195] Don't use long-double for ORBWAVE parameters; it's unnecessary and causes errors with older astropy versions. --- src/pint/models/pulsar_binary.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/pint/models/pulsar_binary.py b/src/pint/models/pulsar_binary.py index db71db7a8..425548c4e 100644 --- a/src/pint/models/pulsar_binary.py +++ b/src/pint/models/pulsar_binary.py @@ -213,7 +213,6 @@ def __init__(self): aliases=["ORBWAVEC"], description_template=self.ORBWAVEC_description, type_match="float", - long_double=True, tcb2tdb_scale_factor=u.Quantity(1), ) ) @@ -227,7 +226,6 @@ def __init__(self): aliases=["ORBWAVES"], description_template=self.ORBWAVES_description, type_match="float", - long_double=True, tcb2tdb_scale_factor=u.Quantity(1), ) ) @@ -237,7 +235,6 @@ def __init__(self): name="ORBWAVE_OM", units="rad/s", description="Base frequency for ORBWAVEs model", - long_double=True, tcb2tdb_scale_factor=u.Quantity(1), ) ) From 58c6062f5a9963bda3720eca99f8bb347f54e1e1 Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Sat, 24 Aug 2024 13:32:46 -0400 Subject: [PATCH 032/195] Initial merge of OrbwavesFBX and friends. --- src/pint/models/pulsar_binary.py | 33 +++++--- .../stand_alone_psr_binaries/binary_orbits.py | 77 ++++++++++++++++--- 2 files changed, 88 insertions(+), 22 deletions(-) diff --git a/src/pint/models/pulsar_binary.py b/src/pint/models/pulsar_binary.py index 425548c4e..609092f87 100644 --- a/src/pint/models/pulsar_binary.py +++ b/src/pint/models/pulsar_binary.py @@ -308,10 +308,9 @@ def setup(self): } if any(v is not None for v in ORBWAVES.values()): - self.binary_instance.add_binary_params("ORBWAVE_OM", self.ORBWAVE_OM.value) - self.binary_instance.add_binary_params( - "ORBWAVE_EPOCH", self.ORBWAVE_EPOCH.value - ) + for k in ['ORBWAVE_OM','ORBWAVE_EPOCH']: + self.binary_instance.add_binary_params( + k,getattr(self,k).value) for k in ORBWAVES.keys(): self.binary_instance.add_binary_params(k, ORBWAVES[k]) @@ -319,12 +318,26 @@ def setup(self): for k in ORBWAVEC.keys(): self.binary_instance.add_binary_params(k, ORBWAVEC[k]) - self.binary_instance.orbits_cls = bo.OrbitWaves( - self.binary_instance, - ["PB", "TASC", "ORBWAVE_OM", "ORBWAVE_EPOCH"] - + list(ORBWAVES.keys()) - + list(ORBWAVEC.keys()), - ) + using_FBX = any(v is not None for v in FBXs.values()) + if using_FBX: + fbx = sorted(list(FBXs.keys())) + if len(fbx) > 2: + raise ValueError('Only FB0/FB1 are supported.') + if (len(fbx) == 2) and (fbx[1] != 'FB1'): + raise ValueError('Only FB0/FB1 are supported.') + self.binary_instance.orbits_cls = bo.OrbitWavesFBX( + self.binary_instance, + fbx + + ["TASC", "ORBWAVE_OM", "ORBWAVE_EPOCH"] + + list(ORBWAVES.keys()) + + list(ORBWAVEC.keys()) + else: + self.binary_instance.orbits_cls = bo.OrbitWaves( + self.binary_instance, + ["PB", "TASC", "ORBWAVE_OM", "ORBWAVE_EPOCH"] + + list(ORBWAVES.keys()) + + list(ORBWAVEC.keys()), + ) # Note: if we are happy to use these to show alternate parameterizations then this can be uncommented # else: diff --git a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py index 705a676ee..f9d03edc4 100644 --- a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py +++ b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py @@ -254,7 +254,10 @@ def __init__( "ORBWAVES0", ], ): - super().__init__("orbitWaves", parent, orbit_params) + # Generalize this to allow for instantiation with OrbitWavesFBX + label = self.__class__.__name__ + label = label[0].lower() + label[1:] + super().__init__(label, parent, orbit_params) Cindices = set() Sindices = set() @@ -423,11 +426,6 @@ def d_pbprime_d_PB(self): def d_pbprime_d_orbwave(self, par): tw = self._tw() WOM = self.ORBWAVE_OM.to("radian/second") - PB = self.PB.to("second") - FB0 = 1.0 / PB - FB0_shift = self._d_deltaPhi_dt() - - FB0_prime = FB0 + FB0_shift nh = int(par[8:]) + 1 if par[7] == "C": @@ -435,7 +433,8 @@ def d_pbprime_d_orbwave(self, par): else: d_deltaFB0_d_orbwave = WOM * nh * np.cos(WOM * nh * tw) - return (-1.0 / FB0_prime**2 * d_deltaFB0_d_orbwave).to( + # use of pbprime should account for both Taylor and Fourier terms + return (-self.pbprime()**2 * d_deltaFB0_d_orbwave).to( "d", equivalencies=u.dimensionless_angles() ) @@ -452,9 +451,63 @@ def d_pbprime_d_par(self, par): if re.match(r"ORBWAVE[CS]\d+", par) is not None: return self.d_pbprime_d_orbwave(par) - elif par == "PB": - return self.d_pbprime_d_PB() + return super().d_pbprime_d_par(par) - # TASC, or other parameters, don't affect PB prime - else: - return np.zeros(len(self.tt0)) * u.second / par_obj.unit +class OrbitWavesFBX(OrbitWaves): + """Orbit with orbital phase variations described both by FBX terms and + by a Fourier series""" + + def __init__( + self, + parent, + orbit_params=[ + "FB0", + "TASC", + "ORBWAVE_OM", + "ORBWAVE_EPOCH", + "ORBWAVEC0", + "ORBWAVES0", + ] + ): + if not hasattr(parent,'FB1'): + parent.add_param(floatParameter(name="FB1",units=u.Hz**2,long_double=True,value=0)) + parent.binary_instance.add_binary_params('FB1',parent.FB1) + orbit_params += ['FB1'] + super().__init__(parent, orbit_params) + + def orbits(self): + """Orbital phase (number of orbits since TASC).""" + tt = self.tt0 + orbits = self.FB0*tt * (1 + (0.5*self.FB1/self.FB0)*tt) + orbits += self._deltaPhi() + return orbits.decompose() + + def pbprime(self): + """Instantaneous binary period as a function of time.""" + + orbit_freq = self.FB0 + self.FB1*self.tt0 + orbit_freq += self._d_deltaPhi_dt() + return 1.0 / orbit_freq.decompose() + + def pbdot_orbit(self): + """Reported value of PBDOT.""" + orbit_freq_dot = self._d2_deltaPhi_dt2() + self.FB1 + return -(self.pbprime() ** 2) * orbit_freq_dot + + def d_orbits_d_TASC(self): + return -self.FB0.to("Hz") * 2 * np.pi * u.rad + + def d_orbits_d_FB0(self): + return self.tt0.decompose() * (2 * np.pi * u.rad) + + def d_orbits_d_FB1(self): + return (0.5*self.tt0**2).decompose() * (2 * np.pi * u.rad) + + def d_pbprime_d_FB0(self): + return -1*self.pbprime()**2 + + def d_pbprime_d_FB1(self): + return -self.tt0*self.pbprime()**2 + + def d_pbprime_d_TASC(self): + return self.FB1*self.pbprime()**2 From 39a0f5fb277a4f9f78ab60991a2f3d428ae29c8f Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Sat, 24 Aug 2024 14:10:00 -0400 Subject: [PATCH 033/195] All relevant tests passing. --- src/pint/models/pulsar_binary.py | 14 ++++---- .../stand_alone_psr_binaries/binary_orbits.py | 29 ++++++++------- tests/test_orbwaves.py | 36 +++++++++++++------ 3 files changed, 48 insertions(+), 31 deletions(-) diff --git a/src/pint/models/pulsar_binary.py b/src/pint/models/pulsar_binary.py index 609092f87..e55f8084a 100644 --- a/src/pint/models/pulsar_binary.py +++ b/src/pint/models/pulsar_binary.py @@ -308,9 +308,8 @@ def setup(self): } if any(v is not None for v in ORBWAVES.values()): - for k in ['ORBWAVE_OM','ORBWAVE_EPOCH']: - self.binary_instance.add_binary_params( - k,getattr(self,k).value) + for k in ["ORBWAVE_OM", "ORBWAVE_EPOCH"]: + self.binary_instance.add_binary_params(k, getattr(self, k).value) for k in ORBWAVES.keys(): self.binary_instance.add_binary_params(k, ORBWAVES[k]) @@ -322,15 +321,16 @@ def setup(self): if using_FBX: fbx = sorted(list(FBXs.keys())) if len(fbx) > 2: - raise ValueError('Only FB0/FB1 are supported.') - if (len(fbx) == 2) and (fbx[1] != 'FB1'): - raise ValueError('Only FB0/FB1 are supported.') + raise ValueError("Only FB0/FB1 are supported.") + if (len(fbx) == 2) and (fbx[1] != "FB1"): + raise ValueError("Only FB0/FB1 are supported.") self.binary_instance.orbits_cls = bo.OrbitWavesFBX( self.binary_instance, fbx + ["TASC", "ORBWAVE_OM", "ORBWAVE_EPOCH"] + list(ORBWAVES.keys()) - + list(ORBWAVEC.keys()) + + list(ORBWAVEC.keys()), + ) else: self.binary_instance.orbits_cls = bo.OrbitWaves( self.binary_instance, diff --git a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py index f9d03edc4..2b3987d6a 100644 --- a/src/pint/models/stand_alone_psr_binaries/binary_orbits.py +++ b/src/pint/models/stand_alone_psr_binaries/binary_orbits.py @@ -434,7 +434,7 @@ def d_pbprime_d_orbwave(self, par): d_deltaFB0_d_orbwave = WOM * nh * np.cos(WOM * nh * tw) # use of pbprime should account for both Taylor and Fourier terms - return (-self.pbprime()**2 * d_deltaFB0_d_orbwave).to( + return (-self.pbprime() ** 2 * d_deltaFB0_d_orbwave).to( "d", equivalencies=u.dimensionless_angles() ) @@ -453,9 +453,10 @@ def d_pbprime_d_par(self, par): return super().d_pbprime_d_par(par) + class OrbitWavesFBX(OrbitWaves): """Orbit with orbital phase variations described both by FBX terms and - by a Fourier series""" + by a Fourier series""" def __init__( self, @@ -467,25 +468,27 @@ def __init__( "ORBWAVE_EPOCH", "ORBWAVEC0", "ORBWAVES0", - ] + ], ): - if not hasattr(parent,'FB1'): - parent.add_param(floatParameter(name="FB1",units=u.Hz**2,long_double=True,value=0)) - parent.binary_instance.add_binary_params('FB1',parent.FB1) - orbit_params += ['FB1'] + if not hasattr(parent, "FB1"): + parent.add_param( + floatParameter(name="FB1", units=u.Hz**2, long_double=True, value=0) + ) + parent.binary_instance.add_binary_params("FB1", parent.FB1) + orbit_params += ["FB1"] super().__init__(parent, orbit_params) def orbits(self): """Orbital phase (number of orbits since TASC).""" tt = self.tt0 - orbits = self.FB0*tt * (1 + (0.5*self.FB1/self.FB0)*tt) + orbits = self.FB0 * tt * (1 + (0.5 * self.FB1 / self.FB0) * tt) orbits += self._deltaPhi() return orbits.decompose() def pbprime(self): """Instantaneous binary period as a function of time.""" - orbit_freq = self.FB0 + self.FB1*self.tt0 + orbit_freq = self.FB0 + self.FB1 * self.tt0 orbit_freq += self._d_deltaPhi_dt() return 1.0 / orbit_freq.decompose() @@ -501,13 +504,13 @@ def d_orbits_d_FB0(self): return self.tt0.decompose() * (2 * np.pi * u.rad) def d_orbits_d_FB1(self): - return (0.5*self.tt0**2).decompose() * (2 * np.pi * u.rad) + return (0.5 * self.tt0**2).decompose() * (2 * np.pi * u.rad) def d_pbprime_d_FB0(self): - return -1*self.pbprime()**2 + return -1 * self.pbprime() ** 2 def d_pbprime_d_FB1(self): - return -self.tt0*self.pbprime()**2 + return -self.tt0 * self.pbprime() ** 2 def d_pbprime_d_TASC(self): - return self.FB1*self.pbprime()**2 + return self.FB1 * self.pbprime() ** 2 diff --git a/tests/test_orbwaves.py b/tests/test_orbwaves.py index 96dcf0f94..49f6c34fd 100644 --- a/tests/test_orbwaves.py +++ b/tests/test_orbwaves.py @@ -1,7 +1,9 @@ +from collections import deque +from io import StringIO import os -import astropy.units as u import pytest +import astropy.units as u import pint.models as tm from pint import fitter, toa, simulation from pinttestdata import datadir @@ -12,9 +14,8 @@ def test_orbwaves_fit(): m, t = get_model_and_toas( - os.path.join(datadir, "J1048+2339_orbwaves.par"), - os.path.join(datadir, "J1048+2339_3PC_fake.tim"), - ) + datadir / "J1048+2339_orbwaves.par", + datadir / "J1048+2339_3PC_fake.tim") f = fitter.WLSFitter(toas=t, model=m) @@ -29,14 +30,27 @@ def test_orbwaves_fit(): def test_invalid_parfiles(): - with pytest.raises(Exception): - m1 = get_model(os.path.join(datadir, "J1048+2339_orbwaves_invalid1.par")) - - with pytest.raises(Exception): - m2 = get_model(os.path.join(datadir, "J1048+2339_orbwaves_invalid2.par")) + parlines = open(datadir / "J1048+2339_orbwaves.par").readlines() + + def _delete_line(labels): + lines = deque() + for line in parlines: + label = line.split()[0] + if label in labels: + continue + lines.append(line) + return StringIO(lines) + + deleted_lines = [ + ['ORBWAVEC0','ORBWAVES0'], + ['ORBWAVEC3'], + ['ORBWAVES4'] + ] + + for lines in deleted_lines: + with pytest.raises(Exception): + m = get_model(_delete_line(lines)) - with pytest.raises(Exception): - m3 = get_model(os.path.join(datadir, "J1048+2339_orbwaves_invalid3.par")) if __name__ == "__main__": From 43dfdcfca1cda0549730ee81f54d4858a4d8ab11 Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Sat, 24 Aug 2024 15:07:41 -0400 Subject: [PATCH 034/195] Replace .par files with StringIO. --- .../datafile/J1048+2339_orbwaves_invalid1.par | 46 ------------------ .../datafile/J1048+2339_orbwaves_invalid2.par | 47 ------------------- .../datafile/J1048+2339_orbwaves_invalid3.par | 47 ------------------- 3 files changed, 140 deletions(-) delete mode 100644 tests/datafile/J1048+2339_orbwaves_invalid1.par delete mode 100644 tests/datafile/J1048+2339_orbwaves_invalid2.par delete mode 100644 tests/datafile/J1048+2339_orbwaves_invalid3.par diff --git a/tests/datafile/J1048+2339_orbwaves_invalid1.par b/tests/datafile/J1048+2339_orbwaves_invalid1.par deleted file mode 100644 index acc571819..000000000 --- a/tests/datafile/J1048+2339_orbwaves_invalid1.par +++ /dev/null @@ -1,46 +0,0 @@ -PSR J1048+2339 -RAJ 10:48:43.41835421 1 0.00007631 -DECJ 23:39:53.4043452 1 0.0020013 -PMRA -18.7000 -PMDEC -9.4000 -POSEPOCH 56700.0000 -F0 214.3547853411294852 1 0.0000000000170721 -F1 -1.381753144359e-15 1 1.531201039458e-18 -PEPOCH 57285.000000 -START 56508.798 -FINISH 57548.936 -#DM 16.654332 -DMEPOCH 56700.0000 -SOLARN0 10.00 -EPHEM DE421 -CLK TT(BIPM2021) -UNITS TDB -TIMEEPH FB90 -T2CMETHOD IAU2000B -CORRECT_TROPOSPHERE N -PLANET_SHAPIRO N -DILATEFREQ N -NTOA 104 -TRES 8.84 -TZRMJD 57285.65854990785506 -TZRFRQ 326.988 -TZRSITE 3 -NITS 1 -BINARY ELL1 -A1 0.836120368 1 0.000003165 -EPS1 0 -EPS2 0 -# ATNF DM info (from drc+16): -DM 16.6544 0.0001 -ORBWAVE_OM 3.495788643739122e-08 -ORBWAVE_EPOCH 57028.867 -TASC 56637.61958641038 1 -PB 0.250506696660119 1 -ORBWAVEC1 -0.009093465738757574 1 -ORBWAVES1 0.03712548529066605 1 -ORBWAVEC2 0.00414066930830874 1 -ORBWAVES2 -0.011358879259751396 1 -ORBWAVEC3 -0.001400204000025873 1 -ORBWAVES3 0.002749601047126059 1 -ORBWAVEC4 0.00019385501703957642 1 -ORBWAVES4 -0.00028698933945954427 1 \ No newline at end of file diff --git a/tests/datafile/J1048+2339_orbwaves_invalid2.par b/tests/datafile/J1048+2339_orbwaves_invalid2.par deleted file mode 100644 index bca3bd853..000000000 --- a/tests/datafile/J1048+2339_orbwaves_invalid2.par +++ /dev/null @@ -1,47 +0,0 @@ -PSR J1048+2339 -RAJ 10:48:43.41835421 1 0.00007631 -DECJ 23:39:53.4043452 1 0.0020013 -PMRA -18.7000 -PMDEC -9.4000 -POSEPOCH 56700.0000 -F0 214.3547853411294852 1 0.0000000000170721 -F1 -1.381753144359e-15 1 1.531201039458e-18 -PEPOCH 57285.000000 -START 56508.798 -FINISH 57548.936 -#DM 16.654332 -DMEPOCH 56700.0000 -SOLARN0 10.00 -EPHEM DE421 -CLK TT(BIPM2021) -UNITS TDB -TIMEEPH FB90 -T2CMETHOD IAU2000B -CORRECT_TROPOSPHERE N -PLANET_SHAPIRO N -DILATEFREQ N -NTOA 104 -TRES 8.84 -TZRMJD 57285.65854990785506 -TZRFRQ 326.988 -TZRSITE 3 -NITS 1 -BINARY ELL1 -A1 0.836120368 1 0.000003165 -EPS1 0 -EPS2 0 -# ATNF DM info (from drc+16): -DM 16.6544 0.0001 -ORBWAVE_OM 3.495788643739122e-08 -ORBWAVE_EPOCH 57028.867 -TASC 56637.61958641038 1 -PB 0.250506696660119 1 -ORBWAVEC0 0.01359122306797746 1 -ORBWAVES0 -0.1138721359160273 1 -ORBWAVEC1 -0.009093465738757574 1 -ORBWAVES1 0.03712548529066605 1 -ORBWAVEC2 0.00414066930830874 1 -ORBWAVES2 -0.011358879259751396 1 -ORBWAVES3 0.002749601047126059 1 -ORBWAVEC4 0.00019385501703957642 1 -ORBWAVES4 -0.00028698933945954427 1 \ No newline at end of file diff --git a/tests/datafile/J1048+2339_orbwaves_invalid3.par b/tests/datafile/J1048+2339_orbwaves_invalid3.par deleted file mode 100644 index 6eb0b2ed1..000000000 --- a/tests/datafile/J1048+2339_orbwaves_invalid3.par +++ /dev/null @@ -1,47 +0,0 @@ -PSR J1048+2339 -RAJ 10:48:43.41835421 1 0.00007631 -DECJ 23:39:53.4043452 1 0.0020013 -PMRA -18.7000 -PMDEC -9.4000 -POSEPOCH 56700.0000 -F0 214.3547853411294852 1 0.0000000000170721 -F1 -1.381753144359e-15 1 1.531201039458e-18 -PEPOCH 57285.000000 -START 56508.798 -FINISH 57548.936 -#DM 16.654332 -DMEPOCH 56700.0000 -SOLARN0 10.00 -EPHEM DE421 -CLK TT(BIPM2021) -UNITS TDB -TIMEEPH FB90 -T2CMETHOD IAU2000B -CORRECT_TROPOSPHERE N -PLANET_SHAPIRO N -DILATEFREQ N -NTOA 104 -TRES 8.84 -TZRMJD 57285.65854990785506 -TZRFRQ 326.988 -TZRSITE 3 -NITS 1 -BINARY ELL1 -A1 0.836120368 1 0.000003165 -EPS1 0 -EPS2 0 -# ATNF DM info (from drc+16): -DM 16.6544 0.0001 -ORBWAVE_OM 3.495788643739122e-08 -ORBWAVE_EPOCH 57028.867 -TASC 56637.61958641038 1 -PB 0.250506696660119 1 -ORBWAVEC0 0.01359122306797746 1 -ORBWAVES0 -0.1138721359160273 1 -ORBWAVEC1 -0.009093465738757574 1 -ORBWAVES1 0.03712548529066605 1 -ORBWAVEC2 0.00414066930830874 1 -ORBWAVES2 -0.011358879259751396 1 -ORBWAVEC3 -0.001400204000025873 1 -ORBWAVES3 0.002749601047126059 1 -ORBWAVEC4 0.00019385501703957642 1 From be13fd4846d29808814485044a8a2e850c67706f Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Sat, 24 Aug 2024 15:09:05 -0400 Subject: [PATCH 035/195] Oops, remove removed .pars from exception list. --- tests/test_all_component_and_model_builder.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/test_all_component_and_model_builder.py b/tests/test_all_component_and_model_builder.py index adbf688a6..893b7bfd9 100644 --- a/tests/test_all_component_and_model_builder.py +++ b/tests/test_all_component_and_model_builder.py @@ -451,9 +451,6 @@ def __init__(self): bad_trouble = [ "J1923+2515_NANOGrav_9yv1.gls.par", "J1744-1134.basic.ecliptic.par", - "J1048+2339_orbwaves_invalid1.par", - "J1048+2339_orbwaves_invalid2.par", - "J1048+2339_orbwaves_invalid3.par", ] From 0eea13a5f37488254028363c48de0c4e911f5ddd Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Thu, 29 Aug 2024 09:19:47 +0200 Subject: [PATCH 036/195] reduce nprocs for macos --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index bba6c8f7d..96e6f403d 100644 --- a/tox.ini +++ b/tox.ini @@ -45,7 +45,7 @@ deps = setuptools commands = pip freeze - !cov: pytest -n 6 --reruns 5 + !cov: pytest --reruns 5 cov: pytest -n 6 --reruns 5 --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} cov: coverage xml -o {toxinidir}/coverage.xml From b65a136cb2d3ca90e5b86c46543118991e04e987 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Thu, 29 Aug 2024 09:20:16 +0200 Subject: [PATCH 037/195] tox.ini --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 96e6f403d..7028ea667 100644 --- a/tox.ini +++ b/tox.ini @@ -45,7 +45,7 @@ deps = setuptools commands = pip freeze - !cov: pytest --reruns 5 + !cov: pytest -n 2 --reruns 5 cov: pytest -n 6 --reruns 5 --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} cov: coverage xml -o {toxinidir}/coverage.xml From 80111e4a819087c4537115d0e9fc03de791f591f Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Thu, 29 Aug 2024 09:24:24 +0200 Subject: [PATCH 038/195] verbose tests --- tox.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index 7028ea667..c5f6e5737 100644 --- a/tox.ini +++ b/tox.ini @@ -45,8 +45,8 @@ deps = setuptools commands = pip freeze - !cov: pytest -n 2 --reruns 5 - cov: pytest -n 6 --reruns 5 --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} + !cov: pytest -n 2 --reruns 5 --verbose + cov: pytest -n 6 --reruns 5 --verbose --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} cov: coverage xml -o {toxinidir}/coverage.xml depends = @@ -77,7 +77,7 @@ deps = pytest-rerunfailures coverage hypothesis<=6.72.0 -commands = {posargs:pytest -n 6 --reruns 5} +commands = {posargs:pytest -n 6 --reruns 5 --verbose} [testenv:report] skip_install = true From d0a85424e0106fbb2d5c3c0c59c5839a9c2e51f6 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Thu, 29 Aug 2024 09:27:32 +0200 Subject: [PATCH 039/195] no parallel in macos --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index c5f6e5737..a56bc2ef9 100644 --- a/tox.ini +++ b/tox.ini @@ -45,7 +45,7 @@ deps = setuptools commands = pip freeze - !cov: pytest -n 2 --reruns 5 --verbose + !cov: pytest --reruns 5 --verbose cov: pytest -n 6 --reruns 5 --verbose --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} cov: coverage xml -o {toxinidir}/coverage.xml From 87ffae37359cd977f66205fb8f8382f2ad18f02c Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Thu, 29 Aug 2024 10:40:18 +0200 Subject: [PATCH 040/195] refresh --- tests/refresh.py | 4 ++++ tox.ini | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 tests/refresh.py diff --git a/tests/refresh.py b/tests/refresh.py new file mode 100644 index 000000000..fce039c31 --- /dev/null +++ b/tests/refresh.py @@ -0,0 +1,4 @@ +from pint.models import get_model_and_toas +from pinttestdata import datadir + +get_model_and_toas(datadir / "NGC6440E.par", datadir / "NGC6440E.tim") diff --git a/tox.ini b/tox.ini index a56bc2ef9..0108b15a7 100644 --- a/tox.ini +++ b/tox.ini @@ -45,6 +45,7 @@ deps = setuptools commands = pip freeze + python tests/refresh.py !cov: pytest --reruns 5 --verbose cov: pytest -n 6 --reruns 5 --verbose --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} cov: coverage xml -o {toxinidir}/coverage.xml @@ -77,7 +78,10 @@ deps = pytest-rerunfailures coverage hypothesis<=6.72.0 -commands = {posargs:pytest -n 6 --reruns 5 --verbose} +commands = + python tests/refresh.py + posargs: pytest -n 6 --reruns 5 --verbose + [testenv:report] skip_install = true From 3e3bdfdaca78f93b6e93cf3fec4893a831e605f9 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Thu, 29 Aug 2024 10:43:22 +0200 Subject: [PATCH 041/195] -- --- tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 0108b15a7..4c2772079 100644 --- a/tox.ini +++ b/tox.ini @@ -46,7 +46,7 @@ deps = commands = pip freeze python tests/refresh.py - !cov: pytest --reruns 5 --verbose + !cov: pytest -n 6 --reruns 5 --verbose cov: pytest -n 6 --reruns 5 --verbose --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} cov: coverage xml -o {toxinidir}/coverage.xml @@ -80,7 +80,7 @@ deps = hypothesis<=6.72.0 commands = python tests/refresh.py - posargs: pytest -n 6 --reruns 5 --verbose + pytest -n 6 --reruns 5 --verbose [testenv:report] From 4555fbe16165049ebff6aa011e1ea9358c8f643f Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Thu, 29 Aug 2024 10:55:22 +0200 Subject: [PATCH 042/195] ignore --- tests/refresh.py | 4 ---- tox.ini | 5 ++--- 2 files changed, 2 insertions(+), 7 deletions(-) delete mode 100644 tests/refresh.py diff --git a/tests/refresh.py b/tests/refresh.py deleted file mode 100644 index fce039c31..000000000 --- a/tests/refresh.py +++ /dev/null @@ -1,4 +0,0 @@ -from pint.models import get_model_and_toas -from pinttestdata import datadir - -get_model_and_toas(datadir / "NGC6440E.par", datadir / "NGC6440E.tim") diff --git a/tox.ini b/tox.ini index 4c2772079..3b714a73f 100644 --- a/tox.ini +++ b/tox.ini @@ -45,8 +45,8 @@ deps = setuptools commands = pip freeze - python tests/refresh.py - !cov: pytest -n 6 --reruns 5 --verbose + !cov: pytest --reruns 5 --verbose tests/test_toa_selection.py + !cov: pytest -n 6 --reruns 5 --verbose --ignore=tests/test_toa_selection.py cov: pytest -n 6 --reruns 5 --verbose --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} cov: coverage xml -o {toxinidir}/coverage.xml @@ -79,7 +79,6 @@ deps = coverage hypothesis<=6.72.0 commands = - python tests/refresh.py pytest -n 6 --reruns 5 --verbose From 80703acf6a709dde1158553f98a214dce77d6785 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Wed, 4 Sep 2024 15:12:01 -0500 Subject: [PATCH 043/195] Revert "Run tests in parallel" --- CHANGELOG-unreleased.md | 1 - requirements_dev.txt | 2 -- tests/test_noisefit.py | 55 +++++++++++++------------------------- tests/test_publish.py | 39 +++++++++++---------------- tests/test_timing_model.py | 3 +++ tests/test_toa_shuffle.py | 30 ++++++++++++--------- tox.ini | 16 +++-------- 7 files changed, 60 insertions(+), 86 deletions(-) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 92ef91fb9..25f3d6283 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -11,7 +11,6 @@ the released changes. ### Changed - Moved the events -> TOAs and photon weights code into the function `load_events_weights` within `event_optimize`. - Updated the `maxMJD` argument in `event_optimize` to default to the current mjd -- Run CI tests in parallel, re-run failed tests (for intermittent failures due to random chance) - `maskParameter.__repr__()` output now includes the frozen attribute. - Changed default value of `FDJUMPLOG` to `Y` - Bumped `black` version to 24.x diff --git a/requirements_dev.txt b/requirements_dev.txt index d210e4854..a00511840 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -12,8 +12,6 @@ wheel>=0.29.0 pytest>=4.3 pytest-cov>=2.7.1 pytest-runner>=5.1 -pytest-xdist -pytest-rerunfailures flake8>=3.7 pep8-naming>=0.8.2 flake8-docstrings>=1.4 diff --git a/tests/test_noisefit.py b/tests/test_noisefit.py index 69f652cec..16e7cdc31 100644 --- a/tests/test_noisefit.py +++ b/tests/test_noisefit.py @@ -6,38 +6,27 @@ from io import StringIO import numpy as np -import pytest +par = """ + ELAT 1.3 1 + ELONG 2.5 1 + F0 100 1 + F1 1e-13 1 + PEPOCH 55000 + EPHEM DE440 + EFAC mjd 50000 53000 2 1 + EQUAD mjd 53000 55000 0.8 1 +""" -@pytest.fixture -def model_and_toas_1(): - par = """ - ELAT 1.3 1 - ELONG 2.5 1 - F0 100 1 - F1 1e-13 1 - PEPOCH 55000 - EPHEM DE440 - EFAC mjd 50000 53000 2 1 - EQUAD mjd 53000 55000 0.8 1 - """ +m = get_model(StringIO(par)) +t = make_fake_toas_uniform(50000, 55000, 200, m, add_noise=True) - m = get_model(StringIO(par)) - t = make_fake_toas_uniform(50000, 55000, 200, m, add_noise=True) +m2, t2 = get_model_and_toas( + datadir / "ecorr_fit_test.par", datadir / "ecorr_fit_test.tim" +) - return m, t - - -@pytest.fixture -def model_and_toas_2(): - return get_model_and_toas( - datadir / "ecorr_fit_test.par", datadir / "ecorr_fit_test.tim" - ) - - -def test_white_noise_fit(model_and_toas_1): - m, t = model_and_toas_1 +def test_white_noise_fit(): assert m.EFAC1.uncertainty_value == 0 and m.EQUAD1.uncertainty_value == 0 ftr = DownhillWLSFitter(t, m) @@ -58,9 +47,7 @@ def test_white_noise_fit(model_and_toas_1): ) -def test_white_noise_refit(model_and_toas_1): - m, t = model_and_toas_1 - +def test_white_noise_refit(): ftr = DownhillWLSFitter(t, m) ftr.model.EFAC1.value = 1.5 @@ -80,9 +67,7 @@ def test_white_noise_refit(model_and_toas_1): ) -def test_ecorr_fit(model_and_toas_2): - m2, t2 = model_and_toas_2 - +def test_ecorr_fit(): ftr = DownhillGLSFitter(t2, m2) ftr.fit_toas() @@ -94,9 +79,7 @@ def test_ecorr_fit(model_and_toas_2): ) -def test_ecorr_refit(model_and_toas_2): - m2, t2 = model_and_toas_2 - +def test_ecorr_refit(): ftr = DownhillGLSFitter(t2, m2) ftr.model.ECORR1.value = 0.75 diff --git a/tests/test_publish.py b/tests/test_publish.py index cab74adb1..f8663ff3d 100644 --- a/tests/test_publish.py +++ b/tests/test_publish.py @@ -5,37 +5,24 @@ from pint.scripts import pintpublish import os +data_NGC6440E = get_model_and_toas(datadir / "NGC6440E.par", datadir / "NGC6440E.tim") -@pytest.fixture -def data_NGC6440E(): - return get_model_and_toas(datadir / "NGC6440E.par", datadir / "NGC6440E.tim") - -@pytest.fixture -def data_J0613m0200_NANOGrav_9yv1(): - return get_model_and_toas( - datadir / "J0613-0200_NANOGrav_9yv1.gls.par", - datadir / "J0613-0200_NANOGrav_9yv1.tim", - ) - - -@pytest.fixture -def data_J1614m2230_NANOGrav_12yv3_wb(): - return get_model_and_toas( - datadir / "J1614-2230_NANOGrav_12yv3.wb.gls.par", - datadir / "J1614-2230_NANOGrav_12yv3.wb.tim", - ) - - -def test_NGC6440E(data_NGC6440E): +def test_NGC6440E(): m, t = data_NGC6440E output = publish(m, t) assert "1748-2021E" in output assert "DE421" in output +data_J0613m0200_NANOGrav_9yv1 = get_model_and_toas( + datadir / "J0613-0200_NANOGrav_9yv1.gls.par", + datadir / "J0613-0200_NANOGrav_9yv1.tim", +) + + @pytest.mark.parametrize("full", [True, False]) -def test_J0613m0200_NANOGrav_9yv1(data_J0613m0200_NANOGrav_9yv1, full): +def test_J0613m0200_NANOGrav_9yv1(full): m, t = data_J0613m0200_NANOGrav_9yv1 output = publish( m, t, include_dmx=full, include_fd=full, include_noise=full, include_jumps=full @@ -52,8 +39,14 @@ def test_J0613m0200_NANOGrav_9yv1(data_J0613m0200_NANOGrav_9yv1, full): assert not full or "RNAMP" in output +data_J1614m2230_NANOGrav_12yv3_wb = get_model_and_toas( + datadir / "J1614-2230_NANOGrav_12yv3.wb.gls.par", + datadir / "J1614-2230_NANOGrav_12yv3.wb.tim", +) + + @pytest.mark.parametrize("full", [True, False]) -def test_J1614m2230_NANOGrav_12yv3_wb(data_J1614m2230_NANOGrav_12yv3_wb, full): +def test_J1614m2230_NANOGrav_12yv3_wb(full): m, t = data_J1614m2230_NANOGrav_12yv3_wb output = publish( m, t, include_dmx=full, include_fd=full, include_noise=full, include_jumps=full diff --git a/tests/test_timing_model.py b/tests/test_timing_model.py index 5c9456757..2cd37645c 100644 --- a/tests/test_timing_model.py +++ b/tests/test_timing_model.py @@ -42,6 +42,9 @@ def timfile_nojumps(): return get_TOAs(os.path.join(datadir, "NGC6440E.tim")) +len_timfile_nojumps = len(get_TOAs(os.path.join(datadir, "NGC6440E.tim"))) + + class TestModelBuilding: def setup_method(self): self.parfile = os.path.join(datadir, "J0437-4715.par") diff --git a/tests/test_toa_shuffle.py b/tests/test_toa_shuffle.py index cd7bd1b3c..2d757c09b 100644 --- a/tests/test_toa_shuffle.py +++ b/tests/test_toa_shuffle.py @@ -18,22 +18,33 @@ import pint.residuals from pint.models import get_model +shuffletoas = """FORMAT 1 +test 1234.0 54321 0 pks +test2 888 59055 0 meerkat +test3 350 59000 0 gbt +""" + class TOAOrderSetup: parfile = os.path.join(datadir, "NGC6440E.par") model = get_model(parfile) # fake a multi-telescope, multi-frequency data-set and make sure the results don't depend on TOA order - t = ( + fakes = [ simulation.make_fake_toas_uniform( 55000, 55500, 30, model=model, freq=1400 * u.MHz, obs="ao" - ) - + simulation.make_fake_toas_uniform( + ), + simulation.make_fake_toas_uniform( 55010, 55500, 40, model=model, freq=800 * u.MHz, obs="gbt" - ) - + simulation.make_fake_toas_uniform( + ), + simulation.make_fake_toas_uniform( 55020, 55500, 50, model=model, freq=2000 * u.MHz, obs="@" - ) - ) + ), + ] + f = io.StringIO() + for t in fakes: + t.write_TOA_file(f) + f.seek(0) + t = toa.get_TOAs(f) r = pint.residuals.Residuals(t, model, subtract_mean=False) @classmethod @@ -84,11 +95,6 @@ def test_resorting_toas_chi2_match(sortkey): class TOALineOrderSetup: - shuffletoas = """FORMAT 1 - test 1234.0 54321 0 pks - test2 888 59055 0 meerkat - test3 350 59000 0 gbt - """ timfile = io.StringIO(shuffletoas) t = toa.get_TOAs(timfile) timfile.seek(0) diff --git a/tox.ini b/tox.ini index 3b714a73f..87a498e01 100644 --- a/tox.ini +++ b/tox.ini @@ -18,8 +18,7 @@ envlist = skip_missing_interpreters = True [tool:pytest] -# pytest docs seem to say that this section should be called just pytest, -# not tool:pytest; is it working? +# pytest docs seem to say that this section should be called just pytest, not tool:pytest; is it working? testpaths = tests addopts = --cov-report=term-missing @@ -34,8 +33,6 @@ passenv = deps = pytest - pytest-xdist - pytest-rerunfailures cov: coverage cov: pytest-cov cov: pytest-remotedata @@ -45,9 +42,8 @@ deps = setuptools commands = pip freeze - !cov: pytest --reruns 5 --verbose tests/test_toa_selection.py - !cov: pytest -n 6 --reruns 5 --verbose --ignore=tests/test_toa_selection.py - cov: pytest -n 6 --reruns 5 --verbose --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} + !cov: pytest + cov: pytest -v --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} cov: coverage xml -o {toxinidir}/coverage.xml depends = @@ -74,13 +70,9 @@ deps = matplotlib==3.2.0 scipy==1.4.1 pytest - pytest-xdist - pytest-rerunfailures coverage hypothesis<=6.72.0 -commands = - pytest -n 6 --reruns 5 --verbose - +commands = {posargs:pytest} [testenv:report] skip_install = true From f1e96e77315e56acfb3edc8a2064dc2352c39a72 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Thu, 5 Sep 2024 10:06:04 +0200 Subject: [PATCH 044/195] no aic for wideband --- src/pint/pintk/pulsar.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pint/pintk/pulsar.py b/src/pint/pintk/pulsar.py index 7e8f3a80e..59a6367f3 100644 --- a/src/pint/pintk/pulsar.py +++ b/src/pint/pintk/pulsar.py @@ -603,9 +603,10 @@ def fit(self, selected, iters=4, compute_random=False): # adds extra prefix params for fitting self.add_model_params() - print( - f"Akaike information criterion = {akaike_information_criterion(self.fitter.model, self.fitter.toas)}" - ) + if self.all_toas.is_wideband(): + print( + f"Akaike information criterion = {akaike_information_criterion(self.fitter.model, self.fitter.toas)}" + ) def random_models(self, selected): """Compute and plot random models""" From 07f9c296db202b6cd1cf1cece0d1c8c85b7797d1 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Thu, 5 Sep 2024 10:08:52 +0200 Subject: [PATCH 045/195] not --- src/pint/pintk/pulsar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pint/pintk/pulsar.py b/src/pint/pintk/pulsar.py index 59a6367f3..65d8048df 100644 --- a/src/pint/pintk/pulsar.py +++ b/src/pint/pintk/pulsar.py @@ -603,7 +603,7 @@ def fit(self, selected, iters=4, compute_random=False): # adds extra prefix params for fitting self.add_model_params() - if self.all_toas.is_wideband(): + if not self.all_toas.is_wideband(): print( f"Akaike information criterion = {akaike_information_criterion(self.fitter.model, self.fitter.toas)}" ) From 3dd400d07ae6e1385d87e7e7d2d82a0621c545d9 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Thu, 5 Sep 2024 10:09:36 +0200 Subject: [PATCH 046/195] CHANGELOG --- CHANGELOG-unreleased.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 25f3d6283..ff4152891 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -32,6 +32,7 @@ the released changes. - SWX model now has SWXP_0001 frozen by default, and new segments should also have SWXP frozen - Can now properly use local files for ephemeris - Typos in `explanation.rst` regarding local ephemeris. +- Don't try to print AIC for wideband data in `pintk` (it's not yet implemented) ### Removed - Removed the argument `--usepickle` in `event_optimize` as the `load_events_weights` function checks the events file type to see if the file is a pickle file. From 73a11e46a5935038251e0c6c229cc74b3ed5dfca Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Thu, 5 Sep 2024 09:03:55 -0500 Subject: [PATCH 047/195] making bad SINI raise exception to help fit --- src/pint/fitter.py | 5 +---- src/pint/models/parameter.py | 2 ++ src/pint/models/stand_alone_psr_binaries/DD_model.py | 5 +++++ src/pint/models/stand_alone_psr_binaries/ELL1_model.py | 3 +++ 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/pint/fitter.py b/src/pint/fitter.py index 1474b6b44..11bd1289e 100644 --- a/src/pint/fitter.py +++ b/src/pint/fitter.py @@ -76,6 +76,7 @@ AngleParameter, boolParameter, strParameter, + InvalidModelParameters, ) from pint.pint_matrix import ( CorrelationMatrix, @@ -887,10 +888,6 @@ def covariance_matrix(self): return self.parameter_covariance_matrix -class InvalidModelParameters(ValueError): - pass - - class CorrelatedErrors(ValueError): def __init__(self, model): trouble_components = [ diff --git a/src/pint/models/parameter.py b/src/pint/models/parameter.py index bb7ad588c..9b0ef7517 100644 --- a/src/pint/models/parameter.py +++ b/src/pint/models/parameter.py @@ -54,6 +54,8 @@ # in one place for consistency _parfile_formats = ["pint", "tempo", "tempo2"] +class InvalidModelParameters(ValueError): + pass def _identity_function(x): """A function to just return the input argument diff --git a/src/pint/models/stand_alone_psr_binaries/DD_model.py b/src/pint/models/stand_alone_psr_binaries/DD_model.py index 6e925fd58..be3886ee0 100644 --- a/src/pint/models/stand_alone_psr_binaries/DD_model.py +++ b/src/pint/models/stand_alone_psr_binaries/DD_model.py @@ -1,11 +1,13 @@ """Damour and Deruelle binary model.""" +from multiprocessing import Value import astropy.constants as c import astropy.units as u import numpy as np from loguru import logger as log from pint import Tsun +from pint.models.parameter import InvalidModelParameters from .binary_generic import PSR_BINARY @@ -709,6 +711,9 @@ def delayS(self): cOmega = np.cos(self.omega()) TM2 = self.M2.value * Tsun + if (self.SINI < 0) or (self.SINI > 1): + raise InvalidModelParameters("SINI parameter must be between 0 and 1") + return ( -2 * TM2 diff --git a/src/pint/models/stand_alone_psr_binaries/ELL1_model.py b/src/pint/models/stand_alone_psr_binaries/ELL1_model.py index d4b9cd8a0..df9858e90 100644 --- a/src/pint/models/stand_alone_psr_binaries/ELL1_model.py +++ b/src/pint/models/stand_alone_psr_binaries/ELL1_model.py @@ -4,6 +4,7 @@ import astropy.units as u import numpy as np +from pint.models.parameter import InvalidModelParameters from .binary_generic import PSR_BINARY @@ -600,6 +601,8 @@ def delayS(self): """ELL1 Shapiro delay. Lange et al 2001 eq. A16""" TM2 = self.TM2() Phi = self.Phi() + if (self.SINI < 0) or (self.SINI > 1): + raise InvalidModelParameters("SINI must be between 0 and 1") return -2 * TM2 * np.log(1 - self.SINI * np.sin(Phi)) def d_delayS_d_par(self, par): From 6253a347accccf1e56ad0d8dc97067f86c5025aa Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Thu, 5 Sep 2024 09:08:18 -0500 Subject: [PATCH 048/195] black --- src/pint/models/parameter.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pint/models/parameter.py b/src/pint/models/parameter.py index 9b0ef7517..0a9a7dce7 100644 --- a/src/pint/models/parameter.py +++ b/src/pint/models/parameter.py @@ -54,9 +54,11 @@ # in one place for consistency _parfile_formats = ["pint", "tempo", "tempo2"] + class InvalidModelParameters(ValueError): pass + def _identity_function(x): """A function to just return the input argument From a9c9c9df1cbdad392ce44079d8e6c7f69aa8a81c Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Thu, 5 Sep 2024 09:17:50 -0500 Subject: [PATCH 049/195] test added --- tests/test_sini.py | 69 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 tests/test_sini.py diff --git a/tests/test_sini.py b/tests/test_sini.py new file mode 100644 index 000000000..7f6f2b9a6 --- /dev/null +++ b/tests/test_sini.py @@ -0,0 +1,69 @@ +import pytest +import io +from astropy import units as u +import pint.logging +from pint.models import get_model +import pint.fitter +import pint.simulation + +pint.logging.setup("ERROR") + + +def test_sini_fit(): + s = """PSRJ J1853+1303 + EPHEM DE440 + CLK TT(TAI) + UNITS TDB + START 55731.1937186050359860 + FINISH 59051.1334073910116910 + TIMEEPH FB90 + T2CMETHOD IAU2000B + DILATEFREQ N + DMDATA N + NTOA 4570 + CHI2R 0.9873 0 4455.0 + TRES 1.297 + ELONG 286.257303932061347 1 0.00000000931838521883 + ELAT 35.743349195626379 1 0.00000001342269042838 + PMELONG -1.9106838589844408 1 0.011774688289719207 + PMELAT -2.7055634767966588 1 0.02499026250312041 + PX 0.6166118941596491 1 0.13495439191146907 + ECL IERS2010 + POSEPOCH 57391.0000000000000000 + F0 244.39137771284777388 1 4.741681125242900587e-13 + F1 -5.2068158193285555695e-16 1 1.657252200776189767e-20 + PEPOCH 57391.0000000000000000 + CORRECT_TROPOSPHERE Y + PLANET_SHAPIRO Y + NE_SW 0.0 + SWM 0.0 + DM 30.570200097819536894 + DM1 0.0 + DMEPOCH 57391.0000000000000000 + BINARY DD + PB 115.65378643873621578 1 3.2368969907e-09 + PBDOT 0.0 + A1 40.769522249658145 1 1.53854961349644e-06 + XDOT 1.564794972862985e-14 1 8.617009015429654e-16 + ECC 2.3701427108198803e-05 1 3.467883031e-09 + EDOT 0.0 + T0 57400.7367807004642730 1 0.00999271094974152688 + OM 346.60040313716600618 1 0.03110468777178034688 + OMDOT 0.0 + M2 0.18373369620702712 1 0.19097347492091507 + SINI 0.8630519453652643 1 0.14457246899831822 + A0 0.0 + B0 0.0 + GAMMA 0.0 + DR 0.0 + DTH 0.0 + TZRMJD 57390.6587742196275694 + TZRSITE arecibo + TZRFRQ 426.875 + """ + m = get_model(io.StringIO(s)) + t = pint.simulation.make_fake_toas_uniform( + 55731, 59051, 100, m, obs="axis", error=1 * u.us, add_noise=True + ) + f = pint.fitter.Fitter.auto(t, m) + f.fit_toas() From c34225cc6a9e8247d422074bc0466511a1222aa6 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Thu, 5 Sep 2024 09:18:38 -0500 Subject: [PATCH 050/195] CHANGELOG --- CHANGELOG-unreleased.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 92ef91fb9..694cb1475 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -33,6 +33,7 @@ the released changes. - SWX model now has SWXP_0001 frozen by default, and new segments should also have SWXP frozen - Can now properly use local files for ephemeris - Typos in `explanation.rst` regarding local ephemeris. +- DD/ELL1 models will check for valid SINI and raise exception if it strays, which will tell the fitter to try elsewhere ### Removed - Removed the argument `--usepickle` in `event_optimize` as the `load_events_weights` function checks the events file type to see if the file is a pickle file. From cc0d156e7fdeb24db89f12e7f2c262c90471251f Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Thu, 5 Sep 2024 10:49:56 -0500 Subject: [PATCH 051/195] test for any bad SINI - not sure if that is what is best? --- src/pint/models/stand_alone_psr_binaries/DD_model.py | 2 +- src/pint/models/stand_alone_psr_binaries/ELL1_model.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pint/models/stand_alone_psr_binaries/DD_model.py b/src/pint/models/stand_alone_psr_binaries/DD_model.py index be3886ee0..90aa84af5 100644 --- a/src/pint/models/stand_alone_psr_binaries/DD_model.py +++ b/src/pint/models/stand_alone_psr_binaries/DD_model.py @@ -711,7 +711,7 @@ def delayS(self): cOmega = np.cos(self.omega()) TM2 = self.M2.value * Tsun - if (self.SINI < 0) or (self.SINI > 1): + if np.any(self.SINI < 0) or np.any(self.SINI > 1): raise InvalidModelParameters("SINI parameter must be between 0 and 1") return ( diff --git a/src/pint/models/stand_alone_psr_binaries/ELL1_model.py b/src/pint/models/stand_alone_psr_binaries/ELL1_model.py index df9858e90..85ec55b47 100644 --- a/src/pint/models/stand_alone_psr_binaries/ELL1_model.py +++ b/src/pint/models/stand_alone_psr_binaries/ELL1_model.py @@ -601,7 +601,7 @@ def delayS(self): """ELL1 Shapiro delay. Lange et al 2001 eq. A16""" TM2 = self.TM2() Phi = self.Phi() - if (self.SINI < 0) or (self.SINI > 1): + if np.any(self.SINI < 0) or np.any(self.SINI > 1): raise InvalidModelParameters("SINI must be between 0 and 1") return -2 * TM2 * np.log(1 - self.SINI * np.sin(Phi)) From 73bf526dccb648ec9d056ac530909a798944863d Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Thu, 5 Sep 2024 12:14:12 -0500 Subject: [PATCH 052/195] change step for SINI derivative tests to avoid NaNs --- tests/test_model_derivatives.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_model_derivatives.py b/tests/test_model_derivatives.py index a3bcb28a4..868a41453 100644 --- a/tests/test_model_derivatives.py +++ b/tests/test_model_derivatives.py @@ -178,6 +178,9 @@ def f(value): stepgen = numdifftools.MaxStepGenerator( np.abs(model.FB3.value.astype(np.float64)) * 1e7 ) + elif param == "SINI": + sini = model.SINI.value + stepgen = numdifftools.MaxStepGenerator(abs(sini) / 2) else: stepgen = None df = numdifftools.Derivative(f, step=stepgen) From 4f8278ddac09a6dbf53535d45e1a830eded4bad8 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Thu, 5 Sep 2024 13:19:52 -0500 Subject: [PATCH 053/195] cast to float64 --- tests/test_model_derivatives.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_model_derivatives.py b/tests/test_model_derivatives.py index 868a41453..26b1933ce 100644 --- a/tests/test_model_derivatives.py +++ b/tests/test_model_derivatives.py @@ -179,7 +179,7 @@ def f(value): np.abs(model.FB3.value.astype(np.float64)) * 1e7 ) elif param == "SINI": - sini = model.SINI.value + sini = model.SINI.value.astype(np.float64) stepgen = numdifftools.MaxStepGenerator(abs(sini) / 2) else: stepgen = None From a722197ff41588ce785ea4145ec3830cccea03c3 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Thu, 5 Sep 2024 14:27:00 -0500 Subject: [PATCH 054/195] add a single test --- .github/workflows/ci_test.yml | 3 +++ tox.ini | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 65f603dba..b3dc75d67 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -53,6 +53,9 @@ jobs: # - os: ubuntu-latest # python: '3.8' # tox_env: 'codestyle' + - os: macos-12 + python: '3.12' + tox_env: 'py312-singletest' steps: - name: Check out repository diff --git a/tox.ini b/tox.ini index 87a498e01..df774e2c2 100644 --- a/tox.ini +++ b/tox.ini @@ -51,6 +51,27 @@ depends = report: py38,py39,py310,py312 docs: notebooks +[testenv:singletest] +# Make sure the astropy cache is shared with the user's usual. +# Also allow tests that pop up a window to work if possible +passenv = + HOME + DISPLAY + HYPOTHESIS_PROFILE + +deps = + pytest + cov: coverage + cov: pytest-cov + cov: pytest-remotedata + hypothesis + numdifftools + pathos + setuptools +commands = + pip freeze + pytest -v --pyargs tests test_model_derivatives.py {posargs} + [testenv:ephemeris_connection] description = Check whether PINT can obtain the DE440 ephemeris (usually from a server) From 3f8dc0e7d44a8f2dd9f735bbd8cc205f79081088 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Thu, 5 Sep 2024 14:30:01 -0500 Subject: [PATCH 055/195] fixing test calls --- tox.ini | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tox.ini b/tox.ini index df774e2c2..3c4454c2c 100644 --- a/tox.ini +++ b/tox.ini @@ -61,16 +61,13 @@ passenv = deps = pytest - cov: coverage - cov: pytest-cov - cov: pytest-remotedata hypothesis numdifftools pathos setuptools commands = pip freeze - pytest -v --pyargs tests test_model_derivatives.py {posargs} + pytest -v --pyargs tests/test_model_derivatives.py {posargs} [testenv:ephemeris_connection] description = From 4da91d4bc9c12208910e928e8bfdf73c049d1366 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Thu, 5 Sep 2024 14:34:33 -0500 Subject: [PATCH 056/195] fixing test calls --- tox.ini | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tox.ini b/tox.ini index 3c4454c2c..8378db960 100644 --- a/tox.ini +++ b/tox.ini @@ -58,16 +58,19 @@ passenv = HOME DISPLAY HYPOTHESIS_PROFILE - + deps = - pytest - hypothesis + numpy numdifftools - pathos + astropy + matplotlib + scipy + pytest + coverage + hypothesis<=6.72.0 setuptools -commands = - pip freeze - pytest -v --pyargs tests/test_model_derivatives.py {posargs} +commands = pytest -v tests/test_model_derivatives.py + [testenv:ephemeris_connection] description = From 1a69cc17ed042c78e69d9dcb3d8081a04df1c6c0 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Thu, 5 Sep 2024 18:42:08 -0500 Subject: [PATCH 057/195] more test updates --- .github/workflows/ci_test.yml | 2 +- tox.ini | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index b3dc75d67..1918c80ee 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -55,7 +55,7 @@ jobs: # tox_env: 'codestyle' - os: macos-12 python: '3.12' - tox_env: 'py312-singletest' + tox_env: 'singletest' steps: - name: Check out repository diff --git a/tox.ini b/tox.ini index 8378db960..037bf62af 100644 --- a/tox.ini +++ b/tox.ini @@ -13,6 +13,7 @@ envlist = report codestyle black + singletest py{38,39,310,311,312}-test{,-alldeps,-devdeps}{,-cov} skip_missing_interpreters = True From 6b662bf59a3a8d441e8d710764aab1a63d16def4 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Thu, 5 Sep 2024 18:48:27 -0500 Subject: [PATCH 058/195] updating tox.ini --- tox.ini | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/tox.ini b/tox.ini index 037bf62af..5b47a5214 100644 --- a/tox.ini +++ b/tox.ini @@ -53,13 +53,8 @@ depends = docs: notebooks [testenv:singletest] -# Make sure the astropy cache is shared with the user's usual. -# Also allow tests that pop up a window to work if possible -passenv = - HOME - DISPLAY - HYPOTHESIS_PROFILE - +description = + Try a simple run with a single test deps = numpy numdifftools @@ -70,7 +65,7 @@ deps = coverage hypothesis<=6.72.0 setuptools -commands = pytest -v tests/test_model_derivatives.py +commands = pytest tests/test_model_derivatives.py [testenv:ephemeris_connection] From 061875165d2079c5c8856a7c6dd2358036f25143 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Thu, 5 Sep 2024 19:05:58 -0500 Subject: [PATCH 059/195] trying to debug tests --- tests/test_model_derivatives.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/test_model_derivatives.py b/tests/test_model_derivatives.py index 26b1933ce..ee6b4c86c 100644 --- a/tests/test_model_derivatives.py +++ b/tests/test_model_derivatives.py @@ -180,11 +180,17 @@ def f(value): ) elif param == "SINI": sini = model.SINI.value.astype(np.float64) - stepgen = numdifftools.MaxStepGenerator(abs(sini) / 2) + print(sini.dtype) + stepgen = numdifftools.MaxStepGenerator(abs(sini) / 10) + print(stepgen) else: stepgen = None df = numdifftools.Derivative(f, step=stepgen) + if param == "SINI": + print(getattr(model, param).value.astype(np.float64).dtype) + print(f(getattr(model, param).value.astype(np.float64)).dtype) + a = model.d_phase_d_param(toas, delay=None, param=param).to_value(1 / units) b = df(getattr(model, param).value.astype(np.float64)) if param.startswith("FB"): From 3dcfb9dadb4993c41221c9d1c0230a87f774d613 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Fri, 6 Sep 2024 09:22:12 -0500 Subject: [PATCH 060/195] trying to fix test --- tests/test_model_derivatives.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_model_derivatives.py b/tests/test_model_derivatives.py index ee6b4c86c..2c897e27e 100644 --- a/tests/test_model_derivatives.py +++ b/tests/test_model_derivatives.py @@ -153,7 +153,7 @@ def f(value): try: dphase = m.phase(toas, abs_phase=False) - phase except ValueError: - return np.nan * np.zeros_like(phase.frac) + return np.nan * np.zeros_like(phase.frac).astype(np.float64) return np.float64(dphase.int + dphase.frac) if param == "ECC": From 113002858f2f360d3fe88fe24367962599413c0e Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Fri, 6 Sep 2024 09:32:56 -0500 Subject: [PATCH 061/195] test seems to be working --- .github/workflows/ci_test.yml | 8 +++++--- tests/test_model_derivatives.py | 6 ------ tox.ini | 1 + 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 1918c80ee..c3a8af4c5 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -53,9 +53,11 @@ jobs: # - os: ubuntu-latest # python: '3.8' # tox_env: 'codestyle' - - os: macos-12 - python: '3.12' - tox_env: 'singletest' +# uncomment this if needed to run a single test quickly +# can specify OS and python versions + # - os: macos-12 + # python: '3.12' + # tox_env: 'singletest' steps: - name: Check out repository diff --git a/tests/test_model_derivatives.py b/tests/test_model_derivatives.py index 2c897e27e..74737eb78 100644 --- a/tests/test_model_derivatives.py +++ b/tests/test_model_derivatives.py @@ -180,17 +180,11 @@ def f(value): ) elif param == "SINI": sini = model.SINI.value.astype(np.float64) - print(sini.dtype) stepgen = numdifftools.MaxStepGenerator(abs(sini) / 10) - print(stepgen) else: stepgen = None df = numdifftools.Derivative(f, step=stepgen) - if param == "SINI": - print(getattr(model, param).value.astype(np.float64).dtype) - print(f(getattr(model, param).value.astype(np.float64)).dtype) - a = model.d_phase_d_param(toas, delay=None, param=param).to_value(1 / units) b = df(getattr(model, param).value.astype(np.float64)) if param.startswith("FB"): diff --git a/tox.ini b/tox.ini index 5b47a5214..4b7f6b153 100644 --- a/tox.ini +++ b/tox.ini @@ -65,6 +65,7 @@ deps = coverage hypothesis<=6.72.0 setuptools +# can change this as needed for a single test run commands = pytest tests/test_model_derivatives.py From 725e879e6fcc19c6609ef17aee7dec051211ccb7 Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Tue, 10 Sep 2024 11:21:50 +0200 Subject: [PATCH 062/195] Make test_orbwaves.py pass the black test --- tests/test_orbwaves.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/test_orbwaves.py b/tests/test_orbwaves.py index 49f6c34fd..75d308b67 100644 --- a/tests/test_orbwaves.py +++ b/tests/test_orbwaves.py @@ -14,8 +14,8 @@ def test_orbwaves_fit(): m, t = get_model_and_toas( - datadir / "J1048+2339_orbwaves.par", - datadir / "J1048+2339_3PC_fake.tim") + datadir / "J1048+2339_orbwaves.par", datadir / "J1048+2339_3PC_fake.tim" + ) f = fitter.WLSFitter(toas=t, model=m) @@ -41,18 +41,13 @@ def _delete_line(labels): lines.append(line) return StringIO(lines) - deleted_lines = [ - ['ORBWAVEC0','ORBWAVES0'], - ['ORBWAVEC3'], - ['ORBWAVES4'] - ] + deleted_lines = [["ORBWAVEC0", "ORBWAVES0"], ["ORBWAVEC3"], ["ORBWAVES4"]] for lines in deleted_lines: with pytest.raises(Exception): m = get_model(_delete_line(lines)) - if __name__ == "__main__": test_orbwaves_fit() test_invalid_parfiles() From 592d1db13c5766d278b6e9c4fd926f38800c7204 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Thu, 12 Sep 2024 12:18:39 -0500 Subject: [PATCH 063/195] removed unneeded import --- src/pint/models/stand_alone_psr_binaries/DD_model.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pint/models/stand_alone_psr_binaries/DD_model.py b/src/pint/models/stand_alone_psr_binaries/DD_model.py index 90aa84af5..828e49610 100644 --- a/src/pint/models/stand_alone_psr_binaries/DD_model.py +++ b/src/pint/models/stand_alone_psr_binaries/DD_model.py @@ -1,6 +1,5 @@ """Damour and Deruelle binary model.""" -from multiprocessing import Value import astropy.constants as c import astropy.units as u import numpy as np From 9440965c1d579661701800dc834b904b2a55fa7b Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Fri, 13 Sep 2024 16:42:30 +0200 Subject: [PATCH 064/195] Adding ORBWAVEs to the changelog, and myself to the author list --- AUTHORS.rst | 1 + CHANGELOG-unreleased.md | 1 + 2 files changed, 2 insertions(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index 1e2ed1489..00342b0b2 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -23,6 +23,7 @@ Active developers are indicated by (*). Authors of the PINT paper are indicated * Bastian Beranek * Deven Bhakta (*) * Chloe Champagne (#) +* Colin Clark * Jonathan Colen (#) * H Thankful Cromartie * Christoph Deil diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 25f3d6283..4cff70ee9 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -23,6 +23,7 @@ the released changes. - Fourier series representation of chromatic noise (`CMWaveX`) - `pint.utils.cmwavex_setup` and `pint.utils.plchromnoise_from_cmwavex` functions - More validation for correlated noise components in `TimingModel.validate_component_types()` +- ORBWAVEs model for modelling binary orbital period variations in the fourier domain ### Fixed - Bug in `DMWaveX.get_indices()` function - Explicit type conversion in `woodbury_dot()` function From ff87d668df8d77513407eeab44d9fc3165ae71ca Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Fri, 13 Sep 2024 16:50:54 +0200 Subject: [PATCH 065/195] Adding a test for ORBWAVEs with the DD model --- tests/datafile/J1048+2339_orbwaves_DD.par | 48 +++++++++++++++++++++++ tests/test_orbwaves.py | 17 ++++++++ 2 files changed, 65 insertions(+) create mode 100644 tests/datafile/J1048+2339_orbwaves_DD.par diff --git a/tests/datafile/J1048+2339_orbwaves_DD.par b/tests/datafile/J1048+2339_orbwaves_DD.par new file mode 100644 index 000000000..acbc3dd11 --- /dev/null +++ b/tests/datafile/J1048+2339_orbwaves_DD.par @@ -0,0 +1,48 @@ +PSR J1048+2339 +RAJ 10:48:43.41835421 1 0.00007631 +DECJ 23:39:53.4043452 1 0.0020013 +PMRA -18.7000 +PMDEC -9.4000 +POSEPOCH 56700.0000 +F0 214.3547853411294852 1 0.0000000000170721 +F1 -1.381753144359e-15 1 1.531201039458e-18 +PEPOCH 57285.000000 +START 56508.798 +FINISH 57548.936 +#DM 16.654332 +DMEPOCH 56700.0000 +SOLARN0 10.00 +EPHEM DE421 +CLK TT(BIPM2021) +UNITS TDB +TIMEEPH FB90 +T2CMETHOD IAU2000B +CORRECT_TROPOSPHERE N +PLANET_SHAPIRO N +DILATEFREQ N +NTOA 104 +TRES 8.84 +TZRMJD 57285.65854990785506 +TZRFRQ 326.988 +TZRSITE 3 +NITS 1 +BINARY DD +A1 0.836120368 1 0.000003165 +E 0 +OM 0 +# ATNF DM info (from drc+16): +DM 16.6544 0.0001 +ORBWAVE_OM 3.495788643739122e-08 +ORBWAVE_EPOCH 57028.867 +T0 56637.61958641038 1 +PB 0.250506696660119 1 +ORBWAVEC0 0.01359122306797746 1 +ORBWAVES0 -0.1138721359160273 1 +ORBWAVEC1 -0.009093465738757574 1 +ORBWAVES1 0.03712548529066605 1 +ORBWAVEC2 0.00414066930830874 1 +ORBWAVES2 -0.011358879259751396 1 +ORBWAVEC3 -0.001400204000025873 1 +ORBWAVES3 0.002749601047126059 1 +ORBWAVEC4 0.00019385501703957642 1 +ORBWAVES4 -0.00028698933945954427 1 \ No newline at end of file diff --git a/tests/test_orbwaves.py b/tests/test_orbwaves.py index 75d308b67..06ce0141d 100644 --- a/tests/test_orbwaves.py +++ b/tests/test_orbwaves.py @@ -29,6 +29,23 @@ def test_orbwaves_fit(): assert rms > 21.1 and rms < 21.2 +def test_orbwaves_DD_fit(): + m, t = get_model_and_toas( + datadir / "J1048+2339_orbwaves_DD.par", datadir / "J1048+2339_3PC_fake.tim" + ) + + f = fitter.WLSFitter(toas=t, model=m) + + rms = f.resids.rms_weighted().to_value("us") + + assert rms > 29.2 and rms < 29.3 + + f.fit_toas() + rms = f.resids.rms_weighted().to_value("us") + + assert rms > 21.1 and rms < 21.2 + + def test_invalid_parfiles(): parlines = open(datadir / "J1048+2339_orbwaves.par").readlines() From 50a9ee9c3be0fe0e490b4f2e90a1c4909078f8ed Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Mon, 16 Sep 2024 16:58:44 +0200 Subject: [PATCH 066/195] Added docstring for ORBWAVEs model --- src/pint/models/pulsar_binary.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/pint/models/pulsar_binary.py b/src/pint/models/pulsar_binary.py index e55f8084a..177108e35 100644 --- a/src/pint/models/pulsar_binary.py +++ b/src/pint/models/pulsar_binary.py @@ -63,6 +63,18 @@ class PulsarBinary(DelayComponent): - FB0 - orbital frequency (1/s, alternative to PB, non-negative) - FBn - time derivatives of orbital frequency (1/s**(n+1)) + The following ORBWAVEs parameters define a Fourier series model for orbital phase + variations, as an alternative to the FBn Taylor series expansion: + + - ORBWAVE_OM - base angular frequency for ORBWAVEs expansion (rad / s) + - ORBWAVE_EPOCH - reference epoch for ORBWAVEs model (MJD) + - ORBWAVECn/ORBWAVESn - coefficients for cosine/sine components (dimensionless) + + The orbital phase is then given by: + orbits(t) = (t - T0) / PB + + \sum_{n=0} (ORBWAVECn cos(ORBWAVE_OM * (n + 1) * (t - ORBWAVE_EPOCH)) + + ORBWAVESn sin(ORBWAVE_OM * (n + 1) * (t - ORBWAVE_EPOCH)) + The internal calculation code uses different names for some parameters: - Eccentric Anomaly: E (not parameter ECC) From e654e5f34e82f58e0fb398581a56206e7a20cf97 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Thu, 26 Sep 2024 19:25:41 +0200 Subject: [PATCH 067/195] Update README.rst --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 76085fe66..75b7862a1 100644 --- a/README.rst +++ b/README.rst @@ -127,6 +127,7 @@ email pint@nanograv.org or one of the people below: * Scott Ransom (sransom@nrao.edu) * Paul Ray (paul.s.ray3.civ@us.navy.mil) * David Kaplan (kaplan@uwm.edu) +* Abhimanyu Susobhanan (abhimanyu.susobhanan@nanograv.org) Want to do something new? Submit a github `issue `_. From a30e8c2d0353db7fa2ebe4893bf126157052e82f Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Fri, 27 Sep 2024 11:54:27 -0500 Subject: [PATCH 068/195] moved exceptions --- src/pint/fitter.py | 37 ++------- src/pint/models/absolute_phase.py | 3 +- src/pint/models/astrometry.py | 3 +- src/pint/models/binary_bt.py | 2 +- src/pint/models/binary_ddk.py | 2 +- src/pint/models/binary_ell1.py | 2 +- src/pint/models/chromatic_model.py | 3 +- src/pint/models/cmwavex.py | 2 +- src/pint/models/dispersion_model.py | 3 +- src/pint/models/dmwavex.py | 2 +- src/pint/models/frequency_dependent.py | 3 +- src/pint/models/glitch.py | 3 +- src/pint/models/ifunc.py | 3 +- src/pint/models/model_builder.py | 17 ++--- src/pint/models/parameter.py | 6 +- src/pint/models/piecewise.py | 3 +- src/pint/models/pulsar_binary.py | 4 +- src/pint/models/spindown.py | 3 +- src/pint/models/timing_model.py | 102 +++---------------------- src/pint/models/wave.py | 3 +- src/pint/models/wavex.py | 3 +- src/pint/observatory/__init__.py | 23 ++---- src/pint/utils.py | 10 +-- tests/test_clockcorr.py | 2 +- tests/test_process_parfile.py | 3 +- tests/test_variety_parfiles.py | 2 +- 26 files changed, 65 insertions(+), 184 deletions(-) diff --git a/src/pint/fitter.py b/src/pint/fitter.py index 11bd1289e..b187fad65 100644 --- a/src/pint/fitter.py +++ b/src/pint/fitter.py @@ -90,6 +90,13 @@ from pint.residuals import Residuals, WidebandTOAResiduals from pint.toa import TOAs from pint.utils import FTest, normalize_designmatrix +from pint.exceptions import ( + DegeneracyWarning, + ConvergenceFailure, + MaxiterReached, + StepProblem, + CorrelatedErrors, +) __all__ = [ @@ -167,22 +174,6 @@ def __get__(self, instance, owner=None): return val -class DegeneracyWarning(UserWarning): - pass - - -class ConvergenceFailure(ValueError): - pass - - -class MaxiterReached(ConvergenceFailure): - pass - - -class StepProblem(ConvergenceFailure): - pass - - class Fitter: """Base class for objects encapsulating fitting problems. @@ -888,20 +879,6 @@ def covariance_matrix(self): return self.parameter_covariance_matrix -class CorrelatedErrors(ValueError): - def __init__(self, model): - trouble_components = [ - c.__class__.__name__ - for c in model.NoiseComponent_list - if c.introduces_correlated_errors - ] - super().__init__( - f"Model has correlated errors and requires a GLS-based fitter; " - f"remove {trouble_components} if you want to use WLS" - ) - self.trouble_components = trouble_components - - class ModelState: """Record a model state and cache calculations diff --git a/src/pint/models/absolute_phase.py b/src/pint/models/absolute_phase.py index 7228c255c..fa1acb741 100644 --- a/src/pint/models/absolute_phase.py +++ b/src/pint/models/absolute_phase.py @@ -5,7 +5,8 @@ import pint.toa as toa from pint.models.parameter import MJDParameter, floatParameter, strParameter -from pint.models.timing_model import MissingParameter, PhaseComponent +from pint.models.timing_model import PhaseComponent +from pint.exceptions import MissingParameter class AbsPhase(PhaseComponent): diff --git a/src/pint/models/astrometry.py b/src/pint/models/astrometry.py index 1ac7e4a90..2f1d4feee 100644 --- a/src/pint/models/astrometry.py +++ b/src/pint/models/astrometry.py @@ -24,9 +24,10 @@ strParameter, ) import pint.toa -from pint.models.timing_model import DelayComponent, MissingParameter +from pint.models.timing_model import DelayComponent from pint.pulsar_ecliptic import OBL, PulsarEcliptic from pint.utils import add_dummy_distance, remove_dummy_distance +from pint.exceptions import MissingParameter astropy_version = sys.modules["astropy"].__version__ mas_yr = u.mas / u.yr diff --git a/src/pint/models/binary_bt.py b/src/pint/models/binary_bt.py index 8c4969c2d..8c54e93da 100644 --- a/src/pint/models/binary_bt.py +++ b/src/pint/models/binary_bt.py @@ -5,7 +5,7 @@ from pint.models.pulsar_binary import PulsarBinary from pint.models.stand_alone_psr_binaries.BT_model import BTmodel from pint.models.stand_alone_psr_binaries.BT_piecewise import BTpiecewise -from pint.models.timing_model import MissingParameter +from pint.exceptions import MissingParameter import astropy.units as u import astropy.constants as consts from pint import ls diff --git a/src/pint/models/binary_ddk.py b/src/pint/models/binary_ddk.py index 37e31856c..9d83403a1 100644 --- a/src/pint/models/binary_ddk.py +++ b/src/pint/models/binary_ddk.py @@ -8,7 +8,7 @@ from pint.models.binary_dd import BinaryDD from pint.models.parameter import boolParameter, floatParameter, funcParameter from pint.models.stand_alone_psr_binaries.DDK_model import DDKmodel -from pint.models.timing_model import MissingParameter, TimingModelError +from pint.exceptions import MissingParameter, TimingModelError def _convert_kin(kin): diff --git a/src/pint/models/binary_ell1.py b/src/pint/models/binary_ell1.py index a34b3c186..bec23f0b3 100644 --- a/src/pint/models/binary_ell1.py +++ b/src/pint/models/binary_ell1.py @@ -17,7 +17,7 @@ from pint.models.stand_alone_psr_binaries.ELL1_model import ELL1model from pint.models.stand_alone_psr_binaries.ELL1H_model import ELL1Hmodel from pint.models.stand_alone_psr_binaries.ELL1k_model import ELL1kmodel -from pint.models.timing_model import MissingParameter +from pint.exceptions import MissingParameter from pint.utils import taylor_horner_deriv from pint import Tsun diff --git a/src/pint/models/chromatic_model.py b/src/pint/models/chromatic_model.py index 49a5c152a..e64b8f421 100644 --- a/src/pint/models/chromatic_model.py +++ b/src/pint/models/chromatic_model.py @@ -2,10 +2,11 @@ from warnings import warn import numpy as np import astropy.units as u -from pint.models.timing_model import DelayComponent, MissingParameter +from pint.models.timing_model import DelayComponent from pint.models.parameter import floatParameter, prefixParameter, MJDParameter from pint.utils import split_prefixed_name, taylor_horner, taylor_horner_deriv from pint import DMconst +from pint.exceptions import MissingParameter from astropy.time import Time cmu = u.pc / u.cm**3 / u.MHz**2 diff --git a/src/pint/models/cmwavex.py b/src/pint/models/cmwavex.py index 465700565..bd1ebca9a 100644 --- a/src/pint/models/cmwavex.py +++ b/src/pint/models/cmwavex.py @@ -6,7 +6,7 @@ from warnings import warn from pint.models.parameter import MJDParameter, prefixParameter -from pint.models.timing_model import MissingParameter +from pint.exceptions import MissingParameter from pint.models.chromatic_model import Chromatic, cmu from pint import DMconst diff --git a/src/pint/models/dispersion_model.py b/src/pint/models/dispersion_model.py index e5317b06c..368392dd9 100644 --- a/src/pint/models/dispersion_model.py +++ b/src/pint/models/dispersion_model.py @@ -14,7 +14,7 @@ prefixParameter, maskParameter, ) -from pint.models.timing_model import DelayComponent, MissingParameter, MissingTOAs +from pint.models.timing_model import DelayComponent from pint.toa_select import TOASelect from pint.utils import ( split_prefixed_name, @@ -22,6 +22,7 @@ taylor_horner_deriv, ) from pint import DMconst +from pint.exceptions import MissingParameter, MissingTOAs # This value is cited from Duncan Lorimer, Michael Kramer, Handbook of Pulsar # Astronomy, Second edition, Page 86, Note 1 diff --git a/src/pint/models/dmwavex.py b/src/pint/models/dmwavex.py index 368862391..9d3fa614f 100644 --- a/src/pint/models/dmwavex.py +++ b/src/pint/models/dmwavex.py @@ -6,7 +6,7 @@ from warnings import warn from pint.models.parameter import MJDParameter, prefixParameter -from pint.models.timing_model import MissingParameter +from pint.exceptions import MissingParameter from pint.models.dispersion_model import Dispersion from pint import DMconst, dmu diff --git a/src/pint/models/frequency_dependent.py b/src/pint/models/frequency_dependent.py index 2215b5c08..a5d37b7a8 100644 --- a/src/pint/models/frequency_dependent.py +++ b/src/pint/models/frequency_dependent.py @@ -6,7 +6,8 @@ import numpy as np from pint.models.parameter import prefixParameter -from pint.models.timing_model import DelayComponent, MissingParameter +from pint.models.timing_model import DelayComponent +from pint.exceptions import MissingParameter class FD(DelayComponent): diff --git a/src/pint/models/glitch.py b/src/pint/models/glitch.py index f198a27c2..2aaf4f8e4 100644 --- a/src/pint/models/glitch.py +++ b/src/pint/models/glitch.py @@ -6,8 +6,9 @@ from loguru import logger as log from pint.models.parameter import prefixParameter -from pint.models.timing_model import MissingParameter, PhaseComponent +from pint.models.timing_model import PhaseComponent from pint.utils import split_prefixed_name +from pint.exceptions import MissingParameter class Glitch(PhaseComponent): diff --git a/src/pint/models/ifunc.py b/src/pint/models/ifunc.py index 323380ac3..465dd2c87 100644 --- a/src/pint/models/ifunc.py +++ b/src/pint/models/ifunc.py @@ -4,7 +4,8 @@ import numpy as np from pint.models.parameter import floatParameter, prefixParameter -from pint.models.timing_model import PhaseComponent, MissingParameter +from pint.models.timing_model import PhaseComponent +from pint.exceptions import MissingParameter class IFunc(PhaseComponent): diff --git a/src/pint/models/model_builder.py b/src/pint/models/model_builder.py index 088989967..560b0ab2c 100644 --- a/src/pint/models/model_builder.py +++ b/src/pint/models/model_builder.py @@ -15,16 +15,11 @@ AllComponents, TimingModel, ignore_prefix, - UnknownBinaryModel, - UnknownParameter, - TimingModelError, - MissingBinaryError, ignore_params, ignore_prefix, ) from pint.toa import TOAs, get_TOAs from pint.utils import ( - PrefixError, interesting_lines, lines_of, split_prefixed_name, @@ -33,6 +28,14 @@ from pint.models.tcb_conversion import convert_tcb_tdb from pint.models.binary_ddk import _convert_kin, _convert_kom from pint.types import file_like, quantity_like +from pint.exceptions import ( + PrefixError, + ComponentConflict, + UnknownParameter, + UnknownBinaryModel, + TimingModelError, + MissingBinaryError, +) __all__ = ["ModelBuilder", "get_model", "get_model_and_toas"] @@ -52,10 +55,6 @@ ] -class ComponentConflict(ValueError): - """Error for multiple components can be select but no other indications.""" - - def parse_parfile(parfile): """Function for parsing .par file or .par style StringIO. diff --git a/src/pint/models/parameter.py b/src/pint/models/parameter.py index 0a9a7dce7..ea92f4611 100644 --- a/src/pint/models/parameter.py +++ b/src/pint/models/parameter.py @@ -48,17 +48,13 @@ ) from pint.toa_select import TOASelect from pint.utils import split_prefixed_name - +from pint.exceptions import InvalidModelParameters # potential parfile formats # in one place for consistency _parfile_formats = ["pint", "tempo", "tempo2"] -class InvalidModelParameters(ValueError): - pass - - def _identity_function(x): """A function to just return the input argument diff --git a/src/pint/models/piecewise.py b/src/pint/models/piecewise.py index 9b9fdd8b3..93c05487a 100644 --- a/src/pint/models/piecewise.py +++ b/src/pint/models/piecewise.py @@ -4,8 +4,9 @@ import numpy as np from pint.models.parameter import prefixParameter -from pint.models.timing_model import MissingParameter, PhaseComponent +from pint.models.timing_model import PhaseComponent from pint.utils import split_prefixed_name, taylor_horner +from pint.exceptions import MissingParameter class PiecewiseSpindown(PhaseComponent): diff --git a/src/pint/models/pulsar_binary.py b/src/pint/models/pulsar_binary.py index 177108e35..26d77bda2 100644 --- a/src/pint/models/pulsar_binary.py +++ b/src/pint/models/pulsar_binary.py @@ -21,12 +21,10 @@ from pint.models.stand_alone_psr_binaries import binary_orbits as bo from pint.models.timing_model import ( DelayComponent, - MissingParameter, - TimingModelError, - UnknownParameter, ) from pint.utils import taylor_horner_deriv, parse_time from pint.pulsar_ecliptic import PulsarEcliptic +from pint.exceptions import MissingParameter, TimingModelError, UnknownParameter # def _p_to_f(p): diff --git a/src/pint/models/spindown.py b/src/pint/models/spindown.py index 8a8bce411..0bc42f996 100644 --- a/src/pint/models/spindown.py +++ b/src/pint/models/spindown.py @@ -6,9 +6,10 @@ import numpy from pint.models.parameter import MJDParameter, prefixParameter -from pint.models.timing_model import MissingParameter, PhaseComponent +from pint.models.timing_model import PhaseComponent from pint.pulsar_mjd import Time from pint.utils import split_prefixed_name, taylor_horner, taylor_horner_deriv +from pint.exceptions import MissingParameter class SpindownBase(PhaseComponent): diff --git a/src/pint/models/timing_model.py b/src/pint/models/timing_model.py index 3c8fd217e..a0b27b090 100644 --- a/src/pint/models/timing_model.py +++ b/src/pint/models/timing_model.py @@ -62,13 +62,23 @@ from pint.phase import Phase from pint.toa import TOAs from pint.utils import ( - PrefixError, split_prefixed_name, open_or_use, colorize, xxxselections, ) from pint.derived_quantities import dispersion_slope +from pint.exceptions import ( + PrefixError, + MissingTOAs, + PropertyAttributeError, + TimingModelError, + MissingParameter, + AliasConflict, + UnknownParameter, + UnknownBinaryModel, + MissingBinaryError, +) __all__ = [ @@ -76,11 +86,6 @@ "TimingModel", "Component", "AllComponents", - "TimingModelError", - "MissingParameter", - "MissingTOAs", - "MissingBinaryError", - "UnknownBinaryModel", ] # Parameters or lines in par files we don't understand but shouldn't # complain about. These are still passed to components so that they @@ -123,26 +128,6 @@ ] -class MissingTOAs(ValueError): - """Some parameter does not describe any TOAs.""" - - def __init__(self, parameter_names): - if isinstance(parameter_names, str): - parameter_names = [parameter_names] - if len(parameter_names) == 1: - msg = f"Parameter {parameter_names[0]} does not correspond to any TOAs: you might need to run `model.find_empty_masks(toas, freeze=True)`" - elif len(parameter_names) > 1: - msg = f"Parameters {' '.join(parameter_names)} do not correspond to any TOAs: you might need to run `model.find_empty_masks(toas, freeze=True)`" - else: - raise ValueError("Incorrect attempt to construct MissingTOAs") - super().__init__(msg) - self.parameter_names = parameter_names - - -class PropertyAttributeError(ValueError): - pass - - def property_exists(f): """Mark a function as a property but handle AttributeErrors. @@ -4023,68 +4008,3 @@ def param_to_unit(self, name): if getattr(self.components[component], firstname).unit_template is None: return self._param_unit_map[firstname] return u.Unit(getattr(self.components[component], firstname).unit_template(idx)) - - -class TimingModelError(ValueError): - """Generic base class for timing model errors.""" - - pass - - -class MissingParameter(TimingModelError): - """A required model parameter was not included. - - Parameters - ---------- - module - name of the model class that raised the error - param - name of the missing parameter - msg - additional message - - """ - - def __init__(self, module, param, msg=None): - super().__init__(msg) - self.module = module - self.param = param - self.msg = msg - - def __str__(self): - result = f"{self.module}.{self.param}" - if self.msg is not None: - result += "\n " + self.msg - return result - - -class AliasConflict(TimingModelError): - """If the same alias is used for different parameters.""" - - pass - - -class UnknownParameter(TimingModelError): - """Signal that a parameter name does not match any PINT parameters and their aliases.""" - - pass - - -class UnknownBinaryModel(TimingModelError): - """Signal that the par file requested a binary model not in PINT.""" - - def __init__(self, message, suggestion=None): - super().__init__(message) - self.suggestion = suggestion - - def __str__(self): - base_message = super().__str__() - if self.suggestion: - return f"{base_message} Perhaps use {self.suggestion}?" - return base_message - - -class MissingBinaryError(TimingModelError): - """Error for missing BINARY parameter.""" - - pass diff --git a/src/pint/models/wave.py b/src/pint/models/wave.py index 0a7cb1dfc..8a902a5ca 100644 --- a/src/pint/models/wave.py +++ b/src/pint/models/wave.py @@ -4,7 +4,8 @@ import numpy as np from pint.models.parameter import MJDParameter, floatParameter, prefixParameter -from pint.models.timing_model import PhaseComponent, MissingParameter +from pint.models.timing_model import PhaseComponent +from pint.exceptions import MissingParameter class Wave(PhaseComponent): diff --git a/src/pint/models/wavex.py b/src/pint/models/wavex.py index 1714f3644..f1dd24a60 100644 --- a/src/pint/models/wavex.py +++ b/src/pint/models/wavex.py @@ -6,7 +6,8 @@ from warnings import warn from pint.models.parameter import MJDParameter, prefixParameter -from pint.models.timing_model import DelayComponent, MissingParameter +from pint.models.timing_model import DelayComponent +from pint.exceptions import MissingParameter class WaveX(DelayComponent): diff --git a/src/pint/observatory/__init__.py b/src/pint/observatory/__init__.py index 8d98e28d7..6f9c3fbcb 100644 --- a/src/pint/observatory/__init__.py +++ b/src/pint/observatory/__init__.py @@ -37,6 +37,11 @@ from pint.config import runtimefile from pint.pulsar_mjd import Time from pint.utils import interesting_lines +from pint.exceptions import ( + ClockCorrectionError, + NoClockCorrections, + ClockCorrectionOutOfRange, +) # Include any files that define observatories here. This will start # with the standard distribution files, then will read any system- or @@ -93,24 +98,6 @@ def find_latest_bipm(): pint_clock_env_var = "PINT_CLOCK_OVERRIDE" -class ClockCorrectionError(RuntimeError): - """Unspecified error doing clock correction.""" - - pass - - -class NoClockCorrections(ClockCorrectionError): - """Clock corrections are expected but none are available.""" - - pass - - -class ClockCorrectionOutOfRange(ClockCorrectionError): - """Clock corrections are available but the requested time is not covered.""" - - pass - - # Global clock files shared by all observatories _gps_clock = None _bipm_clock_versions = {} diff --git a/src/pint/utils.py b/src/pint/utils.py index 758307558..da23092fc 100644 --- a/src/pint/utils.py +++ b/src/pint/utils.py @@ -75,9 +75,9 @@ import pint.pulsar_ecliptic from pint.toa_select import TOASelect from pint.types import file_like, quantity_like +from pint.exceptions import PINTPrecisionError, PrefixError __all__ = [ - "PINTPrecisionError", "check_longdouble_precision", "require_longdouble_precision", "PosVel", @@ -154,10 +154,6 @@ # Actual exported tools -class PINTPrecisionError(RuntimeError): - pass - - # A warning is emitted in pint.pulsar_mjd if sufficient precision is not available @@ -365,10 +361,6 @@ def has_astropy_unit(x: Any) -> bool: ] -class PrefixError(ValueError): - pass - - def split_prefixed_name(name: str) -> Tuple[str, str, int]: """Split a prefixed name. diff --git a/tests/test_clockcorr.py b/tests/test_clockcorr.py index a3871cd0d..b232676c4 100644 --- a/tests/test_clockcorr.py +++ b/tests/test_clockcorr.py @@ -13,8 +13,8 @@ from pint.observatory import ( Observatory, get_observatory, - ClockCorrectionOutOfRange, ) +from pint.exceptions import ClockCorrectionOutOfRange from pint.observatory.clock_file import ClockFile from pint.toa import get_TOAs diff --git a/tests/test_process_parfile.py b/tests/test_process_parfile.py index daaa23d20..da3dbf9e7 100644 --- a/tests/test_process_parfile.py +++ b/tests/test_process_parfile.py @@ -4,9 +4,10 @@ import pytest from io import StringIO -from pint.models.model_builder import ModelBuilder, parse_parfile, TimingModelError +from pint.models.model_builder import ModelBuilder, parse_parfile from pint.models.model_builder import guess_binary_model +from pint.exceptions import TimingModelError from pint.models import get_model base_par = """ diff --git a/tests/test_variety_parfiles.py b/tests/test_variety_parfiles.py index c137d59a1..bac88e9ac 100644 --- a/tests/test_variety_parfiles.py +++ b/tests/test_variety_parfiles.py @@ -3,7 +3,7 @@ import pytest from io import StringIO -from pint.models.timing_model import ( +from pint.exceptions import ( TimingModelError, UnknownBinaryModel, MissingBinaryError, From ebd46d2f371b4bc9d751cdd5b6e8c7856d816cbe Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Fri, 27 Sep 2024 11:57:45 -0500 Subject: [PATCH 069/195] forgot new file --- src/pint/exceptions.py | 162 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 src/pint/exceptions.py diff --git a/src/pint/exceptions.py b/src/pint/exceptions.py new file mode 100644 index 000000000..610459bea --- /dev/null +++ b/src/pint/exceptions.py @@ -0,0 +1,162 @@ +__all__ = [ + "TimingModelError", + "MissingParameter", + "MissingTOAs", + "MissingBinaryError", + "UnknownBinaryModel", +] + + +# originally from fitter.py +class DegeneracyWarning(UserWarning): + pass + + +class ConvergenceFailure(ValueError): + pass + + +class MaxiterReached(ConvergenceFailure): + pass + + +class StepProblem(ConvergenceFailure): + pass + + +class CorrelatedErrors(ValueError): + def __init__(self, model): + trouble_components = [ + c.__class__.__name__ + for c in model.NoiseComponent_list + if c.introduces_correlated_errors + ] + super().__init__( + f"Model has correlated errors and requires a GLS-based fitter; " + f"remove {trouble_components} if you want to use WLS" + ) + self.trouble_components = trouble_components + + +# from timing_model.py +class MissingTOAs(ValueError): + """Some parameter does not describe any TOAs.""" + + def __init__(self, parameter_names): + if isinstance(parameter_names, str): + parameter_names = [parameter_names] + if len(parameter_names) == 1: + msg = f"Parameter {parameter_names[0]} does not correspond to any TOAs: you might need to run `model.find_empty_masks(toas, freeze=True)`" + elif len(parameter_names) > 1: + msg = f"Parameters {' '.join(parameter_names)} do not correspond to any TOAs: you might need to run `model.find_empty_masks(toas, freeze=True)`" + else: + raise ValueError("Incorrect attempt to construct MissingTOAs") + super().__init__(msg) + self.parameter_names = parameter_names + + +class PropertyAttributeError(ValueError): + pass + + +class TimingModelError(ValueError): + """Generic base class for timing model errors.""" + + pass + + +class MissingParameter(TimingModelError): + """A required model parameter was not included. + + Parameters + ---------- + module + name of the model class that raised the error + param + name of the missing parameter + msg + additional message + + """ + + def __init__(self, module, param, msg=None): + super().__init__(msg) + self.module = module + self.param = param + self.msg = msg + + def __str__(self): + result = f"{self.module}.{self.param}" + if self.msg is not None: + result += "\n " + self.msg + return result + + +class AliasConflict(TimingModelError): + """If the same alias is used for different parameters.""" + + pass + + +class UnknownParameter(TimingModelError): + """Signal that a parameter name does not match any PINT parameters and their aliases.""" + + pass + + +class UnknownBinaryModel(TimingModelError): + """Signal that the par file requested a binary model not in PINT.""" + + def __init__(self, message, suggestion=None): + super().__init__(message) + self.suggestion = suggestion + + def __str__(self): + base_message = super().__str__() + if self.suggestion: + return f"{base_message} Perhaps use {self.suggestion}?" + return base_message + + +class MissingBinaryError(TimingModelError): + """Error for missing BINARY parameter.""" + + pass + + +# from utils.py +class PINTPrecisionError(RuntimeError): + pass + + +class PrefixError(ValueError): + pass + + +# from models.parameter.py +class InvalidModelParameters(ValueError): + pass + + +# models.model_builder.py +class ComponentConflict(ValueError): + """Error for multiple components can be select but no other indications.""" + + +# observatories.__init__.py +class ClockCorrectionError(RuntimeError): + """Unspecified error doing clock correction.""" + + pass + + +class NoClockCorrections(ClockCorrectionError): + """Clock corrections are expected but none are available.""" + + pass + + +class ClockCorrectionOutOfRange(ClockCorrectionError): + """Clock corrections are available but the requested time is not covered.""" + + pass From e4740940fd2c2bb839c36b9cee9c47ea13de57b4 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Mon, 7 Oct 2024 10:55:52 +0200 Subject: [PATCH 070/195] compare_parfiles --- src/pint/scripts/compare_parfiles.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pint/scripts/compare_parfiles.py b/src/pint/scripts/compare_parfiles.py index 0c4ca5da2..87eb005a0 100644 --- a/src/pint/scripts/compare_parfiles.py +++ b/src/pint/scripts/compare_parfiles.py @@ -89,8 +89,9 @@ def main(argv=None): level=pint.logging.get_level(args.loglevel, args.verbosity, args.quiet) ) - m1 = get_model(args.input1) - m2 = get_model(args.input2) + m1 = get_model(args.input1, allow_T2=True, allow_tcb=True) + m2 = get_model(args.input2, allow_T2=True, allow_tcb=True) + print( m1.compare( m2, From 5f7bc2dd431a0209bc29d41fc5f238f9cda11d5d Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Mon, 7 Oct 2024 10:56:50 +0200 Subject: [PATCH 071/195] convert_parfile --- src/pint/scripts/convert_parfile.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pint/scripts/convert_parfile.py b/src/pint/scripts/convert_parfile.py index 55b45415b..0612a46a8 100644 --- a/src/pint/scripts/convert_parfile.py +++ b/src/pint/scripts/convert_parfile.py @@ -83,7 +83,9 @@ def main(argv=None): return log.info(f"Reading '{args.input}'") - model = get_model(args.input) + + model = get_model(args.input, allow_T2=True, allow_tcb=True) + if hasattr(model, "BINARY") and args.binary is not None: log.info(f"Converting from {model.BINARY.value} to {args.binary}") if args.binary == "ELL1H": From f2abeb723c588d6d00333ed8430b541d78295359 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Mon, 7 Oct 2024 11:01:53 +0200 Subject: [PATCH 072/195] scripts --- src/pint/pintk/pulsar.py | 8 ++++++-- src/pint/scripts/event_optimize.py | 2 +- src/pint/scripts/event_optimize_MCMCFitter.py | 2 +- src/pint/scripts/event_optimize_multiple.py | 2 +- src/pint/scripts/fermiphase.py | 3 ++- src/pint/scripts/photonphase.py | 3 ++- src/pint/scripts/pintbary.py | 2 +- src/pint/scripts/pintempo.py | 2 +- src/pint/scripts/pintpublish.py | 2 +- src/pint/scripts/tcb2tdb.py | 2 +- src/pint/scripts/zima.py | 2 +- 11 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/pint/pintk/pulsar.py b/src/pint/pintk/pulsar.py index 65d8048df..ce6aa8560 100644 --- a/src/pint/pintk/pulsar.py +++ b/src/pint/pintk/pulsar.py @@ -151,7 +151,9 @@ def __contains__(self, key): return key in self.prefit_model.params def reset_model(self): - self.prefit_model = pint.models.get_model(self.parfile) + self.prefit_model = pint.models.get_model( + self.parfile, allow_T2=True, allow_tcb=True + ) self.add_model_params() self.postfit_model = None self.postfit_resids = None @@ -172,7 +174,9 @@ def reset_TOAs(self): self.update_resids() def resetAll(self): - self.prefit_model = pint.models.get_model(self.parfile) + self.prefit_model = pint.models.get_model( + self.parfile, allow_T2=True, allow_tcb=True + ) self.postfit_model = None self.postfit_resids = None self.fitted = False diff --git a/src/pint/scripts/event_optimize.py b/src/pint/scripts/event_optimize.py index e4c9dd4ff..b79fb1c20 100755 --- a/src/pint/scripts/event_optimize.py +++ b/src/pint/scripts/event_optimize.py @@ -719,7 +719,7 @@ def main(argv=None): ncores = args.ncores # Read in initial model - modelin = pint.models.get_model(parfile) + modelin = pint.models.get_model(parfile, allow_T2=True, allow_tcb=True) # File name setup and clobber file check filepath = args.filepath or os.getcwd() diff --git a/src/pint/scripts/event_optimize_MCMCFitter.py b/src/pint/scripts/event_optimize_MCMCFitter.py index bbab8ccee..43bc89858 100755 --- a/src/pint/scripts/event_optimize_MCMCFitter.py +++ b/src/pint/scripts/event_optimize_MCMCFitter.py @@ -164,7 +164,7 @@ def main(argv=None): wgtexp = args.wgtexp # Read in initial model - modelin = pint.models.get_model(parfile) + modelin = pint.models.get_model(parfile, allow_T2=True, allow_tcb=True) # The custom_timing version below is to manually construct the TimingModel # class, which allows it to be pickled. This is needed for parallelizing diff --git a/src/pint/scripts/event_optimize_multiple.py b/src/pint/scripts/event_optimize_multiple.py index 41316a000..daa40a9e9 100755 --- a/src/pint/scripts/event_optimize_multiple.py +++ b/src/pint/scripts/event_optimize_multiple.py @@ -261,7 +261,7 @@ def main(argv=None): wgtexp = args.wgtexp # Read in initial model - modelin = pint.models.get_model(parfile) + modelin = pint.models.get_model(parfile, allow_T2=True, allow_tcb=True) # Set the target coords for automatic weighting if necessary if "ELONG" in modelin.params: diff --git a/src/pint/scripts/fermiphase.py b/src/pint/scripts/fermiphase.py index b1427e61f..6785bc156 100755 --- a/src/pint/scripts/fermiphase.py +++ b/src/pint/scripts/fermiphase.py @@ -88,7 +88,8 @@ def main(argv=None): args.addphase = True # Read in model - modelin = pint.models.get_model(args.parfile) + modelin = pint.models.get_model(args.parfile, allow_T2=True, allow_tcb=True) + if "ELONG" in modelin.params: tc = SkyCoord( modelin.ELONG.quantity, diff --git a/src/pint/scripts/photonphase.py b/src/pint/scripts/photonphase.py index 7d72eec18..38505c629 100755 --- a/src/pint/scripts/photonphase.py +++ b/src/pint/scripts/photonphase.py @@ -153,7 +153,8 @@ def main(argv=None): "Please barycenter the event file using the official mission tools before processing with PINT" ) # Read in model - modelin = pint.models.get_model(args.parfile) + modelin = pint.models.get_model(args.parfile, allow_T2=True, allow_tcb=True) + use_planets = False if "PLANET_SHAPIRO" in modelin.params: if modelin.PLANET_SHAPIRO.value: diff --git a/src/pint/scripts/pintbary.py b/src/pint/scripts/pintbary.py index 4876474d8..c29d42fbb 100755 --- a/src/pint/scripts/pintbary.py +++ b/src/pint/scripts/pintbary.py @@ -105,7 +105,7 @@ def main(argv=None): ) if args.parfile is not None: - m = pint.models.get_model(args.parfile) + m = pint.models.get_model(args.parfile, allow_T2=True, allow_tcb=True) else: # Construct model by hand m = pint.models.StandardTimingModel diff --git a/src/pint/scripts/pintempo.py b/src/pint/scripts/pintempo.py index d99c772ba..36e8ca509 100755 --- a/src/pint/scripts/pintempo.py +++ b/src/pint/scripts/pintempo.py @@ -69,7 +69,7 @@ def main(argv=None): ) log.info("Reading model from {0}".format(args.parfile)) - m = pint.models.get_model(args.parfile) + m = pint.models.get_model(args.parfile, allow_T2=True, allow_tcb=True) log.warning(m.params) diff --git a/src/pint/scripts/pintpublish.py b/src/pint/scripts/pintpublish.py index 6d5b0142f..36cc5786e 100644 --- a/src/pint/scripts/pintpublish.py +++ b/src/pint/scripts/pintpublish.py @@ -62,7 +62,7 @@ def main(argv=None): args = parser.parse_args(argv) - model, toas = get_model_and_toas(args.parfile, args.timfile) + model, toas = get_model_and_toas(args.parfile, args.timfile, allow_T2=True) output = publish( model, diff --git a/src/pint/scripts/tcb2tdb.py b/src/pint/scripts/tcb2tdb.py index 4c427d21a..5b15d56ae 100644 --- a/src/pint/scripts/tcb2tdb.py +++ b/src/pint/scripts/tcb2tdb.py @@ -34,7 +34,7 @@ def main(argv=None): args = parser.parse_args(argv) mb = ModelBuilder() - model = mb(args.input_par, allow_tcb=True) + model = mb(args.input_par, allow_tcb=True, allow_T2=True) model.write_parfile(args.output_par) log.info(f"Output written to {args.output_par}.") diff --git a/src/pint/scripts/zima.py b/src/pint/scripts/zima.py index 3305129f7..3485c6c5b 100755 --- a/src/pint/scripts/zima.py +++ b/src/pint/scripts/zima.py @@ -122,7 +122,7 @@ def main(argv=None): ) log.info("Reading model from {0}".format(args.parfile)) - m = pint.models.get_model(args.parfile) + m = pint.models.get_model(args.parfile, allow_T2=True, allow_tcb=True) out_format = args.format error = args.error * u.microsecond From f8bbeae61c7651341e82168b4f7cc9e075ac4c6d Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Mon, 7 Oct 2024 11:03:13 +0200 Subject: [PATCH 073/195] CHANGELOG --- CHANGELOG-unreleased.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 2c7ea6521..2d433bfab 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -14,6 +14,7 @@ the released changes. - `maskParameter.__repr__()` output now includes the frozen attribute. - Changed default value of `FDJUMPLOG` to `Y` - Bumped `black` version to 24.x +- Command line scripts now automatically do `allow_tcb` and `allow_T2` while reading par files. ### Added - arXiv link of PINT noise paper in README - Type hints in `pint.derived_quantities`, `pint.modelutils`, `pint.binaryconvert`, `pint.config`, From 7a9fcc5e152a16fde7f04906793fd8cc98043f22 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 8 Oct 2024 14:12:17 -0500 Subject: [PATCH 074/195] test pyproject install --- pyproject.toml | 144 +++++++++++++++++++++++++++++++++++++++++++++++++ setup.cfg | 132 --------------------------------------------- 2 files changed, 144 insertions(+), 132 deletions(-) create mode 100644 pyproject.toml delete mode 100644 setup.cfg diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..8b85722d9 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,144 @@ +[build-system] +requires = ["setuptools>=61.2", "versioneer"] +build-backend = "setuptools.build_meta" + +[project] +name = "pint-pulsar" +description = "A Pulsar Timing Package, written in Python from scratch" +authors = [ + {name = "Luo Jing", email = "sransom@nrao.edu"}, + {name = "Scott Ransom"}, + {name = "Paul Demorest"}, + {name = "Paul Ray"}, + {name = "et al."}, +] +license = {text = "License :: OSI Approved :: BSD License"} +classifiers = [ + "Intended Audience :: Science/Research", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Scientific/Engineering :: Astronomy", + "Topic :: Software Development :: Libraries :: Python Modules", +] +requires-python = ">=3.8" +dependencies = [ + "numpy>=1.18.5", + "astropy>=4.0,!=4.0.1,!=4.0.1.post1", + "pyerfa", + "scipy>=1.4.1", + "jplephem>=2.6", + "matplotlib>=3.2.0", + "emcee>=3.0.1", + "corner>=2.0.1", + "uncertainties", + "loguru", + "nestle>=0.2.0", + "numdifftools", +] +dynamic = ["version"] + +[project.readme] +file = "README.rst" +content-type = "text/x-rst" + +[project.urls] +Homepage = "https://github.com/nanograv/PINT" +Documentation = "https://nanograv-pint.readthedocs.io/" + +[project.entry-points] +# See the docstring in versioneer.py for instructions. Note that you must +# re-run 'versioneer.py setup' after changing this section, and commit the +# resulting files. + +[project.scripts] +photonphase = "pint.scripts.photonphase:main" +event_optimize = "pint.scripts.event_optimize:main" +event_optimize_multiple = "pint.scripts.event_optimize_multiple:main" +pintempo = "pint.scripts.pintempo:main" +zima = "pint.scripts.zima:main" +pintbary = "pint.scripts.pintbary:main" +fermiphase = "pint.scripts.fermiphase:main" +pintk = "pint.scripts.pintk:main" +convert_parfile = "pint.scripts.convert_parfile:main" +compare_parfiles = "pint.scripts.compare_parfiles:main" +tcb2tdb = "pint.scripts.tcb2tdb:main" +t2binary2pint = "pint.scripts.t2binary2pint:main" +pintpublish = "pint.scripts.pintpublish:main" + +[tool.setuptools] +zip-safe = false +package-dir = {"" = "src"} +include-package-data = true +# These should match requirements.txt + +[tool.setuptools.packages.find] +where = ["src"] +namespaces = false + +[tool.setuptools.package-data] +"*" = ["*.*"] + +[tool.versioneer] +VCS = "git" +style = "pep440" +versionfile_source = "src/pint/extern/_version.py" +versionfile_build = "pint/extern/_version.py" +tag_prefix = "''" +parentdir_prefix = "'pint-'" + +[tool.distutils.bdist_wheel] +universal = 0 + +[tool.aliases] +test = "pytest" + +[tool.flake8] +max-line-length = "100" +# This is an inappropriate non-error for slicing +extend-ignore = """ +E203, +E265 +# __init__ doesn't need a docstring, should be in the class +D107 +# Other magic methods don't necessarily need docstings, what they do is well-defined +D105 +# Style issues, suppress these for a full flake8 run +# E111,E114,E115,E116,E122,E123,E124,E125,E126,E127,E128,E129,E131 +# E201,E202,E203,E221,E222,E225,E226,E227,E228,E231,E241,E251,E261,E262,E265,E266,E271,E272 +# E301,E302,E303,E305,E306 +# E401,E501,E502 +# E701,E702,E703,E704,E741 +# W291,W293,W391,W503,W504 +# D100,D101,D102,D103,D104,D105 +# D200,D202,D204,D205,D207,D208,D209,D210 +# D300 +# D400,D401,D402,D403,D412,D413 +# RST201,RST202,RST203,RST210,RST212,RST299 +# RST301,RST304,RST306 +# Ugh people want to break these rules +N802 # Function names should be lowercase +N803 # argument name should be lowercase +N806 # variable should be lowercase""" +statistics = "True" +exclude = """ +docs/conf.py +versioneer.py +pint/mcmc_fitter.py""" +rst-roles = """ +class, +module, +func,""" + +[tool.isort] +multi_line_output = 3 +line_length = 88 +skip_glob = ["src/pint/extern/*"] +include_trailing_comma = true +combine_as_imports = true diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 28dfa2974..000000000 --- a/setup.cfg +++ /dev/null @@ -1,132 +0,0 @@ -[metadata] -name = pint-pulsar -description = A Pulsar Timing Package, written in Python from scratch -long_description = file: README.rst -long_description_content_type = text/x-rst -author = Luo Jing, Scott Ransom, Paul Demorest, Paul Ray, et al. -author_email = sransom@nrao.edu -url = https://github.com/nanograv/PINT -project_urls = - Documentation = https://nanograv-pint.readthedocs.io/ -license = License :: OSI Approved :: BSD License -classifier = - Intended Audience :: Science/Research - License :: OSI Approved :: BSD License - Operating System :: OS Independent - Programming Language :: Python - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - Programming Language :: Python :: 3.11 - Programming Language :: Python :: 3.12 - Topic :: Scientific/Engineering :: Astronomy - Topic :: Software Development :: Libraries :: Python Modules - -[options] -zip_safe = False -packages = find: -package_dir = - = src -include_package_data = True -python_requires = >=3.8 -# These should match requirements.txt -install_requires = - numpy>=1.18.5 - astropy>=4.0,!=4.0.1,!=4.0.1.post1 - pyerfa - scipy>=1.4.1 - jplephem>=2.6 - matplotlib>=3.2.0 - emcee>=3.0.1 - corner>=2.0.1 - uncertainties - loguru - nestle>=0.2.0 - numdifftools - -[options.packages.find] -where = src - -[options.package_data] -* = *.* - -[options.entry_points] -console_scripts = - photonphase = pint.scripts.photonphase:main - event_optimize = pint.scripts.event_optimize:main - event_optimize_multiple = pint.scripts.event_optimize_multiple:main - pintempo = pint.scripts.pintempo:main - zima = pint.scripts.zima:main - pintbary = pint.scripts.pintbary:main - fermiphase = pint.scripts.fermiphase:main - pintk = pint.scripts.pintk:main - convert_parfile = pint.scripts.convert_parfile:main - compare_parfiles = pint.scripts.compare_parfiles:main - tcb2tdb = pint.scripts.tcb2tdb:main - t2binary2pint = pint.scripts.t2binary2pint:main - pintpublish = pint.scripts.pintpublish:main - - -# See the docstring in versioneer.py for instructions. Note that you must -# re-run 'versioneer.py setup' after changing this section, and commit the -# resulting files. - -[versioneer] -VCS = git -style = pep440 -versionfile_source = src/pint/extern/_version.py -versionfile_build = pint/extern/_version.py -tag_prefix = '' -parentdir_prefix = 'pint-' - -[bdist_wheel] -universal = 0 - -[aliases] -test=pytest - -[flake8] -max-line-length = 100 -# This is an inappropriate non-error for slicing -extend-ignore = E203, - E265 -# __init__ doesn't need a docstring, should be in the class - D107 -# Other magic methods don't necessarily need docstings, what they do is well-defined - D105 -# Style issues, suppress these for a full flake8 run -# E111,E114,E115,E116,E122,E123,E124,E125,E126,E127,E128,E129,E131 -# E201,E202,E203,E221,E222,E225,E226,E227,E228,E231,E241,E251,E261,E262,E265,E266,E271,E272 -# E301,E302,E303,E305,E306 -# E401,E501,E502 -# E701,E702,E703,E704,E741 -# W291,W293,W391,W503,W504 -# D100,D101,D102,D103,D104,D105 -# D200,D202,D204,D205,D207,D208,D209,D210 -# D300 -# D400,D401,D402,D403,D412,D413 -# RST201,RST202,RST203,RST210,RST212,RST299 -# RST301,RST304,RST306 -# Ugh people want to break these rules - N802 # Function names should be lowercase - N803 # argument name should be lowercase - N806 # variable should be lowercase - -statistics = True -exclude = - docs/conf.py - versioneer.py - pint/mcmc_fitter.py -rst-roles = - class, - module, - func, - -[isort] -multi_line_output = 3 -line_length = 88 -skip_glob = - src/pint/extern/* -include_trailing_comma = True -combine_as_imports = True From 1c3e541fb2d30008edb5402e22f3c68a63686782 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Wed, 9 Oct 2024 09:46:47 -0500 Subject: [PATCH 075/195] added changelog --- CHANGELOG-unreleased.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 2c7ea6521..ab79d2e87 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -14,6 +14,7 @@ the released changes. - `maskParameter.__repr__()` output now includes the frozen attribute. - Changed default value of `FDJUMPLOG` to `Y` - Bumped `black` version to 24.x +- Changed from `setup.cfg` to `pyproject.toml` ### Added - arXiv link of PINT noise paper in README - Type hints in `pint.derived_quantities`, `pint.modelutils`, `pint.binaryconvert`, `pint.config`, From c687416fd51a508daf50012f31f1099137d9dd77 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Wed, 9 Oct 2024 09:49:01 -0500 Subject: [PATCH 076/195] added changelog --- CHANGELOG-unreleased.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 2c7ea6521..fecd803d3 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -14,6 +14,7 @@ the released changes. - `maskParameter.__repr__()` output now includes the frozen attribute. - Changed default value of `FDJUMPLOG` to `Y` - Bumped `black` version to 24.x +- Moved all custom exceptions and warnings to a single module `pint.exceptions` ### Added - arXiv link of PINT noise paper in README - Type hints in `pint.derived_quantities`, `pint.modelutils`, `pint.binaryconvert`, `pint.config`, From f8822f17a661c94bd93c3b9238033113df225941 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Wed, 9 Oct 2024 09:52:42 -0500 Subject: [PATCH 077/195] updated __all__ --- src/pint/exceptions.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/pint/exceptions.py b/src/pint/exceptions.py index 610459bea..81b11a606 100644 --- a/src/pint/exceptions.py +++ b/src/pint/exceptions.py @@ -1,9 +1,24 @@ __all__ = [ + "DegeneracyWarning", + "ConvergenceFailure", + "MaxiterReached", + "StepProblem", + "CorrelatedErrors", + "MissingTOAs", + "PropertyAttributeError", "TimingModelError", "MissingParameter", - "MissingTOAs", - "MissingBinaryError", + "AliasConflict", + "UnknownParameter", "UnknownBinaryModel", + "MissingBinaryError", + "PINTPrecisionError", + "PrefixError", + "InvalidModelParameters", + "ComponentConflict", + "ClockCorrectionError", + "NoClockCorrections", + "ClockCorrectionOutOfRange", ] From 86c81408a803c29b7a03d6d2960b65f66bd8ea99 Mon Sep 17 00:00:00 2001 From: Deven Bhakta Date: Thu, 17 Oct 2024 13:17:06 -0400 Subject: [PATCH 078/195] Phases calculation using the Designmatrix feature --- src/pint/plot_utils.py | 6 +++-- src/pint/scripts/event_optimize.py | 35 ++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/pint/plot_utils.py b/src/pint/plot_utils.py index 45eba3977..917412b71 100644 --- a/src/pint/plot_utils.py +++ b/src/pint/plot_utils.py @@ -279,11 +279,13 @@ def plot_priors( for i in range(len(keys[:-1])): values[i] = values[i][burnin:].flatten() x_range.append(np.linspace(values[i].min(), values[i].max(), num=bins)) - priors.append(getattr(model, keys[i]).prior.pdf(x_range[i])) + priors.append(getattr(model, keys[i]).prior.logpdf(x_range[i])) a, x = np.histogram(values[i], bins=bins, density=True) counts.append(a) - fig, axs = plt.subplots(len(keys), figsize=(8, 11), constrained_layout=True) + fig, axs = plt.subplots( + len(keys), figsize=(8, len(keys) * 1.5), constrained_layout=True + ) for i, p in enumerate(keys): if i != len(keys[:-1]): diff --git a/src/pint/scripts/event_optimize.py b/src/pint/scripts/event_optimize.py index e4c9dd4ff..1b66b2229 100755 --- a/src/pint/scripts/event_optimize.py +++ b/src/pint/scripts/event_optimize.py @@ -414,6 +414,16 @@ def __init__( self.model, phs, phserr ) self.n_fit_params = len(self.fitvals) + self.M, _, _ = self.model.designmatrix(self.toas) + self.M = self.M.transpose() * -self.model.F0.value + self.phases = self.get_event_phases() + self.calc_phase = False + + def calc_phase_matrix(self, theta): + d_phs = np.zeros(len(self.toas)) + for i in range(len(theta) - 1): + d_phs += self.M[i + 1] * (self.fitvals[i] - theta[i]) + return (self.phases - d_phs) % 1 def get_event_phases(self): """ @@ -446,7 +456,10 @@ def lnposterior(self, theta): return -np.inf, -np.inf, -np.inf # Call PINT to compute the phases - phases = self.get_event_phases() + if self.calc_phase: + phases = self.calc_phase_matrix(theta) + else: + phases = self.get_event_phases() lnlikelihood = profile_likelihood( theta[-1], self.xtemp, phases, self.template, self.weights ) @@ -686,6 +699,13 @@ def main(argv=None): action="store_true", dest="noautocorr", ) + parser.add_argument( + "--calc_phase", + help="Calculates the phase at each MCMC step using the designmatrix", + default=False, + action="store_true", + dest="calc_phase", + ) args = parser.parse_args(argv) pint.logging.setup( @@ -862,6 +882,9 @@ def main(argv=None): # This way, one walker should always be in a good position pos[0] = ftr.fitvals + # How phase will be calculated at each step (either with the designmatrix or ) + ftr.calc_phase = True if args.calc_phase else False + import emcee # Setting up a backend to save the chains into an h5 file @@ -925,7 +948,7 @@ def chains_to_dict(names, sampler): def plot_chains(chain_dict, file=False): npts = len(chain_dict) - fig, axes = plt.subplots(npts, 1, sharex=True, figsize=(8, 9)) + fig, axes = plt.subplots(npts, 1, sharex=True, figsize=(8, npts * 1.5)) for ii, name in enumerate(chain_dict.keys()): axes[ii].plot(chain_dict[name], color="k", alpha=0.3) axes[ii].set_ylabel(name) @@ -950,6 +973,7 @@ def plot_chains(chain_dict, file=False): lnprior_samps = blobs["lnprior"] lnlikelihood_samps = blobs["lnlikelihood"] lnpost_samps = lnprior_samps + lnlikelihood_samps + maxpost = lnpost_samps[:][burnin:].max() ind = np.unravel_index( np.argmax(lnpost_samps[:][burnin:]), lnpost_samps[:][burnin:].shape ) @@ -1000,8 +1024,15 @@ def plot_chains(chain_dict, file=False): ] ftr.set_param_uncertainties(dict(zip(ftr.fitkeys[:-1], errors[:-1]))) + # Calculating the AIC and BIC + n_params = len(ftr.model.free_params) + AIC = 2 * (n_params - maxpost) + BIC = n_params * np.log(len(ts)) - 2 * maxpost + ftr.model.NTOA.value = ts.ntoas f = open(filename + "_post.par", "w") f.write(ftr.model.as_parfile()) + f.write(f"\n#The AIC is {AIC}") + f.write(f"\n#The BIC is {BIC}") f.close() # Print the best MCMC values and ranges From 9b37999bf4e7d11ff37c55a54e70da215b1584fe Mon Sep 17 00:00:00 2001 From: Paul Ray Date: Fri, 18 Oct 2024 15:29:39 -0400 Subject: [PATCH 079/195] Update CHANGELOG for 1.0.2 --- CHANGELOG-unreleased.md | 31 ------------------------------- CHANGELOG.md | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index e71079078..2899b99f8 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -9,37 +9,6 @@ the released changes. ## Unreleased ### Changed -- Moved the events -> TOAs and photon weights code into the function `load_events_weights` within `event_optimize`. -- Updated the `maxMJD` argument in `event_optimize` to default to the current mjd -- `maskParameter.__repr__()` output now includes the frozen attribute. -- Changed default value of `FDJUMPLOG` to `Y` -- Bumped `black` version to 24.x -- Moved all custom exceptions and warnings to a single module `pint.exceptions` -- Changed from `setup.cfg` to `pyproject.toml` ### Added -- arXiv link of PINT noise paper in README -- Type hints in `pint.derived_quantities`, `pint.modelutils`, `pint.binaryconvert`, `pint.config`, -`pint.erfautils`, `pint.fits_utils`, `pint.logging` and `pint.residuals` -- Doing `model.par = something` will try to assign to `par.quantity` or `par.value` but will give warning -- `PLChromNoise` component to model chromatic red noise with a power law spectrum -- Fourier series representation of chromatic noise (`CMWaveX`) -- `pint.utils.cmwavex_setup` and `pint.utils.plchromnoise_from_cmwavex` functions -- More validation for correlated noise components in `TimingModel.validate_component_types()` -- ORBWAVEs model for modelling binary orbital period variations in the fourier domain ### Fixed -- Bug in `DMWaveX.get_indices()` function -- Explicit type conversion in `woodbury_dot()` function -- Documentation: Fixed empty descriptions in the timing model components table -- BIC implementation -- `event_optimize`: Fixed a bug that was causing the results.txt file to be written without the median values. -- SWX model now has SWXP_0001 frozen by default, and new segments should also have SWXP frozen -- Can now properly use local files for ephemeris -- Typos in `explanation.rst` regarding local ephemeris. -- DD/ELL1 models will check for valid SINI and raise exception if it strays, which will tell the fitter to try elsewhere -- Don't try to print AIC for wideband data in `pintk` (it's not yet implemented) ### Removed -- Removed the argument `--usepickle` in `event_optimize` as the `load_events_weights` function checks the events file type to see if the -file is a pickle file. -- Removed obsolete code, such as manually tracking the progress of the MCMC run within `event_optimize` -- `download_data.sh` script and `de432s.bsp` ephemeris file -`` diff --git a/CHANGELOG.md b/CHANGELOG.md index 80348c541..3c905242f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,41 @@ and this project, at least loosely, adheres to [Semantic Versioning](https://sem This file contains the released changes to the codebase. See CHANGELOG-unreleased.md for the unreleased changes. This file should only be changed while tagging a new version. +## [1.0.2] 2024-10-18 +### Changed +- Moved the events -> TOAs and photon weights code into the function `load_events_weights` within `event_optimize`. +- Updated the `maxMJD` argument in `event_optimize` to default to the current mjd +- `maskParameter.__repr__()` output now includes the frozen attribute. +- Changed default value of `FDJUMPLOG` to `Y` +- Bumped `black` version to 24.x +- Moved all custom exceptions and warnings to a single module `pint.exceptions` +- Changed from `setup.cfg` to `pyproject.toml` +### Added +- arXiv link of PINT noise paper in README +- Type hints in `pint.derived_quantities`, `pint.modelutils`, `pint.binaryconvert`, `pint.config`, +`pint.erfautils`, `pint.fits_utils`, `pint.logging` and `pint.residuals` +- Doing `model.par = something` will try to assign to `par.quantity` or `par.value` but will give warning +- `PLChromNoise` component to model chromatic red noise with a power law spectrum +- Fourier series representation of chromatic noise (`CMWaveX`) +- `pint.utils.cmwavex_setup` and `pint.utils.plchromnoise_from_cmwavex` functions +- More validation for correlated noise components in `TimingModel.validate_component_types()` +- ORBWAVEs model for modelling binary orbital period variations in the fourier domain +### Fixed +- Bug in `DMWaveX.get_indices()` function +- Explicit type conversion in `woodbury_dot()` function +- Documentation: Fixed empty descriptions in the timing model components table +- BIC implementation +- `event_optimize`: Fixed a bug that was causing the results.txt file to be written without the median values. +- SWX model now has SWXP_0001 frozen by default, and new segments should also have SWXP frozen +- Can now properly use local files for ephemeris +- Typos in `explanation.rst` regarding local ephemeris. +- DD/ELL1 models will check for valid SINI and raise exception if it strays, which will tell the fitter to try elsewhere +- Don't try to print AIC for wideband data in `pintk` (it's not yet implemented) +### Removed +- Removed the argument `--usepickle` in `event_optimize` as the `load_events_weights` function checks the events file type to see if the file is a pickle file. +- Removed obsolete code, such as manually tracking the progress of the MCMC run within `event_optimize` +- `download_data.sh` script and `de432s.bsp` ephemeris file + ## [1.0.1] 2024-07-01 ### Changed - Avoided unnecessary creation of `SkyCoord` objects in `AstrometryEquatorial` and `AstrometryEcliptic`. From 1d9b66e1ff70b4c439fe227209d42c96f3503665 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Fri, 18 Oct 2024 15:22:02 -0500 Subject: [PATCH 080/195] moving from pkg_resources -> importlib --- src/pint/__init__.py | 1 - src/pint/config.py | 12 ++++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/pint/__init__.py b/src/pint/__init__.py index c0d511e7c..5706dff7e 100644 --- a/src/pint/__init__.py +++ b/src/pint/__init__.py @@ -16,7 +16,6 @@ import astropy.time as time import astropy.units as u import numpy as np -import pkg_resources from astropy.units import si from pathlib import Path diff --git a/src/pint/config.py b/src/pint/config.py index a24bec249..344bc71b1 100644 --- a/src/pint/config.py +++ b/src/pint/config.py @@ -1,7 +1,7 @@ """Functions related to PINT configuration.""" import os -import pkg_resources +import importlib.resources __all__ = ["datadir", "examplefile", "runtimefile"] @@ -15,7 +15,7 @@ def datadir() -> str: str Directory of PINT data files """ - return pkg_resources.resource_filename(__name__, "data/") + return os.path.join(importlib.resources.files("pint"), "data/") def examplefile(filename: str) -> str: @@ -35,9 +35,7 @@ def examplefile(filename: str) -> str: This is **not** for files needed at runtime. Those are located by :func:`pint.config.runtimefile`. This is for files needed for the example notebooks. """ - return pkg_resources.resource_filename( - __name__, os.path.join("data/examples/", filename) - ) + return os.path.join(importlib.resources.files("pint"), f"data/examples/{filename}") def runtimefile(filename: str) -> str: @@ -57,6 +55,4 @@ def runtimefile(filename: str) -> str: This **is** for files needed at runtime. Files needed for the example notebooks are found via :func:`pint.config.examplefile`. """ - return pkg_resources.resource_filename( - __name__, os.path.join("data/runtime/", filename) - ) + return os.path.join(importlib.resources.files("pint"), f"data/runtime/{filename}") From 44ff0c6f3b7ccff5a597a18a450136a7870b257b Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Fri, 18 Oct 2024 15:41:44 -0500 Subject: [PATCH 081/195] change function for compatibility --- src/pint/config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pint/config.py b/src/pint/config.py index 344bc71b1..843dba08d 100644 --- a/src/pint/config.py +++ b/src/pint/config.py @@ -15,7 +15,7 @@ def datadir() -> str: str Directory of PINT data files """ - return os.path.join(importlib.resources.files("pint"), "data/") + return importlib.resources.path("pint", "data/") def examplefile(filename: str) -> str: @@ -35,7 +35,7 @@ def examplefile(filename: str) -> str: This is **not** for files needed at runtime. Those are located by :func:`pint.config.runtimefile`. This is for files needed for the example notebooks. """ - return os.path.join(importlib.resources.files("pint"), f"data/examples/{filename}") + return importlib.resources.path("pint", "data", "examples", filename) def runtimefile(filename: str) -> str: @@ -55,4 +55,4 @@ def runtimefile(filename: str) -> str: This **is** for files needed at runtime. Files needed for the example notebooks are found via :func:`pint.config.examplefile`. """ - return os.path.join(importlib.resources.files("pint"), f"data/runtime/{filename}") + return importlib.resources.path("pint", "data", "runtime", filename) From 3150b6dedf71254395747d6c0838970246c64c75 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Fri, 18 Oct 2024 15:51:04 -0500 Subject: [PATCH 082/195] using resources.file --- src/pint/config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pint/config.py b/src/pint/config.py index 843dba08d..344bc71b1 100644 --- a/src/pint/config.py +++ b/src/pint/config.py @@ -15,7 +15,7 @@ def datadir() -> str: str Directory of PINT data files """ - return importlib.resources.path("pint", "data/") + return os.path.join(importlib.resources.files("pint"), "data/") def examplefile(filename: str) -> str: @@ -35,7 +35,7 @@ def examplefile(filename: str) -> str: This is **not** for files needed at runtime. Those are located by :func:`pint.config.runtimefile`. This is for files needed for the example notebooks. """ - return importlib.resources.path("pint", "data", "examples", filename) + return os.path.join(importlib.resources.files("pint"), f"data/examples/{filename}") def runtimefile(filename: str) -> str: @@ -55,4 +55,4 @@ def runtimefile(filename: str) -> str: This **is** for files needed at runtime. Files needed for the example notebooks are found via :func:`pint.config.examplefile`. """ - return importlib.resources.path("pint", "data", "runtime", filename) + return os.path.join(importlib.resources.files("pint"), f"data/runtime/{filename}") From b087804f01c25d7038500a9ecfd018a3376434e1 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 21 Oct 2024 09:11:38 -0500 Subject: [PATCH 083/195] bump oldest to 3.9 --- .github/workflows/ci_test.yml | 2 +- docs/installation.rst | 2 +- pyproject.toml | 3 +-- tox.ini | 6 +++--- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index c3a8af4c5..35d2c4e99 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -48,7 +48,7 @@ jobs: # python: '3.8' # tox_env: 'py38-test' - os: ubuntu-latest - python: '3.8' + python: '3.9' tox_env: 'oldestdeps' # - os: ubuntu-latest # python: '3.8' diff --git a/docs/installation.rst b/docs/installation.rst index eb780c9ea..c6e23b549 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -14,7 +14,7 @@ is more complicated (but not too much). Prerequisites ------------- -PINT requires Python 3.8+ [1]_ +PINT requires Python 3.9+ [1]_ Your Python must have the package installation tool pip_ installed. Also make sure your ``setuptools`` are up to date (e.g. ``pip install -U setuptools``). diff --git a/pyproject.toml b/pyproject.toml index 8b85722d9..d07fdc799 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,6 @@ classifiers = [ "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -27,7 +26,7 @@ classifiers = [ "Topic :: Scientific/Engineering :: Astronomy", "Topic :: Software Development :: Libraries :: Python Modules", ] -requires-python = ">=3.8" +requires-python = ">=3.9" dependencies = [ "numpy>=1.18.5", "astropy>=4.0,!=4.0.1,!=4.0.1.post1", diff --git a/tox.ini b/tox.ini index 4b7f6b153..f48795c55 100644 --- a/tox.ini +++ b/tox.ini @@ -48,8 +48,8 @@ commands = cov: coverage xml -o {toxinidir}/coverage.xml depends = - {py38,py39,py310,py311,py312}: clean - report: py38,py39,py310,py312 + {py39,py310,py311,py312}: clean + report: py39,py310,py312 docs: notebooks [testenv:singletest] @@ -80,7 +80,7 @@ deps = [testenv:oldestdeps] description = Run tests on Python 3 with minimum supported versions of astropy, numpy -basepython = python3.8 +basepython = python3.9 deps = numpy==1.18.5 numdifftools==0.9.39 From c8fc8fc6398f1006de836c544b7df82cb348419b Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 21 Oct 2024 11:09:47 -0500 Subject: [PATCH 084/195] limit setuptools version --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index f48795c55..8ab080d35 100644 --- a/tox.ini +++ b/tox.ini @@ -82,6 +82,7 @@ description = Run tests on Python 3 with minimum supported versions of astropy, numpy basepython = python3.9 deps = + setuptools<65 numpy==1.18.5 numdifftools==0.9.39 astropy==4.0 From 3fd81c25e9a87358a74798eceb338a3fc6fda8c4 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 21 Oct 2024 11:16:52 -0500 Subject: [PATCH 085/195] limit setuptools in pyproject --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d07fdc799..e4c5d7463 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=61.2", "versioneer"] +requires = ["setuptools>=61.2,<65", "versioneer"] build-backend = "setuptools.build_meta" [project] From 8eaf91818587a62192a8d4c7f03ec255ef39e04f Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 21 Oct 2024 11:25:21 -0500 Subject: [PATCH 086/195] added printing of setuptools version --- .github/workflows/ci_test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 35d2c4e99..3fba6841e 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -76,11 +76,12 @@ jobs: - name: Install pandoc dependency if: "endsWith(matrix.tox_env, 'docs')" run: sudo apt-get -y install pandoc - - name: Print Python, pip, and tox versions + - name: Print Python, pip, setuptools, and tox versions run: | python -c "import sys; print(f'Python {sys.version}')" python -c "import pip; print(f'pip {pip.__version__}')" python -c "import tox; print(f'tox {tox.__version__}')" + python -c "import setuptools; print(f'setuptools {setuptools.__version__}')" - name: Run tests run: tox -e ${{ matrix.tox_env }} - name: Upload coverage to codecov From 034ae0c82465cad28712502579307ba6b2d10b0c Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 21 Oct 2024 11:28:20 -0500 Subject: [PATCH 087/195] changing print of setuptools --- .github/workflows/ci_test.yml | 3 +-- tox.ini | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 3fba6841e..35d2c4e99 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -76,12 +76,11 @@ jobs: - name: Install pandoc dependency if: "endsWith(matrix.tox_env, 'docs')" run: sudo apt-get -y install pandoc - - name: Print Python, pip, setuptools, and tox versions + - name: Print Python, pip, and tox versions run: | python -c "import sys; print(f'Python {sys.version}')" python -c "import pip; print(f'pip {pip.__version__}')" python -c "import tox; print(f'tox {tox.__version__}')" - python -c "import setuptools; print(f'setuptools {setuptools.__version__}')" - name: Run tests run: tox -e ${{ matrix.tox_env }} - name: Upload coverage to codecov diff --git a/tox.ini b/tox.ini index 8ab080d35..373cd1ed6 100644 --- a/tox.ini +++ b/tox.ini @@ -91,7 +91,9 @@ deps = pytest coverage hypothesis<=6.72.0 -commands = {posargs:pytest} +commands = + python -c "import setuptools; print(f'setuptools {setuptools.__version__}')" + {posargs:pytest} [testenv:report] skip_install = true From fd99107ce63990539eb46aeeeedca35214c106b4 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 21 Oct 2024 11:29:39 -0500 Subject: [PATCH 088/195] remove print of setuptools --- tox.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/tox.ini b/tox.ini index 373cd1ed6..7decdcabe 100644 --- a/tox.ini +++ b/tox.ini @@ -92,7 +92,6 @@ deps = coverage hypothesis<=6.72.0 commands = - python -c "import setuptools; print(f'setuptools {setuptools.__version__}')" {posargs:pytest} [testenv:report] From 08e93838cc0615ab39e54d52766e45c8bd103c35 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 21 Oct 2024 11:38:28 -0500 Subject: [PATCH 089/195] Revert "remove print of setuptools" This reverts commit fd99107ce63990539eb46aeeeedca35214c106b4. --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 7decdcabe..373cd1ed6 100644 --- a/tox.ini +++ b/tox.ini @@ -92,6 +92,7 @@ deps = coverage hypothesis<=6.72.0 commands = + python -c "import setuptools; print(f'setuptools {setuptools.__version__}')" {posargs:pytest} [testenv:report] From 17461d9faadcaa83a10df137858a2497c1493e9c Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 21 Oct 2024 11:38:31 -0500 Subject: [PATCH 090/195] Revert "changing print of setuptools" This reverts commit 034ae0c82465cad28712502579307ba6b2d10b0c. --- .github/workflows/ci_test.yml | 3 ++- tox.ini | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 35d2c4e99..3fba6841e 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -76,11 +76,12 @@ jobs: - name: Install pandoc dependency if: "endsWith(matrix.tox_env, 'docs')" run: sudo apt-get -y install pandoc - - name: Print Python, pip, and tox versions + - name: Print Python, pip, setuptools, and tox versions run: | python -c "import sys; print(f'Python {sys.version}')" python -c "import pip; print(f'pip {pip.__version__}')" python -c "import tox; print(f'tox {tox.__version__}')" + python -c "import setuptools; print(f'setuptools {setuptools.__version__}')" - name: Run tests run: tox -e ${{ matrix.tox_env }} - name: Upload coverage to codecov diff --git a/tox.ini b/tox.ini index 373cd1ed6..8ab080d35 100644 --- a/tox.ini +++ b/tox.ini @@ -91,9 +91,7 @@ deps = pytest coverage hypothesis<=6.72.0 -commands = - python -c "import setuptools; print(f'setuptools {setuptools.__version__}')" - {posargs:pytest} +commands = {posargs:pytest} [testenv:report] skip_install = true From d8de228a3fab221e2cc4f7c16a1ff6846d54181d Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 21 Oct 2024 11:38:33 -0500 Subject: [PATCH 091/195] Revert "added printing of setuptools version" This reverts commit 8eaf91818587a62192a8d4c7f03ec255ef39e04f. --- .github/workflows/ci_test.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 3fba6841e..35d2c4e99 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -76,12 +76,11 @@ jobs: - name: Install pandoc dependency if: "endsWith(matrix.tox_env, 'docs')" run: sudo apt-get -y install pandoc - - name: Print Python, pip, setuptools, and tox versions + - name: Print Python, pip, and tox versions run: | python -c "import sys; print(f'Python {sys.version}')" python -c "import pip; print(f'pip {pip.__version__}')" python -c "import tox; print(f'tox {tox.__version__}')" - python -c "import setuptools; print(f'setuptools {setuptools.__version__}')" - name: Run tests run: tox -e ${{ matrix.tox_env }} - name: Upload coverage to codecov From c3e17b2f09a354bea26119225171f0e48754f3d9 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 21 Oct 2024 11:42:29 -0500 Subject: [PATCH 092/195] trying to get things working --- pyproject.toml | 2 +- tox.ini | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e4c5d7463..d07fdc799 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=61.2,<65", "versioneer"] +requires = ["setuptools>=61.2", "versioneer"] build-backend = "setuptools.build_meta" [project] diff --git a/tox.ini b/tox.ini index 8ab080d35..f48795c55 100644 --- a/tox.ini +++ b/tox.ini @@ -82,7 +82,6 @@ description = Run tests on Python 3 with minimum supported versions of astropy, numpy basepython = python3.9 deps = - setuptools<65 numpy==1.18.5 numdifftools==0.9.39 astropy==4.0 From 5ad772eb498df1c532ecca25f7538d4675ea7cab Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 21 Oct 2024 12:49:59 -0500 Subject: [PATCH 093/195] trying again to specify setuptools --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d07fdc799..af3e0fdc9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=61.2", "versioneer"] +requires = ["setuptools>=61.2", "setuptools<65", "versioneer"] build-backend = "setuptools.build_meta" [project] From 8ec2226e6fceca30985881ddb77a65481cf32e61 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 21 Oct 2024 12:51:47 -0500 Subject: [PATCH 094/195] cannot specify setuptools --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index af3e0fdc9..d07fdc799 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=61.2", "setuptools<65", "versioneer"] +requires = ["setuptools>=61.2", "versioneer"] build-backend = "setuptools.build_meta" [project] From 05ceea2b12b3a4f5b9957b242f10c2e45e3e8ed5 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 21 Oct 2024 14:52:10 -0500 Subject: [PATCH 095/195] add setuptools --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index f48795c55..56b28d520 100644 --- a/tox.ini +++ b/tox.ini @@ -82,6 +82,7 @@ description = Run tests on Python 3 with minimum supported versions of astropy, numpy basepython = python3.9 deps = + setuptools numpy==1.18.5 numdifftools==0.9.39 astropy==4.0 From 1415bf76f189463ed8b1eb4c5f1adb6e22f9c376 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 21 Oct 2024 14:54:04 -0500 Subject: [PATCH 096/195] add setuptools version --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 56b28d520..455a693c0 100644 --- a/tox.ini +++ b/tox.ini @@ -82,7 +82,7 @@ description = Run tests on Python 3 with minimum supported versions of astropy, numpy basepython = python3.9 deps = - setuptools + setuptools<=65 numpy==1.18.5 numdifftools==0.9.39 astropy==4.0 From 479f1c118b4a7b9e80cab8d334d91162710dd575 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 21 Oct 2024 14:58:08 -0500 Subject: [PATCH 097/195] change numpy to 1.19.5 --- tox.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 455a693c0..629b2ef19 100644 --- a/tox.ini +++ b/tox.ini @@ -82,8 +82,7 @@ description = Run tests on Python 3 with minimum supported versions of astropy, numpy basepython = python3.9 deps = - setuptools<=65 - numpy==1.18.5 + numpy==1.19.5 numdifftools==0.9.39 astropy==4.0 matplotlib==3.2.0 From 30e64b46dc8ca2df00aaf17641c51d1f627e40d1 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 21 Oct 2024 15:00:49 -0500 Subject: [PATCH 098/195] add distutils explicitly --- tox.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 629b2ef19..084401f07 100644 --- a/tox.ini +++ b/tox.ini @@ -82,7 +82,7 @@ description = Run tests on Python 3 with minimum supported versions of astropy, numpy basepython = python3.9 deps = - numpy==1.19.5 + numpy==1.18.5 numdifftools==0.9.39 astropy==4.0 matplotlib==3.2.0 @@ -90,6 +90,7 @@ deps = pytest coverage hypothesis<=6.72.0 + distutils commands = {posargs:pytest} [testenv:report] From 9b075795723be66c974c8295f599ca6069aaba34 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 21 Oct 2024 15:41:28 -0500 Subject: [PATCH 099/195] try 3.10 for oldest? --- .github/workflows/ci_test.yml | 2 +- tox.ini | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 35d2c4e99..7823a60e0 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -48,7 +48,7 @@ jobs: # python: '3.8' # tox_env: 'py38-test' - os: ubuntu-latest - python: '3.9' + python: '3.10' tox_env: 'oldestdeps' # - os: ubuntu-latest # python: '3.8' diff --git a/tox.ini b/tox.ini index 084401f07..6c8cf11c4 100644 --- a/tox.ini +++ b/tox.ini @@ -80,7 +80,7 @@ deps = [testenv:oldestdeps] description = Run tests on Python 3 with minimum supported versions of astropy, numpy -basepython = python3.9 +basepython = python3.10 deps = numpy==1.18.5 numdifftools==0.9.39 @@ -90,7 +90,6 @@ deps = pytest coverage hypothesis<=6.72.0 - distutils commands = {posargs:pytest} [testenv:report] From 223e5153464bb06794a15b2bca770dbd5c64b68f Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 22 Oct 2024 09:20:19 -0500 Subject: [PATCH 100/195] back to 3.9; try other versions of packages --- .github/workflows/ci_test.yml | 2 +- pyproject.toml | 2 +- tox.ini | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 7823a60e0..35d2c4e99 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -48,7 +48,7 @@ jobs: # python: '3.8' # tox_env: 'py38-test' - os: ubuntu-latest - python: '3.10' + python: '3.9' tox_env: 'oldestdeps' # - os: ubuntu-latest # python: '3.8' diff --git a/pyproject.toml b/pyproject.toml index d07fdc799..896bf40c6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=61.2", "versioneer"] +requires = ["setuptools>=62.1.0", "versioneer"] build-backend = "setuptools.build_meta" [project] diff --git a/tox.ini b/tox.ini index 6c8cf11c4..1b0900bd9 100644 --- a/tox.ini +++ b/tox.ini @@ -80,13 +80,13 @@ deps = [testenv:oldestdeps] description = Run tests on Python 3 with minimum supported versions of astropy, numpy -basepython = python3.10 +basepython = python3.9 deps = - numpy==1.18.5 + numpy==1.23.5 numdifftools==0.9.39 - astropy==4.0 - matplotlib==3.2.0 - scipy==1.4.1 + astropy==4.0.6 + matplotlib==3.4.3 + scipy==1.13.1 pytest coverage hypothesis<=6.72.0 From 4dcead63ea6ca54c0686d1a1c79cb1bf3100ed2d Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 22 Oct 2024 09:25:52 -0500 Subject: [PATCH 101/195] numpy to 1.16 to keep asscalar --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 1b0900bd9..f7befdd1b 100644 --- a/tox.ini +++ b/tox.ini @@ -82,7 +82,7 @@ description = Run tests on Python 3 with minimum supported versions of astropy, numpy basepython = python3.9 deps = - numpy==1.23.5 + numpy==1.26 numdifftools==0.9.39 astropy==4.0.6 matplotlib==3.4.3 From c17b5b357b486364e004f0bfc2338bc53259e019 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 22 Oct 2024 09:28:50 -0500 Subject: [PATCH 102/195] numpy to 1.16 to keep asscalar --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index f7befdd1b..92defb727 100644 --- a/tox.ini +++ b/tox.ini @@ -82,7 +82,7 @@ description = Run tests on Python 3 with minimum supported versions of astropy, numpy basepython = python3.9 deps = - numpy==1.26 + numpy==1.16 numdifftools==0.9.39 astropy==4.0.6 matplotlib==3.4.3 From 91360927e11f0b1995434bba515840a20b3e69b3 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 22 Oct 2024 09:38:39 -0500 Subject: [PATCH 103/195] moving to astropy 5 and related --- tox.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index 92defb727..3bd6fa863 100644 --- a/tox.ini +++ b/tox.ini @@ -82,11 +82,11 @@ description = Run tests on Python 3 with minimum supported versions of astropy, numpy basepython = python3.9 deps = - numpy==1.16 + numpy==1.23.5 numdifftools==0.9.39 - astropy==4.0.6 + astropy==5.0.5 matplotlib==3.4.3 - scipy==1.13.1 + scipy==1.9.1 pytest coverage hypothesis<=6.72.0 From 0b00c719c10d5c1baad58bb88011b2abe55ba4fc Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 22 Oct 2024 09:53:34 -0500 Subject: [PATCH 104/195] try a little earlier --- tox.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index 3bd6fa863..1bc8eb401 100644 --- a/tox.ini +++ b/tox.ini @@ -82,11 +82,11 @@ description = Run tests on Python 3 with minimum supported versions of astropy, numpy basepython = python3.9 deps = - numpy==1.23.5 + numpy==1.23.0 numdifftools==0.9.39 - astropy==5.0.5 + astropy==5.0 matplotlib==3.4.3 - scipy==1.9.1 + scipy==1.9.0 pytest coverage hypothesis<=6.72.0 From 3b10171e81861ceaccbf537549bae40a6603f1e7 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 22 Oct 2024 09:56:21 -0500 Subject: [PATCH 105/195] astropy to 5.0.5 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 1bc8eb401..0bf7e9816 100644 --- a/tox.ini +++ b/tox.ini @@ -84,7 +84,7 @@ basepython = python3.9 deps = numpy==1.23.0 numdifftools==0.9.39 - astropy==5.0 + astropy==5.0.5 matplotlib==3.4.3 scipy==1.9.0 pytest From 1f60fcb9fd326e5a5daa17b77f1c549859bc21c3 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 22 Oct 2024 11:35:06 -0500 Subject: [PATCH 106/195] setuptools to 61.2? --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 896bf40c6..d07fdc799 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=62.1.0", "versioneer"] +requires = ["setuptools>=61.2", "versioneer"] build-backend = "setuptools.build_meta" [project] From 333049872fbcb44886546ed5d47140dc36baad4e Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 22 Oct 2024 14:03:06 -0500 Subject: [PATCH 107/195] update dependency versions --- pyproject.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d07fdc799..448711d0e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,12 +28,12 @@ classifiers = [ ] requires-python = ">=3.9" dependencies = [ - "numpy>=1.18.5", - "astropy>=4.0,!=4.0.1,!=4.0.1.post1", + "numpy>=1.23.0", + "astropy>=5.0.5", "pyerfa", - "scipy>=1.4.1", + "scipy>=1.9.0", "jplephem>=2.6", - "matplotlib>=3.2.0", + "matplotlib>=3.4.3", "emcee>=3.0.1", "corner>=2.0.1", "uncertainties", From b3b90d0beaec211b73d4cc1d8914c8d49a3b9d5e Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 22 Oct 2024 14:04:48 -0500 Subject: [PATCH 108/195] changed in requirements*.txt --- requirements.txt | 8 ++++---- requirements_dev.txt | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/requirements.txt b/requirements.txt index 16f76401e..293e3d07a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,9 @@ -numpy>=1.18.5 -astropy>=4.0,!=4.0.1,!=4.0.1.post1 +numpy>=1.23.0 +astropy>=5.0.5 pyerfa -scipy>=1.4.1 +scipy>=1.9.0 jplephem>=2.6 -matplotlib>=3.2.0 +matplotlib>=3.4.3 emcee>=3.0.1 corner>=2.0.1 uncertainties diff --git a/requirements_dev.txt b/requirements_dev.txt index a00511840..c4fba2da1 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,10 +1,9 @@ attrs>=19.2 pip>=9.0.1 -setuptools>=41.0 +setuptools>=61.2 coverage>=4.3.4 traitlets Sphinx==6.2.1 -astropy>=4.0,!=4.0.1,!=4.0.1.post1 #astropy-helpers>=1.3 sphinx-rtd-theme==1.2.2 coveralls>=1.1 From 30ef430f47558067ee680a220d73fb0287aa6011 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Wed, 23 Oct 2024 11:40:26 -0500 Subject: [PATCH 109/195] try python 3.13 --- .github/workflows/ci_test.yml | 12 ++++++------ pyproject.toml | 1 + tox.ini | 10 +++++----- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 35d2c4e99..a5f6c9756 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -24,16 +24,16 @@ jobs: matrix: include: - os: ubuntu-latest - python: '3.12' + python: '3.13' tox_env: 'ephemeris_connection' - os: ubuntu-latest - python: '3.12' + python: '3.13' tox_env: 'black' - os: ubuntu-latest - python: '3.12' + python: '3.13' tox_env: 'py312-test-cov' - os: ubuntu-latest - python: '3.12' + python: '3.13' tox_env: 'notebooks' # - os: ubuntu-latest # python: '3.8' @@ -42,8 +42,8 @@ jobs: # python: '3.10' # tox_env: 'py310-test-alldeps-cov' - os: macos-12 - python: '3.12' - tox_env: 'py312-test' + python: '3.13' + tox_env: 'py313-test' # - os: windows-latest # python: '3.8' # tox_env: 'py38-test' diff --git a/pyproject.toml b/pyproject.toml index 448711d0e..fa5ebdbe7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Scientific/Engineering :: Astronomy", "Topic :: Software Development :: Libraries :: Python Modules", ] diff --git a/tox.ini b/tox.ini index 0bf7e9816..efadd9b9c 100644 --- a/tox.ini +++ b/tox.ini @@ -14,7 +14,7 @@ envlist = codestyle black singletest - py{38,39,310,311,312}-test{,-alldeps,-devdeps}{,-cov} + py{38,39,310,311,312,313}-test{,-alldeps,-devdeps}{,-cov} skip_missing_interpreters = True @@ -48,8 +48,8 @@ commands = cov: coverage xml -o {toxinidir}/coverage.xml depends = - {py39,py310,py311,py312}: clean - report: py39,py310,py312 + {py39,py310,py311,py312,313}: clean + report: py39,py310,py312,py313 docs: notebooks [testenv:singletest] @@ -102,7 +102,7 @@ commands = [testenv:notebooks] description = update the notebooks -basepython = python3.12 +basepython = python3.13 deps = traitlets sphinx >= 2.2, != 5.1.0 @@ -130,7 +130,7 @@ commands = coverage erase [testenv:docs] changedir = {toxinidir}/docs description = invoke sphinx-build to build the HTML docs -basepython = python3.12 +basepython = python3.13 deps = traitlets sphinx >= 2.2, != 5.1.0 From 5dfc3490914f442550f28bd77318a10655c5184d Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Wed, 23 Oct 2024 11:44:45 -0500 Subject: [PATCH 110/195] fix 3.13 tests --- .github/workflows/ci_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index a5f6c9756..79d3ca0a2 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -31,7 +31,7 @@ jobs: tox_env: 'black' - os: ubuntu-latest python: '3.13' - tox_env: 'py312-test-cov' + tox_env: 'py313-test-cov' - os: ubuntu-latest python: '3.13' tox_env: 'notebooks' From eb43e6c0e5a8a232060bc706c39b01b2f297142b Mon Sep 17 00:00:00 2001 From: Deven Bhakta Date: Thu, 24 Oct 2024 11:24:42 -0400 Subject: [PATCH 111/195] Renamed calc_phase option to linearize_model option within event_optimze --- CHANGELOG-unreleased.md | 2 ++ src/pint/scripts/event_optimize.py | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 2899b99f8..991f5caad 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -9,6 +9,8 @@ the released changes. ## Unreleased ### Changed +- Updated the `plot_priors` function in `plot_utils.py` and `plot_chains` function in `event_optimize` so that the subplots are a fixed size to prevent the subplots from being condensed in the case of many fit parameters. ### Added +- Added an option `linearize_model` to speed up the photon phases calculation within `event_optimize` through the designmatrix. ### Fixed ### Removed diff --git a/src/pint/scripts/event_optimize.py b/src/pint/scripts/event_optimize.py index 1b66b2229..071860a8d 100755 --- a/src/pint/scripts/event_optimize.py +++ b/src/pint/scripts/event_optimize.py @@ -417,7 +417,7 @@ def __init__( self.M, _, _ = self.model.designmatrix(self.toas) self.M = self.M.transpose() * -self.model.F0.value self.phases = self.get_event_phases() - self.calc_phase = False + self.linearize_model = False def calc_phase_matrix(self, theta): d_phs = np.zeros(len(self.toas)) @@ -456,7 +456,7 @@ def lnposterior(self, theta): return -np.inf, -np.inf, -np.inf # Call PINT to compute the phases - if self.calc_phase: + if self.linearize_model: phases = self.calc_phase_matrix(theta) else: phases = self.get_event_phases() @@ -700,11 +700,11 @@ def main(argv=None): dest="noautocorr", ) parser.add_argument( - "--calc_phase", + "--linearize_model", help="Calculates the phase at each MCMC step using the designmatrix", default=False, action="store_true", - dest="calc_phase", + dest="linearize_model", ) args = parser.parse_args(argv) @@ -882,8 +882,8 @@ def main(argv=None): # This way, one walker should always be in a good position pos[0] = ftr.fitvals - # How phase will be calculated at each step (either with the designmatrix or ) - ftr.calc_phase = True if args.calc_phase else False + # How phase will be calculated at each step (either with the designmatrix orthe exact phase calculation) + ftr.linearize_model = args.linearize_model import emcee From 827bcbbabe0b4977feecf8b1d14646f746ac2762 Mon Sep 17 00:00:00 2001 From: Deven Bhakta Date: Thu, 24 Oct 2024 11:26:55 -0400 Subject: [PATCH 112/195] Changelog entry update --- CHANGELOG-unreleased.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 991f5caad..366c272e0 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -12,5 +12,6 @@ the released changes. - Updated the `plot_priors` function in `plot_utils.py` and `plot_chains` function in `event_optimize` so that the subplots are a fixed size to prevent the subplots from being condensed in the case of many fit parameters. ### Added - Added an option `linearize_model` to speed up the photon phases calculation within `event_optimize` through the designmatrix. +- Added AIC and BIC calculation to be written in the post fit parfile from `event_optimize` ### Fixed ### Removed From 5813090dc86bb0d6e3fa37857711d9528c648236 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Thu, 24 Oct 2024 11:59:01 -0500 Subject: [PATCH 113/195] changelog --- CHANGELOG-unreleased.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 2899b99f8..0a3db3563 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -9,6 +9,9 @@ the released changes. ## Unreleased ### Changed +* Bump oldest python to 3.9 +* Change oldest dependencies: `numpy` 1.18.5 to 1.23.0; `astropy` 4.0 to 5.0.5; `scipy` 1.4.1 to 1.9.0; `matplotlib` 3.2.0 to 3.4.3 +* Update CI testing to use python 3.13 ### Added ### Fixed ### Removed From 8c8b1269ea2b6cf5f4b9da8e744fc4742eeb90d7 Mon Sep 17 00:00:00 2001 From: Paul Ray Date: Tue, 5 Nov 2024 10:40:11 -0500 Subject: [PATCH 114/195] Update CHANGELOG for version 1.1 --- CHANGELOG-unreleased.md | 3 --- CHANGELOG.md | 6 ++++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 0a3db3563..2899b99f8 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -9,9 +9,6 @@ the released changes. ## Unreleased ### Changed -* Bump oldest python to 3.9 -* Change oldest dependencies: `numpy` 1.18.5 to 1.23.0; `astropy` 4.0 to 5.0.5; `scipy` 1.4.1 to 1.9.0; `matplotlib` 3.2.0 to 3.4.3 -* Update CI testing to use python 3.13 ### Added ### Fixed ### Removed diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c905242f..3f24dffe3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project, at least loosely, adheres to [Semantic Versioning](https://sem This file contains the released changes to the codebase. See CHANGELOG-unreleased.md for the unreleased changes. This file should only be changed while tagging a new version. +## [1.1] 2024-11-05 +### Changed +* Bump oldest python to 3.9 +* Change oldest dependencies: `numpy` 1.18.5 to 1.23.0; `astropy` 4.0 to 5.0.5; `scipy` 1.4.1 to 1.9.0; `matplotlib` 3.2.0 to 3.4.3 +* Update CI testing to use python 3.13 + ## [1.0.2] 2024-10-18 ### Changed - Moved the events -> TOAs and photon weights code into the function `load_events_weights` within `event_optimize`. From b88b28edbdce0fda8b8e3f6e3698b32e082c2cf8 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 5 Nov 2024 14:03:45 -0600 Subject: [PATCH 115/195] add printing of parameters that need TCB->TDB scaling; make conversion from TNEQUAD to EQUAD free of scaling --- src/pint/models/noise_model.py | 1 + src/pint/models/parameter.py | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/pint/models/noise_model.py b/src/pint/models/noise_model.py index b53ebdb2d..b1af8e10f 100644 --- a/src/pint/models/noise_model.py +++ b/src/pint/models/noise_model.py @@ -122,6 +122,7 @@ def setup(self): index=tneq_par.index, aliases=["T2EQUAD"], description="An error term added in quadrature to the scaled (by EFAC) TOA uncertainty.", + convert_tcb2tdb=False, ) ) EQUAD_par = getattr(self, EQUAD_name) diff --git a/src/pint/models/parameter.py b/src/pint/models/parameter.py index ea92f4611..5e3d9e607 100644 --- a/src/pint/models/parameter.py +++ b/src/pint/models/parameter.py @@ -709,7 +709,7 @@ def __init__( assert ( not convert_tcb2tdb or tcb2tdb_scale_factor is not None - ), "Please specify the tcb2tdb_scale_factor explicitly." + ), f"Please specify the tcb2tdb_scale_factor explicitly for {name}." self.convert_tcb2tdb = convert_tcb2tdb self.tcb2tdb_scale_factor = tcb2tdb_scale_factor @@ -1133,7 +1133,7 @@ def __init__( assert ( not convert_tcb2tdb or tcb2tdb_scale_factor is not None - ), "Please specify the tcb2tdb_scale_factor explicitly." + ), f"Please specify the tcb2tdb_scale_factor explicitly for {name}." self.convert_tcb2tdb = convert_tcb2tdb self.tcb2tdb_scale_factor = tcb2tdb_scale_factor @@ -1334,7 +1334,7 @@ def __init__( assert ( not convert_tcb2tdb or tcb2tdb_scale_factor is not None - ), "Please specify the tcb2tdb_scale_factor explicitly." + ), f"Please specify the tcb2tdb_scale_factor explicitly for {name}." self.convert_tcb2tdb = convert_tcb2tdb self.tcb2tdb_scale_factor = tcb2tdb_scale_factor @@ -1554,7 +1554,7 @@ def __init__( # a function of the prefix. assert ( not convert_tcb2tdb or tcb2tdb_scale_factor is not None - ), "Please specify the tcb2tdb_scale_factor explicitly." + ), f"Please specify the tcb2tdb_scale_factor explicitly for {name}." tcb2tdb_scale_factor_val = ( tcb2tdb_scale_factor(self.prefix) if hasattr(tcb2tdb_scale_factor, "__call__") From d1c6b0be80e2375439774e5350ac1aa40d0dc120 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 5 Nov 2024 14:08:45 -0600 Subject: [PATCH 116/195] Revert "add printing of parameters that need TCB->TDB scaling; make conversion from TNEQUAD to EQUAD free of scaling" This reverts commit b88b28edbdce0fda8b8e3f6e3698b32e082c2cf8. --- src/pint/models/noise_model.py | 1 - src/pint/models/parameter.py | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/pint/models/noise_model.py b/src/pint/models/noise_model.py index b1af8e10f..b53ebdb2d 100644 --- a/src/pint/models/noise_model.py +++ b/src/pint/models/noise_model.py @@ -122,7 +122,6 @@ def setup(self): index=tneq_par.index, aliases=["T2EQUAD"], description="An error term added in quadrature to the scaled (by EFAC) TOA uncertainty.", - convert_tcb2tdb=False, ) ) EQUAD_par = getattr(self, EQUAD_name) diff --git a/src/pint/models/parameter.py b/src/pint/models/parameter.py index 5e3d9e607..ea92f4611 100644 --- a/src/pint/models/parameter.py +++ b/src/pint/models/parameter.py @@ -709,7 +709,7 @@ def __init__( assert ( not convert_tcb2tdb or tcb2tdb_scale_factor is not None - ), f"Please specify the tcb2tdb_scale_factor explicitly for {name}." + ), "Please specify the tcb2tdb_scale_factor explicitly." self.convert_tcb2tdb = convert_tcb2tdb self.tcb2tdb_scale_factor = tcb2tdb_scale_factor @@ -1133,7 +1133,7 @@ def __init__( assert ( not convert_tcb2tdb or tcb2tdb_scale_factor is not None - ), f"Please specify the tcb2tdb_scale_factor explicitly for {name}." + ), "Please specify the tcb2tdb_scale_factor explicitly." self.convert_tcb2tdb = convert_tcb2tdb self.tcb2tdb_scale_factor = tcb2tdb_scale_factor @@ -1334,7 +1334,7 @@ def __init__( assert ( not convert_tcb2tdb or tcb2tdb_scale_factor is not None - ), f"Please specify the tcb2tdb_scale_factor explicitly for {name}." + ), "Please specify the tcb2tdb_scale_factor explicitly." self.convert_tcb2tdb = convert_tcb2tdb self.tcb2tdb_scale_factor = tcb2tdb_scale_factor @@ -1554,7 +1554,7 @@ def __init__( # a function of the prefix. assert ( not convert_tcb2tdb or tcb2tdb_scale_factor is not None - ), f"Please specify the tcb2tdb_scale_factor explicitly for {name}." + ), "Please specify the tcb2tdb_scale_factor explicitly." tcb2tdb_scale_factor_val = ( tcb2tdb_scale_factor(self.prefix) if hasattr(tcb2tdb_scale_factor, "__call__") From 71bd859152ebb5aaca19cb91668987f56b23aa2d Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 5 Nov 2024 14:10:55 -0600 Subject: [PATCH 117/195] add printing of parameters that need TCB->TDB scaling; make conversion from TNEQUAD to EQUAD free of scaling --- src/pint/models/noise_model.py | 1 + src/pint/models/parameter.py | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/pint/models/noise_model.py b/src/pint/models/noise_model.py index b53ebdb2d..b1af8e10f 100644 --- a/src/pint/models/noise_model.py +++ b/src/pint/models/noise_model.py @@ -122,6 +122,7 @@ def setup(self): index=tneq_par.index, aliases=["T2EQUAD"], description="An error term added in quadrature to the scaled (by EFAC) TOA uncertainty.", + convert_tcb2tdb=False, ) ) EQUAD_par = getattr(self, EQUAD_name) diff --git a/src/pint/models/parameter.py b/src/pint/models/parameter.py index ea92f4611..5e3d9e607 100644 --- a/src/pint/models/parameter.py +++ b/src/pint/models/parameter.py @@ -709,7 +709,7 @@ def __init__( assert ( not convert_tcb2tdb or tcb2tdb_scale_factor is not None - ), "Please specify the tcb2tdb_scale_factor explicitly." + ), f"Please specify the tcb2tdb_scale_factor explicitly for {name}." self.convert_tcb2tdb = convert_tcb2tdb self.tcb2tdb_scale_factor = tcb2tdb_scale_factor @@ -1133,7 +1133,7 @@ def __init__( assert ( not convert_tcb2tdb or tcb2tdb_scale_factor is not None - ), "Please specify the tcb2tdb_scale_factor explicitly." + ), f"Please specify the tcb2tdb_scale_factor explicitly for {name}." self.convert_tcb2tdb = convert_tcb2tdb self.tcb2tdb_scale_factor = tcb2tdb_scale_factor @@ -1334,7 +1334,7 @@ def __init__( assert ( not convert_tcb2tdb or tcb2tdb_scale_factor is not None - ), "Please specify the tcb2tdb_scale_factor explicitly." + ), f"Please specify the tcb2tdb_scale_factor explicitly for {name}." self.convert_tcb2tdb = convert_tcb2tdb self.tcb2tdb_scale_factor = tcb2tdb_scale_factor @@ -1554,7 +1554,7 @@ def __init__( # a function of the prefix. assert ( not convert_tcb2tdb or tcb2tdb_scale_factor is not None - ), "Please specify the tcb2tdb_scale_factor explicitly." + ), f"Please specify the tcb2tdb_scale_factor explicitly for {name}." tcb2tdb_scale_factor_val = ( tcb2tdb_scale_factor(self.prefix) if hasattr(tcb2tdb_scale_factor, "__call__") From a88f15ade5bd19549d26034f17ade32c6a2557aa Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Wed, 6 Nov 2024 12:51:04 -0500 Subject: [PATCH 118/195] Provide physical formulas for magnetic field calculations. --- src/pint/derived_quantities.py | 70 +++++++++++++++++++++----------- tests/test_derived_quantities.py | 4 +- 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/src/pint/derived_quantities.py b/src/pint/derived_quantities.py index d5852ae4b..6cae3c39a 100644 --- a/src/pint/derived_quantities.py +++ b/src/pint/derived_quantities.py @@ -130,12 +130,22 @@ def pferrs( return [1.0 / porf, porferr / porf**2.0] forperr = porferr / porf**2.0 fdorpderr = np.sqrt( - (4.0 * pdorfd**2.0 * porferr**2.0) / porf**6.0 + pdorfderr**2.0 / porf**4.0 + (4.0 * pdorfd**2.0 * porferr**2.0) / porf**6.0 + + pdorfderr**2.0 / porf**4.0 ) [forp, fdorpd] = p_to_f(porf, pdorfd) return (forp, forperr, fdorpd, fdorpderr) +def _to_gauss(B: u.Quantity) -> u.G: + """Convert quantity with mass, length, and time units to Gauss. + + In cgs units, magnetic field is has units (mass/length)^(1/2) / time. + """ + eq = [u.Gauss, u.Hz * (u.g / u.cm) ** (1 / 2), lambda x: x, lambda x: x] + return B.to(u.Gauss, equivalencies=[eq]) + + @u.quantity_input(f=u.Hz, fdot=u.Hz / u.s, fo=u.Hz) def pulsar_age( f: u.Quantity, fdot: u.Quantity, n: int = 3, fo: u.Quantity = 1e99 * u.Hz @@ -219,12 +229,16 @@ def pulsar_edot( return (-4.0 * np.pi**2 * I * f * fdot).to(u.erg / u.s) -@u.quantity_input(f=u.Hz, fdot=u.Hz / u.s) -def pulsar_B(f: u.Quantity, fdot: u.Quantity) -> u.G: +@u.quantity_input(f=u.Hz, fdot=u.Hz / u.s, I=u.g * u.cm**2, R=u.km) +def pulsar_B( + f: u.Quantity, + fdot: u.Quantity, + I: u.Quantity = 1.0e45 * u.g * u.cm**2, + R: u.Quantity = 10 * u.km, +) -> u.G: r"""Compute pulsar surface magnetic field - Return the estimated pulsar surface magnetic field strength - given the spin frequency and frequency derivative. + Return the pulsar surface magnetic field strength given the spin frequency `f` and frequency derivative `fdot`. Parameters ---------- @@ -232,6 +246,10 @@ def pulsar_B(f: u.Quantity, fdot: u.Quantity) -> u.G: pulsar frequency fdot : astropy.units.Quantity frequency derivative :math:`\dot f` + I : astropy.units.Quantity, optional + pulsar moment of inertia, default of 1e45 g*cm**2 + R : astropy.units.Quantity, optional + pulsar radius, default of 10 km Returns ------- @@ -247,15 +265,19 @@ def pulsar_B(f: u.Quantity, fdot: u.Quantity) -> u.G: Notes ----- - Calculates :math:`B=3.2\times 10^{19}\,{\rm G}\sqrt{ f \dot f^{-3}}` + Calculates :math:`B=\sqrt{\frac{3\,I\,c^3}{8\pi^2\,R^6}\times\frac{-\dot{f}}{f^3}}` """ - # This is a hack to use the traditional formula by stripping the units. - # It would be nice to improve this to a proper formula with units - return 3.2e19 * u.G * np.sqrt(-fdot.to_value(u.Hz / u.s) / f.to_value(u.Hz) ** 3.0) + factor = (3.0 * I * const.c**3) / (8.0 * np.pi**2 * R**6) + return _to_gauss((factor * (-fdot) / f**3) ** 0.5) -@u.quantity_input(f=u.Hz, fdot=u.Hz / u.s) -def pulsar_B_lightcyl(f: u.Quantity, fdot: u.Quantity) -> u.G: +@u.quantity_input(f=u.Hz, fdot=u.Hz / u.s, I=u.g * u.cm**2, R=u.km) +def pulsar_B_lightcyl( + f: u.Quantity, + fdot: u.Quantity, + I: u.Quantity = 1.0e45 * u.g * u.cm**2, + R=10 * u.km, +) -> u.G: r"""Compute pulsar magnetic field at the light cylinder Return the estimated pulsar magnetic field strength at the @@ -268,6 +290,10 @@ def pulsar_B_lightcyl(f: u.Quantity, fdot: u.Quantity) -> u.G: pulsar frequency fdot : astropy.units.Quantity frequency derivative :math:`\dot f` + I : astropy.units.Quantity, optional + pulsar moment of inertia, default of 1e45 g*cm**2 + R : astropy.units.Quantity, optional + pulsar radius, default of 10 km Returns ------- @@ -283,17 +309,10 @@ def pulsar_B_lightcyl(f: u.Quantity, fdot: u.Quantity) -> u.G: Notes ----- - Calculates :math:`B_{LC} = 2.9\times 10^8\,{\rm G} P^{-5/2} \dot P^{1/2}` + Calculates :math:`B_{LC} = \sqrt{\frac{-24\pi^4\,I}{c^3}\dot{f}f^3}` """ - p, pd = p_to_f(f, fdot) - # This is a hack to use the traditional formula by stripping the units. - # It would be nice to improve this to a proper formula with units - return ( - 2.9e8 - * u.G - * p.to_value(u.s) ** (-5.0 / 2.0) - * np.sqrt(pd.to(u.dimensionless_unscaled).value) - ) + factor = 24.0 * np.pi**4.0 * I / const.c**3.0 + return _to_gauss((factor * (-fdot) * f**3.0) ** 0.5) @u.quantity_input(pb=u.d, x=u.cm) @@ -533,12 +552,17 @@ def companion_mass( # delta1 is always <0 # delta1 = 2 * b ** 3 - 9 * a * b * c + 27 * a ** 2 * d delta1 = ( - -2 * massfunct**3 - 18 * a * mp * massfunct**2 - 27 * a**2 * massfunct * mp**2 + -2 * massfunct**3 + - 18 * a * mp * massfunct**2 + - 27 * a**2 * massfunct * mp**2 ) # Q**2 is always > 0, so this is never a problem # in terms of complex numbers # Q = np.sqrt(delta1**2 - 4*delta0**3) - Q = np.sqrt(108 * a**3 * mp**3 * massfunct**3 + 729 * a**4 * mp**4 * massfunct**2) + Q = np.sqrt( + 108 * a**3 * mp**3 * massfunct**3 + + 729 * a**4 * mp**4 * massfunct**2 + ) # this could be + or - Q # pick the - branch since delta1 is <0 so that delta1 - Q is never near 0 Ccubed = 0.5 * (delta1 + Q) diff --git a/tests/test_derived_quantities.py b/tests/test_derived_quantities.py index cf5e845b0..833e98a86 100644 --- a/tests/test_derived_quantities.py +++ b/tests/test_derived_quantities.py @@ -67,7 +67,7 @@ def test_Edot(): def test_Bfield(): # B assert np.isclose( - pulsar_B(0.033 * u.Hz, -2.0e-15 * u.Hz / u.s), 238722891596281.66 * u.G + pulsar_B(0.033 * u.Hz, -2.0e-15 * u.Hz / u.s), 238693670891966.22 * u.G ) @@ -75,7 +75,7 @@ def test_Blc(): # B_lc assert np.isclose( pulsar_B_lightcyl(0.033 * u.Hz, -2.0e-15 * u.Hz / u.s), - 0.07774704753236616 * u.G, + 0.07896965114785195 * u.G, ) From bc3873d2fc85f6462bbf19beb9fc44ad9e939874 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Wed, 6 Nov 2024 12:17:57 -0600 Subject: [PATCH 119/195] changelog --- CHANGELOG-unreleased.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 2899b99f8..175886dcc 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -10,5 +10,7 @@ the released changes. ## Unreleased ### Changed ### Added +* When TCB->TDB conversion info is missing, will print parameter name ### Fixed +* When EQUAD is created from TNEQ, has proper TCB->TDB conversion info ### Removed From 4917a346644e88e127b101a08a528f1624d3d56d Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Mon, 11 Nov 2024 09:49:32 +0100 Subject: [PATCH 120/195] ne_sw derivatives --- src/pint/models/dispersion_model.py | 4 ++-- src/pint/models/solar_wind_dispersion.py | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/pint/models/dispersion_model.py b/src/pint/models/dispersion_model.py index 368392dd9..39a16f1c8 100644 --- a/src/pint/models/dispersion_model.py +++ b/src/pint/models/dispersion_model.py @@ -206,10 +206,10 @@ def validate(self): ) def DM_derivative_unit(self, n): - return "pc cm^-3/yr^%d" % n if n else "pc cm^-3" + return f"pc cm^-3/yr^{n}" if n != 0 else "pc cm^-3" def DM_derivative_description(self, n): - return "%d'th time derivative of the dispersion measure" % n + return f"{n}'th time derivative of the dispersion measure" def get_DM_terms(self): """Return a list of the DM term values in the model: [DM, DM1, ..., DMn]""" diff --git a/src/pint/models/solar_wind_dispersion.py b/src/pint/models/solar_wind_dispersion.py index dddaeb0f2..f82e8c9db 100644 --- a/src/pint/models/solar_wind_dispersion.py +++ b/src/pint/models/solar_wind_dispersion.py @@ -302,6 +302,17 @@ def __init__(self): tcb2tdb_scale_factor=(const.c * DMconst), ) ) + self.add_param( + floatParameter( + name="NE_SW1", + units="cm^-3", + value=0.0, + description="Derivative of Solar Wind density at 1 AU", + unit_template=self.NE_SW_derivative_unit, + description_template=self.NE_SW_derivative_description, + tcb2tdb_scale_factor=(const.c * DMconst), + ) + ) self.add_param( floatParameter( name="SWP", @@ -329,6 +340,12 @@ def setup(self): self.register_dm_deriv_funcs(self.d_dm_d_swp, "SWP") self.register_deriv_funcs(self.d_delay_d_swp, "SWP") + def NE_SW_derivative_unit(self, n): + return f"cm^-3/yr^{n}" if n != 0 else "cm^-3" + + def NE_SW_derivative_description(self, n): + return f"{n}'th time derivative of the Solar Wind density at 1 AU" + def solar_wind_geometry(self, toas): """Return the geometry of solar wind dispersion. From f61c0125991b1acccb7b9d6c4e8b5f12f347221f Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Mon, 11 Nov 2024 11:24:29 +0100 Subject: [PATCH 121/195] solar_wind_dispersion --- src/pint/models/dispersion_model.py | 6 +- src/pint/models/solar_wind_dispersion.py | 92 +++++++++++++++++++----- 2 files changed, 79 insertions(+), 19 deletions(-) diff --git a/src/pint/models/dispersion_model.py b/src/pint/models/dispersion_model.py index 39a16f1c8..e417b2be6 100644 --- a/src/pint/models/dispersion_model.py +++ b/src/pint/models/dispersion_model.py @@ -183,8 +183,8 @@ def __init__(self): def setup(self): super().setup() - base_dms = list(self.get_prefix_mapping_component("DM").values()) - base_dms += ["DM"] + + base_dms = ["DM"] + list(self.get_prefix_mapping_component("DM").values()) for dm_name in base_dms: self.register_deriv_funcs(self.d_delay_d_dmparam, dm_name) @@ -223,7 +223,7 @@ def base_dm(self, toas): if DMEPOCH is None: # Should be ruled out by validate() raise ValueError( - f"DMEPOCH not set but some derivatives are not zero: {dm_terms}" + f"DMEPOCH not set but some DM derivatives are not zero: {dm_terms}" ) else: dt = (toas["tdbld"] - DMEPOCH) * u.day diff --git a/src/pint/models/solar_wind_dispersion.py b/src/pint/models/solar_wind_dispersion.py index f82e8c9db..abdd3d16f 100644 --- a/src/pint/models/solar_wind_dispersion.py +++ b/src/pint/models/solar_wind_dispersion.py @@ -10,7 +10,12 @@ from pint import DMconst from pint.models.dispersion_model import Dispersion -from pint.models.parameter import floatParameter, intParameter, prefixParameter +from pint.models.parameter import ( + MJDParameter, + floatParameter, + intParameter, + prefixParameter, +) import pint.utils from pint.models.timing_model import MissingTOAs from pint.toa_select import TOASelect @@ -313,6 +318,14 @@ def __init__(self): tcb2tdb_scale_factor=(const.c * DMconst), ) ) + self.add_param( + MJDParameter( + name="SWEPOCH", + description="Epoch of NE_SW measurement", + time_scale="tdb", + tcb2tdb_scale_factor=u.Quantity(1), + ) + ) self.add_param( floatParameter( name="SWP", @@ -335,11 +348,18 @@ def __init__(self): def setup(self): super().setup() - self.register_dm_deriv_funcs(self.d_dm_d_ne_sw, "NE_SW") - self.register_deriv_funcs(self.d_delay_d_ne_sw, "NE_SW") + self.register_dm_deriv_funcs(self.d_dm_d_swp, "SWP") self.register_deriv_funcs(self.d_delay_d_swp, "SWP") + base_nesws = ["NE_SW"] + list( + self.get_prefix_mapping_component("NE_SW").values() + ) + + for nesw_name in base_nesws: + self.register_deriv_funcs(self.d_delay_d_ne_sw, nesw_name) + self.register_dm_deriv_funcs(self.d_dm_d_ne_sw, nesw_name) + def NE_SW_derivative_unit(self, n): return f"cm^-3/yr^{n}" if n != 0 else "cm^-3" @@ -392,22 +412,46 @@ def solar_wind_dm(self, toas): SWM==1: Hazboun et al. 2022 """ - if self.NE_SW.value == 0: + ne_sw_terms = self.get_NE_SW_terms() + + if any(t.value != 0 for t in ne_sw_terms[1:]): + SWEPOCH = self.SWEPOCH.value + if SWEPOCH is None: + # Should be ruled out by validate() + raise ValueError( + f"SWEPOCH not set but some NE_SW derivatives are not zero: {ne_sw_terms}" + ) + else: + dt = (toas["tdbld"] - SWEPOCH) * u.day + dt_value = dt.to_value(u.yr) + else: + dt_value = np.zeros(len(toas), dtype=np.longdouble) + + ne_sw_terms_value = [d.value for d in ne_sw_terms] + ne_sw = pint.utils.taylor_horner(dt_value, ne_sw_terms_value) * self.NE_SW.units + + if np.all(ne_sw.value == 0): return np.zeros(len(toas)) * u.pc / u.cm**3 + if self.SWM.value not in [0, 1]: raise NotImplementedError( f"Solar Dispersion Delay not implemented for SWM {self.SWM.value}" ) + solar_wind_geometry = self.solar_wind_geometry(toas) - solar_wind_dm = self.NE_SW.quantity * solar_wind_geometry + solar_wind_dm = ne_sw * solar_wind_geometry return solar_wind_dm.to(u.pc / u.cm**3) def solar_wind_delay(self, toas, acc_delay=None): """This is a wrapper function to compute solar wind dispersion delay.""" - if self.NE_SW.value == 0: - return np.zeros(len(toas)) * u.s return self.dispersion_type_delay(toas) + def get_NE_SW_terms(self): + """Return a list of the NE_SW term values in the model: [NE_SW, NE_SW1, ..., NE_SWn]""" + return [self.NE_SW.quantity] + self._parent.get_prefix_list( + "NE_SW", start_index=1 + ) + def d_dm_d_ne_sw(self, toas, param_name, acc_delay=None): """Derivative of of DM wrt the solar wind ne amplitude.""" if self.SWM.value in [0, 1]: @@ -416,17 +460,33 @@ def d_dm_d_ne_sw(self, toas, param_name, acc_delay=None): raise NotImplementedError( "Solar Dispersion Delay not implemented for SWM %d" % self.SWM.value ) - return solar_wind_geometry + + par = getattr(self, param_name) + order = 0 if param_name == "DM" else par.index + + ne_sws = self.get_NE_SW_terms() + + dm_terms = np.longdouble(np.zeros(len(ne_sws))) + dm_terms[order] = np.longdouble(1.0) + + if self.SWEPOCH.value is None: + if any(t.value != 0 for t in ne_sws[1:]): + # Should be ruled out by validate() + raise ValueError(f"SWEPOCH is not set but {param_name} is not zero") + SWEPOCH = 0 + else: + SWEPOCH = self.DMEPOCH.value + + dt = (toas["tdbld"] - SWEPOCH) * u.day + dt_value = (dt.to(u.yr)).value + return ( + solar_wind_geometry + * pint.utils.taylor_horner(dt_value, dm_terms) + * (u.pc / u.cm**3 / par.units) + ) def d_delay_d_ne_sw(self, toas, param_name, acc_delay=None): - try: - bfreq = self._parent.barycentric_radio_freq(toas) - except AttributeError: - warn("Using topocentric frequency for dedispersion!") - bfreq = toas.table["freq"] - deriv = self.d_delay_d_dmparam(toas, "NE_SW") - deriv[bfreq < 1.0 * u.MHz] = 0.0 - return deriv + return self.d_delay_d_dmparam(toas, "NE_SW") def d_solar_wind_geometry_d_swp(self, toas, param_name, acc_delay=None): """Derivative of solar_wind_geometry (path length) wrt power-law index p From 227d76881d7a75be70fdd65b966ae3afd760812f Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Mon, 11 Nov 2024 14:18:38 +0100 Subject: [PATCH 122/195] fix solar_wind_dispersion --- src/pint/models/solar_wind_dispersion.py | 33 ++++++++++++------------ src/pint/utils.py | 2 +- tests/test_solar_wind.py | 26 +++++++++++++++++++ 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/src/pint/models/solar_wind_dispersion.py b/src/pint/models/solar_wind_dispersion.py index abdd3d16f..12bf8d58c 100644 --- a/src/pint/models/solar_wind_dispersion.py +++ b/src/pint/models/solar_wind_dispersion.py @@ -308,13 +308,14 @@ def __init__(self): ) ) self.add_param( - floatParameter( + prefixParameter( name="NE_SW1", - units="cm^-3", + units="cm^-3 / yr", value=0.0, description="Derivative of Solar Wind density at 1 AU", unit_template=self.NE_SW_derivative_unit, description_template=self.NE_SW_derivative_description, + type_match="float", tcb2tdb_scale_factor=(const.c * DMconst), ) ) @@ -462,12 +463,12 @@ def d_dm_d_ne_sw(self, toas, param_name, acc_delay=None): ) par = getattr(self, param_name) - order = 0 if param_name == "DM" else par.index + order = 0 if param_name == "NE_SW" else par.index ne_sws = self.get_NE_SW_terms() - dm_terms = np.longdouble(np.zeros(len(ne_sws))) - dm_terms[order] = np.longdouble(1.0) + ne_sw_terms = np.longdouble(np.zeros(len(ne_sws))) + ne_sw_terms[order] = np.longdouble(1.0) if self.SWEPOCH.value is None: if any(t.value != 0 for t in ne_sws[1:]): @@ -475,18 +476,16 @@ def d_dm_d_ne_sw(self, toas, param_name, acc_delay=None): raise ValueError(f"SWEPOCH is not set but {param_name} is not zero") SWEPOCH = 0 else: - SWEPOCH = self.DMEPOCH.value + SWEPOCH = self.SWEPOCH.value dt = (toas["tdbld"] - SWEPOCH) * u.day - dt_value = (dt.to(u.yr)).value - return ( - solar_wind_geometry - * pint.utils.taylor_horner(dt_value, dm_terms) - * (u.pc / u.cm**3 / par.units) + + return (solar_wind_geometry * dt**order / scipy.special.factorial(order)).to( + u.pc / u.cm**3 / par.units ) def d_delay_d_ne_sw(self, toas, param_name, acc_delay=None): - return self.d_delay_d_dmparam(toas, "NE_SW") + return self.d_delay_d_dmparam(toas, param_name) def d_solar_wind_geometry_d_swp(self, toas, param_name, acc_delay=None): """Derivative of solar_wind_geometry (path length) wrt power-law index p @@ -529,10 +528,12 @@ def d_delay_d_swp(self, toas, param_name, acc_delay=None): def print_par(self, format="pint"): result = "" - result += getattr(self, "NE_SW").as_parfile_line(format=format) - result += getattr(self, "SWM").as_parfile_line(format=format) - if self.SWM.value == 1: - result += getattr(self, "SWP").as_parfile_line(format=format) + for par in self.params: + if par == "SWP" and self.SWM.value != 1: + continue + else: + result += getattr(self, par).as_parfile_line(format=format) + return result def get_max_dm(self): diff --git a/src/pint/utils.py b/src/pint/utils.py index da23092fc..c1fc82e13 100644 --- a/src/pint/utils.py +++ b/src/pint/utils.py @@ -357,7 +357,7 @@ def has_astropy_unit(x: Any) -> bool: re.compile(r"^([a-zA-Z]*\d+[a-zA-Z]+)(\d+)$"), # For the prefix like T2EFAC2 re.compile(r"^([a-zA-Z]+)0*(\d+)$"), # For the prefix like F12 re.compile(r"^([a-zA-Z0-9]+_)(\d+)$"), # For the prefix like DMXR1_3 - # re.compile(r'([a-zA-Z]\d[a-zA-Z]+)(\d+)'), # for prefixes like PLANET_SHAPIRO2? + re.compile(r"([a-zA-Z]+_[a-zA-Z]+)(\d+)$"), # for prefixes like NE_SW2? ] diff --git a/tests/test_solar_wind.py b/tests/test_solar_wind.py index bfa8e0eea..b847d513e 100644 --- a/tests/test_solar_wind.py +++ b/tests/test_solar_wind.py @@ -359,3 +359,29 @@ def test_overlapping_swx(): dm3 = model3.components["SolarWindDispersionX"].swx_dm(toas) dm3[toas.get_mjds() >= 54180 * u.d] = 0 assert np.allclose(dm2 - dm, dm3) + + +def test_nesw_derivatives(): + par = """ + PSRJ J1744-1134 + ELONG 266.119458498 6.000e-09 + ELAT 11.80517508 3.000e-08 + DM 3.1379 4.000e-04 + PEPOCH 55000 + F0 245.4261196898081 5.000e-13 + F1 -5.38156E-16 3.000e-21 + PMRA 18.806 2.000e-03 + PMDEC -9.386 1.000e-02 + POSEPOCH 59150 + DMEPOCH 55000 + CLK TT(BIPM2018) + EPHEM DE436 + RM 1.62 9.000e-02 + PX 2.61 9.000e-02 + DM1 -7.0E-5 3.000e-05 + PMELONG 19.11 2.000e-02 + DM2 1.7E-5 4.000e-06 + PMELAT -9.21 1.300e-01 + UNITS TDB + NE_SW + """ From 60bfa50f03569dd6630226535884f0aaa0841251 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Mon, 11 Nov 2024 14:21:28 +0100 Subject: [PATCH 123/195] CHANGELOG --- CHANGELOG-unreleased.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 2899b99f8..a99f78e4d 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -10,5 +10,7 @@ the released changes. ## Unreleased ### Changed ### Added +- Derivatives of NE_SW in `SolarWindDispersion` +- New prefix pattern for `split_prefixed_name` to handle derivatives of NE_SW ### Fixed ### Removed From 90af831d0034fb643d63ac0af50a7f2c993cc65e Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Mon, 11 Nov 2024 14:28:04 +0100 Subject: [PATCH 124/195] test_nesw_derivatives --- tests/test_solar_wind.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/tests/test_solar_wind.py b/tests/test_solar_wind.py index b847d513e..b9dba12ce 100644 --- a/tests/test_solar_wind.py +++ b/tests/test_solar_wind.py @@ -370,8 +370,6 @@ def test_nesw_derivatives(): PEPOCH 55000 F0 245.4261196898081 5.000e-13 F1 -5.38156E-16 3.000e-21 - PMRA 18.806 2.000e-03 - PMDEC -9.386 1.000e-02 POSEPOCH 59150 DMEPOCH 55000 CLK TT(BIPM2018) @@ -383,5 +381,22 @@ def test_nesw_derivatives(): DM2 1.7E-5 4.000e-06 PMELAT -9.21 1.300e-01 UNITS TDB - NE_SW + NE_SW 8 1 + NE_SW1 0 1 + NE_SW2 0 1 + SWEPOCH 55000 """ + m = get_model(StringIO(par)) + t = make_fake_toas_uniform(54500, 55500, 1000, m, add_noise=True) + ftr = Fitter.auto(t, m) + ftr.fit_toas() + + assert ( + m.NE_SW.value - ftr.model.NE_SW.value + ) / ftr.model.NE_SW.uncertainty_value < 3 + assert ( + m.NE_SW1.value - ftr.model.NE_SW1.value + ) / ftr.model.NE_SW1.uncertainty_value < 3 + assert ( + m.NE_SW2.value - ftr.model.NE_SW2.value + ) / ftr.model.NE_SW2.uncertainty_value < 3 From 75eb2c8f9470d06ebc71974b33a4d32bc9d33b6a Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Mon, 11 Nov 2024 14:33:56 +0100 Subject: [PATCH 125/195] update black --- .pre-commit-config.yaml | 2 +- requirements_dev.txt | 3 +-- tox.ini | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6c2c4b8cc..82fcce346 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,6 +6,6 @@ repos: - id: check-merge-conflict - id: check-symlinks - repo: https://github.com/psf/black - rev: 24.2.0 + rev: 24.10.0 hooks: - id: black diff --git a/requirements_dev.txt b/requirements_dev.txt index c4fba2da1..f5dfff94b 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -28,8 +28,7 @@ pdbpp tox pre-commit typed-ast>=1.5.0 -#black>=19.0a0,<20.0a0 -black~=23.0 +black~=24.0 pygments ipython pathlib2 diff --git a/tox.ini b/tox.ini index efadd9b9c..1fcb0003b 100644 --- a/tox.ini +++ b/tox.ini @@ -12,7 +12,7 @@ envlist = docs report codestyle - black + black~=24.0 singletest py{38,39,310,311,312,313}-test{,-alldeps,-devdeps}{,-cov} @@ -114,7 +114,7 @@ deps = nbconvert pytest jupytext - black + black~=24.0 setuptools commands = jupytext --sync examples/*.py @@ -141,7 +141,7 @@ deps = nbconvert pytest jupytext - black + black~=24.0 setuptools commands = sphinx-build -d "{toxworkdir}/docs_doctree" . "{toxworkdir}/docs_out" --color -bhtml {posargs} python -c 'import pathlib; print("documentation available under file://\{0\}".format(pathlib.Path(r"{toxworkdir}") / "docs_out" / "index.html"))' From ac14c917600bbbc5c170add84a46ca30aeecd32c Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Mon, 11 Nov 2024 14:36:30 +0100 Subject: [PATCH 126/195] tox.ini --- tox.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tox.ini b/tox.ini index 1fcb0003b..d00727885 100644 --- a/tox.ini +++ b/tox.ini @@ -12,7 +12,7 @@ envlist = docs report codestyle - black~=24.0 + black singletest py{38,39,310,311,312,313}-test{,-alldeps,-devdeps}{,-cov} @@ -114,7 +114,7 @@ deps = nbconvert pytest jupytext - black~=24.0 + black setuptools commands = jupytext --sync examples/*.py @@ -141,7 +141,7 @@ deps = nbconvert pytest jupytext - black~=24.0 + black setuptools commands = sphinx-build -d "{toxworkdir}/docs_doctree" . "{toxworkdir}/docs_out" --color -bhtml {posargs} python -c 'import pathlib; print("documentation available under file://\{0\}".format(pathlib.Path(r"{toxworkdir}") / "docs_out" / "index.html"))' @@ -151,7 +151,7 @@ skip_install = true changedir = . description = use black deps = - black~=24.0 + black commands = black --check src tests examples From 2487924e0b4dee89cf38f2ea2c7d309221a1273b Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Mon, 11 Nov 2024 14:38:29 +0100 Subject: [PATCH 127/195] tox.ini --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index d00727885..efadd9b9c 100644 --- a/tox.ini +++ b/tox.ini @@ -151,7 +151,7 @@ skip_install = true changedir = . description = use black deps = - black + black~=24.0 commands = black --check src tests examples From d6c4d5516bf6c3315bce4efa4dfbaba40458aa44 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Mon, 11 Nov 2024 15:22:43 +0100 Subject: [PATCH 128/195] dispersion_model --- src/pint/models/dispersion_model.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pint/models/dispersion_model.py b/src/pint/models/dispersion_model.py index e417b2be6..5dd7c11cf 100644 --- a/src/pint/models/dispersion_model.py +++ b/src/pint/models/dispersion_model.py @@ -21,7 +21,7 @@ taylor_horner, taylor_horner_deriv, ) -from pint import DMconst +from pint import DMconst, dmu from pint.exceptions import MissingParameter, MissingTOAs # This value is cited from Duncan Lorimer, Michael Kramer, Handbook of Pulsar @@ -76,7 +76,7 @@ def dm_value(self, toas): DM values at given TOAs in the unit of DM. """ toas_table = toas if isinstance(toas, Table) else toas.table - dm = np.zeros(len(toas_table)) * self._parent.DM.units + dm = np.zeros(len(toas_table)) * dmu for dm_f in self.dm_value_funcs: dm += dm_f(toas) @@ -673,7 +673,7 @@ def dmx_dm(self, toas): condition, tbl["mjd_float"] ) # Get DMX delays - dm = np.zeros(len(tbl)) * self._parent.DM.units + dm = np.zeros(len(tbl)) * dmu for k, v in select_idx.items(): dm[v] += getattr(self, k).quantity return dm From e55903551c397c9fe1bc7a01ffc3edd05747ded7 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 11 Nov 2024 09:11:48 -0600 Subject: [PATCH 129/195] fixed changelog --- CHANGELOG-unreleased.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 175886dcc..d15e5e781 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -10,7 +10,7 @@ the released changes. ## Unreleased ### Changed ### Added -* When TCB->TDB conversion info is missing, will print parameter name +- When TCB->TDB conversion info is missing, will print parameter name ### Fixed -* When EQUAD is created from TNEQ, has proper TCB->TDB conversion info +- When EQUAD is created from TNEQ, has proper TCB->TDB conversion info ### Removed From 73732784fcf618c449800fb774ac1b4105e304e2 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Wed, 13 Nov 2024 10:13:59 +0100 Subject: [PATCH 130/195] docs --- src/pint/models/chromatic_model.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/pint/models/chromatic_model.py b/src/pint/models/chromatic_model.py index 5b6b5f298..52592bb14 100644 --- a/src/pint/models/chromatic_model.py +++ b/src/pint/models/chromatic_model.py @@ -15,7 +15,7 @@ class Chromatic(DelayComponent): - """A base chromatic timing model.""" + """A base chromatic timing model with a constant chromatic index.""" def __init__(self): super().__init__() @@ -114,11 +114,14 @@ def register_cm_deriv_funcs(self, func, param): class ChromaticCM(Chromatic): - """Simple chromatic delay model. + """Simple chromatic delay model with a constant chromatic index. This model uses Taylor expansion to model CM variation over time. It can also be used for a constant CM. + Fitting for the chromatic index is not supported because the fit is too + unstable when fit simultaneously with the DM. + Parameters supported: .. paramtable:: @@ -306,10 +309,13 @@ def change_cmepoch(self, new_epoch): class ChromaticCMX(Chromatic): - """This class provides a CMX model - piecewise-constant chromatic variations. + """This class provides a CMX model - piecewise-constant chromatic variations with constant + chromatic index. + + This model lets the user specify time ranges and fit for a different CMX value in each time range. - This model lets the user specify time ranges and fit for a different - CMX value in each time range. + It should be used in combination with the `ChromaticCM` model. Specifically, TNCHROMIDX must be + set. Parameters supported: From 3c91b51caf6247e13e962a35b69abafb6eadee9e Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Wed, 13 Nov 2024 10:36:03 +0100 Subject: [PATCH 131/195] test_cmx --- src/pint/models/__init__.py | 2 +- src/pint/models/chromatic_model.py | 2 +- tests/test_cmx.py | 77 ++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 tests/test_cmx.py diff --git a/src/pint/models/__init__.py b/src/pint/models/__init__.py index 67201a259..27c78a4f4 100644 --- a/src/pint/models/__init__.py +++ b/src/pint/models/__init__.py @@ -25,7 +25,7 @@ from pint.models.binary_dd import BinaryDD, BinaryDDS, BinaryDDGR, BinaryDDH from pint.models.binary_ddk import BinaryDDK from pint.models.binary_ell1 import BinaryELL1, BinaryELL1H, BinaryELL1k -from pint.models.chromatic_model import ChromaticCM +from pint.models.chromatic_model import ChromaticCM, ChromaticCMX from pint.models.cmwavex import CMWaveX from pint.models.dispersion_model import ( DispersionDM, diff --git a/src/pint/models/chromatic_model.py b/src/pint/models/chromatic_model.py index 52592bb14..8f9dcb815 100644 --- a/src/pint/models/chromatic_model.py +++ b/src/pint/models/chromatic_model.py @@ -672,7 +672,7 @@ def cmx_cm(self, toas): def CMX_chromatic_delay(self, toas, acc_delay=None): """This is a wrapper function for interacting with the TimingModel class""" - return self.dispersion_type_delay(toas) + return self.chromatic_type_delay(toas) def d_cm_d_CMX(self, toas, param_name, acc_delay=None): condition = {} diff --git a/tests/test_cmx.py b/tests/test_cmx.py new file mode 100644 index 000000000..b92b68dd8 --- /dev/null +++ b/tests/test_cmx.py @@ -0,0 +1,77 @@ +from io import StringIO +from pint.models import get_model +from pint.simulation import make_fake_toas_uniform +from pint.fitter import Fitter + +import pytest +import numpy as np +import astropy.units as u + + +@pytest.fixture +def model_and_toas(): + par = """ + RAJ 05:00:00 + DECJ 12:00:00 + F0 101.0 + F1 -1.1e-14 + PEPOCH 55000 + DM 12 + DMEPOCH 55000 + CMEPOCH 55000 + CM 3.5 + TNCHROMIDX 4.0 + EPHEM DE440 + CLOCK TT(BIPM2021) + UNITS TDB + TZRMJD 55000 + TZRFRQ 1400 + TZRSITE gmrt + CMXR1_0001 53999.9 + CMXR2_0001 54500 + CMX_0001 0.5 1 + CMXR1_0002 54500.1 + CMXR2_0002 55000 + CMX_0002 -0.5 1 + CMXR1_0003 55000.1 + CMXR2_0003 55500 + CMX_0003 -0.1 1 + """ + + model = get_model(StringIO(par)) + + freqs = np.linspace(300, 1600, 16) * u.MHz + toas = make_fake_toas_uniform( + startMJD=54000, + endMJD=55500, + ntoas=2000, + model=model, + freq=freqs, + add_noise=True, + obs="gmrt", + include_bipm=True, + multi_freqs_in_epoch=True, + ) + + return model, toas + + +def test_cmx(model_and_toas): + model, toas = model_and_toas + + assert "ChromaticCMX" in model.components + + ftr = Fitter.auto(toas, model) + ftr.fit_toas() + + assert np.abs(model.CMX_0001.value - ftr.model.CMX_0001.value) / ( + 3 * ftr.model.CMX_0001.uncertainty_value + ) + assert np.abs(model.CMX_0002.value - ftr.model.CMX_0002.value) / ( + 3 * ftr.model.CMX_0002.uncertainty_value + ) + assert np.abs(model.CMX_0003.value - ftr.model.CMX_0003.value) / ( + 3 * ftr.model.CMX_0003.uncertainty_value + ) + + assert ftr.resids.chi2_reduced < 1.6 From 4cab923a4cfa81590b48188ae2af348c24afded5 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Wed, 13 Nov 2024 10:39:30 +0100 Subject: [PATCH 132/195] test --- src/pint/models/chromatic_model.py | 1 - tests/test_cmx.py | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pint/models/chromatic_model.py b/src/pint/models/chromatic_model.py index 8f9dcb815..d745729ce 100644 --- a/src/pint/models/chromatic_model.py +++ b/src/pint/models/chromatic_model.py @@ -705,7 +705,6 @@ def print_par(self, format="pint"): CMX_mapping = self.get_prefix_mapping_component("CMX_") CMXR1_mapping = self.get_prefix_mapping_component("CMXR1_") CMXR2_mapping = self.get_prefix_mapping_component("CMXR2_") - result += getattr(self, "CMX").as_parfile_line(format=format) sorted_list = sorted(CMX_mapping.keys()) for ii in sorted_list: result += getattr(self, CMX_mapping[ii]).as_parfile_line(format=format) diff --git a/tests/test_cmx.py b/tests/test_cmx.py index b92b68dd8..f62563840 100644 --- a/tests/test_cmx.py +++ b/tests/test_cmx.py @@ -75,3 +75,5 @@ def test_cmx(model_and_toas): ) assert ftr.resids.chi2_reduced < 1.6 + + assert "CMX_0001" in str(ftr.model) From 85b27a22fab1584099361b74f57828058fa44be8 Mon Sep 17 00:00:00 2001 From: Deven Bhakta Date: Thu, 14 Nov 2024 10:39:34 -0500 Subject: [PATCH 133/195] Revert plot_priors change --- CHANGELOG-unreleased.md | 2 +- src/pint/plot_utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index f5892a3f9..09561bfca 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -9,7 +9,7 @@ the released changes. ## Unreleased ### Changed -- Updated the `plot_priors` function in `plot_utils.py` and `plot_chains` function in `event_optimize` so that the subplots are a fixed size to prevent the subplots from being condensed in the case of many fit parameters. +- Updated the `plot_chains` function in `event_optimize` so that the subplots are a fixed size to prevent the subplots from being condensed in the case of many fit parameters. ### Added - Added an option `linearize_model` to speed up the photon phases calculation within `event_optimize` through the designmatrix. - Added AIC and BIC calculation to be written in the post fit parfile from `event_optimize` diff --git a/src/pint/plot_utils.py b/src/pint/plot_utils.py index 917412b71..289655f6d 100644 --- a/src/pint/plot_utils.py +++ b/src/pint/plot_utils.py @@ -279,7 +279,7 @@ def plot_priors( for i in range(len(keys[:-1])): values[i] = values[i][burnin:].flatten() x_range.append(np.linspace(values[i].min(), values[i].max(), num=bins)) - priors.append(getattr(model, keys[i]).prior.logpdf(x_range[i])) + priors.append(getattr(model, keys[i]).prior.pdf(x_range[i])) a, x = np.histogram(values[i], bins=bins, density=True) counts.append(a) From dbdef6d25a54e932281f0edd7862120d1e19b9ed Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Thu, 14 Nov 2024 10:45:49 -0500 Subject: [PATCH 134/195] Fix units on WAVE_OM. --- src/pint/models/wave.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/pint/models/wave.py b/src/pint/models/wave.py index 8a902a5ca..64e6da264 100644 --- a/src/pint/models/wave.py +++ b/src/pint/models/wave.py @@ -15,9 +15,8 @@ class Wave(PhaseComponent): sine/cosine components. For consistency with the implementation in tempo2, this signal is treated - as a time series, but trivially converted into phase by multiplication by - F0, which could makes changes to PEPOCH fragile if there is strong spin - frequency evolution. + as a time series and trivially converted into phase by multiplication by + F0. Parameters supported: @@ -42,7 +41,7 @@ def __init__(self): floatParameter( name="WAVE_OM", description="Base frequency of wave solution", - units="1/d", + units="rad/d", convert_tcb2tdb=False, ) ) From e5ce925376eeef08e3054047724bedf18321ae70 Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Thu, 14 Nov 2024 10:46:08 -0500 Subject: [PATCH 135/195] Add explicit test for WAVE calculation. --- tests/test_model_wave.py | 85 ++++++++++++++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 16 deletions(-) diff --git a/tests/test_model_wave.py b/tests/test_model_wave.py index 1e57d640f..ab1707088 100644 --- a/tests/test_model_wave.py +++ b/tests/test_model_wave.py @@ -1,28 +1,81 @@ +from io import StringIO import os import pytest import astropy.units as u +import numpy as np -import pint.fitter -import pint.models +from pint.models import get_model +from pint import toa import pint.residuals -import pint.toa from pinttestdata import datadir -# Not included in the test here, but as a sanity check I used this same -# ephemeris to phase up Fermi data, and it looks good. +par_nowave = """ + PSRJ J0835-4510 + RAJ 08:35:20.61149 + DECJ -45:10:34.8751 + F0 11.18965156782 + PEPOCH 55305 + DM 67.99 + UNITS TDB +""" -parfile = os.path.join(datadir, "vela_wave.par") -timfile = os.path.join(datadir, "vela_wave.tim") +wave_terms = """ + WAVEEPOCH 55305 + WAVE_OM 0.0015182579855022 + WAVE1 -0.21573979911255 -0.049063841960712 + WAVE2 0.62795320246729 -0.11984954655989 + WAVE3 0.099618608456845 0.28530756908788 + WAVE4 -0.21537340649058 0.18849486610628 + WAVE5 0.021980474493165 -0.23566696662127 +""" -class TestWave: - @classmethod - def setup_class(cls): - cls.m = pint.models.get_model(parfile) - cls.t = pint.toa.get_TOAs(timfile, ephem="DE405", include_bipm=False) +def test_wave_ephem(): + parfile = os.path.join(datadir, "vela_wave.par") + timfile = os.path.join(datadir, "vela_wave.tim") + m = get_model(parfile) + t = toa.get_TOAs(timfile, ephem="DE405", include_bipm=False) + rs = pint.residuals.Residuals(t, m).time_resids + assert rs.std() < 350.0 * u.us - def test_vela_rms_is_small_enough(self): - rs = pint.residuals.Residuals(self.t, self.m).time_resids - rms = rs.to(u.us).std() - assert rms < 350.0 * u.us + +def test_wave_construction(): + m = get_model(StringIO(par_nowave + wave_terms)) + assert np.allclose(m.WAVE_OM.quantity, 0.0015182579855022 * u.rad / u.day) + assert np.allclose(m.WAVE1.quantity[0], -0.21573979911255 * u.s) + assert np.allclose(m.WAVE2.quantity[1], -0.1198495465598 * u.s) + + +def test_wave_computation(): + m0 = get_model(StringIO(par_nowave)) + m1 = get_model(StringIO(par_nowave + wave_terms)) + # make some barycentric TOAs + tdbs = np.linspace(54500, 60000, 10) + ts = toa.TOAs( + toalist=[ + toa.TOA(t, obs="@", freq=np.inf, error=1 * u.ms, scale="tdb") for t in tdbs + ] + ) + ts.compute_TDBs(ephem="DE421") + ts.compute_posvels(ephem="DE421") + ph0 = m0.phase(ts) + ph1 = m1.phase(ts) + dphi = (ph1.int - ph0.int) + (ph1.frac - ph0.frac) + test_phase = np.zeros(len(tdbs)) + WAVEEPOCH = 55305 + WAVE_OM = 0.0015182579855022 + WAVE = [ + [-0.21573979911255, -0.049063841960712], + [0.62795320246729, -0.11984954655989], + [0.099618608456845, 0.28530756908788], + [-0.21537340649058, 0.18849486610628], + [0.021980474493165, -0.23566696662127], + ] + ph = (tdbs - WAVEEPOCH) * WAVE_OM + for i in range(5): + test_phase += WAVE[i][0] * np.sin((i + 1) * ph) + WAVE[i][1] * np.cos( + (i + 1) * ph + ) + test_phase *= m0.F0.quantity.to(u.Hz).value + assert np.allclose(test_phase, dphi) From 4b2c184a3c0e44eaf05dc7003f3262ae3e27e2b3 Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Thu, 14 Nov 2024 10:46:27 -0500 Subject: [PATCH 136/195] Remove extraneous JUMPs from test .par file. --- tests/datafile/vela_wave.par | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/tests/datafile/vela_wave.par b/tests/datafile/vela_wave.par index e8aba5a4c..889361b01 100644 --- a/tests/datafile/vela_wave.par +++ b/tests/datafile/vela_wave.par @@ -28,45 +28,18 @@ TZRMJD 55896.55312516020475 TZRFRQ 1370.2919919999999365 TZRSITE pks TRES 310.453 -EPHVER 2 CLK TT(TAI) MODE 1 UNITS TDB TIMEEPH FB90 DILATEFREQ N PLANET_SHAPIRO N -T2CMETHOD TEMPO NE_SW 9.961 CORRECT_TROPOSPHERE N EPHEM DE405 NITS 1 NTOA 339 CHI2R 328088.1294 298 -JUMP -B 20CM 0 0 -JUMP -B 40CM 0 0 -JUMP -B 50CM 0 0 -JUMP -dfb3_J0437_55319_56160 1 2.2e-07 0 -JUMP -dfb3_J0437_56160_60000 1 4.5e-07 0 -JUMP -pdfb1_128_ch 1 -3.5547e-06 0 -JUMP -pdfb1_2048_ch 1 -4.68829e-05 0 -JUMP -pdfb1_512_ch 1 -1.22813e-05 0 -JUMP -pdfb1_post_2006 1 -1.3e-07 0 -JUMP -pdfb1_pre_2006 1 -1.13e-06 0 -JUMP -pdfb2_1024_MHz 1 -5.435e-06 0 -JUMP -pdfb2_256MHz_1024_ch 1 -1.1395e-05 0 -JUMP -pdfb2_256MHz_512ch 1 -4.75e-06 0 -JUMP -pdfb3_1024_256_512 1 2.45e-06 0 -JUMP -pdfb3_1024_MHz 1 1.03e-06 0 -JUMP -pdfb3_256MHz_1024ch 1 4.295e-06 0 -JUMP -pdfb3_64MHz_1024ch 1 1.494e-05 0 -JUMP -pdfb3_64MHz_512ch 1 8.9e-06 0 -JUMP -pdfb4.*_1024_[1,2]... 1 2.23e-06 0 -JUMP -pdfb4_256MHz_1024ch 1 5.05e-06 0 -JUMP -pdfb4_55319_56055_cals 1 9.27e-07 0 -JUMP -pdfb4_56110_56160_cals 1 5.41e-07 0 -JUMP -pdfb4_56160_60000_cals 1 4.25e-07 0 -JUMP -wbb256_512_128_3p_b 1 -6.2e-07 0 -JUMP -wbb_c_config 1 3.8e-07 0 WAVEEPOCH 55305 WAVE_OM 0.0015182579855022 0 WAVE1 -0.21573979911255 -0.049063841960712 From 87939cd468d00cc8760080d6742e19d07f8270ce Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Thu, 14 Nov 2024 12:44:48 -0500 Subject: [PATCH 137/195] Fix WAVE<-->WAVEX conversion. --- src/pint/utils.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pint/utils.py b/src/pint/utils.py index da23092fc..4f6523455 100644 --- a/src/pint/utils.py +++ b/src/pint/utils.py @@ -1746,10 +1746,10 @@ def _translate_wave_freqs(om: Union[float, u.Quantity], k: int) -> u.Quantity: WXFREQ_ quantity in units 1/d that can be used in WaveX model """ if isinstance(om, u.quantity.Quantity): - om.to(u.d**-1) + om.to(u.rad*u.d**-1) else: - om *= u.d**-1 - return (om * (k + 1)) / (2.0 * np.pi) + om *= u.rad*u.d**-1 + return (om * (k + 1)) / (2.0 * np.pi * u.rad) def _translate_wavex_freqs(wxfreq: Union[float, u.Quantity], k: int) -> u.Quantity: @@ -1774,8 +1774,8 @@ def _translate_wavex_freqs(wxfreq: Union[float, u.Quantity], k: int) -> u.Quanti else: wxfreq *= u.d**-1 if len(wxfreq) == 1: - return (2.0 * np.pi * wxfreq) / (k + 1.0) - wave_om = [((2.0 * np.pi * wxfreq[i]) / (k[i] + 1.0)) for i in range(len(wxfreq))] + return (2.0 * np.pi * u.rad * wxfreq) / (k + 1.0) + wave_om = [((2.0 * np.pi * u.rad * wxfreq[i]) / (k[i] + 1.0)) for i in range(len(wxfreq))] return ( sum(wave_om) / len(wave_om) if np.allclose(wave_om, wave_om[0], atol=1e-3) From 53ae031e946af0e75c27ecdbbec8f0411487f0df Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Thu, 14 Nov 2024 12:45:51 -0500 Subject: [PATCH 138/195] Re-black with v24. --- src/pint/derived_quantities.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/pint/derived_quantities.py b/src/pint/derived_quantities.py index 6cae3c39a..8f3373cf6 100644 --- a/src/pint/derived_quantities.py +++ b/src/pint/derived_quantities.py @@ -130,8 +130,7 @@ def pferrs( return [1.0 / porf, porferr / porf**2.0] forperr = porferr / porf**2.0 fdorpderr = np.sqrt( - (4.0 * pdorfd**2.0 * porferr**2.0) / porf**6.0 - + pdorfderr**2.0 / porf**4.0 + (4.0 * pdorfd**2.0 * porferr**2.0) / porf**6.0 + pdorfderr**2.0 / porf**4.0 ) [forp, fdorpd] = p_to_f(porf, pdorfd) return (forp, forperr, fdorpd, fdorpderr) @@ -552,17 +551,12 @@ def companion_mass( # delta1 is always <0 # delta1 = 2 * b ** 3 - 9 * a * b * c + 27 * a ** 2 * d delta1 = ( - -2 * massfunct**3 - - 18 * a * mp * massfunct**2 - - 27 * a**2 * massfunct * mp**2 + -2 * massfunct**3 - 18 * a * mp * massfunct**2 - 27 * a**2 * massfunct * mp**2 ) # Q**2 is always > 0, so this is never a problem # in terms of complex numbers # Q = np.sqrt(delta1**2 - 4*delta0**3) - Q = np.sqrt( - 108 * a**3 * mp**3 * massfunct**3 - + 729 * a**4 * mp**4 * massfunct**2 - ) + Q = np.sqrt(108 * a**3 * mp**3 * massfunct**3 + 729 * a**4 * mp**4 * massfunct**2) # this could be + or - Q # pick the - branch since delta1 is <0 so that delta1 - Q is never near 0 Ccubed = 0.5 * (delta1 + Q) From 4219a9b6294b8af91b4c4e838bc4440df287e598 Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Thu, 14 Nov 2024 12:54:09 -0500 Subject: [PATCH 139/195] Simply astropy units syntax. --- src/pint/utils.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/pint/utils.py b/src/pint/utils.py index 4f6523455..27af72c85 100644 --- a/src/pint/utils.py +++ b/src/pint/utils.py @@ -1745,10 +1745,7 @@ def _translate_wave_freqs(om: Union[float, u.Quantity], k: int) -> u.Quantity: astropy.units.Quantity WXFREQ_ quantity in units 1/d that can be used in WaveX model """ - if isinstance(om, u.quantity.Quantity): - om.to(u.rad*u.d**-1) - else: - om *= u.rad*u.d**-1 + om <<= u.rad/u.d return (om * (k + 1)) / (2.0 * np.pi * u.rad) @@ -1769,10 +1766,7 @@ def _translate_wavex_freqs(wxfreq: Union[float, u.Quantity], k: int) -> u.Quanti astropy.units.Quantity WAVEOM quantity in units 1/d that can be used in Wave model """ - if isinstance(wxfreq, u.quantity.Quantity): - wxfreq.to(u.d**-1) - else: - wxfreq *= u.d**-1 + wxfreq <<= u.d**-1 if len(wxfreq) == 1: return (2.0 * np.pi * u.rad * wxfreq) / (k + 1.0) wave_om = [((2.0 * np.pi * u.rad * wxfreq[i]) / (k[i] + 1.0)) for i in range(len(wxfreq))] From 3ad5f9b39f0e81f5c7e7e67f879bea35b5d82092 Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Thu, 14 Nov 2024 13:28:31 -0500 Subject: [PATCH 140/195] Move gauss equivalency to pint __init__ file. --- src/pint/__init__.py | 3 +++ src/pint/derived_quantities.py | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pint/__init__.py b/src/pint/__init__.py index 5706dff7e..7906be01f 100644 --- a/src/pint/__init__.py +++ b/src/pint/__init__.py @@ -105,6 +105,9 @@ "hourangle_second": hourangle_second, } +# define a units equivalency for gauss in cgs +gauss_equiv = [u.Gauss, u.Hz * (u.g / u.cm) ** (1 / 2), lambda x: x, lambda x: x] + import astropy.version if astropy.version.major < 4: diff --git a/src/pint/derived_quantities.py b/src/pint/derived_quantities.py index 8f3373cf6..24dcb1934 100644 --- a/src/pint/derived_quantities.py +++ b/src/pint/derived_quantities.py @@ -141,8 +141,7 @@ def _to_gauss(B: u.Quantity) -> u.G: In cgs units, magnetic field is has units (mass/length)^(1/2) / time. """ - eq = [u.Gauss, u.Hz * (u.g / u.cm) ** (1 / 2), lambda x: x, lambda x: x] - return B.to(u.Gauss, equivalencies=[eq]) + return B.to(u.Gauss, equivalencies=[pint.gauss_equiv]) @u.quantity_input(f=u.Hz, fdot=u.Hz / u.s, fo=u.Hz) From ba48280d2a0f20e10cd7e6bb13f8f6c35f49401a Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Thu, 14 Nov 2024 15:10:11 -0500 Subject: [PATCH 141/195] black is going to make me run screaming into the night --- src/pint/utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pint/utils.py b/src/pint/utils.py index 27af72c85..59f0d3076 100644 --- a/src/pint/utils.py +++ b/src/pint/utils.py @@ -1745,7 +1745,7 @@ def _translate_wave_freqs(om: Union[float, u.Quantity], k: int) -> u.Quantity: astropy.units.Quantity WXFREQ_ quantity in units 1/d that can be used in WaveX model """ - om <<= u.rad/u.d + om <<= u.rad / u.d return (om * (k + 1)) / (2.0 * np.pi * u.rad) @@ -1769,7 +1769,9 @@ def _translate_wavex_freqs(wxfreq: Union[float, u.Quantity], k: int) -> u.Quanti wxfreq <<= u.d**-1 if len(wxfreq) == 1: return (2.0 * np.pi * u.rad * wxfreq) / (k + 1.0) - wave_om = [((2.0 * np.pi * u.rad * wxfreq[i]) / (k[i] + 1.0)) for i in range(len(wxfreq))] + wave_om = [ + ((2.0 * np.pi * u.rad * wxfreq[i]) / (k[i] + 1.0)) for i in range(len(wxfreq)) + ] return ( sum(wave_om) / len(wave_om) if np.allclose(wave_om, wave_om[0], atol=1e-3) From ffc5a2d1cf2a5c1650fa4f0775508d307ca7685c Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Fri, 15 Nov 2024 07:57:34 -0500 Subject: [PATCH 142/195] Add changelog entry. --- CHANGELOG-unreleased.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 2899b99f8..8f6c7f411 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -11,4 +11,5 @@ the released changes. ### Changed ### Added ### Fixed +- Changed WAVE\_OM units from 1/d to rad/d. ### Removed From ab4a22e923bdf2aadcdc1600a7d93bdeefdae7d5 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Fri, 15 Nov 2024 16:39:55 -0600 Subject: [PATCH 143/195] return name of added param, helpful when adding maskParameter --- src/pint/models/timing_model.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pint/models/timing_model.py b/src/pint/models/timing_model.py index a0b27b090..68fe886bf 100644 --- a/src/pint/models/timing_model.py +++ b/src/pint/models/timing_model.py @@ -3425,6 +3425,7 @@ def add_param(self, param, deriv_func=None, setup=False): if deriv_func is not None: self.register_deriv_funcs(deriv_func, param.name) param._parent = self + return param.name def remove_param(self, param): """Remove a parameter from the Component. From 7c2bf806bff01136fb7e7df298539932b1ad0325 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Fri, 15 Nov 2024 16:40:16 -0600 Subject: [PATCH 144/195] fix logic when selection mask is array([0]) --- src/pint/models/noise_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pint/models/noise_model.py b/src/pint/models/noise_model.py index b1af8e10f..299787fe5 100644 --- a/src/pint/models/noise_model.py +++ b/src/pint/models/noise_model.py @@ -164,14 +164,14 @@ def scale_toa_sigma(self, toas, warn=True): if equad.quantity is None: continue mask = equad.select_toa_mask(toas) - if np.any(mask): + if len(mask) > 0: sigma_scaled[mask] = np.hypot(sigma_scaled[mask], equad.quantity) elif warn: warnings.warn(f"EQUAD {equad} has no TOAs") for efac_name in self.EFACs: efac = getattr(self, efac_name) mask = efac.select_toa_mask(toas) - if np.any(mask): + if len(mask) > 0: sigma_scaled[mask] *= efac.quantity elif warn: warnings.warn(f"EFAC {efac} has no TOAs") From a17f4aabce38b60502d1c0f350980d884cfa9d9c Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 18 Nov 2024 12:36:53 -0600 Subject: [PATCH 145/195] changelog --- CHANGELOG-unreleased.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index d15e5e781..8e7b884e3 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -11,6 +11,8 @@ the released changes. ### Changed ### Added - When TCB->TDB conversion info is missing, will print parameter name +- `add_param` returns the name of the parameter (useful for numbered parameters) ### Fixed - When EQUAD is created from TNEQ, has proper TCB->TDB conversion info +- TOA selection masks will work when only TOA is the first one ### Removed From b21fd69beae00abec1c042e075759a26e642da12 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 19 Nov 2024 10:07:52 +0100 Subject: [PATCH 146/195] short cercuit --- src/pint/models/solar_wind_dispersion.py | 31 ++++++++++++++---------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/pint/models/solar_wind_dispersion.py b/src/pint/models/solar_wind_dispersion.py index 12bf8d58c..8a282fee3 100644 --- a/src/pint/models/solar_wind_dispersion.py +++ b/src/pint/models/solar_wind_dispersion.py @@ -415,21 +415,26 @@ def solar_wind_dm(self, toas): """ ne_sw_terms = self.get_NE_SW_terms() - if any(t.value != 0 for t in ne_sw_terms[1:]): - SWEPOCH = self.SWEPOCH.value - if SWEPOCH is None: - # Should be ruled out by validate() - raise ValueError( - f"SWEPOCH not set but some NE_SW derivatives are not zero: {ne_sw_terms}" - ) - else: - dt = (toas["tdbld"] - SWEPOCH) * u.day - dt_value = dt.to_value(u.yr) + if len(ne_sw_terms) == 1: + ne_sw = self.NE_SW.quantity * np.ones(len(toas)) else: - dt_value = np.zeros(len(toas), dtype=np.longdouble) + if any(t.value != 0 for t in ne_sw_terms[1:]): + SWEPOCH = self.SWEPOCH.value + if SWEPOCH is None: + # Should be ruled out by validate() + raise ValueError( + f"SWEPOCH not set but some NE_SW derivatives are not zero: {ne_sw_terms}" + ) + else: + dt = (toas["tdbld"] - SWEPOCH) * u.day + dt_value = dt.to_value(u.yr) + else: + dt_value = np.zeros(len(toas), dtype=np.longdouble) - ne_sw_terms_value = [d.value for d in ne_sw_terms] - ne_sw = pint.utils.taylor_horner(dt_value, ne_sw_terms_value) * self.NE_SW.units + ne_sw_terms_value = [d.value for d in ne_sw_terms] + ne_sw = ( + pint.utils.taylor_horner(dt_value, ne_sw_terms_value) * self.NE_SW.units + ) if np.all(ne_sw.value == 0): return np.zeros(len(toas)) * u.pc / u.cm**3 From b4dba2e04adc11a7200a459db4f0fe7b39246a26 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 19 Nov 2024 10:22:03 +0100 Subject: [PATCH 147/195] test_expression --- tests/test_solar_wind.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/test_solar_wind.py b/tests/test_solar_wind.py index b9dba12ce..69a79fd52 100644 --- a/tests/test_solar_wind.py +++ b/tests/test_solar_wind.py @@ -400,3 +400,42 @@ def test_nesw_derivatives(): assert ( m.NE_SW2.value - ftr.model.NE_SW2.value ) / ftr.model.NE_SW2.uncertainty_value < 3 + + m.components["SolarWindDispersion"] + + +def test_expression(): + par = """ + PSRJ J1744-1134 + ELONG 266.119458498 6.000e-09 + ELAT 11.80517508 3.000e-08 + DM 3.1379 4.000e-04 + PEPOCH 55000 + F0 245.4261196898081 5.000e-13 + F1 -5.38156E-16 3.000e-21 + POSEPOCH 59150 + DMEPOCH 55000 + CLK TT(BIPM2018) + EPHEM DE436 + PX 2.61 9.000e-02 + PMELONG 19.11 2.000e-02 + PMELAT -9.21 1.300e-01 + UNITS TDB + NE_SW 8 1 + NE_SW1 1 1 + SWEPOCH 55000 + """ + m = get_model(StringIO(par)) + t = make_fake_toas_uniform(54500, 55500, 10, m, add_noise=True) + + t0 = m.SWEPOCH.value * u.day + t1 = t["tdbld"][-1] * u.day + dt = t1 - t0 + + assert np.isclose( + ( + m.components["SolarWindDispersion"].solar_wind_dm(t) + / m.components["SolarWindDispersion"].solar_wind_geometry(t) + )[-1], + (m.NE_SW.quantity + dt * m.NE_SW1.quantity), + ) From b9d1e7109c40dbcb89c432a6ee90b7fd2adcb74c Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 19 Nov 2024 13:21:25 +0100 Subject: [PATCH 148/195] Add an nbin option to photonphase Allow photonphase to plot a pulse profile with a custom number of bins, while maintaining the current value as default --- src/pint/scripts/photonphase.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pint/scripts/photonphase.py b/src/pint/scripts/photonphase.py index 7d72eec18..d21679138 100755 --- a/src/pint/scripts/photonphase.py +++ b/src/pint/scripts/photonphase.py @@ -106,6 +106,9 @@ def main(argv=None): help="Logging level", dest="loglevel", ) + parser.add_argument( + "--nbin", help="Number of phase bins in the phaseogram", default=100, type=int + ) parser.add_argument( "-v", "--verbosity", default=0, action="count", help="Increase output verbosity" ) @@ -254,7 +257,7 @@ def main(argv=None): print("Htest : {0:.2f} ({1:.2f} sigma)".format(h, h2sig(h))) if args.plot: - phaseogram_binned(mjds, phases, bins=100, plotfile=args.plotfile) + phaseogram_binned(mjds, phases, bins=args.nbin, plotfile=args.plotfile) # Compute orbital phases for each photon TOA if args.addorbphase: From cbf1e57f8cb5ef5d96092cc8e14df280ea6dd2e9 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Wed, 20 Nov 2024 09:36:09 +0100 Subject: [PATCH 149/195] allow_tcb and allow_T2 are false by default --- src/pint/scripts/compare_parfiles.py | 14 ++++++++++++-- src/pint/scripts/convert_parfile.py | 12 +++++++++++- src/pint/scripts/event_optimize.py | 14 +++++++++++++- src/pint/scripts/event_optimize_MCMCFitter.py | 15 ++++++++++++++- src/pint/scripts/event_optimize_multiple.py | 14 +++++++++++++- src/pint/scripts/fermiphase.py | 14 +++++++++++++- 6 files changed, 76 insertions(+), 7 deletions(-) diff --git a/src/pint/scripts/compare_parfiles.py b/src/pint/scripts/compare_parfiles.py index 87eb005a0..d65785041 100644 --- a/src/pint/scripts/compare_parfiles.py +++ b/src/pint/scripts/compare_parfiles.py @@ -83,14 +83,24 @@ def main(argv=None): parser.add_argument( "-q", "--quiet", default=0, action="count", help="Decrease output verbosity" ) + parser.add_argument( + "--allow_tcb", + action="store_true", + help="Convert TCB par files to TDB automatically", + ) + parser.add_argument( + "--allow_T2", + action="store_true", + help="Guess the underlying binary model when T2 is given", + ) args = parser.parse_args(argv) pint.logging.setup( level=pint.logging.get_level(args.loglevel, args.verbosity, args.quiet) ) - m1 = get_model(args.input1, allow_T2=True, allow_tcb=True) - m2 = get_model(args.input2, allow_T2=True, allow_tcb=True) + m1 = get_model(args.input1, allow_T2=args.allow_T2, allow_tcb=args.allow_tcb) + m2 = get_model(args.input2, allow_T2=args.allow_T2, allow_tcb=args.allow_tcb) print( m1.compare( diff --git a/src/pint/scripts/convert_parfile.py b/src/pint/scripts/convert_parfile.py index 0612a46a8..2975d5acc 100644 --- a/src/pint/scripts/convert_parfile.py +++ b/src/pint/scripts/convert_parfile.py @@ -73,6 +73,16 @@ def main(argv=None): parser.add_argument( "-q", "--quiet", default=0, action="count", help="Decrease output verbosity" ) + parser.add_argument( + "--allow_tcb", + action="store_true", + help="Convert TCB par files to TDB automatically", + ) + parser.add_argument( + "--allow_T2", + action="store_true", + help="Guess the underlying binary model when T2 is given", + ) args = parser.parse_args(argv) pint.logging.setup( @@ -84,7 +94,7 @@ def main(argv=None): log.info(f"Reading '{args.input}'") - model = get_model(args.input, allow_T2=True, allow_tcb=True) + model = get_model(args.input, allow_T2=args.allow_T2, allow_tcb=args.allow_tcb) if hasattr(model, "BINARY") and args.binary is not None: log.info(f"Converting from {model.BINARY.value} to {args.binary}") diff --git a/src/pint/scripts/event_optimize.py b/src/pint/scripts/event_optimize.py index b91c30a04..6e26ba784 100755 --- a/src/pint/scripts/event_optimize.py +++ b/src/pint/scripts/event_optimize.py @@ -706,6 +706,16 @@ def main(argv=None): action="store_true", dest="linearize_model", ) + parser.add_argument( + "--allow_tcb", + action="store_true", + help="Convert TCB par files to TDB automatically", + ) + parser.add_argument( + "--allow_T2", + action="store_true", + help="Guess the underlying binary model when T2 is given", + ) args = parser.parse_args(argv) pint.logging.setup( @@ -739,7 +749,9 @@ def main(argv=None): ncores = args.ncores # Read in initial model - modelin = pint.models.get_model(parfile, allow_T2=True, allow_tcb=True) + modelin = pint.models.get_model( + parfile, allow_T2=args.allow_T2, allow_tcb=args.allow_tcb + ) # File name setup and clobber file check filepath = args.filepath or os.getcwd() diff --git a/src/pint/scripts/event_optimize_MCMCFitter.py b/src/pint/scripts/event_optimize_MCMCFitter.py index 43bc89858..7357b1028 100755 --- a/src/pint/scripts/event_optimize_MCMCFitter.py +++ b/src/pint/scripts/event_optimize_MCMCFitter.py @@ -128,6 +128,17 @@ def main(argv=None): help="Logging level", dest="loglevel", ) + parser.add_argument( + "--allow_tcb", + action="store_true", + help="Convert TCB par files to TDB automatically", + ) + parser.add_argument( + "--allow_T2", + action="store_true", + help="Guess the underlying binary model when T2 is given", + ) + global nwalkers, nsteps, ftr args = parser.parse_args(argv) @@ -164,7 +175,9 @@ def main(argv=None): wgtexp = args.wgtexp # Read in initial model - modelin = pint.models.get_model(parfile, allow_T2=True, allow_tcb=True) + modelin = pint.models.get_model( + parfile, allow_T2=args.allow_T2, allow_tcb=args.allow_tcb + ) # The custom_timing version below is to manually construct the TimingModel # class, which allows it to be pickled. This is needed for parallelizing diff --git a/src/pint/scripts/event_optimize_multiple.py b/src/pint/scripts/event_optimize_multiple.py index daa40a9e9..0a3dc7336 100755 --- a/src/pint/scripts/event_optimize_multiple.py +++ b/src/pint/scripts/event_optimize_multiple.py @@ -228,6 +228,16 @@ def main(argv=None): help="Logging level", dest="loglevel", ) + parser.add_argument( + "--allow_tcb", + action="store_true", + help="Convert TCB par files to TDB automatically", + ) + parser.add_argument( + "--allow_T2", + action="store_true", + help="Guess the underlying binary model when T2 is given", + ) global nwalkers, nsteps, ftr @@ -261,7 +271,9 @@ def main(argv=None): wgtexp = args.wgtexp # Read in initial model - modelin = pint.models.get_model(parfile, allow_T2=True, allow_tcb=True) + modelin = pint.models.get_model( + parfile, allow_T2=args.allow_T2, allow_tcb=args.allow_tcb + ) # Set the target coords for automatic weighting if necessary if "ELONG" in modelin.params: diff --git a/src/pint/scripts/fermiphase.py b/src/pint/scripts/fermiphase.py index 6785bc156..c5e43bb93 100755 --- a/src/pint/scripts/fermiphase.py +++ b/src/pint/scripts/fermiphase.py @@ -77,6 +77,16 @@ def main(argv=None): parser.add_argument( "-q", "--quiet", default=0, action="count", help="Decrease output verbosity" ) + parser.add_argument( + "--allow_tcb", + action="store_true", + help="Convert TCB par files to TDB automatically", + ) + parser.add_argument( + "--allow_T2", + action="store_true", + help="Guess the underlying binary model when T2 is given", + ) args = parser.parse_args(argv) pint.logging.setup( @@ -88,7 +98,9 @@ def main(argv=None): args.addphase = True # Read in model - modelin = pint.models.get_model(args.parfile, allow_T2=True, allow_tcb=True) + modelin = pint.models.get_model( + args.parfile, allow_T2=args.allow_T2, allow_tcb=args.allow_tcb + ) if "ELONG" in modelin.params: tc = SkyCoord( From 706f041098be6b14f862d7c0d569de4ffb7daf2d Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Wed, 20 Nov 2024 09:55:25 +0100 Subject: [PATCH 150/195] no default tcb t2 --- src/pint/scripts/photonphase.py | 14 +++++++++++++- src/pint/scripts/pintbary.py | 14 +++++++++++++- src/pint/scripts/pintempo.py | 14 +++++++++++++- src/pint/scripts/pintpublish.py | 14 +++++++++++++- src/pint/scripts/t2binary2pint.py | 7 ++++++- src/pint/scripts/tcb2tdb.py | 7 ++++++- src/pint/scripts/zima.py | 14 +++++++++++++- 7 files changed, 77 insertions(+), 7 deletions(-) diff --git a/src/pint/scripts/photonphase.py b/src/pint/scripts/photonphase.py index 38505c629..85a80907f 100755 --- a/src/pint/scripts/photonphase.py +++ b/src/pint/scripts/photonphase.py @@ -112,6 +112,16 @@ def main(argv=None): parser.add_argument( "-q", "--quiet", default=0, action="count", help="Decrease output verbosity" ) + parser.add_argument( + "--allow_tcb", + action="store_true", + help="Convert TCB par files to TDB automatically", + ) + parser.add_argument( + "--allow_T2", + action="store_true", + help="Guess the underlying binary model when T2 is given", + ) args = parser.parse_args(argv) pint.logging.setup( @@ -153,7 +163,9 @@ def main(argv=None): "Please barycenter the event file using the official mission tools before processing with PINT" ) # Read in model - modelin = pint.models.get_model(args.parfile, allow_T2=True, allow_tcb=True) + modelin = pint.models.get_model( + args.parfile, allow_T2=args.allow_T2, allow_tcb=args.allow_tcb + ) use_planets = False if "PLANET_SHAPIRO" in modelin.params: diff --git a/src/pint/scripts/pintbary.py b/src/pint/scripts/pintbary.py index c29d42fbb..61cdcd0a0 100755 --- a/src/pint/scripts/pintbary.py +++ b/src/pint/scripts/pintbary.py @@ -74,6 +74,16 @@ def main(argv=None): parser.add_argument( "-q", "--quiet", default=0, action="count", help="Decrease output verbosity" ) + parser.add_argument( + "--allow_tcb", + action="store_true", + help="Convert TCB par files to TDB automatically", + ) + parser.add_argument( + "--allow_T2", + action="store_true", + help="Guess the underlying binary model when T2 is given", + ) args = parser.parse_args(argv) pint.logging.setup( @@ -105,7 +115,9 @@ def main(argv=None): ) if args.parfile is not None: - m = pint.models.get_model(args.parfile, allow_T2=True, allow_tcb=True) + m = pint.models.get_model( + args.parfile, allow_T2=args.allow_T2, allow_tcb=args.allow_tcb + ) else: # Construct model by hand m = pint.models.StandardTimingModel diff --git a/src/pint/scripts/pintempo.py b/src/pint/scripts/pintempo.py index 36e8ca509..ac9099008 100755 --- a/src/pint/scripts/pintempo.py +++ b/src/pint/scripts/pintempo.py @@ -62,6 +62,16 @@ def main(argv=None): parser.add_argument( "-q", "--quiet", default=0, action="count", help="Decrease output verbosity" ) + parser.add_argument( + "--allow_tcb", + action="store_true", + help="Convert TCB par files to TDB automatically", + ) + parser.add_argument( + "--allow_T2", + action="store_true", + help="Guess the underlying binary model when T2 is given", + ) args = parser.parse_args(argv) pint.logging.setup( @@ -69,7 +79,9 @@ def main(argv=None): ) log.info("Reading model from {0}".format(args.parfile)) - m = pint.models.get_model(args.parfile, allow_T2=True, allow_tcb=True) + m = pint.models.get_model( + args.parfile, allow_T2=args.allow_T2, allow_tcb=args.allow_tcb + ) log.warning(m.params) diff --git a/src/pint/scripts/pintpublish.py b/src/pint/scripts/pintpublish.py index 36cc5786e..1828a05c6 100644 --- a/src/pint/scripts/pintpublish.py +++ b/src/pint/scripts/pintpublish.py @@ -59,10 +59,22 @@ def main(argv=None): action="store_true", default=False, ) + parser.add_argument( + "--allow_tcb", + action="store_true", + help="Convert TCB par files to TDB automatically", + ) + parser.add_argument( + "--allow_T2", + action="store_true", + help="Guess the underlying binary model when T2 is given", + ) args = parser.parse_args(argv) - model, toas = get_model_and_toas(args.parfile, args.timfile, allow_T2=True) + model, toas = get_model_and_toas( + args.parfile, args.timfile, allow_T2=args.allow_T2, allow_tcb=args.allow_tcb + ) output = publish( model, diff --git a/src/pint/scripts/t2binary2pint.py b/src/pint/scripts/t2binary2pint.py index 42d70f89a..bab43eef4 100644 --- a/src/pint/scripts/t2binary2pint.py +++ b/src/pint/scripts/t2binary2pint.py @@ -45,12 +45,17 @@ def main(argv=None): default=True, help="Whether to drop SINI if the model is DDK (True)", ) + parser.add_argument( + "--allow_tcb", + action="store_true", + help="Convert TCB par files to TDB automatically", + ) args = parser.parse_args(argv) mb = ModelBuilder() - model = mb(args.input_par, allow_T2=True, allow_tcb=True) + model = mb(args.input_par, allow_T2=True, allow_tcb=args.allow_tcb) model.write_parfile(args.output_par) print(f"Output written to {args.output_par}") diff --git a/src/pint/scripts/tcb2tdb.py b/src/pint/scripts/tcb2tdb.py index 5b15d56ae..02a485d3c 100644 --- a/src/pint/scripts/tcb2tdb.py +++ b/src/pint/scripts/tcb2tdb.py @@ -30,11 +30,16 @@ def main(argv=None): ) parser.add_argument("input_par", help="Input par file name (TCB)") parser.add_argument("output_par", help="Output par file name (TDB)") + parser.add_argument( + "--allow_T2", + action="store_true", + help="Guess the underlying binary model when T2 is given", + ) args = parser.parse_args(argv) mb = ModelBuilder() - model = mb(args.input_par, allow_tcb=True, allow_T2=True) + model = mb(args.input_par, allow_tcb=True, allow_T2=args.allow_T2) model.write_parfile(args.output_par) log.info(f"Output written to {args.output_par}.") diff --git a/src/pint/scripts/zima.py b/src/pint/scripts/zima.py index 3485c6c5b..29b3e354c 100755 --- a/src/pint/scripts/zima.py +++ b/src/pint/scripts/zima.py @@ -115,6 +115,16 @@ def main(argv=None): parser.add_argument( "-q", "--quiet", default=0, action="count", help="Decrease output verbosity" ) + parser.add_argument( + "--allow_tcb", + action="store_true", + help="Convert TCB par files to TDB automatically", + ) + parser.add_argument( + "--allow_T2", + action="store_true", + help="Guess the underlying binary model when T2 is given", + ) args = parser.parse_args(argv) pint.logging.setup( @@ -122,7 +132,9 @@ def main(argv=None): ) log.info("Reading model from {0}".format(args.parfile)) - m = pint.models.get_model(args.parfile, allow_T2=True, allow_tcb=True) + m = pint.models.get_model( + args.parfile, allow_T2=args.allow_T2, allow_tcb=args.allow_tcb + ) out_format = args.format error = args.error * u.microsecond From 52645a901f05019b7aad0a707484cb4c33636888 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Wed, 20 Nov 2024 15:01:56 +0100 Subject: [PATCH 151/195] test_cmx_delay --- src/pint/models/chromatic_model.py | 9 +---- tests/test_cmx.py | 55 +++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/pint/models/chromatic_model.py b/src/pint/models/chromatic_model.py index d745729ce..8f428fea2 100644 --- a/src/pint/models/chromatic_model.py +++ b/src/pint/models/chromatic_model.py @@ -357,7 +357,6 @@ def add_CMX_range(self, mjd_start, mjd_end, index=None, cmx=0, frozen=True): index : int Index that has been assigned to new CMX event. - """ #### Setting up the CMX title convention. If index is None, want to increment the current max CMX index by 1. @@ -447,7 +446,6 @@ def add_CMX_ranges(self, mjd_starts, mjd_ends, indices=None, cmxs=0, frozens=Tru indices : list Indices that has been assigned to new CMX events - """ if len(mjd_starts) != len(mjd_ends): raise ValueError( @@ -574,7 +572,7 @@ def get_indices(self): Returns ------- inds : np.ndarray - Array of CMX indices in model. + Array of CMX indices in model. """ inds = [int(p.split("_")[-1]) for p in self.params if "CMX_" in p] return np.array(inds) @@ -690,11 +688,6 @@ def d_cm_d_CMX(self, toas, param_name, acc_delay=None): condition, tbl["mjd_float"] ) - try: - bfreq = self._parent.barycentric_radio_freq(toas) - except AttributeError: - warn("Using topocentric frequency for dedispersion!") - bfreq = tbl["freq"] cmx = np.zeros(len(tbl)) for k, v in select_idx.items(): cmx[v] = 1.0 diff --git a/tests/test_cmx.py b/tests/test_cmx.py index f62563840..976581880 100644 --- a/tests/test_cmx.py +++ b/tests/test_cmx.py @@ -43,7 +43,7 @@ def model_and_toas(): freqs = np.linspace(300, 1600, 16) * u.MHz toas = make_fake_toas_uniform( startMJD=54000, - endMJD=55500, + endMJD=56000, ntoas=2000, model=model, freq=freqs, @@ -77,3 +77,56 @@ def test_cmx(model_and_toas): assert ftr.resids.chi2_reduced < 1.6 assert "CMX_0001" in str(ftr.model) + + +def test_cmx_delay(model_and_toas): + model, toas = model_and_toas + + # Zero delay outside CMX ranges + nocmx_mask = toas.get_mjds().value > 55500 + assert all( + model.components["ChromaticCMX"].CMX_chromatic_delay(toas)[nocmx_mask] == 0 + ) + + # The delay is consistent + cmx1_mask = np.logical_and( + toas.get_mjds().value >= model.CMXR1_0001.value, + toas.get_mjds().value <= model.CMXR2_0001.value, + ) + cmx1_freqs = toas.get_freqs()[cmx1_mask] + assert all( + np.isclose( + model.components["ChromaticCMX"].chromatic_time_delay( + model.CMX_0001.quantity, model.TNCHROMIDX.quantity, cmx1_freqs + ), + model.components["ChromaticCMX"].CMX_chromatic_delay(toas)[cmx1_mask], + ) + ) + + cmx2_mask = np.logical_and( + toas.get_mjds().value >= model.CMXR1_0002.value, + toas.get_mjds().value <= model.CMXR2_0002.value, + ) + cmx2_freqs = toas.get_freqs()[cmx2_mask] + assert all( + np.isclose( + model.components["ChromaticCMX"].chromatic_time_delay( + model.CMX_0002.quantity, model.TNCHROMIDX.quantity, cmx2_freqs + ), + model.components["ChromaticCMX"].CMX_chromatic_delay(toas)[cmx2_mask], + ) + ) + + cmx3_mask = np.logical_and( + toas.get_mjds().value >= model.CMXR1_0003.value, + toas.get_mjds().value <= model.CMXR2_0003.value, + ) + cmx3_freqs = toas.get_freqs()[cmx3_mask] + assert all( + np.isclose( + model.components["ChromaticCMX"].chromatic_time_delay( + model.CMX_0003.quantity, model.TNCHROMIDX.quantity, cmx3_freqs + ), + model.components["ChromaticCMX"].CMX_chromatic_delay(toas)[cmx3_mask], + ) + ) From f608d8b6118c6f8f45dc8f78f9ebd904934b2e14 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Thu, 21 Nov 2024 19:42:00 +0100 Subject: [PATCH 152/195] Add changelog --- CHANGELOG-unreleased.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index fc3962080..03eabf590 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -11,6 +11,7 @@ the released changes. ### Changed - Updated the `plot_chains` function in `event_optimize` so that the subplots are a fixed size to prevent the subplots from being condensed in the case of many fit parameters. ### Added +- Added an option `nbin` to `photonphase` to decide how many phase bins to use for the phaseogram - Added an option `linearize_model` to speed up the photon phases calculation within `event_optimize` through the designmatrix. - Added AIC and BIC calculation to be written in the post fit parfile from `event_optimize` - When TCB->TDB conversion info is missing, will print parameter name From 062cd52e7fc9832b3861aedc41f68bc505178a85 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Wed, 27 Nov 2024 10:32:06 -0600 Subject: [PATCH 153/195] add CI workflow using mamba --- .github/workflows/ci_test.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 79d3ca0a2..fa2243acb 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -94,3 +94,33 @@ jobs: # with: # name: documentation # path: .tox/docs_out/ + test-mamba: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set-Up Python Env + uses: mamba-org/setup-micromamba@v1 + with: + init-shell: bash + environment-name: pint + cache-environment: true + cache-downloads: true + create-args: >- + -c conda-forge + python=3.11 + astropy + git + - name: Install base dependencies + shell: bash -el {0} + run: | + python -m pip install --upgrade pip + python -m pip install tox + - name: Print Python, pip, and tox versions + run: | + python -c "import sys; print(f'Python {sys.version}')" + python -c "import pip; print(f'pip {pip.__version__}')" + python -c "import tox; print(f'tox {tox.__version__}')" + - name: Run tests + shell: bash -el {0} + run: tox -e singletest + \ No newline at end of file From 54e3c3a1b4f94be964c1be943924b9c628952c4e Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Wed, 27 Nov 2024 10:34:47 -0600 Subject: [PATCH 154/195] changed indent --- .github/workflows/ci_test.yml | 54 +++++++++++++++++------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index fa2243acb..c9f762c26 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -97,30 +97,30 @@ jobs: test-mamba: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - name: Set-Up Python Env - uses: mamba-org/setup-micromamba@v1 - with: - init-shell: bash - environment-name: pint - cache-environment: true - cache-downloads: true - create-args: >- - -c conda-forge - python=3.11 - astropy - git - - name: Install base dependencies - shell: bash -el {0} - run: | - python -m pip install --upgrade pip - python -m pip install tox - - name: Print Python, pip, and tox versions - run: | - python -c "import sys; print(f'Python {sys.version}')" - python -c "import pip; print(f'pip {pip.__version__}')" - python -c "import tox; print(f'tox {tox.__version__}')" - - name: Run tests - shell: bash -el {0} - run: tox -e singletest - \ No newline at end of file + - uses: actions/checkout@v4 + - name: Set-Up Python Env + uses: mamba-org/setup-micromamba@v1 + with: + init-shell: bash + environment-name: pint + cache-environment: true + cache-downloads: true + create-args: >- + -c conda-forge + python=3.11 + astropy + git + - name: Install base dependencies + shell: bash -el {0} + run: | + python -m pip install --upgrade pip + python -m pip install tox + - name: Print Python, pip, and tox versions + run: | + python -c "import sys; print(f'Python {sys.version}')" + python -c "import pip; print(f'pip {pip.__version__}')" + python -c "import tox; print(f'tox {tox.__version__}')" + - name: Run tests + shell: bash -el {0} + run: tox -e singletest + \ No newline at end of file From 2c9f049a6fa1ed1234791ad971a99b1a404a77be Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Wed, 27 Nov 2024 10:36:57 -0600 Subject: [PATCH 155/195] changed indent --- .github/workflows/ci_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index c9f762c26..694951b7a 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -96,7 +96,7 @@ jobs: # path: .tox/docs_out/ test-mamba: runs-on: ubuntu-latest - steps: + steps: - uses: actions/checkout@v4 - name: Set-Up Python Env uses: mamba-org/setup-micromamba@v1 From c28bd49460f6e3fe8c907c537d805f8db06bd379 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Wed, 27 Nov 2024 10:40:22 -0600 Subject: [PATCH 156/195] make sure tox is installed in the right place --- .github/workflows/ci_test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 694951b7a..db8587e2c 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -116,6 +116,7 @@ jobs: python -m pip install --upgrade pip python -m pip install tox - name: Print Python, pip, and tox versions + shell: bash -el {0} run: | python -c "import sys; print(f'Python {sys.version}')" python -c "import pip; print(f'pip {pip.__version__}')" From 50c687c91df3644f4be04694712783173d42c296 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Wed, 27 Nov 2024 10:44:45 -0600 Subject: [PATCH 157/195] change test --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index efadd9b9c..60f8fa754 100644 --- a/tox.ini +++ b/tox.ini @@ -66,7 +66,7 @@ deps = hypothesis<=6.72.0 setuptools # can change this as needed for a single test run -commands = pytest tests/test_model_derivatives.py +commands = pytest tests/test_precision.py [testenv:ephemeris_connection] From 38a4f3e74080811b482e1fc7193d98e1c3482a58 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Wed, 27 Nov 2024 10:48:42 -0600 Subject: [PATCH 158/195] change to macos --- .github/workflows/ci_test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index db8587e2c..985cd8bef 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -95,7 +95,7 @@ jobs: # name: documentation # path: .tox/docs_out/ test-mamba: - runs-on: ubuntu-latest + runs-on: macos-latest steps: - uses: actions/checkout@v4 - name: Set-Up Python Env @@ -106,6 +106,7 @@ jobs: cache-environment: true cache-downloads: true create-args: >- + --platform osx-64 -c conda-forge python=3.11 astropy From f51ce84a6dfaa0f5a871515126bfc13dd93fe34f Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 2 Dec 2024 09:23:28 -0600 Subject: [PATCH 159/195] try all tests --- .github/workflows/ci_test.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 985cd8bef..a0e500d5a 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -94,7 +94,7 @@ jobs: # with: # name: documentation # path: .tox/docs_out/ - test-mamba: + ci-tests-macos: runs-on: macos-latest steps: - uses: actions/checkout@v4 @@ -124,5 +124,6 @@ jobs: python -c "import tox; print(f'tox {tox.__version__}')" - name: Run tests shell: bash -el {0} - run: tox -e singletest + run: tox -e py313-test + \ No newline at end of file From b2a8785c5941fabb2adb5c940159e3cf6cdf74e1 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 2 Dec 2024 09:33:16 -0600 Subject: [PATCH 160/195] see if x64 precision is available --- .github/workflows/ci_test.yml | 3 +-- tox.ini | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index a0e500d5a..b2042b8a5 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -124,6 +124,5 @@ jobs: python -c "import tox; print(f'tox {tox.__version__}')" - name: Run tests shell: bash -el {0} - run: tox -e py313-test - + run: tox -e singletest \ No newline at end of file diff --git a/tox.ini b/tox.ini index 60f8fa754..50df42eb5 100644 --- a/tox.ini +++ b/tox.ini @@ -66,7 +66,7 @@ deps = hypothesis<=6.72.0 setuptools # can change this as needed for a single test run -commands = pytest tests/test_precision.py +commands = pytest conftest.py [testenv:ephemeris_connection] From e08615742197184478f175ef6509c26aac692470 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 2 Dec 2024 09:42:22 -0600 Subject: [PATCH 161/195] see if x64 precision is available --- .github/workflows/ci_test.yml | 2 +- tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index b2042b8a5..0e5498d68 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -124,5 +124,5 @@ jobs: python -c "import tox; print(f'tox {tox.__version__}')" - name: Run tests shell: bash -el {0} - run: tox -e singletest + run: tox -e py313-test \ No newline at end of file diff --git a/tox.ini b/tox.ini index 50df42eb5..60f8fa754 100644 --- a/tox.ini +++ b/tox.ini @@ -66,7 +66,7 @@ deps = hypothesis<=6.72.0 setuptools # can change this as needed for a single test run -commands = pytest conftest.py +commands = pytest tests/test_precision.py [testenv:ephemeris_connection] From 333df4ce65a23b4dcf6504e81403ebc22156d0e8 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 2 Dec 2024 11:26:27 -0600 Subject: [PATCH 162/195] added print of os, platform info --- .github/workflows/ci_test.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 0e5498d68..e7e95bba9 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -116,6 +116,11 @@ jobs: run: | python -m pip install --upgrade pip python -m pip install tox + - name: Print OS, machine info + shell: bash -el {0} + run: | + python -c "import os; print(f'os {os.uname()}')" + python -c "import platform; print(f'processor {platform.processor}')" - name: Print Python, pip, and tox versions shell: bash -el {0} run: | From 408cd25ca162e58f4b9fddb364fec37a4c18bea5 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 2 Dec 2024 11:31:32 -0600 Subject: [PATCH 163/195] added print of eps for longdouble --- .github/workflows/ci_test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index e7e95bba9..9f5d3169f 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -120,7 +120,8 @@ jobs: shell: bash -el {0} run: | python -c "import os; print(f'os {os.uname()}')" - python -c "import platform; print(f'processor {platform.processor}')" + python -c "import platform; print(f'processor {platform.processor()}')" + python -c "import numpy as np; print(f'eps: {np.finfo(np.longdouble).eps}')" - name: Print Python, pip, and tox versions shell: bash -el {0} run: | From 649340069f38294f01ad88aafd329de03b7415b5 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 2 Dec 2024 11:38:03 -0600 Subject: [PATCH 164/195] debug info to utils --- src/pint/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pint/utils.py b/src/pint/utils.py index 59f0d3076..b903da260 100644 --- a/src/pint/utils.py +++ b/src/pint/utils.py @@ -163,6 +163,7 @@ def check_longdouble_precision() -> bool: Returns True if long doubles have enough precision to use PINT for sub-microsecond timing on this machine. """ + log.debug(f"longdouble eps: {np.finfo(np.longdouble).eps}") return np.finfo(np.longdouble).eps < 2e-19 From 22484ce20c165a5b9073a2947d982a9c4155332d Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 2 Dec 2024 11:44:39 -0600 Subject: [PATCH 165/195] more debug info --- src/pint/utils.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pint/utils.py b/src/pint/utils.py index b903da260..436cfb3da 100644 --- a/src/pint/utils.py +++ b/src/pint/utils.py @@ -163,7 +163,12 @@ def check_longdouble_precision() -> bool: Returns True if long doubles have enough precision to use PINT for sub-microsecond timing on this machine. """ + log.debug(f"os {os.uname()}") + log.debug(f"processor {platform.processor()}") + log.debug(f"Python {sys.version}") + log.debug(f"eps: {np.finfo(np.longdouble).eps}") log.debug(f"longdouble eps: {np.finfo(np.longdouble).eps}") + log.debug(f"Info: {info_string()}") return np.finfo(np.longdouble).eps < 2e-19 From af53ed6dd269e5ee4af0c8728406b25cccce5aa5 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 2 Dec 2024 11:55:31 -0600 Subject: [PATCH 166/195] try to make shell env explicit --- .github/workflows/ci_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 9f5d3169f..0e1cfdf84 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -130,5 +130,5 @@ jobs: python -c "import tox; print(f'tox {tox.__version__}')" - name: Run tests shell: bash -el {0} - run: tox -e py313-test + run: bash -el {0} -c 'tox -e py313-test' \ No newline at end of file From 9dccea999b16294a16618bcca8fa5979a24ed2a5 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 2 Dec 2024 11:57:40 -0600 Subject: [PATCH 167/195] undo that --- .github/workflows/ci_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 0e1cfdf84..9f5d3169f 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -130,5 +130,5 @@ jobs: python -c "import tox; print(f'tox {tox.__version__}')" - name: Run tests shell: bash -el {0} - run: bash -el {0} -c 'tox -e py313-test' + run: tox -e py313-test \ No newline at end of file From f583171c104440cdcf0b453f058d868c260da2aa Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 2 Dec 2024 12:53:34 -0600 Subject: [PATCH 168/195] avoid tox? --- .github/workflows/ci_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 9f5d3169f..f9a8814c1 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -130,5 +130,5 @@ jobs: python -c "import tox; print(f'tox {tox.__version__}')" - name: Run tests shell: bash -el {0} - run: tox -e py313-test + run: pytest -v --pyargs tests \ No newline at end of file From 82c6fbab7682536f9ec65897b98cf9b6421f2cb2 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 2 Dec 2024 14:08:26 -0600 Subject: [PATCH 169/195] added requirements --- .github/workflows/ci_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index f9a8814c1..77b571aaf 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -115,7 +115,7 @@ jobs: shell: bash -el {0} run: | python -m pip install --upgrade pip - python -m pip install tox + python -m pip install tox pytest hypothesis numdifftools pathos setuptools - name: Print OS, machine info shell: bash -el {0} run: | From a1a2a6cfbd6dafa8e657180e6f3df5401d8c5afb Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 2 Dec 2024 14:27:34 -0600 Subject: [PATCH 170/195] added requirements --- .github/workflows/ci_test.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 77b571aaf..f306b0af2 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -128,6 +128,12 @@ jobs: python -c "import sys; print(f'Python {sys.version}')" python -c "import pip; print(f'pip {pip.__version__}')" python -c "import tox; print(f'tox {tox.__version__}')" + - name: Install PINT and requirements + shell: bash -el {0} + run: | + python -m pip install -r requirements.txt + python -m pip install -r requirements_dev.txt + python -m pip install --force-reinstall --no-deps . - name: Run tests shell: bash -el {0} run: pytest -v --pyargs tests From 4f204b8dc6480570327c1c9c377224ff8ce54bb6 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 3 Dec 2024 11:21:52 -0600 Subject: [PATCH 171/195] only do the test thats failing --- .github/workflows/ci_test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index f306b0af2..639262177 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -136,5 +136,6 @@ jobs: python -m pip install --force-reinstall --no-deps . - name: Run tests shell: bash -el {0} - run: pytest -v --pyargs tests + #run: pytest -v --pyargs tests + run: pytest -v --pyargs tests/test_phase_offset.py \ No newline at end of file From 89b75e88f0133c55834f2ba9d6840d218ad9627a Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 3 Dec 2024 11:26:23 -0600 Subject: [PATCH 172/195] back to all tests --- .github/workflows/ci_test.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 639262177..f306b0af2 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -136,6 +136,5 @@ jobs: python -m pip install --force-reinstall --no-deps . - name: Run tests shell: bash -el {0} - #run: pytest -v --pyargs tests - run: pytest -v --pyargs tests/test_phase_offset.py + run: pytest -v --pyargs tests \ No newline at end of file From ddfe38307077ce14e7becf826a837039e1e71eb1 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 3 Dec 2024 13:39:22 -0600 Subject: [PATCH 173/195] explicit seed --- tests/test_phase_offset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_phase_offset.py b/tests/test_phase_offset.py index d28fc26c0..61d46bd5f 100644 --- a/tests/test_phase_offset.py +++ b/tests/test_phase_offset.py @@ -26,7 +26,7 @@ def test_phase_offset(): m = get_model(io.StringIO(simplepar)) assert hasattr(m, "PHOFF") and m.PHOFF.value == 0.2 - + np.random.seed(1929) t = make_fake_toas_uniform( startMJD=50000, endMJD=50500, From 6864fd581a92c6376240453f779b5f82da7941b7 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 3 Dec 2024 14:20:42 -0600 Subject: [PATCH 174/195] remove debugging info --- src/pint/utils.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/pint/utils.py b/src/pint/utils.py index 436cfb3da..59f0d3076 100644 --- a/src/pint/utils.py +++ b/src/pint/utils.py @@ -163,12 +163,6 @@ def check_longdouble_precision() -> bool: Returns True if long doubles have enough precision to use PINT for sub-microsecond timing on this machine. """ - log.debug(f"os {os.uname()}") - log.debug(f"processor {platform.processor()}") - log.debug(f"Python {sys.version}") - log.debug(f"eps: {np.finfo(np.longdouble).eps}") - log.debug(f"longdouble eps: {np.finfo(np.longdouble).eps}") - log.debug(f"Info: {info_string()}") return np.finfo(np.longdouble).eps < 2e-19 From 7f643620223e5a927a0695d035e16bd1e946e99d Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 3 Dec 2024 14:20:55 -0600 Subject: [PATCH 175/195] remove old MacOS tests --- .github/workflows/ci_test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index f306b0af2..aa3a532cc 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -41,9 +41,9 @@ jobs: # - os: ubuntu-latest # python: '3.10' # tox_env: 'py310-test-alldeps-cov' - - os: macos-12 - python: '3.13' - tox_env: 'py313-test' + # - os: macos-12 + # python: '3.13' + # tox_env: 'py313-test' # - os: windows-latest # python: '3.8' # tox_env: 'py38-test' From 14c571846282cd6b3ba72428b5a479e42162ae67 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Wed, 4 Dec 2024 09:39:23 +0100 Subject: [PATCH 176/195] reruns --- requirements_dev.txt | 3 ++- tox.ini | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/requirements_dev.txt b/requirements_dev.txt index f5dfff94b..b3c22a6ac 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -11,6 +11,8 @@ wheel>=0.29.0 pytest>=4.3 pytest-cov>=2.7.1 pytest-runner>=5.1 +pytest-xdist +pytest-rerunfailures flake8>=3.7 pep8-naming>=0.8.2 flake8-docstrings>=1.4 @@ -38,4 +40,3 @@ loguru # click<=8.0.4 gprof2dot py-cpuinfo -pytest-xdist diff --git a/tox.ini b/tox.ini index efadd9b9c..58c0e0ebb 100644 --- a/tox.ini +++ b/tox.ini @@ -37,14 +37,15 @@ deps = cov: coverage cov: pytest-cov cov: pytest-remotedata + pytest-rerunfailures hypothesis numdifftools pathos setuptools commands = pip freeze - !cov: pytest - cov: pytest -v --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} + !cov: pytest --reruns 5 + cov: pytest -v --pyargs tests --cov=pint --cov-config={toxinidir}/.coveragerc {posargs} --reruns 5 cov: coverage xml -o {toxinidir}/coverage.xml depends = @@ -88,9 +89,11 @@ deps = matplotlib==3.4.3 scipy==1.9.0 pytest + pytest-rerunfailures coverage hypothesis<=6.72.0 -commands = {posargs:pytest} +commands + pytest --reruns 5 [testenv:report] skip_install = true From 443d4a6a89bc2712dad86b9ad45d89d61ada8699 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Wed, 4 Dec 2024 09:40:10 +0100 Subject: [PATCH 177/195] changelog --- CHANGELOG-unreleased.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index cd766f352..67577f84c 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -20,6 +20,7 @@ the released changes. - When TCB->TDB conversion info is missing, will print parameter name - Piecewise-constant model for chromatic variations (CMX) - `add_param` returns the name of the parameter (useful for numbered parameters) +- Rerun intermittent failures in CI ### Fixed - Changed WAVE_OM units from 1/d to rad/d. - When EQUAD is created from TNEQ, has proper TCB->TDB conversion info From 66e736b2c7ea6e8b98b7b2835d5dc0be3fcded00 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Wed, 4 Dec 2024 09:41:49 +0100 Subject: [PATCH 178/195] typo --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 58c0e0ebb..e54f6071f 100644 --- a/tox.ini +++ b/tox.ini @@ -92,7 +92,7 @@ deps = pytest-rerunfailures coverage hypothesis<=6.72.0 -commands +commands = pytest --reruns 5 [testenv:report] From c0965712e3857dbd1c748f9e2f2cc94381f73aef Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Wed, 4 Dec 2024 09:31:15 -0600 Subject: [PATCH 179/195] changelog, changed name of CI, changed python version --- .github/workflows/ci_test.yml | 4 ++-- CHANGELOG-unreleased.md | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index aa3a532cc..e550e50d4 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -94,7 +94,7 @@ jobs: # with: # name: documentation # path: .tox/docs_out/ - ci-tests-macos: + macos-latest-py313: runs-on: macos-latest steps: - uses: actions/checkout@v4 @@ -108,7 +108,7 @@ jobs: create-args: >- --platform osx-64 -c conda-forge - python=3.11 + python=3.13 astropy git - name: Install base dependencies diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 1f2a84439..1d63588d1 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -16,8 +16,11 @@ the released changes. - Added AIC and BIC calculation to be written in the post fit parfile from `event_optimize` - When TCB->TDB conversion info is missing, will print parameter name - `add_param` returns the name of the parameter (useful for numbered parameters) +- micromamba CI environment for testing macOS-latest, without tox ### Fixed - Changed WAVE_OM units from 1/d to rad/d. - When EQUAD is created from TNEQ, has proper TCB->TDB conversion info - TOA selection masks will work when only TOA is the first one ### Removed +- macOS 12 CI + From 6491552f689b4ab7cfbbc2fa48da881662902c6f Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Wed, 4 Dec 2024 11:18:38 -0600 Subject: [PATCH 180/195] remove typed_ast (deprecated) --- requirements_dev.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements_dev.txt b/requirements_dev.txt index f5dfff94b..de85bbaca 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -27,7 +27,6 @@ jupytext pdbpp tox pre-commit -typed-ast>=1.5.0 black~=24.0 pygments ipython From 9f7f0164ad888438d6b66284bc38b83435283131 Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Wed, 4 Dec 2024 17:25:54 -0500 Subject: [PATCH 181/195] Condense similar lines in derivative code. --- src/pint/models/glitch.py | 98 ++++++++++++--------------------------- 1 file changed, 29 insertions(+), 69 deletions(-) diff --git a/src/pint/models/glitch.py b/src/pint/models/glitch.py index 2aaf4f8e4..34071bd23 100644 --- a/src/pint/models/glitch.py +++ b/src/pint/models/glitch.py @@ -177,10 +177,7 @@ def validate(self): glf0d = getattr(self, glf0dnm) idx = glf0d.index if glf0d.value != 0.0 and getattr(self, "GLTD_%d" % idx).value == 0.0: - msg = ( - "None zero GLF0D_%d parameter needs a none" - " zero GLTD_%d parameter" % (idx, idx) - ) + msg = f"Non-zero GLF0D_{idx} parameter needs a non-zero GLTD_{idx} parameter" raise MissingParameter("Glitch", "GLTD_%d" % idx, msg) def print_par(self, format="pint"): @@ -232,114 +229,77 @@ def glitch_phase(self, toas, delay): ) return phs - def deriv_prep(self, toas, param, delay): + def deriv_prep(self, toas, param, delay, check_param): """Get the things we need for any of the derivative calcs""" - tbl = toas.table p, ids, idv = split_prefixed_name(param) + if p != f'{check_param}_': + raise ValueError( + f"Can not calculate d_phase_d_{check_param} with respect to {param}." + ) + tbl = toas.table eph = getattr(self, f"GLEP_{ids}").value dt = (tbl["tdbld"] - eph) * u.day - delay dt = dt.to(u.second) affected = np.where(dt > 0.0)[0] - return tbl, p, ids, idv, dt, affected + par = getattr(self, param) + zeros = np.zeros(len(tbl), dtype=np.longdouble) << 1/par.units + return tbl, p, ids, idv, dt, affected, par, zeros def d_phase_d_GLPH(self, toas, param, delay): """Calculate the derivative wrt GLPH""" - tbl, p, ids, idv, dt, affected = self.deriv_prep(toas, param, delay) - if p != "GLPH_": - raise ValueError( - f"Can not calculate d_phase_d_GLPH with respect to {param}." - ) - par_GLPH = getattr(self, param) - dpdGLPH = np.zeros(len(tbl), dtype=np.longdouble) / par_GLPH.units - dpdGLPH[affected] += 1.0 / par_GLPH.units + tbl, p, ids, idv, dt, affected, par_GLPH, dpdGLPH = self.deriv_prep(toas, param, delay, 'GLPH') + dpdGLPH[affected] = 1.0 / par_GLPH.units return dpdGLPH def d_phase_d_GLF0(self, toas, param, delay): """Calculate the derivative wrt GLF0""" - tbl, p, ids, idv, dt, affected = self.deriv_prep(toas, param, delay) - if p != "GLF0_": - raise ValueError( - f"Can not calculate d_phase_d_GLF0 with respect to {param}." - ) - par_GLF0 = getattr(self, param) - dpdGLF0 = np.zeros(len(tbl), dtype=np.longdouble) / par_GLF0.units + tbl, p, ids, idv, dt, affected, par_GLF0, dpdGLF0 = self.deriv_prep(toas, param, delay, 'GLF0') dpdGLF0[affected] = dt[affected] return dpdGLF0 def d_phase_d_GLF1(self, toas, param, delay): """Calculate the derivative wrt GLF1""" - tbl, p, ids, idv, dt, affected = self.deriv_prep(toas, param, delay) - if p != "GLF1_": - raise ValueError( - f"Can not calculate d_phase_d_GLF1 with respect to {param}." - ) - par_GLF1 = getattr(self, param) - dpdGLF1 = np.zeros(len(tbl), dtype=np.longdouble) / par_GLF1.units - dpdGLF1[affected] += np.longdouble(0.5) * dt[affected] * dt[affected] + tbl, p, ids, idv, dt, affected, par_GLF1, dpdGLF1 = self.deriv_prep(toas, param, delay,'GLF1') + dpdGLF1[affected] = 0.5 * dt[affected]**2 return dpdGLF1 def d_phase_d_GLF2(self, toas, param, delay): """Calculate the derivative wrt GLF1""" - tbl, p, ids, idv, dt, affected = self.deriv_prep(toas, param, delay) - if p != "GLF2_": - raise ValueError( - f"Can not calculate d_phase_d_GLF2 with respect to {param}." - ) - par_GLF2 = getattr(self, param) - dpdGLF2 = np.zeros(len(tbl), dtype=np.longdouble) / par_GLF2.units - dpdGLF2[affected] += ( - np.longdouble(1.0) / 6.0 * dt[affected] * dt[affected] * dt[affected] - ) + tbl, p, ids, idv, dt, affected, par_GLF2, dpdGLF2 = self.deriv_prep(toas, param, delay,'GLF2') + dpdGLF2[affected] = (1.0 / 6.0) * dt[affected]**3 return dpdGLF2 def d_phase_d_GLF0D(self, toas, param, delay): """Calculate the derivative wrt GLF0D""" - tbl, p, ids, idv, dt, affected = self.deriv_prep(toas, param, delay) - if p != "GLF0D_": - raise ValueError( - f"Can not calculate d_phase_d_GLF0D with respect to {param}." - ) - par_GLF0D = getattr(self, param) - tau = getattr(self, "GLTD_%d" % idv).quantity - dpdGLF0D = np.zeros(len(tbl), dtype=np.longdouble) / par_GLF0D.units - dpdGLF0D[affected] += tau * (np.longdouble(1.0) - np.exp(-dt[affected] / tau)) + tbl, p, ids, idv, dt, affected, par_GLF0D, dpdGLF0D = self.deriv_prep(toas, param, delay,'GLF0D') + print('glf0d','ids',ids,'idv',idv) + tau = getattr(self, f"GLTD_{idv}").quantity # CHECK, idv/ids + dpdGLF0D[affected] = tau * (1.0 - np.exp(-dt[affected] / tau)) return dpdGLF0D def d_phase_d_GLTD(self, toas, param, delay): """Calculate the derivative wrt GLTD""" - tbl, p, ids, idv, dt, affected = self.deriv_prep(toas, param, delay) - if p != "GLTD_": - raise ValueError( - f"Can not calculate d_phase_d_GLTD with respect to {param}." - ) - par_GLTD = getattr(self, param) + tbl, p, ids, idv, dt, affected, par_GLTD, dpdGLTD = self.deriv_prep(toas, param, delay,'GLTD') + print('gltd','ids',ids,'idv',idv) if par_GLTD.value == 0.0: - return np.zeros(len(tbl), dtype=np.longdouble) / par_GLTD.units - glf0d = getattr(self, f"GLF0D_{ids}").quantity + return dpdGLTD + glf0d = getattr(self, f"GLF0D_{ids}").quantity # CHECK, idv/ids tau = par_GLTD.quantity - dpdGLTD = np.zeros(len(tbl), dtype=np.longdouble) / par_GLTD.units - dpdGLTD[affected] += glf0d * ( - np.longdouble(1.0) - np.exp(-dt[affected] / tau) - ) + glf0d * tau * (-np.exp(-dt[affected] / tau)) * dt[affected] / (tau * tau) + et = np.exp(-dt[affected] / tau) + dpdGLTD[affected] = glf0d * (1.0 - np.exp(-dt[affected] / tau) * (1.0 + dt[affected]/tau)) return dpdGLTD def d_phase_d_GLEP(self, toas, param, delay): """Calculate the derivative wrt GLEP""" - tbl, p, ids, idv, dt, affected = self.deriv_prep(toas, param, delay) - if p != "GLEP_": - raise ValueError( - f"Can not calculate d_phase_d_GLEP with respect to {param}." - ) - par_GLEP = getattr(self, param) + tbl, p, ids, idv, dt, affected, par_GLEP, dpdGLEP = self.deriv_prep(toas, param, delay,'GLEP') glf0 = getattr(self, f"GLF0_{ids}").quantity glf1 = getattr(self, f"GLF1_{ids}").quantity glf2 = getattr(self, f"GLF2_{ids}").quantity glf0d = getattr(self, f"GLF0D_{ids}").quantity tau = getattr(self, f"GLTD_{ids}").quantity - dpdGLEP = np.zeros(len(tbl), dtype=np.longdouble) / par_GLEP.units dpdGLEP[affected] += ( -glf0 + -glf1 * dt[affected] + -0.5 * glf2 * dt[affected] ** 2 ) if tau.value != 0.0: - dpdGLEP[affected] += -glf0d / np.exp(dt[affected] / tau) + dpdGLEP[affected] -= glf0d * np.exp(-dt[affected] / tau) return dpdGLEP From 90f4ae1a8407162870f5f643f0c3aea3d73722fe Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Wed, 4 Dec 2024 18:01:51 -0500 Subject: [PATCH 182/195] F-strings, add tests, black. --- src/pint/models/glitch.py | 95 ++++++++++++++++++++++----------------- tests/test_glitch.py | 67 ++++++++++++++++++++++++--- 2 files changed, 116 insertions(+), 46 deletions(-) diff --git a/src/pint/models/glitch.py b/src/pint/models/glitch.py index 34071bd23..71714cdc3 100644 --- a/src/pint/models/glitch.py +++ b/src/pint/models/glitch.py @@ -145,40 +145,41 @@ def setup(self): ] for idx in set(self.glitch_indices): for param in self.glitch_prop: - if not hasattr(self, param + "%d" % idx): + if not hasattr(self, param + str(idx)): param0 = getattr(self, f"{param}1") self.add_param(param0.new_param(idx)) - getattr(self, param + "%d" % idx).value = 0.0 + getattr(self, param + str(idx)).value = 0.0 self.register_deriv_funcs( - getattr(self, f"d_phase_d_{param[:-1]}"), param + "%d" % idx + getattr(self, f"d_phase_d_{param[:-1]}"), param + str(idx) ) def validate(self): """Validate parameters input.""" super().validate() for idx in set(self.glitch_indices): - if not hasattr(self, "GLEP_%d" % idx): - msg = "Glitch Epoch is needed for Glitch %d." % idx - raise MissingParameter("Glitch", "GLEP_%d" % idx, msg) - else: # Check to see if both the epoch and phase are to be fit - if ( - hasattr(self, "GLPH_%d" % idx) - and (not getattr(self, "GLEP_%d" % idx).frozen) - and (not getattr(self, "GLPH_%d" % idx).frozen) - ): - raise ValueError( - "Both the glitch epoch and phase cannot be fit for Glitch %d." - % idx - ) + glep = f"GLEP_{idx}" + glph = f"GLPH_{idx}" + if (not hasattr(self, glep)) or (getattr(self, glep).quantity is None): + msg = f"Glitch Epoch is needed for Glitch {idx}" + raise MissingParameter("Glitch", glep, msg) + # Check to see if both the epoch and phase are to be fit + if ( + hasattr(self, glph) + and (not getattr(self, glep).frozen) + and (not getattr(self, glph).frozen) + ): + raise ValueError( + f"Both the glitch epoch and phase cannot be fit for Glitch {idx}." + ) # Check the Decay Term. glf0dparams = [x for x in self.params if x.startswith("GLF0D_")] for glf0dnm in glf0dparams: glf0d = getattr(self, glf0dnm) idx = glf0d.index - if glf0d.value != 0.0 and getattr(self, "GLTD_%d" % idx).value == 0.0: + if glf0d.value != 0.0 and getattr(self, f"GLTD_{idx}").value == 0.0: msg = f"Non-zero GLF0D_{idx} parameter needs a non-zero GLTD_{idx} parameter" - raise MissingParameter("Glitch", "GLTD_%d" % idx, msg) + raise MissingParameter("Glitch", f"GLTD_{idx}", msg) def print_par(self, format="pint"): result = "" @@ -201,17 +202,17 @@ def glitch_phase(self, toas, delay): glep = getattr(self, glepnm) idx = glep.index eph = glep.value - dphs = getattr(self, "GLPH_%d" % idx).quantity - dF0 = getattr(self, "GLF0_%d" % idx).quantity - dF1 = getattr(self, "GLF1_%d" % idx).quantity - dF2 = getattr(self, "GLF2_%d" % idx).quantity + dphs = getattr(self, f"GLPH_{idx}").quantity + dF0 = getattr(self, f"GLF0_{idx}").quantity + dF1 = getattr(self, f"GLF1_{idx}").quantity + dF2 = getattr(self, f"GLF2_{idx}").quantity dt = (tbl["tdbld"] - eph) * u.day - delay dt = dt.to(u.second) affected = dt > 0.0 # TOAs affected by glitch # decay term - dF0D = getattr(self, "GLF0D_%d" % idx).quantity + dF0D = getattr(self, f"GLF0D_{idx}").quantity if dF0D != 0.0: - tau = getattr(self, "GLTD_%d" % idx).quantity + tau = getattr(self, f"GLTD_{idx}").quantity decayterm = dF0D * tau * (1.0 - np.exp(-(dt[affected] / tau))) else: decayterm = u.Quantity(0) @@ -232,7 +233,7 @@ def glitch_phase(self, toas, delay): def deriv_prep(self, toas, param, delay, check_param): """Get the things we need for any of the derivative calcs""" p, ids, idv = split_prefixed_name(param) - if p != f'{check_param}_': + if p != f"{check_param}_": raise ValueError( f"Can not calculate d_phase_d_{check_param} with respect to {param}." ) @@ -242,56 +243,70 @@ def deriv_prep(self, toas, param, delay, check_param): dt = dt.to(u.second) affected = np.where(dt > 0.0)[0] par = getattr(self, param) - zeros = np.zeros(len(tbl), dtype=np.longdouble) << 1/par.units + zeros = np.zeros(len(tbl), dtype=np.longdouble) << 1 / par.units return tbl, p, ids, idv, dt, affected, par, zeros def d_phase_d_GLPH(self, toas, param, delay): """Calculate the derivative wrt GLPH""" - tbl, p, ids, idv, dt, affected, par_GLPH, dpdGLPH = self.deriv_prep(toas, param, delay, 'GLPH') + tbl, p, ids, idv, dt, affected, par_GLPH, dpdGLPH = self.deriv_prep( + toas, param, delay, "GLPH" + ) dpdGLPH[affected] = 1.0 / par_GLPH.units return dpdGLPH def d_phase_d_GLF0(self, toas, param, delay): """Calculate the derivative wrt GLF0""" - tbl, p, ids, idv, dt, affected, par_GLF0, dpdGLF0 = self.deriv_prep(toas, param, delay, 'GLF0') + tbl, p, ids, idv, dt, affected, par_GLF0, dpdGLF0 = self.deriv_prep( + toas, param, delay, "GLF0" + ) dpdGLF0[affected] = dt[affected] return dpdGLF0 def d_phase_d_GLF1(self, toas, param, delay): """Calculate the derivative wrt GLF1""" - tbl, p, ids, idv, dt, affected, par_GLF1, dpdGLF1 = self.deriv_prep(toas, param, delay,'GLF1') - dpdGLF1[affected] = 0.5 * dt[affected]**2 + tbl, p, ids, idv, dt, affected, par_GLF1, dpdGLF1 = self.deriv_prep( + toas, param, delay, "GLF1" + ) + dpdGLF1[affected] = 0.5 * dt[affected] ** 2 return dpdGLF1 def d_phase_d_GLF2(self, toas, param, delay): """Calculate the derivative wrt GLF1""" - tbl, p, ids, idv, dt, affected, par_GLF2, dpdGLF2 = self.deriv_prep(toas, param, delay,'GLF2') - dpdGLF2[affected] = (1.0 / 6.0) * dt[affected]**3 + tbl, p, ids, idv, dt, affected, par_GLF2, dpdGLF2 = self.deriv_prep( + toas, param, delay, "GLF2" + ) + dpdGLF2[affected] = (1.0 / 6.0) * dt[affected] ** 3 return dpdGLF2 def d_phase_d_GLF0D(self, toas, param, delay): """Calculate the derivative wrt GLF0D""" - tbl, p, ids, idv, dt, affected, par_GLF0D, dpdGLF0D = self.deriv_prep(toas, param, delay,'GLF0D') - print('glf0d','ids',ids,'idv',idv) - tau = getattr(self, f"GLTD_{idv}").quantity # CHECK, idv/ids + tbl, p, ids, idv, dt, affected, par_GLF0D, dpdGLF0D = self.deriv_prep( + toas, param, delay, "GLF0D" + ) + tau = getattr(self, f"GLTD_{ids}").quantity dpdGLF0D[affected] = tau * (1.0 - np.exp(-dt[affected] / tau)) return dpdGLF0D def d_phase_d_GLTD(self, toas, param, delay): """Calculate the derivative wrt GLTD""" - tbl, p, ids, idv, dt, affected, par_GLTD, dpdGLTD = self.deriv_prep(toas, param, delay,'GLTD') - print('gltd','ids',ids,'idv',idv) + tbl, p, ids, idv, dt, affected, par_GLTD, dpdGLTD = self.deriv_prep( + toas, param, delay, "GLTD" + ) if par_GLTD.value == 0.0: return dpdGLTD - glf0d = getattr(self, f"GLF0D_{ids}").quantity # CHECK, idv/ids + glf0d = getattr(self, f"GLF0D_{ids}").quantity tau = par_GLTD.quantity et = np.exp(-dt[affected] / tau) - dpdGLTD[affected] = glf0d * (1.0 - np.exp(-dt[affected] / tau) * (1.0 + dt[affected]/tau)) + dpdGLTD[affected] = glf0d * ( + 1.0 - np.exp(-dt[affected] / tau) * (1.0 + dt[affected] / tau) + ) return dpdGLTD def d_phase_d_GLEP(self, toas, param, delay): """Calculate the derivative wrt GLEP""" - tbl, p, ids, idv, dt, affected, par_GLEP, dpdGLEP = self.deriv_prep(toas, param, delay,'GLEP') + tbl, p, ids, idv, dt, affected, par_GLEP, dpdGLEP = self.deriv_prep( + toas, param, delay, "GLEP" + ) glf0 = getattr(self, f"GLF0_{ids}").quantity glf1 = getattr(self, f"GLF1_{ids}").quantity glf2 = getattr(self, f"GLF2_{ids}").quantity diff --git a/tests/test_glitch.py b/tests/test_glitch.py index 4d7eac8ad..150879120 100644 --- a/tests/test_glitch.py +++ b/tests/test_glitch.py @@ -1,3 +1,4 @@ +from io import StringIO import os import pytest @@ -5,8 +6,9 @@ import numpy as np import pytest +from pint.exceptions import MissingParameter import pint.fitter -import pint.models +from pint.models import get_model import pint.residuals import pint.toa from pinttestdata import datadir @@ -14,11 +16,54 @@ parfile = os.path.join(datadir, "prefixtest.par") timfile = os.path.join(datadir, "prefixtest.tim") +basepar = """ + PSRJ J0835-4510 + RAJ 08:35:20.61149 + DECJ -45:10:34.8751 + F0 11.18965156782 + PEPOCH 55305 + DM 67.99 + UNITS TDB +""" + +good = """ + GLEP_1 55555 + GLPH_1 0 + GLF0_1 1.0e-6 + GLF1_1 -1.0e-12 + GLF0D_1 1.0e-6 + GLTD_1 10.0 +""" + +# no exponential decay set +bad1 = """ + GLEP_1 55555 + GLF0_1 1.0e-6 + GLF1_1 -1.0e-12 + GLF0D_1 1.0e-6 + GLTD_1 0.0 +""" + +# no epoch set +bad2 = """ + GLPH_1 0 + GLF0_1 1.0e-6 + GLF1_1 -1.0e-12 +""" + +# fitting both epoch and glitch phase +bad3 = """ + GLEP_1 55555 1 0 + GLPH_1 0 1 0 + GLF0_1 1.0e-6 + GLF1_1 -1.0e-12 +""" + class TestGlitch: @classmethod def setup_class(cls): - cls.m = pint.models.get_model(parfile) + cls.m = get_model(parfile) cls.t = pint.toa.get_TOAs(timfile, ephem="DE405", include_bipm=False) cls.f = pint.fitter.WLSFitter(cls.t, cls.m) @@ -37,11 +82,11 @@ def test_glitch_der(self): for pf in self.m.glitch_prop: for idx in set(self.m.glitch_indices): if pf in ["GLF0D_", "GLTD_"]: - getattr(self.m, "GLF0D_%d" % idx).value = 1.0 - getattr(self.m, "GLTD_%d" % idx).value = 100 + getattr(self.m, f"GLF0D_{idx}").value = 1.0 + getattr(self.m, f"GLTD_{idx}").value = 100 else: - getattr(self.m, "GLF0D_%d" % idx).value = 0.0 - getattr(self.m, "GLTD_%d" % idx).value = 0.0 + getattr(self.m, f"GLF0D_{idx}").value = 0.0 + getattr(self.m, f"GLTD_{idx}").value = 0.0 param = pf + str(idx) adf = self.m.d_phase_d_param(self.t, delay, param) param_obj = getattr(self.m, param) @@ -54,3 +99,13 @@ def test_glitch_der(self): errormsg = f"Derivatives for {param} is not accurate, max relative difference is" errormsg += " %lf" % np.nanmax(np.abs(r_diff.value)) assert np.nanmax(np.abs(r_diff.value)) < 1e-3, errormsg + + def test_bad_input(self): + get_model(StringIO(basepar + good)) + with pytest.raises(MissingParameter): + get_model(StringIO(basepar + bad1)) + with pytest.raises(MissingParameter): + m = get_model(StringIO(basepar + bad2)) + print(m) + with pytest.raises(ValueError): + get_model(StringIO(basepar + bad3)) From b4b01c126761bcc7250de8061bf45f2dd1f4a32d Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Thu, 5 Dec 2024 13:28:10 -0500 Subject: [PATCH 183/195] f-string tweaks. --- src/pint/models/glitch.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/pint/models/glitch.py b/src/pint/models/glitch.py index 71714cdc3..6bac43dc4 100644 --- a/src/pint/models/glitch.py +++ b/src/pint/models/glitch.py @@ -145,12 +145,13 @@ def setup(self): ] for idx in set(self.glitch_indices): for param in self.glitch_prop: - if not hasattr(self, param + str(idx)): + check = f"{param}{idx}" + if not hasattr(self, check): param0 = getattr(self, f"{param}1") self.add_param(param0.new_param(idx)) - getattr(self, param + str(idx)).value = 0.0 + getattr(self, check).value = 0.0 self.register_deriv_funcs( - getattr(self, f"d_phase_d_{param[:-1]}"), param + str(idx) + getattr(self, f"d_phase_d_{param[:-1]}"), check ) def validate(self): @@ -185,7 +186,7 @@ def print_par(self, format="pint"): result = "" for idx in set(self.glitch_indices): for param in self.glitch_prop: - par = getattr(self, param + "%d" % idx) + par = getattr(self, f"{param}{idx}") result += par.as_parfile_line(format=format) return result From 5eab9d737d885c0a7aa1efb8ff61ca24186d4803 Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Thu, 5 Dec 2024 13:58:02 -0500 Subject: [PATCH 184/195] Remove debug info on glitch phase. --- src/pint/models/glitch.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pint/models/glitch.py b/src/pint/models/glitch.py index 6bac43dc4..33d90e9f1 100644 --- a/src/pint/models/glitch.py +++ b/src/pint/models/glitch.py @@ -218,7 +218,6 @@ def glitch_phase(self, toas, delay): else: decayterm = u.Quantity(0) - log.debug(f"Glitch phase for glitch {idx}: {dphs} {dphs.unit}") phs[affected] += ( dphs + dt[affected] From 9fa73a573ae07c2de6fe558b6ac69dc6dcf8c2bd Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Fri, 6 Dec 2024 21:28:12 +0100 Subject: [PATCH 185/195] cleanup --- CHANGELOG-unreleased.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index bdf8d466d..140adcef0 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -20,9 +20,7 @@ the released changes. - When TCB->TDB conversion info is missing, will print parameter name - Piecewise-constant model for chromatic variations (CMX) - `add_param` returns the name of the parameter (useful for numbered parameters) - - Rerun intermittent failures in CI - - micromamba CI environment for testing macOS-latest, without tox ### Fixed From 0ac3926c64bae82aa7ece432bbe1499f8ea517c8 Mon Sep 17 00:00:00 2001 From: Matthew Kerr Date: Fri, 6 Dec 2024 18:42:45 -0500 Subject: [PATCH 186/195] Add change log entry. --- CHANGELOG-unreleased.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index cd766f352..28c549584 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -24,4 +24,5 @@ the released changes. - Changed WAVE_OM units from 1/d to rad/d. - When EQUAD is created from TNEQ, has proper TCB->TDB conversion info - TOA selection masks will work when only TOA is the first one +- Condense code in Glitch model and add test coverage. ### Removed From b75c94669dd044a29411a40557dc0faa2a9ba73f Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 10 Dec 2024 10:06:48 +0100 Subject: [PATCH 187/195] reruns for macos --- .github/workflows/ci_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index e550e50d4..dc096a29c 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -136,5 +136,5 @@ jobs: python -m pip install --force-reinstall --no-deps . - name: Run tests shell: bash -el {0} - run: pytest -v --pyargs tests + run: pytest -v --pyargs tests --reruns 5 \ No newline at end of file From 38dd5118bb2cfa36e5bc20c8ec97bcf3ae6ae981 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 10 Dec 2024 10:09:20 +0100 Subject: [PATCH 188/195] cleanup --- CHANGELOG-unreleased.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index f95d81a8d..575b8ebca 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -22,7 +22,6 @@ the released changes. - `add_param` returns the name of the parameter (useful for numbered parameters) - Rerun intermittent failures in CI - micromamba CI environment for testing macOS-latest, without tox - ### Fixed - Changed WAVE_OM units from 1/d to rad/d. - When EQUAD is created from TNEQ, has proper TCB->TDB conversion info From 091b531113dfa310ddf455695798da6346aedcf2 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 10 Dec 2024 11:37:29 -0600 Subject: [PATCH 189/195] fixed some docstrings --- src/pint/models/binary_bt.py | 43 +++++++++++++++++++++------------- src/pint/models/noise_model.py | 29 +++++++++++++---------- src/pint/models/wavex.py | 39 +++++++++++++++++------------- 3 files changed, 66 insertions(+), 45 deletions(-) diff --git a/src/pint/models/binary_bt.py b/src/pint/models/binary_bt.py index 8c54e93da..03ad52583 100644 --- a/src/pint/models/binary_bt.py +++ b/src/pint/models/binary_bt.py @@ -21,7 +21,7 @@ class BinaryBT(PulsarBinary): """Blandford and Teukolsky binary model. - This binary model is described in Blandford and Teukolshy 1976. It is + This binary model is described in Blandford and Teukolsky (1976). It is a relatively simple parametrized post-Keplerian model that does not support Shapiro delay calculations. @@ -36,12 +36,16 @@ class BinaryBT(PulsarBinary): Notes ----- Because PINT's binary models all support specification of multiple orbital - frequency derivatives FBn, this is capable of behaving like the model called - BTX in tempo2. The model called BTX in tempo instead supports multiple - (non-interacting) companions, and that is not supported here. Neither can - PINT accept "BTX" as an alias for this model. + frequency derivatives ``FBn``, this is capable of behaving like the model called + ``BTX`` in ``tempo2``. The model called ``BTX`` in ``tempo`` instead supports multiple + (non-interacting) companions, and that is not supported here. + + References + ---------- + - Blandford & Teukolsky 1976, ApJ, 205, 580 [1]_ + + .. [1] https://ui.adsabs.harvard.edu/abs/1976ApJ...205..580B/abstract - See Blandford & Teukolsky 1976, ApJ, 205, 580. """ register = True @@ -82,16 +86,23 @@ def validate(self): class BinaryBTPiecewise(PulsarBinary): - """Model implementing the BT model with piecewise orbital parameters A1X and T0X. This model lets the user specify time ranges and fit for a different piecewise orbital parameter in each time range, - This is a PINT pulsar binary BTPiecewise model class, a subclass of PulsarBinary. - It is a wrapper for stand alone BTPiecewise class defined in - ./stand_alone_psr_binary/BT_piecewise.py - The aim for this class is to connect the stand alone binary model with the PINT platform. - BTpiecewise special parameters, where xxxx denotes the 4-digit index of the piece: - T0X_xxxx Piecewise T0 values for piece - A1X_xxxx Piecewise A1 values for piece - XR1_xxxx Lower time boundary of piece - XR2_xxxx Upper time boundary of piece + """BT model with piecewise orbital parameters ``A1X`` and ``T0X``. This model lets the user specify time ranges and fit for a different piecewise orbital parameter in each time range. + + ``BTpiecewise`` special parameters, where xxxx denotes the 4-digit index of the piece: + + - ``T0X_xxxx``: Piecewise ``T0`` values for piece + - ``A1X_xxxx``: Piecewise ``A1`` values for piece + - ``XR1_xxxx``: Lower time boundary of piece + - ``XR2_xxxx``: Upper time boundary of piece + + The actual calculations for this are done in + :class:`pint.models.stand_alone_psr_binaries.BT_piecewise.BTpiecewise` + + Parameters supported: + + .. paramtable:: + :class: pint.models.binary_bt.BinaryBTPiecewise + """ register = True diff --git a/src/pint/models/noise_model.py b/src/pint/models/noise_model.py index 299787fe5..364b0b660 100644 --- a/src/pint/models/noise_model.py +++ b/src/pint/models/noise_model.py @@ -442,8 +442,7 @@ def ecorr_cov_matrix(self, toas): class PLDMNoise(NoiseComponent): - """Model of DM variations as radio frequency-dependent noise with a - power-law spectrum. + """Model of DM variations as radio frequency-dependent noise with a power-law spectrum. Variations in DM over time result from both the proper motion of the pulsar and the changing electron number density along the line of sight @@ -459,9 +458,11 @@ class PLDMNoise(NoiseComponent): .. paramtable:: :class: pint.models.noise_model.PLDMNoise - Note - ---- - Ref: Lentati et al. 2014, MNRAS 437(3), 3004-3023 + References + ---------- + - Lentati et al. 2014, MNRAS 437(3), 3004-3023 [1]_ + + .. [1] https://ui.adsabs.harvard.edu/abs/2014MNRAS.437.3004L/abstract """ @@ -558,8 +559,7 @@ def pl_dm_cov_matrix(self, toas): class PLChromNoise(NoiseComponent): - """Model of a radio frequency-dependent noise with a power-law spectrum and - arbitrary chromatic index. + """Model of a radio frequency-dependent noise with a power-law spectrum and arbitrary chromatic index. Such variations are usually attributed to time-variable scattering in the ISM. Scattering smears/broadens the shape of the pulse profile by convolving it with @@ -579,9 +579,11 @@ class PLChromNoise(NoiseComponent): .. paramtable:: :class: pint.models.noise_model.PLChromNoise - Note - ---- - Ref: Lentati et al. 2014, MNRAS 437(3), 3004-3023 + References + ---------- + - Lentati et al. 2014, MNRAS 437(3), 3004-3023 [1]_ + + .. [1] https://ui.adsabs.harvard.edu/abs/2014MNRAS.437.3004L/abstract """ register = True @@ -692,10 +694,11 @@ class PLRedNoise(NoiseComponent): .. paramtable:: :class: pint.models.noise_model.PLRedNoise - Note - ---- - Ref: Lentati et al. 2014, MNRAS 437(3), 3004-3023 + References + ---------- + - Lentati et al. 2014, MNRAS 437(3), 3004-3023 [1]_ + .. [1] https://ui.adsabs.harvard.edu/abs/2014MNRAS.437.3004L/abstract """ register = True diff --git a/src/pint/models/wavex.py b/src/pint/models/wavex.py index f1dd24a60..ecaf34f5a 100644 --- a/src/pint/models/wavex.py +++ b/src/pint/models/wavex.py @@ -12,9 +12,7 @@ class WaveX(DelayComponent): """ - Implementation of the wave model as a delay correction - - Delays are expressed as a sum of sinusoids. + Implementation of the wave model as a delay correction, with delays are expressed as a sum of sinusoids. Used for decomposition of timing noise into a series of sine/cosine components with the amplitudes as fitted parameters. @@ -23,25 +21,34 @@ class WaveX(DelayComponent): .. paramtable:: :class: pint.models.wavex.WaveX - This is an extension of the L13 method described in Lentati et al., 2013 doi: 10.1103/PhysRevD.87.104021 - This model is similar to the TEMPO2 WAVE model parameters and users can convert a `TimingModel` with a Wave model - to a WaveX model and produce the same results. The main differences are that the WaveX frequencies are explicitly stated, + This is an extension of the method described in Lentati et al. (2013). + This model is similar to the TEMPO2 WAVE model parameters and users can convert a :class:`~pint.models/timing_model.TimingModel` + with a :class:`~pint.models.wave.Wave` model to a ``WaveX`` model and produce the same results. + The main differences are that the ``WaveX`` frequencies are explicitly stated, they do not necessarily need to be harmonics of some base frequency, the wave amplitudes are fittable parameters, and the - sine and cosine amplutides are reported as separate `prefixParameter`s rather than as a single `pairParameter`. + sine and cosine amplutides are reported as separate :class:`~pint.models.parameter.prefixParameter` rather than as a + single :class:`pint.models.parameter.pairParameter`. Analogous parameters in both models have the same units: - WAVEEPOCH is the same as WXEPOCH - WAVEOM and WXFREQ_000N have units of 1/d - WAVEN and WXSIN_000N/WXCOS_000N have units of seconds - The `pint.utils` functions `translate_wave_to_wavex()` and `translate_wavex_to_wave()` can be used to go back and forth between - two model. + - ``WAVEEPOCH`` is the same as ``WXEPOCH`` + - ``WAVEOM`` and ``WXFREQ_000N`` have units of 1/d + - ``WAVEN`` and ``WXSIN_000N/WXCOS_000N`` have units of seconds + + The :mod:`pint.utils` functions :func:`~pint.utils.translate_wave_to_wavex` and :func:`~pint.utils.translate_wavex_to_wave` + can be used to go back and forth between two model. + + WARNING: If the choice of ``WaveX`` frequencies in a :class:`~pint.models/timing_model.TimingModel` doesn't correspond to harmonics of some base + freqeuncy, it will not be possible to convert it to a :class:`~pint.models.wave.Wave` model. + + To set up a ``WaveX`` model, users can use the :mod:`pint.utils` function :func:`~pint.utils.wavex_setup` with either a list of frequencies or a choice + of harmonics of a base frequency determined by ``2 * pi /Timespan`` - WARNING: If the choice of WaveX frequencies in a `TimingModel` doesn't correspond to harmonics of some base - freqeuncy, it will not be possible to convert it to a Wave model. + References + ---------- + - Lentati et al. (2013), PRD, 87, 104021 [1]_ - To set up a WaveX model, users can use the `pint.utils` function `wavex_setup()` with either a list of frequencies or a choice - of harmonics of a base frequency determined by 2 * pi /Timespan + .. [1] https://ui.adsabs.harvard.edu/abs/2013PhRvD..87j4021L/abstract """ register = True From 4a67d29f232b9791ec7d543c57caa6ca5fdec41e Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 10 Dec 2024 12:07:18 -0600 Subject: [PATCH 190/195] changelog --- CHANGELOG-unreleased.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 7579adb51..7f41a59b7 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -26,6 +26,7 @@ the released changes. - When EQUAD is created from TNEQ, has proper TCB->TDB conversion info - TOA selection masks will work when only TOA is the first one - Condense code in Glitch model and add test coverage. +- Fixed some docstrings for binary models. ### Removed - macOS 12 CI From a8a811d467f7175cc3c6a570f0c86e12b93101f7 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 10 Dec 2024 12:23:46 -0600 Subject: [PATCH 191/195] fixed find_empty_masks --- CHANGELOG-unreleased.md | 1 + src/pint/models/timing_model.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 7579adb51..51545be13 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -26,6 +26,7 @@ the released changes. - When EQUAD is created from TNEQ, has proper TCB->TDB conversion info - TOA selection masks will work when only TOA is the first one - Condense code in Glitch model and add test coverage. +- `find_empty_masks` will now search through `CMX` parameters ### Removed - macOS 12 CI diff --git a/src/pint/models/timing_model.py b/src/pint/models/timing_model.py index 68fe886bf..0d3d99431 100644 --- a/src/pint/models/timing_model.py +++ b/src/pint/models/timing_model.py @@ -109,6 +109,9 @@ ignore_prefix = {"DMXF1_", "DMXF2_", "DMXEP_"} +# prefixes of parameters that may need to be checked for empty ranges +prefixes = ["DM", "SW", "CM"] + DEFAULT_ORDER = [ "astrometry", "jump_delay", @@ -2901,7 +2904,7 @@ def find_empty_masks(self, toas, freeze=False): if freeze: log.info(f"'{maskpar}' has no TOAs so freezing") getattr(self, maskpar).frozen = True - for prefix in ["DM", "SW"]: + for prefix in prefixes: mapping = pint.utils.xxxselections(self, toas, prefix=prefix) for k in mapping: if len(mapping[k]) == 0: From 9994a0c55f2738373bcaf3650dbfe2262b3a8499 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 10 Dec 2024 14:59:40 -0600 Subject: [PATCH 192/195] validation allows for R1<=toa and R2>=toa; warns when R1==R2 --- src/pint/models/dispersion_model.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pint/models/dispersion_model.py b/src/pint/models/dispersion_model.py index 5262795ce..218a9bec7 100644 --- a/src/pint/models/dispersion_model.py +++ b/src/pint/models/dispersion_model.py @@ -627,6 +627,10 @@ def validate(self): r2[j] = getattr(self, f"DMXR2_{index:04d}").quantity.mjd indices[j] = index for j, index in enumerate(DMXR1_mapping): + if (r1[j] == r2[j]) and (r1[j] > 0): + log.warning( + f"Start of DMX_{index:04d} ({r1[j]}) equal to end of DMX_{index:04d} ({r2[j]})" + ) if np.any((r1[j] > r1) & (r1[j] < r2)): k = np.where((r1[j] > r1) & (r1[j] < r2))[0] for kk in k.flatten(): @@ -651,7 +655,7 @@ def validate_toas(self, toas): b = self._parent[DMXR1_mapping[k]].quantity.mjd * u.d e = self._parent[DMXR2_mapping[k]].quantity.mjd * u.d mjds = toas.get_mjds() - n = np.sum((b <= mjds) & (mjds < e)) + n = np.sum((b <= mjds) & (mjds <= e)) if n == 0: bad_parameters.append(DMX_mapping[k]) if bad_parameters: From 6b9c61f599da70cdbfb9630512430a3022dce3e0 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Wed, 11 Dec 2024 11:46:57 -0600 Subject: [PATCH 193/195] initialization of dmx_selector now in validate() --- src/pint/models/dispersion_model.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pint/models/dispersion_model.py b/src/pint/models/dispersion_model.py index 218a9bec7..595379717 100644 --- a/src/pint/models/dispersion_model.py +++ b/src/pint/models/dispersion_model.py @@ -643,6 +643,8 @@ def validate(self): log.warning( f"End of DMX_{index:04d} ({r1[j]}-{r2[j]}) overlaps with DMX_{indices[kk]:04d} ({r1[kk]}-{r2[kk]})" ) + if not hasattr(self, "dmx_toas_selector"): + self.dmx_toas_selector = TOASelect(is_range=True) def validate_toas(self, toas): DMX_mapping = self.get_prefix_mapping_component("DMX_") From 92675b80ae48384bb5a5eb4b3ad9a333a4438963 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Thu, 12 Dec 2024 13:40:11 -0600 Subject: [PATCH 194/195] added metadata to model, and included it in printout --- CHANGELOG-unreleased.md | 1 + src/pint/models/model_builder.py | 5 +++++ src/pint/models/timing_model.py | 7 +++++++ 3 files changed, 13 insertions(+) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index c9222a23d..d3f685ee6 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -22,6 +22,7 @@ the released changes. - `add_param` returns the name of the parameter (useful for numbered parameters) - Rerun intermittent failures in CI - micromamba CI environment for testing macOS-latest, without tox +- models now have metadata dictionary ### Fixed - Changed WAVE_OM units from 1/d to rad/d. - When EQUAD is created from TNEQ, has proper TCB->TDB conversion info diff --git a/src/pint/models/model_builder.py b/src/pint/models/model_builder.py index 560b0ab2c..36a7ac5dc 100644 --- a/src/pint/models/model_builder.py +++ b/src/pint/models/model_builder.py @@ -251,6 +251,10 @@ def __call__( if not hasattr(tm, "NoiseComponent_list"): setattr(tm, "NoiseComponent_list", []) + tm.meta["allow_tcb"] = allow_tcb_ + tm.meta["convert_tcb"] = convert_tcb + tm.meta["allow_T2"] = allow_T2 + return tm def _validate_components(self): @@ -851,6 +855,7 @@ def get_model( **kwargs, ) model.name = parfile + model.meta["original_name"] = parfile return model diff --git a/src/pint/models/timing_model.py b/src/pint/models/timing_model.py index 0d3d99431..d6aeb0525 100644 --- a/src/pint/models/timing_model.py +++ b/src/pint/models/timing_model.py @@ -29,6 +29,7 @@ import abc import copy +import datetime import inspect import contextlib from collections import OrderedDict, defaultdict @@ -228,6 +229,8 @@ class TimingModel: ---------- name : str The name of the timing model + meta : dict + A dictionary of metadata component_types : list A list of the distinct categories of component. For example, delay components will be register as 'DelayComponent'. @@ -242,6 +245,9 @@ def __init__(self, name="", components=[]): "First parameter should be the model name, was {!r}".format(name) ) self.name = name + self.meta = { + "read_time": f"{datetime.datetime.now().isoformat()}", + } self.component_types = [] self.top_level_params = [] self.add_param_from_top( @@ -2766,6 +2772,7 @@ def as_parfile( if include_info: info_string = pint.utils.info_string(prefix_string="# ", comment=comment) info_string += f"\n# Format: {format.lower()}" + info_string += "".join([f"\n# {x}: {self.meta[x]}" for x in self.meta]) result_begin = info_string + "\n" else: result_begin = "" From 91be3152c983670d8c6bc16a749f4457ac138eb6 Mon Sep 17 00:00:00 2001 From: Paul Ray Date: Wed, 18 Dec 2024 12:03:06 -0500 Subject: [PATCH 195/195] Update CHANGELOG for v 1.1.1 --- CHANGELOG-unreleased.md | 20 -------------------- CHANGELOG.md | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index d3f685ee6..a2deae5cd 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -9,27 +9,7 @@ the released changes. ## Unreleased ### Changed -- Command line scripts now automatically do `allow_tcb` and `allow_T2` while reading par files. -- Updated the `plot_chains` function in `event_optimize` so that the subplots are a fixed size to prevent the subplots from being condensed in the case of many fit parameters. ### Added -- Time derivatives of NE_SW in `SolarWindDispersion` -- New prefix pattern for `split_prefixed_name` to handle derivatives of NE_SW -- Added an option `nbin` to `photonphase` to decide how many phase bins to use for the phaseogram -- Added an option `linearize_model` to speed up the photon phases calculation within `event_optimize` through the designmatrix. -- Added AIC and BIC calculation to be written in the post fit parfile from `event_optimize` -- When TCB->TDB conversion info is missing, will print parameter name -- Piecewise-constant model for chromatic variations (CMX) -- `add_param` returns the name of the parameter (useful for numbered parameters) -- Rerun intermittent failures in CI -- micromamba CI environment for testing macOS-latest, without tox -- models now have metadata dictionary ### Fixed -- Changed WAVE_OM units from 1/d to rad/d. -- When EQUAD is created from TNEQ, has proper TCB->TDB conversion info -- TOA selection masks will work when only TOA is the first one -- Condense code in Glitch model and add test coverage. -- `find_empty_masks` will now search through `CMX` parameters -- Fixed some docstrings for binary models. ### Removed -- macOS 12 CI diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f24dffe3..8131c21b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,32 @@ and this project, at least loosely, adheres to [Semantic Versioning](https://sem This file contains the released changes to the codebase. See CHANGELOG-unreleased.md for the unreleased changes. This file should only be changed while tagging a new version. +## [1.1.1] 2024-012-18 +### Changed +- Command line scripts now automatically do `allow_tcb` and `allow_T2` while reading par files. +- Updated the `plot_chains` function in `event_optimize` so that the subplots are a fixed size to prevent the subplots from being condensed in the case of many fit parameters. +### Added +- Time derivatives of NE_SW in `SolarWindDispersion` +- New prefix pattern for `split_prefixed_name` to handle derivatives of NE_SW +- Added an option `nbin` to `photonphase` to decide how many phase bins to use for the phaseogram +- Added an option `linearize_model` to speed up the photon phases calculation within `event_optimize` through the designmatrix. +- Added AIC and BIC calculation to be written in the post fit parfile from `event_optimize` +- When TCB->TDB conversion info is missing, will print parameter name +- Piecewise-constant model for chromatic variations (CMX) +- `add_param` returns the name of the parameter (useful for numbered parameters) +- Rerun intermittent failures in CI +- micromamba CI environment for testing macOS-latest, without tox +- models now have metadata dictionary +### Fixed +- Changed WAVE_OM units from 1/d to rad/d. +- When EQUAD is created from TNEQ, has proper TCB->TDB conversion info +- TOA selection masks will work when only TOA is the first one +- Condense code in Glitch model and add test coverage. +- `find_empty_masks` will now search through `CMX` parameters +- Fixed some docstrings for binary models. +### Removed +- macOS 12 CI + ## [1.1] 2024-11-05 ### Changed * Bump oldest python to 3.9