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
pw_model_simulations.py
Go to the documentation of this file.
1# Copyright (C) 2019--2023 Benjamin Grace
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## \file
18## \ingroup lalpulsar_python_piecewise_model
19"""
20Functions used in simulation studies of the piecewise model.
21"""
22
23import logging
24import os
25
26import numpy as np
27
28import lal
29import lalpulsar as lp
30from lalpulsar import simulateCW
31
32from . import basis_functions as bf
33from . import mols_for_gte as mols
34from . import semicoherent_metric_methods as scmm
35from . import tbank_estimates as tbe
36
37
38def waveform(h0, params, cosi, tref):
39
40 s = len(params[0][0])
41 coeffs = bf.allcoeffs(s)
42 f0 = params[0][0][0]
43
44 def wf(dt):
45
46 freq = mols.modelvalueatpoint(dt + tref, coeffs, params, ignoreintcheck=True)
47
48 h_t = h0 * (freq / f0) ** 2
49
50 ap = h_t * (1.0 + cosi**2) / 2.0
51 ax = h_t * cosi
52
53 dphi = mols.phase(dt + tref, coeffs, params, ignoreintcheck=True)
54
55 return dphi, ap, ax
56
57 return wf
58
59
60# Builds and saves SFTs to files where a signal of strain h0 is randomly chosen and injected. Tdata is the length of data
61# to be used. tbank contains all the parameters which defines the parameter space. tstart is the start time of the data
62# trefsegfrac tells us how far through the data tref is defined. E.g. If set to 0, tref occurs at the start of the data,
63# if 0.5 tref occurs half way through the data and so on. Tsft is the length of SFTs to be built. parentdirectory is the
64# path leading to the directory where the SFTs will be saved. h0 is the strain of the injected signal and noiseratio is
65# what fraction weaker the noise is to the signal. E.g. if set to 100, then the noise will be at 1/100 of h0.
67 Tdata, tbank, finputdata, trefsegfrac=0.0, parentdirectory=".", rand_seed=0
68):
69
70 # Double check the start time of the knots agrees with tstart and set them to be equal if they don't
71 if bf.knotslist[0] != finputdata.tstart:
72 for i in range(len(bf.knotslist)):
73 bf.knotslist[i] = bf.knotslist[i] + finputdata.tstart
74
75 logging.info("Knots: " + str(bf.knotslist))
76
77 # Set Bounds, metric, mismatch and lattice type
78 finalknot = len(bf.knotslist)
79 s = tbank.s
80 mismatch = tbank.maxmismatch
81
82 tiling = lp.CreateLatticeTiling(s * finalknot)
83
84 metric = scmm.PreCompMetric(s)
85
86 logging.info("Knots before bounds set: " + str(bf.knotslist))
87 tbe.setbounds(tiling, tbank)
88
89 logging.info("Knots after bounds set: " + str(bf.knotslist))
90 lp.SetTilingLatticeAndMetric(tiling, lp.TILING_LATTICE_ANSTAR, metric, mismatch)
91
92 # Create random parameters to be used as an injected signal
93 randparams = lal.CreateRandomParams(rand_seed)
94 signalparams = lal.gsl_matrix(s * finalknot, 1)
95 lp.RandomLatticeTilingPoints(tiling, 0, randparams, signalparams)
96
97 f0 = signalparams.data[0][0]
98 f1 = signalparams.data[1][0]
99 f2 = signalparams.data[2][0]
100
101 logging.info(
102 "Randomly generated Signal Params: %s", str(np.transpose(signalparams.data)[0])
103 )
104
105 # Waveform and simulateCW object
106 tref = bf.knotslist[0] + Tdata * trefsegfrac
107 params = mols.solsbyint(np.transpose(signalparams.data)[0], s)
108 wf = waveform(finputdata.h0, params, finputdata.cosi, tref)
109
110 for i, detector in enumerate(finputdata.detectors.data):
111
113 tref,
114 bf.knotslist[0],
115 Tdata,
116 wf,
117 finputdata.dt_wf,
118 finputdata.phi0,
119 finputdata.psi,
120 finputdata.Alpha,
121 finputdata.Delta,
122 detector,
123 tref_at_det=True,
124 )
125
126 # Create directory to save SFTs into using strain and signal parameters as directory name
127 # directoryname = os.path.join(parentdirectory, f"SFTs_h0-{finputdata.h0:.2e}_f0-{f0:.3f}_f1-{f1:.2e}_f2-{f2:.2e}_dur-{tbank.dur}_tstart-{finputdata.tstart}/")
128
129 path_to_detector_sfts = os.path.join(
130 parentdirectory,
131 f"SFTs_h0-{finputdata.h0:.2e}_f0-{f0:.3f}_f1-{f1:.2e}_f2-{f2:.2e}_dur-{tbank.dur}_tstart-{finputdata.tstart}/",
132 )
133 directoryname = os.path.join(path_to_detector_sfts, detector + "/")
134
135 if not os.path.isdir(path_to_detector_sfts):
136 os.mkdir(path_to_detector_sfts)
137
138 if not os.path.isdir(directoryname):
139 os.mkdir(directoryname)
140
141 # Write SFT files
142
143 # Rule of thumb given by Karl for fmax -> fmax = f0 + 10^-4 * f0 + (50 + 8)/Tsft
144 # The 10^-4 comes from an approximation doppler modulation, 50 + 8 is the number of bins extra either side we should have
145 for file, i, N in S.write_sft_files(
146 fmax=tbank.fmax + 20,
147 Tsft=finputdata.Tsft,
148 noise_sqrt_Sh=finputdata.noise_sqrt_Sh[i],
149 comment="PWModPhase",
150 out_dir=directoryname,
151 ):
152 logging.info("Generated SFT file %s (%i of %i)" % (file, i + 1, N))
153
154 # Return signal parameters so they can be known outside of this method
155
156 return np.transpose(signalparams.data)[0], path_to_detector_sfts
def buildSFTs(Tdata, tbank, finputdata, trefsegfrac=0.0, parentdirectory=".", rand_seed=0)