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_computePSD.py
Go to the documentation of this file.
1# Copyright (C) 2020 Rodrigo Tenorio, David Keitel
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
19import numpy as np
20from numpy.testing import assert_allclose
21import lal
22import lalpulsar
23import pytest
24
25# load Earth and Sun ephemerides
26earth_ephem_file = os.path.join(
27 os.environ["LAL_TEST_PKGDATADIR"], "earth00-40-DE405.dat.gz"
28)
29sun_ephem_file = os.path.join(
30 os.environ["LAL_TEST_PKGDATADIR"], "sun00-40-DE405.dat.gz"
31)
32ephemerides = lalpulsar.InitBarycenter(earth_ephem_file, sun_ephem_file)
33
34# parameters to make fake data
35IFOs = ["H1", "L1"]
36numDet = len(IFOs)
37sqrtSX = ["1e-23"]
38f_min = 20
39f_max = 21
40T0 = 900000000
41Tspan = 86400
42Tsft = 1800
43Toverlap = 0
44dataParams = lalpulsar.CWMFDataParams()
45dataParams.fMin = f_min
46dataParams.Band = f_max - f_min
47lalpulsar.ParseMultiLALDetector(dataParams.multiIFO, IFOs)
48lalpulsar.ParseMultiNoiseFloor(dataParams.multiNoiseFloor, sqrtSX, numDet)
49multiTS = lalpulsar.MakeMultiTimestamps(T0, Tspan, Tsft, Toverlap, numDet)
50dataParams.multiTimestamps = multiTS
51dataParams.randSeed = 42
52dataParams.inputMultiTS = None
53injectionSources = (
54 lalpulsar.PulsarParamsVector()
55) # empty struct, don't actually inject a signal
56
57# make fake data directly in memory
58multiSFTs = 0
59print("Generating SFTs with CWMakeFakeMultiData...")
60multiSFTs, _ = lalpulsar.CWMakeFakeMultiData(
61 multiSFTs,
62 None,
63 injectionSources=injectionSources,
64 dataParams=dataParams,
65 edat=ephemerides,
66)
67assert multiSFTs.length == numDet
68numSFTs = lal.CreateUINT4Vector(numDet)
69numSFTs.data = [sft.length for sft in multiSFTs.data]
70f0 = multiSFTs.data[0].data[0].f0
71deltaF = multiSFTs.data[0].data[0].deltaF
72numBins = multiSFTs.data[0].data[0].data.length
73print("numIFOs:", numDet)
74print("numSFTs per IFO:", numSFTs.data)
75print("numBins per SFT:", numBins)
76
77# make an additional hard copy of the SFTs
78# to test PSD computation with/without normalizing in place
79print("Copying SFTs...")
80multiSFTs_copy = lalpulsar.CreateEmptyMultiSFTVector(numSFTs)
81for X, sftvec in enumerate(multiSFTs.data):
82 for k, sft in enumerate(sftvec.data):
83 lalpulsar.CopySFT(multiSFTs_copy.data[X].data[k], sft)
84
85
87 rtol = 1e-15 # float comparison tolerance
88
89 print("Calling ComputePSDandNormSFTPower() with normalizeSFTsInPlace=False...")
90 psd, multiPSDVector, normSFT = lalpulsar.ComputePSDandNormSFTPower(
91 inputSFTs=multiSFTs,
92 returnMultiPSDVector=True,
93 returnNormSFT=True,
94 blocksRngMed=101,
95 PSDmthopSFTs=1, # arithmean
96 PSDmthopIFOs=0, # arithsum
97 nSFTmthopIFOs=1, # arithmean
98 nSFTmthopSFTs=0, # arithsum
99 normalizeByTotalNumSFTs=False,
100 FreqMin=f_min,
101 FreqBand=f_max - f_min,
102 normalizeSFTsInPlace=False,
103 )
104 print(
105 "PSD from ComputePSDandNormSFTPower() with normalizeSFTsInPlace=False:",
106 psd.data,
107 )
108 assert psd.length == numBins
109 print("normSFT:", normSFT.data)
110 assert normSFT.length == numBins
111 assert multiPSDVector.length == numDet
112 summed_average_IFO_PSD_vector = np.zeros_like(psd.data)
113 for X in range(numDet):
114 assert multiPSDVector.data[X].length == numSFTs.data[X]
115 assert multiPSDVector.data[X].data[0].data.length == psd.length
116 assert multiPSDVector.data[X].data[0].f0 == f0
117 assert multiPSDVector.data[X].data[0].deltaF == deltaF
118 average_IFO_PSD_vector = np.array(
119 [
120 np.mean(
121 [
122 multiPSDVector.data[X].data[n].data.data[k]
123 for n in range(numSFTs.data[X])
124 ]
125 )
126 for k in range(numBins)
127 ]
128 )
129 print("multiPSDVector[{:d}] averaged: {}".format(X, average_IFO_PSD_vector))
130 summed_average_IFO_PSD_vector += average_IFO_PSD_vector
131 print(
132 "sum of per-IFO averaged multiPSDVector entries:", summed_average_IFO_PSD_vector
133 )
134 assert_allclose(summed_average_IFO_PSD_vector, psd.data, rtol=rtol)
135 print("Relative agreement to within {:e}.".format(rtol))
136
137 print(
138 "Calling ComputePSDandNormSFTPower() again, with normalizeSFTsInPlace=True..."
139 )
140 psd2, multiPSDVector, normSFT2 = lalpulsar.ComputePSDandNormSFTPower(
141 inputSFTs=multiSFTs,
142 returnMultiPSDVector=True,
143 returnNormSFT=True,
144 blocksRngMed=101,
145 PSDmthopSFTs=1, # arithmean
146 PSDmthopIFOs=0, # arithsum
147 nSFTmthopIFOs=1, # arithmean
148 nSFTmthopSFTs=0, # arithsum
149 normalizeByTotalNumSFTs=False,
150 FreqMin=f_min,
151 FreqBand=f_max - f_min,
152 normalizeSFTsInPlace=True,
153 )
154 print(
155 "PSD from ComputePSDandNormSFTPower() with normalizeSFTsInPlace=True:",
156 psd2.data,
157 )
158 assert psd2.length == numBins
159 assert_allclose(psd2.data, psd.data, rtol=rtol)
160 print("Relative PSD agreement to within {:e}.".format(rtol))
161 print("normSFT:", normSFT2.data)
162 assert normSFT2.length == numBins
163 assert_allclose(normSFT2.data, normSFT.data, rtol=rtol)
164 print("Relative normSFT agreement to within {:e}.".format(rtol))
165
166 print("Calling ComputePSDfromSFTs() on original (now normalized) SFTs...")
167 psd3 = lalpulsar.ComputePSDfromSFTs(
168 inputSFTs=multiSFTs,
169 blocksRngMed=101,
170 PSDmthopSFTs=1, # arithmean
171 PSDmthopIFOs=0, # arithsum
172 normalizeByTotalNumSFTs=False,
173 FreqMin=f_min,
174 FreqBand=f_max - f_min,
175 )
176 print("PSD from ComputePSDfromSFTs() on normalized SFTs:", psd3.data)
177 assert psd3.length == numBins
178 # these will be different, so not comparing the output
179
180 print("Calling ComputePSDfromSFTs() on copied SFTs...")
181 psd4 = lalpulsar.ComputePSDfromSFTs(
182 inputSFTs=multiSFTs_copy,
183 blocksRngMed=101,
184 PSDmthopSFTs=1, # arithmean
185 PSDmthopIFOs=0, # arithsum
186 normalizeByTotalNumSFTs=False,
187 FreqMin=f_min,
188 FreqBand=f_max - f_min,
189 )
190 print("PSD from ComputePSDfromSFTs() on copied SFTs:", psd4.data)
191 assert psd4.length == numBins
192 assert_allclose(psd4.data, psd.data, rtol=rtol)
193 print("Relative agreement to within {:e}.".format(rtol))
194
195
196if __name__ == "__main__":
197 args = sys.argv[1:] or ["-v", "-rs", "--junit-xml=junit-computePSD.xml"]
198 sys.exit(pytest.main(args=[__file__] + args))
def test_ComputePSDandNormSFTPower()