From 86c81408a803c29b7a03d6d2960b65f66bd8ea99 Mon Sep 17 00:00:00 2001 From: Deven Bhakta Date: Thu, 17 Oct 2024 13:17:06 -0400 Subject: [PATCH 01/12] 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 eb43e6c0e5a8a232060bc706c39b01b2f297142b Mon Sep 17 00:00:00 2001 From: Deven Bhakta Date: Thu, 24 Oct 2024 11:24:42 -0400 Subject: [PATCH 02/12] 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 03/12] 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 b88b28edbdce0fda8b8e3f6e3698b32e082c2cf8 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Tue, 5 Nov 2024 14:03:45 -0600 Subject: [PATCH 04/12] 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 05/12] 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 06/12] 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 bc3873d2fc85f6462bbf19beb9fc44ad9e939874 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Wed, 6 Nov 2024 12:17:57 -0600 Subject: [PATCH 07/12] 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 75eb2c8f9470d06ebc71974b33a4d32bc9d33b6a Mon Sep 17 00:00:00 2001 From: Abhimanyu Susobhanan Date: Mon, 11 Nov 2024 14:33:56 +0100 Subject: [PATCH 08/12] 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 09/12] 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 10/12] 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 e55903551c397c9fe1bc7a01ffc3edd05747ded7 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 11 Nov 2024 09:11:48 -0600 Subject: [PATCH 11/12] 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 85b27a22fab1584099361b74f57828058fa44be8 Mon Sep 17 00:00:00 2001 From: Deven Bhakta Date: Thu, 14 Nov 2024 10:39:34 -0500 Subject: [PATCH 12/12] 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)