LALPulsar  6.1.0.1-b72065a
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 
17 import os
18 import sys
19 
20 
21 import numpy as np
22 from numpy.testing import assert_allclose
23 
24 import pytest
25 
26 import lal
27 import lalpulsar
28 from lalpulsar import simulateCW as simCW
29 
30 # load Earth and Sun ephemerides
31 earth_ephem_file = os.path.join(
32  os.environ["LAL_TEST_PKGDATADIR"], "earth00-40-DE405.dat.gz"
33 )
34 sun_ephem_file = os.path.join(
35  os.environ["LAL_TEST_PKGDATADIR"], "sun00-40-DE405.dat.gz"
36 )
37 ephemerides = lalpulsar.InitBarycenter(earth_ephem_file, sun_ephem_file)
38 
39 # amplitude parameters
40 h0 = 1e-24
41 assume_sqrtSh = 1e-23
42 cosi = 0.123
43 psi = 2.345
44 phi0 = 3.210
45 
46 # phase parameters
47 freq = 10.0
48 fcmin = 5.0
49 fcmax = 15.0
50 f1dot = -1.35e-8
51 alpha = 6.12
52 delta = 1.02
53 
54 # detector parameters
55 detector = "V1"
56 
57 # data parameters
58 tref = 900043200
59 tstart = 900000000
60 Tdata = 86400
61 
62 # SFT parameters
63 fmax = 32.0
64 Tsft = 1800
65 
66 # F-statistic parameters
67 dfreq = 0.1 / Tdata
68 Nfs = 111
69 fsmin = freq - (Nfs - 1) * 0.5 * dfreq
70 
71 
72 # waveform: simple spindown model
73 def waveform(h0, cosi, freq, f1dot):
74  def wf(dt):
75  dphi = lal.TWOPI * (freq * dt + f1dot * 0.5 * dt**2)
76  ap = h0 * (1.0 + cosi**2) / 2.0
77  ax = h0 * cosi
78  return dphi, ap, ax
79 
80  return wf
81 
82 
83 # compute F-statistic of reference spindown signal
85  # create fake SFT catalog
86  sft_ts = lalpulsar.MakeTimestamps(tstart, Tdata, Tsft, 0)
87  sft_catalog = lalpulsar.AddToFakeSFTCatalog(None, detector, sft_ts)
88 
89  # create default F-statistic optional arguments
90  Fstat_opt_args = lalpulsar.FstatOptionalArgs(lalpulsar.FstatOptionalArgsDefaults)
91  Fstat_opt_args.FstatMethod = lalpulsar.FMETHOD_DEMOD_BEST
92 
93  # create injection parameters
94  Fstat_signal = lalpulsar.CreatePulsarParamsVector(1)
95  Fstat_signal.data[0].Amp.aPlus = 0.5 * h0 * (1.0 + cosi * cosi)
96  Fstat_signal.data[0].Amp.aCross = h0 * cosi
97  Fstat_signal.data[0].Amp.psi = psi
98  Fstat_signal.data[0].Amp.phi0 = phi0
99  Fstat_signal.data[0].Doppler.refTime = tref
100  Fstat_signal.data[0].Doppler.Alpha = alpha
101  Fstat_signal.data[0].Doppler.Delta = delta
102  Fstat_signal.data[0].Doppler.fkdot[0] = freq
103  Fstat_signal.data[0].Doppler.fkdot[1] = f1dot
104  Fstat_opt_args.injectSources = Fstat_signal
105  Fstat_assume_noise = lalpulsar.MultiNoiseFloor()
106  Fstat_assume_noise.length = 1
107  Fstat_assume_noise.sqrtSn[0] = assume_sqrtSh
108  Fstat_opt_args.assumeSqrtSX = Fstat_assume_noise
109 
110  # create F-statistic input data
111  Fstat_input = lalpulsar.CreateFstatInput(
112  sft_catalog, fcmin, fcmax, dfreq, ephemerides, Fstat_opt_args
113  )
114  Fstat_res = 0
115  doppler = lalpulsar.PulsarDopplerParams(Fstat_signal.data[0].Doppler)
116  doppler.fkdot[0] = fsmin
117 
118  # search SFTs using F-statistic
119  Fstat_res = lalpulsar.ComputeFstat(
120  Fstat_res, Fstat_input, doppler, Nfs, lalpulsar.FSTATQ_2F
121  )
122 
123  return Fstat_res.twoF
124 
125 
126 # compute F-statistic of spindown signal simulated by simulateCW
128  # waveform parameters
129  dt_wf = 5
130 
131  # create simulator
132  S = simCW.CWSimulator(
133  tref,
134  tstart,
135  Tdata,
136  waveform(h0, cosi, freq, f1dot),
137  dt_wf,
138  phi0,
139  psi,
140  alpha,
141  delta,
142  detector,
143  earth_ephem_file=earth_ephem_file,
144  sun_ephem_file=sun_ephem_file,
145  )
146 
147  # write SFTs
148  allpaths = []
149  for path, i, N in S.write_sft_files(fmax, Tsft, "simCWTestFstatSpindown"):
150  allpaths.append(path)
151 
152  # load SFTs from catalog
153  sft_catalog = lalpulsar.SFTdataFind(
154  "V-1_V1_1800SFT_simCWTestFstatSpindown-*.sft", None
155  )
156 
157  # create default F-statistic optional arguments
158  Fstat_opt_args = lalpulsar.FstatOptionalArgs(lalpulsar.FstatOptionalArgsDefaults)
159  Fstat_opt_args.FstatMethod = lalpulsar.FMETHOD_DEMOD_BEST
160  Fstat_assume_noise = lalpulsar.MultiNoiseFloor()
161  Fstat_assume_noise.length = 1
162  Fstat_assume_noise.sqrtSn[0] = assume_sqrtSh
163  Fstat_opt_args.assumeSqrtSX = Fstat_assume_noise
164 
165  # create F-statistic input data
166  Fstat_input = lalpulsar.CreateFstatInput(
167  sft_catalog, fcmin, fcmax, dfreq, ephemerides, Fstat_opt_args
168  )
169  Fstat_res = 0
170  doppler = lalpulsar.PulsarDopplerParams()
171  doppler.refTime = tref
172  doppler.Alpha = alpha
173  doppler.Delta = delta
174  doppler.fkdot[0] = fsmin
175  doppler.fkdot[1] = f1dot
176 
177  # search SFTs using F-statistic
178  Fstat_res = lalpulsar.ComputeFstat(
179  Fstat_res, Fstat_input, doppler, Nfs, lalpulsar.FSTATQ_2F
180  )
181 
182  # remove SFTs
183  for path in allpaths:
184  os.remove(path)
185 
186  return Fstat_res.twoF
187 
188 
190  # compute F-statistic of reference spindown signal
192  print(
193  "F-statistic of reference spindown signal:\n %s\n"
194  % (", ".join(["%0.4f"] * len(Fstat_ref)) % tuple(Fstat_ref))
195  )
196 
197  # compute F-statistic of spindown signal from simulateCW
198  Fstat_simCW = compute_Fstat_spindown_simulateCW()
199  print(
200  "F-statistic of spindown signal from simulateCW:\n %s\n"
201  % (" ".join(["%0.4f"] * len(Fstat_simCW)) % tuple(Fstat_simCW))
202  )
203 
204  # compute root-mean-square error between F-statistics
205  Fstat_rmserr = np.sqrt(np.mean((1 - (Fstat_simCW / Fstat_ref)) ** 2))
206  assert_allclose(
207  Fstat_rmserr,
208  0.0,
209  atol=1e-3,
210  err_msg="Root-mean-square error between F-statistics: %0.2e" % Fstat_rmserr,
211  )
212 
213 
215  # simulation parameters
216  dt_wf = 5
217  Tdata = 3600
218  asd = 1.0
219 
220  # create noise-only simulator
221  alpha = 1
222  S = simCW.CWSimulator(
223  tref,
224  tstart,
225  Tdata,
226  waveform(h0=0, cosi=0, freq=0, f1dot=0),
227  dt_wf,
228  phi0,
229  psi,
230  alpha,
231  delta,
232  detector,
233  earth_ephem_file=earth_ephem_file,
234  sun_ephem_file=sun_ephem_file,
235  )
236 
237  # write sets of 2 SFTs each with different noise seed choices, two rounds each
238  allpaths = []
239  paths = {}
240  paths["None"] = [[], []]
241  paths["1"] = [[], []]
242  for path, i, N in S.write_sft_files(
243  fmax, Tsft, noise_sqrt_Sh=asd, comment="simCWTestSeedNoneRound1"
244  ):
245  allpaths.append(path)
246  paths["None"][0].append(path)
247  pass
248  for path, i, N in S.write_sft_files(
249  fmax, Tsft, noise_sqrt_Sh=asd, comment="simCWTestSeedNoneRound2"
250  ):
251  allpaths.append(path)
252  paths["None"][1].append(path)
253  pass
254  for path, i, N in S.write_sft_files(
255  fmax, Tsft, noise_sqrt_Sh=asd, comment="simCWTestSeed1Round1", noise_seed=1
256  ):
257  allpaths.append(path)
258  paths["1"][0].append(path)
259  pass
260  for path, i, N in S.write_sft_files(
261  fmax, Tsft, noise_sqrt_Sh=asd, comment="simCWTestSeed1Round2", noise_seed=1
262  ):
263  allpaths.append(path)
264  paths["1"][1].append(path)
265  pass
266  return_codes = {}
267  return_codes["None"] = np.zeros(2)
268  return_codes["1"] = np.zeros(2)
269  for seed in ["None", "1"]:
270  for i in range(N):
271  catalog0 = lalpulsar.SFTdataFind(paths[seed][0][i], None)
272  sft0 = lalpulsar.LoadSFTs(catalog0, -1, -1)
273  catalog1 = lalpulsar.SFTdataFind(paths[seed][1][i], None)
274  sft1 = lalpulsar.LoadSFTs(catalog1, -1, -1)
275  rms = np.sqrt(
276  np.mean(abs(sft0.data[0].data.data - sft1.data[0].data.data) ** 2)
277  )
278  return_codes[seed][i] = rms > 0
279  for code in return_codes["None"]:
280  # if randoms seeds are redrawn internally, we expect the comparison of rounds 1 and 2 to fail
281  assert code > 0
282  for code in return_codes["1"]:
283  # if seeds are fixed, we expect identical outputs from both rounds
284  assert code == 0
285 
286  # remove SFTs
287  for path in allpaths:
288  os.remove(path)
289 
290 
291 if __name__ == "__main__":
292  args = sys.argv[1:] or ["-v", "-rs", "--junit-xml=junit-simulateCW.xml"]
293  sys.exit(pytest.main(args=[__file__] + args))
def waveform(h0, cosi, freq, f1dot)
def compute_Fstat_spindown_reference()
def compute_Fstat_spindown_simulateCW()