forked from nanograv/PINT
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathphase_offset_example.py
More file actions
139 lines (111 loc) · 3.87 KB
/
phase_offset_example.py
File metadata and controls
139 lines (111 loc) · 3.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#! /usr/bin/env python
# ---
# jupyter:
# jupytext:
# cell_metadata_filter: -all
# formats: ipynb,py:percent
# text_representation:
# extension: .py
# format_name: percent
# format_version: '1.3'
# jupytext_version: 1.14.4
# kernelspec:
# display_name: .env
# language: python
# name: python3
# ---
# %% [markdown]
# # Demonstrate phase offset
#
# This notebook is primarily designed to operate as a plain `.py` script.
# You should be able to run the `.py` script that occurs in the
# `docs/examples/` directory in order to carry out a simple fit of a
# timing model to some data. You should also be able to run the notebook
# version as it is here (it may be necessary to `make notebooks` to
# produce a `.ipynb` version using `jupytext`).
# %%
from pint.models import get_model_and_toas, PhaseOffset
from pint.residuals import Residuals
from pint.config import examplefile
from pint.fitter import DownhillWLSFitter
import matplotlib.pyplot as plt
from astropy.visualization import quantity_support
quantity_support()
# %%
# Read the TOAs and the model
parfile = examplefile("J1028-5819-example.par")
timfile = examplefile("J1028-5819-example.tim")
model, toas = get_model_and_toas(parfile, timfile)
# %%
# Create a Residuals object
res = Residuals(toas, model)
# %%
# By default, the residuals are mean-subtracted.
resids1 = res.calc_phase_resids().to("")
# We can disable mean subtraction by setting `subtract_mean` to False.
resids2 = res.calc_phase_resids(subtract_mean=False).to("")
# %%
# Let us plot the residuals with and without mean subtraction.
# In the bottom plot, there is clearly an offset between the two cases
# although it is not so clear in the top plot.
mjds = toas.get_mjds()
errors = toas.get_errors() * model.F0.quantity
plt.subplot(211)
plt.errorbar(mjds, resids1, errors, ls="", marker="x", label="Mean subtracted")
plt.errorbar(mjds, resids2, errors, ls="", marker="x", label="Not mean subtracted")
plt.xlabel("MJD")
plt.ylabel("Phase residuals")
plt.axhline(0, ls="dotted", color="grey")
plt.legend()
plt.subplot(212)
plt.plot(mjds, resids2 - resids1, ls="", marker="x")
plt.xlabel("MJD")
plt.ylabel("Phase residual difference")
plt.show()
# %%
# This phase offset that gets subtracted implicitly can be computed
# using the `calc_phase_mean` function. There is also a similar function
# `calc_time_mean` for time offsets.
implicit_offset = res.calc_phase_mean().to("")
print("Implicit offset = ", implicit_offset)
# %%
# Now let us look at the design matrix.
T, Tparams, Tunits = model.designmatrix(toas)
print("Design matrix params :", Tparams)
# The implicit offset is represented as "Offset".
# %%
# We can explicitly fit for this offset using the "PHOFF" parameter.
# This is available in the "PhaseOffset" component
po = PhaseOffset()
model.add_component(po)
assert hasattr(model, "PHOFF")
# %%
# Let us fit this now.
model.PHOFF.frozen = False
ftr = DownhillWLSFitter(toas, model)
ftr.fit_toas()
print(
f"PHOFF fit value = {ftr.model.PHOFF.value} +/- {ftr.model.PHOFF.uncertainty_value}"
)
# This is consistent with the implicit offset we got earlier.
# %%
# Let us plot the post-fit residuals.
mjds = ftr.toas.get_mjds()
errors = ftr.toas.get_errors() * model.F0.quantity
resids = ftr.resids.calc_phase_resids().to("")
plt.errorbar(mjds, resids, errors, ls="", marker="x", label="After fitting PHOFF")
plt.xlabel("MJD")
plt.ylabel("Phase residuals")
plt.axhline(0, ls="dotted", color="grey")
plt.legend()
plt.show()
# %%
# Let us compute the phase residual mean again.
phase_mean = ftr.resids.calc_phase_mean().to("")
print("Phase residual mean = ", phase_mean)
# i.e., we have successfully gotten rid of the offset by fitting PHOFF.
# %%
# Now let us look at the design matrix again.
T, Tparams, Tunits = model.designmatrix(toas)
print("Design matrix params :", Tparams)
# The explicit offset "PHOFF" has replaced the implicit "Offset".