Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALPulsar 7.1.1.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
test_simulateCW.py
Go to the documentation of this file.
1# Copyright (C) 2017 Karl Wette
2#
3# This program is free software; you can redistribute it and/or modify it
4# under the terms of the GNU General Public License as published by the
5# Free Software Foundation; either version 2 of the License, or (at your
6# option) any later version.
7#
8# This program is distributed in the hope that it will be useful, but
9# WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
11# Public License for more details.
12#
13# You should have received a copy of the GNU General Public License along
14# with this program; if not, write to the Free Software Foundation, Inc.,
15# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
17import os
18import sys
19
20
21import numpy as np
22from numpy.testing import assert_allclose
23
24import pytest
25
26import lal
27import lalpulsar
28from lalpulsar import simulateCW as simCW
29
30try:
31 from tqdm import tqdm
32
33 prog_bar = tqdm
34except:
35 prog_bar = None
36
37# load Earth and Sun ephemerides
38earth_ephem_file = os.path.join(
39 os.environ["LAL_TEST_PKGDATADIR"], "earth00-40-DE405.dat.gz"
40)
41sun_ephem_file = os.path.join(
42 os.environ["LAL_TEST_PKGDATADIR"], "sun00-40-DE405.dat.gz"
43)
44ephemerides = lalpulsar.InitBarycenter(earth_ephem_file, sun_ephem_file)
45
46# amplitude parameters
47h0 = 1e-24
48assume_sqrtSh = 1e-23
49cosi = 0.123
50psi = 2.345
51phi0 = 3.210
52
53# phase parameters
54freq = 10.0
55fcmin = 5.0
56fcmax = 15.0
57f1dot = -1.35e-8
58alpha = 6.12
59delta = 1.02
60
61# detector parameters
62detector = "V1"
63
64# data parameters
65tref = 900043200
66tstart = 900000000
67Tdata = 86400
68
69# SFT parameters
70fmax = 32.0
71Tsft = 1800
72
73# F-statistic parameters
74dfreq = 0.1 / Tdata
75Nfs = 111
76fsmin = freq - (Nfs - 1) * 0.5 * dfreq
77
78
79# waveform: simple spindown model
80def waveform(h0, cosi, freq, f1dot):
81 def wf(dt):
82 dphi = lal.TWOPI * (freq * dt + f1dot * 0.5 * dt**2)
83 ap = h0 * (1.0 + cosi**2) / 2.0
84 ax = h0 * cosi
85 return dphi, ap, ax
86
87 return wf
88
89
90# compute F-statistic of reference spindown signal
92 # create fake SFT catalog
93 sft_ts = lalpulsar.MakeTimestamps(tstart, Tdata, Tsft, 0)
94 sft_catalog = lalpulsar.AddToFakeSFTCatalog(None, detector, sft_ts)
95
96 # create default F-statistic optional arguments
97 Fstat_opt_args = lalpulsar.FstatOptionalArgs(lalpulsar.FstatOptionalArgsDefaults)
98 Fstat_opt_args.FstatMethod = lalpulsar.FMETHOD_DEMOD_BEST
99
100 # create injection parameters
101 Fstat_signal = lalpulsar.CreatePulsarParamsVector(1)
102 Fstat_signal.data[0].Amp.aPlus = 0.5 * h0 * (1.0 + cosi * cosi)
103 Fstat_signal.data[0].Amp.aCross = h0 * cosi
104 Fstat_signal.data[0].Amp.psi = psi
105 Fstat_signal.data[0].Amp.phi0 = phi0
106 Fstat_signal.data[0].Doppler.refTime = tref
107 Fstat_signal.data[0].Doppler.Alpha = alpha
108 Fstat_signal.data[0].Doppler.Delta = delta
109 Fstat_signal.data[0].Doppler.fkdot[0] = freq
110 Fstat_signal.data[0].Doppler.fkdot[1] = f1dot
111 Fstat_opt_args.injectSources = Fstat_signal
112 Fstat_assume_noise = lalpulsar.MultiNoiseFloor()
113 Fstat_assume_noise.length = 1
114 Fstat_assume_noise.sqrtSn[0] = assume_sqrtSh
115 Fstat_opt_args.assumeSqrtSX = Fstat_assume_noise
116
117 # create F-statistic input data
118 Fstat_input = lalpulsar.CreateFstatInput(
119 sft_catalog, fcmin, fcmax, dfreq, ephemerides, Fstat_opt_args
120 )
121 Fstat_res = 0
122 doppler = lalpulsar.PulsarDopplerParams(Fstat_signal.data[0].Doppler)
123 doppler.fkdot[0] = fsmin
124
125 # search SFTs using F-statistic
126 Fstat_res = lalpulsar.ComputeFstat(
127 Fstat_res, Fstat_input, doppler, Nfs, lalpulsar.FSTATQ_2F
128 )
129
130 return Fstat_res.twoF
131
132
133# compute F-statistic of spindown signal simulated by simulateCW
135 # waveform parameters
136 dt_wf = 5
137
138 # create simulator
139 S = simCW.CWSimulator(
140 tref,
141 tstart,
142 Tdata,
143 waveform(h0, cosi, freq, f1dot),
144 dt_wf,
145 phi0,
146 psi,
147 alpha,
148 delta,
149 detector,
150 earth_ephem_file=earth_ephem_file,
151 sun_ephem_file=sun_ephem_file,
152 )
153
154 # write SFTs
155 allpaths = []
156 for path, i, N in S.write_sft_files(
157 fmax, Tsft, "simCWTestFstatSpindown", prog_bar=prog_bar
158 ):
159 allpaths.append(path)
160
161 # load SFTs from catalog
162 sft_catalog = lalpulsar.SFTdataFind(
163 "V-1_V1_1800SFT_simCWTestFstatSpindown-*.sft", None
164 )
165
166 # create default F-statistic optional arguments
167 Fstat_opt_args = lalpulsar.FstatOptionalArgs(lalpulsar.FstatOptionalArgsDefaults)
168 Fstat_opt_args.FstatMethod = lalpulsar.FMETHOD_DEMOD_BEST
169 Fstat_assume_noise = lalpulsar.MultiNoiseFloor()
170 Fstat_assume_noise.length = 1
171 Fstat_assume_noise.sqrtSn[0] = assume_sqrtSh
172 Fstat_opt_args.assumeSqrtSX = Fstat_assume_noise
173
174 # create F-statistic input data
175 Fstat_input = lalpulsar.CreateFstatInput(
176 sft_catalog, fcmin, fcmax, dfreq, ephemerides, Fstat_opt_args
177 )
178 Fstat_res = 0
179 doppler = lalpulsar.PulsarDopplerParams()
180 doppler.refTime = tref
181 doppler.Alpha = alpha
182 doppler.Delta = delta
183 doppler.fkdot[0] = fsmin
184 doppler.fkdot[1] = f1dot
185
186 # search SFTs using F-statistic
187 Fstat_res = lalpulsar.ComputeFstat(
188 Fstat_res, Fstat_input, doppler, Nfs, lalpulsar.FSTATQ_2F
189 )
190
191 # remove SFTs
192 for path in allpaths:
193 os.remove(path)
194
195 return Fstat_res.twoF
196
197
199 # compute F-statistic of reference spindown signal
201 print(
202 "F-statistic of reference spindown signal:\n %s\n"
203 % (", ".join(["%0.4f"] * len(Fstat_ref)) % tuple(Fstat_ref))
204 )
205
206 # compute F-statistic of spindown signal from simulateCW
208 print(
209 "F-statistic of spindown signal from simulateCW:\n %s\n"
210 % (" ".join(["%0.4f"] * len(Fstat_simCW)) % tuple(Fstat_simCW))
211 )
212
213 # compute root-mean-square error between F-statistics
214 Fstat_rmserr = np.sqrt(np.mean((1 - (Fstat_simCW / Fstat_ref)) ** 2))
215 assert_allclose(
216 Fstat_rmserr,
217 0.0,
218 atol=1e-3,
219 err_msg="Root-mean-square error between F-statistics: %0.2e" % Fstat_rmserr,
220 )
221
222
224 # simulation parameters
225 dt_wf = 5
226 Tdata = 3600
227 asd = 1.0
228
229 # create noise-only simulator
230 alpha = 1
231 S = simCW.CWSimulator(
232 tref,
233 tstart,
234 Tdata,
235 waveform(h0=0, cosi=0, freq=0, f1dot=0),
236 dt_wf,
237 phi0,
238 psi,
239 alpha,
240 delta,
241 detector,
242 earth_ephem_file=earth_ephem_file,
243 sun_ephem_file=sun_ephem_file,
244 )
245
246 # write sets of 2 SFTs each with different noise seed choices, two rounds each
247 allpaths = []
248 paths = {}
249 paths["None"] = [[], []]
250 paths["1"] = [[], []]
251 for path, i, N in S.write_sft_files(
252 fmax, Tsft, noise_sqrt_Sh=asd, comment="simCWTestSeedNoneRound1"
253 ):
254 allpaths.append(path)
255 paths["None"][0].append(path)
256 pass
257 for path, i, N in S.write_sft_files(
258 fmax, Tsft, noise_sqrt_Sh=asd, comment="simCWTestSeedNoneRound2"
259 ):
260 allpaths.append(path)
261 paths["None"][1].append(path)
262 pass
263 for path, i, N in S.write_sft_files(
264 fmax, Tsft, noise_sqrt_Sh=asd, comment="simCWTestSeed1Round1", noise_seed=1
265 ):
266 allpaths.append(path)
267 paths["1"][0].append(path)
268 pass
269 for path, i, N in S.write_sft_files(
270 fmax, Tsft, noise_sqrt_Sh=asd, comment="simCWTestSeed1Round2", noise_seed=1
271 ):
272 allpaths.append(path)
273 paths["1"][1].append(path)
274 pass
275 return_codes = {}
276 return_codes["None"] = np.zeros(2)
277 return_codes["1"] = np.zeros(2)
278 for seed in ["None", "1"]:
279 for i in range(N):
280 catalog0 = lalpulsar.SFTdataFind(paths[seed][0][i], None)
281 sft0 = lalpulsar.LoadSFTs(catalog0, -1, -1)
282 catalog1 = lalpulsar.SFTdataFind(paths[seed][1][i], None)
283 sft1 = lalpulsar.LoadSFTs(catalog1, -1, -1)
284 rms = np.sqrt(
285 np.mean(abs(sft0.data[0].data.data - sft1.data[0].data.data) ** 2)
286 )
287 return_codes[seed][i] = rms > 0
288 for code in return_codes["None"]:
289 # if randoms seeds are redrawn internally, we expect the comparison of rounds 1 and 2 to fail
290 assert code > 0
291 for code in return_codes["1"]:
292 # if seeds are fixed, we expect identical outputs from both rounds
293 assert code == 0
294
295 # remove SFTs
296 for path in allpaths:
297 os.remove(path)
298
299
300if __name__ == "__main__":
301 args = sys.argv[1:] or ["-v", "-rs", "--junit-xml=junit-simulateCW.xml"]
302 sys.exit(pytest.main(args=[__file__] + args))
def waveform(h0, cosi, freq, f1dot)
def compute_Fstat_spindown_reference()
def compute_Fstat_spindown_simulateCW()