From 091b531113dfa310ddf455695798da6346aedcf2 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 10 Dec 2024 11:37:29 -0600 Subject: [PATCH 1/6] 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 2/6] 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 3/6] 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 4/6] 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 5/6] 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 6/6] 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 = ""