-
Notifications
You must be signed in to change notification settings - Fork 101
/
understanding_timing_models.py
180 lines (135 loc) · 5.28 KB
/
understanding_timing_models.py
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# ---
# jupyter:
# jupytext:
# formats: ipynb,py:percent
# text_representation:
# extension: .py
# format_name: percent
# format_version: '1.3'
# jupytext_version: 1.16.0
# kernelspec:
# display_name: Python 3
# language: python
# name: python3
# ---
# %% [markdown]
# # Understanding Timing Models
# %% [markdown]
# ## Build a timing model starting from a par file
# %%
from pint.models import get_model
from pint.models.timing_model import Component
import pint.config
import pint.logging
# setup logging
pint.logging.setup(level="INFO")
# %% [markdown]
# One can build a timing model via `get_model()` method. This will read the par file and instantiate all the delay and phase components, using the default ordering.
# %%
par = "B1855+09_NANOGrav_dfg+12_TAI.par"
m = get_model(pint.config.examplefile(par))
# %%
# %% [markdown]
# Each of the parameters in the model can be accessed as an attribute of the `TimingModel` object.
# Behind the scenes PINT figures out which component the parameter is stored in.
#
# Each parameter has attributes like the quantity (which includes units), and a description (see the Understanding Parameters notebook for more detail)
# %%
print(m.F0.quantity)
print(m.F0.description)
# %% [markdown]
# We can now explore the structure of the model
# %%
# This gives a list of all of the component types (so far there are only delay and phase components)
m.component_types
# %%
dir(m)
# %% [markdown]
# The TimingModel class stores lists of the delay model components and phase components that make up the model
# %%
# When this list gets printed, it shows the parameters that are associated with each component as well.
m.DelayComponent_list
# %%
# Now let's look at the phase components. These include the absolute phase, the spindown model, and phase jumps
m.PhaseComponent_list
# %% [markdown]
# We can add a component to an existing model
# %%
from pint.models.astrometry import AstrometryEcliptic
# %%
a = AstrometryEcliptic() # init the AstrometryEcliptic instance
# %%
# Add the component to the model
# It will be put in the default order
# We set validate=False since we have not set the parameter values yet, which would cause validate to fail
m.add_component(a, validate=False)
# %%
m.DelayComponent_list # The new instance is added to delay component list
# %% [markdown]
# There are two ways to remove a component from a model. This simplest is to use the `remove_component` method to remove it by name.
# %%
# We will not do this here, since we'll demonstrate a different method below.
# m.remove_component("AstrometryEcliptic")
# %% [markdown]
# Alternatively, you can have more control using the `map_component()` method, which takes either a string with component name,
# or a Component instance and returns a tuple containing the Component instance, its order in the relevant component list,
# the list of components of this type in the model, and the component type (as a string)
# %%
component, order, from_list, comp_type = m.map_component("AstrometryEcliptic")
print("Component : ", component)
print("Type : ", comp_type)
print("Order : ", order)
print("List : ")
_ = [print(c) for c in from_list]
# %%
# Now we can remove the component by directly manipulating the list
from_list.remove(component)
# %%
m.DelayComponent_list # AstrometryEcliptic has been removed from delay list.
# %% [markdown]
# To switch the order of a component, just change the order of the component list
#
# **NB: that this should almost never be done! In most cases the default order of the delay components is correct. Experts only!**
# %%
# Let's look at the order of the components in the delay list first
_ = [print(dc.__class__) for dc in m.DelayComponent_list]
# %%
# Now let's swap the order of DispersionDMX and Dispersion
component, order, from_list, comp_type = m.map_component("DispersionDMX")
new_order = 3
from_list[order], from_list[new_order] = from_list[new_order], from_list[order]
# %%
# Print the classes to see the order switch
_ = [print(dc.__class__) for dc in m.DelayComponent_list]
# %% [markdown]
# Delays are always computed in the order of the DelayComponent_list
# %%
# First get the toas
from pint.toa import get_TOAs
t = get_TOAs(pint.config.examplefile("B1855+09_NANOGrav_dfg+12.tim"), model=m)
# %%
# compute the total delay
total_delay = m.delay(t)
total_delay
# %% [markdown]
# One can get the delay up to some component. For example, if you want the delay computation stop after the Solar System Shapiro delay.
#
# By default the delay of the specified component *is* included. This can be changed by the keyword parameter `include_last=False`.
# %%
to_jump_delay = m.delay(t, cutoff_component="SolarSystemShapiro")
to_jump_delay
# %% [markdown]
# Here is a list of all the Component types that PINT knows about
# %%
Component.component_types
# %% [markdown]
# When PINT builds a model from a par file, it has to infer what components to include in the model.
# This is done by the `component_special_params` of each `Component`. A component will be instantiated
# when one of its special parameters is present in the par file.
# %%
from collections import defaultdict
special = defaultdict(list)
for comp, tp in Component.component_types.items():
for p in tp().component_special_params:
special[p].append(comp)
special