From 9d2d9f958cfcea36ef0ba26cdd7fa1baf7dcaa37 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Wed, 4 Oct 2023 16:32:42 -0500 Subject: [PATCH 01/10] fittable_params --- src/pint/models/timing_model.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/pint/models/timing_model.py b/src/pint/models/timing_model.py index 657319fbf..977e1c3ae 100644 --- a/src/pint/models/timing_model.py +++ b/src/pint/models/timing_model.py @@ -615,6 +615,15 @@ def free_params(self, params): f"Parameter(s) are familiar but not in the model: {params}" ) + @property_exists + def fittable_params(self): + return [ + p + for p in self.params + if (p in self.phase_deriv_funcs or p in self.delay_deriv_funcs) + and self[p].quantity is not None + ] + def match_param_aliases(self, alias): """Return PINT parameter name corresponding to this alias. From ac62966763b7edc829bca62272accba07f109b12 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Wed, 4 Oct 2023 16:42:49 -0500 Subject: [PATCH 02/10] free_unfittable_params check --- src/pint/fitter.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/pint/fitter.py b/src/pint/fitter.py index 2e6a31a9b..b473494e4 100644 --- a/src/pint/fitter.py +++ b/src/pint/fitter.py @@ -217,6 +217,15 @@ class Fitter: """ def __init__(self, toas, model, track_mode=None, residuals=None): + if not set(model.free_params).issubset(model.fittable_params): + free_unfittable_params = set(model.free_params).difference( + model.fittable_params + ) + raise ValueError( + f"Cannot create fitter because the following unfittable parameters" + f" were found unfrozen in the model: {free_unfittable_params}" + ) + self.toas = toas self.model_init = model self.track_mode = track_mode From 26c0ed87f877d88014c15a23be0b87e24984fdc4 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Wed, 4 Oct 2023 17:05:39 -0500 Subject: [PATCH 03/10] designmatrix exception --- CHANGELOG-unreleased.md | 3 +++ src/pint/fitter.py | 5 +++-- src/pint/models/timing_model.py | 10 ++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 0e36437c8..357abb7ce 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -12,6 +12,8 @@ the released changes. - `WAVE` parameters can be added to a `Wave` model with `add_wave_component()` in `wave.py` - Moved design matrix normalization code from `pint.fitter` to the new `pint.utils.normalize_designmatrix()` function. - Made `Residuals` independent of `GLSFitter` (GLS chi2 is now computed using the new function `Residuals._calc_gls_chi2()`). +- Creation of `Fitter` objects will fail if there are free unfittable parameters in the timing model. +- `TimingModel.designmatrix()` method will fail with an informative error message if there are free unfittable parameters in the timing model. ### Added - CHI2, CHI2R, TRES, DMRES now in postfit par files - Added `WaveX` model as a `DelayComponent` with Fourier amplitudes as fitted parameters @@ -21,6 +23,7 @@ the released changes. - Support for wideband data in `pint.bayesian` (no correlated noise). - Added `DMWaveX` model (Fourier representation of DM noise) - Piecewise orbital model (`BinaryBTPiecewise`) +- `TimingModel.fittable_params` property ### Fixed - Wave model `validate()` can correctly use PEPOCH to assign WAVEEPOCH parameter - Fixed RTD by specifying theme explicitly. diff --git a/src/pint/fitter.py b/src/pint/fitter.py index b473494e4..ce678edc2 100644 --- a/src/pint/fitter.py +++ b/src/pint/fitter.py @@ -222,8 +222,9 @@ def __init__(self, toas, model, track_mode=None, residuals=None): model.fittable_params ) raise ValueError( - f"Cannot create fitter because the following unfittable parameters" - f" were found unfrozen in the model: {free_unfittable_params}" + f"Cannot create fitter because the following unfittable parameters " + f"were found unfrozen in the model: {free_unfittable_params}. " + f"Freeze these parameters before creating the fitter." ) self.toas = toas diff --git a/src/pint/models/timing_model.py b/src/pint/models/timing_model.py index 977e1c3ae..5da2189aa 100644 --- a/src/pint/models/timing_model.py +++ b/src/pint/models/timing_model.py @@ -1983,6 +1983,16 @@ def designmatrix(self, toas, acc_delay=None, incfrozen=False, incoffset=True): keeps the conventional way. """ + if not set(self.free_params).issubset(self.fittable_params): + free_unfittable_params = set(self.free_params).difference( + self.fittable_params + ) + raise ValueError( + f"Cannot compute the design matrix because the following unfittable parameters " + f"were found unfrozen in the model: {free_unfittable_params}. " + f"Freeze these parameters before computing the design matrix." + ) + noise_params = self.get_params_of_component_type("NoiseComponent") # unfrozen_noise_params = [ # param for param in noise_params if not getattr(self, param).frozen From 30153b95c7728fa3351eb4b1bb0f8e5e449e7f45 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Fri, 6 Oct 2023 16:42:51 -0500 Subject: [PATCH 04/10] designmatrix --- src/pint/models/timing_model.py | 34 ++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/pint/models/timing_model.py b/src/pint/models/timing_model.py index 5da2189aa..5c2a99796 100644 --- a/src/pint/models/timing_model.py +++ b/src/pint/models/timing_model.py @@ -1974,18 +1974,31 @@ def designmatrix(self, toas, acc_delay=None, incfrozen=False, incoffset=True): units : astropy.units.Unit The units of the corresponding parts of the design matrix - Note - ---- - Here we have negative sign here. Since in pulsar timing - the residuals are calculated as (Phase - int(Phase)), which is different - from the conventional definition of least square definition (Data - model) - We decide to add minus sign here in the design matrix, so the fitter - keeps the conventional way. + Notes + ----- + 1. We have negative sign here. Since the residuals are calculated as + (Phase - int(Phase)) in pulsar timing, which is different from the conventional + definition of least square definition (Data - model), we have decided to add + a minus sign here in the design matrix so that the fitter keeps the conventional + sign. + + 2. Design matrix entries can be computed only for parameters for which the + derivatives are implemented. If a parameter without a derivative is unfrozen + while calling this method, it will raise an informative error, except in the + case of unfrozen noise parameters, which are simply ignored. """ - if not set(self.free_params).issubset(self.fittable_params): - free_unfittable_params = set(self.free_params).difference( - self.fittable_params + noise_params = self.get_params_of_component_type("NoiseComponent") + + if ( + not set(self.free_params) + .difference(noise_params) + .issubset(self.fittable_params) + ): + free_unfittable_params = ( + set(self.free_params) + .difference(noise_params) + .difference(self.fittable_params) ) raise ValueError( f"Cannot compute the design matrix because the following unfittable parameters " @@ -1993,7 +2006,6 @@ def designmatrix(self, toas, acc_delay=None, incfrozen=False, incoffset=True): f"Freeze these parameters before computing the design matrix." ) - noise_params = self.get_params_of_component_type("NoiseComponent") # unfrozen_noise_params = [ # param for param in noise_params if not getattr(self, param).frozen # ] From 5f27fc21aa80ca788b452ab41a9c8b50f30aa32d Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Fri, 6 Oct 2023 17:22:17 -0500 Subject: [PATCH 05/10] funcparam --- src/pint/models/binary_ell1.py | 8 +++++--- src/pint/models/timing_model.py | 7 ++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/pint/models/binary_ell1.py b/src/pint/models/binary_ell1.py index 8e3c93b4e..01b619c0e 100644 --- a/src/pint/models/binary_ell1.py +++ b/src/pint/models/binary_ell1.py @@ -433,6 +433,11 @@ def __init__(self): self.binary_model_name = "ELL1k" self.binary_model_class = ELL1kmodel + self.remove_param("OMDOT") + self.remove_param("EDOT") + self.remove_param("EPS1DOT") + self.remove_param("EPS2DOT") + self.add_param( floatParameter( name="OMDOT", @@ -451,9 +456,6 @@ def __init__(self): ) ) - self.remove_param("EPS1DOT") - self.remove_param("EPS2DOT") - def validate(self): """Validate parameters.""" super().validate() diff --git a/src/pint/models/timing_model.py b/src/pint/models/timing_model.py index 5c2a99796..f259fcfdd 100644 --- a/src/pint/models/timing_model.py +++ b/src/pint/models/timing_model.py @@ -53,6 +53,7 @@ Parameter, boolParameter, floatParameter, + funcParameter, intParameter, maskParameter, strParameter, @@ -2949,7 +2950,11 @@ def __init__(self): def __repr__(self): return "{}(\n {})".format( self.__class__.__name__, - ",\n ".join(str(getattr(self, p)) for p in self.params), + ",\n ".join( + str(getattr(self, p)) + for p in self.params + if not isinstance(p, funcParameter) + ), ) def setup(self): From 628e6bd6893ceb3526faeaa45a9249ab6ad535d9 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Fri, 6 Oct 2023 17:35:06 -0500 Subject: [PATCH 06/10] test_ddgr --- src/pint/models/timing_model.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pint/models/timing_model.py b/src/pint/models/timing_model.py index f259fcfdd..c5eed025e 100644 --- a/src/pint/models/timing_model.py +++ b/src/pint/models/timing_model.py @@ -622,7 +622,6 @@ def fittable_params(self): p for p in self.params if (p in self.phase_deriv_funcs or p in self.delay_deriv_funcs) - and self[p].quantity is not None ] def match_param_aliases(self, alias): From ddf1b9a902a6e7fa5271808cfd77b6c2f96a2e8c Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 10 Oct 2023 09:34:34 -0500 Subject: [PATCH 07/10] no unfittable params in plk --- src/pint/pintk/plk.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pint/pintk/plk.py b/src/pint/pintk/plk.py index 368e19599..3a32ad013 100644 --- a/src/pint/pintk/plk.py +++ b/src/pint/pintk/plk.py @@ -208,6 +208,7 @@ def addFitCheckBoxes(self, model): for p in model.components[comp].params if p not in pulsar.nofitboxpars and getattr(model, p).quantity is not None + and p in model.fittable_params ] # Don't bother showing components without any fittable parameters From e55ff9606fc1535ce09f779c35557bf38094b350 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Tue, 10 Oct 2023 09:45:29 -0500 Subject: [PATCH 08/10] CHANGELOG --- CHANGELOG-unreleased.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-unreleased.md b/CHANGELOG-unreleased.md index 357abb7ce..ce9a23c78 100644 --- a/CHANGELOG-unreleased.md +++ b/CHANGELOG-unreleased.md @@ -13,7 +13,7 @@ the released changes. - Moved design matrix normalization code from `pint.fitter` to the new `pint.utils.normalize_designmatrix()` function. - Made `Residuals` independent of `GLSFitter` (GLS chi2 is now computed using the new function `Residuals._calc_gls_chi2()`). - Creation of `Fitter` objects will fail if there are free unfittable parameters in the timing model. -- `TimingModel.designmatrix()` method will fail with an informative error message if there are free unfittable parameters in the timing model. +- Only fittable parameters will be listed as check boxes in the `plk` interface. ### Added - CHI2, CHI2R, TRES, DMRES now in postfit par files - Added `WaveX` model as a `DelayComponent` with Fourier amplitudes as fitted parameters @@ -32,4 +32,5 @@ the released changes. - Fixed an incorrect docstring in `pbprime()` functions. - Fix ICRS -> ECL conversion when parameter uncertainties are not set. - `get_TOAs` raises an exception upon finding mixed narrowband and wideband TOAs in a tim file. `TOAs.is_wideband` returns True only if *ALL* TOAs have the -pp_dm flag. +- `TimingModel.designmatrix()` method will fail with an informative error message if there are free unfittable parameters in the timing model. ### Removed From f4e1c75056afd9a73fa3d6fd09e9128f865052bc Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Thu, 12 Oct 2023 13:36:16 -0500 Subject: [PATCH 09/10] doc update --- src/pint/models/timing_model.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pint/models/timing_model.py b/src/pint/models/timing_model.py index c5eed025e..bac89b324 100644 --- a/src/pint/models/timing_model.py +++ b/src/pint/models/timing_model.py @@ -607,6 +607,8 @@ def free_params(self): @free_params.setter def free_params(self, params): + """List of free parameters, i.e., the parameters whose `frozen` + attribute is set to False.""" params_true = {self.match_param_aliases(p) for p in params} for p in self.params: getattr(self, p).frozen = p not in params_true @@ -618,6 +620,9 @@ def free_params(self, params): @property_exists def fittable_params(self): + """List of parameters that are fittable, i.e., the parameters + which have a derivative implemented. These derivatives are usually + accessed via the `d_delay_d_param` and `d_phase_d_param` methods.""" return [ p for p in self.params From 1628e1f7cff33545b2b96602d1dbe1fc3e82e783 Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Thu, 12 Oct 2023 13:37:29 -0500 Subject: [PATCH 10/10] -- --- src/pint/models/timing_model.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pint/models/timing_model.py b/src/pint/models/timing_model.py index bac89b324..5c0df4b5d 100644 --- a/src/pint/models/timing_model.py +++ b/src/pint/models/timing_model.py @@ -593,7 +593,8 @@ def params(self): @property_exists def free_params(self): - """List of all the free parameters in the timing model. Can be set to change which are free. + """List of all the free parameters in the timing model. + Can be set to change which are free. These are ordered as ``self.params`` does. @@ -607,8 +608,6 @@ def free_params(self): @free_params.setter def free_params(self, params): - """List of free parameters, i.e., the parameters whose `frozen` - attribute is set to False.""" params_true = {self.match_param_aliases(p) for p in params} for p in self.params: getattr(self, p).frozen = p not in params_true