46 from pylal
import datatypes
as laltypes
47 from pylal
import lalfft
48 from pylal
import spawaveform
49 import lalsimulation
as lalsim
50 from gstlal
import chirptime
51 from lal
import MSUN_SI
54 __author__ =
"Kipp Cannon <kipp.cannon@ligo.org>, Chad Hanna <chad.hanna@ligo.org>, Drew Keppel <drew.keppel@ligo.org>"
67 gstlal_FD_approximants = set((
'IMRPhenomC',
'SEOBNRv2_ROM_DoubleSpin',
'TaylorF2',
'TaylorF2RedSpin',
'TaylorF2RedSpinTidal'))
68 gstlal_TD_approximants = set((
'TaylorT1',
'TaylorT2',
'TaylorT3',
'TaylorT4',
'EOBNRv2'))
69 gstlal_approximants = gstlal_FD_approximants | gstlal_TD_approximants
70 gstlal_IMR_approximants = set((
'IMRPhenomC',
'SEOBNRv2_ROM_DoubleSpin',
'EOBNRv2'))
72 def gstlal_valid_approximant(appx_str):
74 lalsim.GetApproximantFromString(str(appx_str))
76 raise ValueError(
"Approximant not supported by lalsimulation: %s" % appx_str)
77 if appx_str
not in gstlal_approximants:
78 raise ValueError(
"Approximant not currently supported by gstlal, but is supported by lalsimulation: %s. Please consider preparing a patch" % appx_str)
81 def add_quadrature_phase(fseries, n):
83 From the Fourier transform of a real-valued function of time,
84 compute and return the Fourier transform of the complex-valued
85 function of time whose real component is the original time series
86 and whose imaginary component is the quadrature phase of the real
87 part. fseries is a LAL COMPLEX16FrequencySeries and n is the
88 number of samples in the original time series.
94 out_fseries = laltypes.COMPLEX16FrequencySeries(
96 epoch = fseries.epoch,
98 deltaF = fseries.deltaF,
99 sampleUnits = fseries.sampleUnits
106 have_nyquist =
not (n % 2)
112 positive_frequencies = fseries.data
113 positive_frequencies[0] = 0
115 positive_frequencies[-1] = 0
116 zeros = numpy.zeros((len(positive_frequencies),), dtype =
"cdouble")
119 positive_frequencies = positive_frequencies[:-1]
121 out_fseries.data = numpy.concatenate((zeros, 2 * positive_frequencies[1:]))
128 A tool for generating the quadrature phase of a real-valued
134 >>> from pylal.datatypes import REAL8TimeSeries
135 >>> q = QuadraturePhase(128) # initialize for 128-sample templates
136 >>> inseries = REAL8TimeSeries(deltaT = 1.0 / 128, data = numpy.cos(numpy.arange(128, dtype = "double") * 2 * numpy.pi / 128)) # one cycle of cos(t)
137 >>> outseries = q(inseries) # output has cos(t) in real part, sin(t) in imaginary part
142 Initialize. n is the size, in samples, of the templates to
143 be processed. This is used to pre-allocate work space.
146 self.
fwdplan = lalfft.XLALCreateForwardREAL8FFTPlan(n, 1)
147 self.
revplan = lalfft.XLALCreateReverseCOMPLEX16FFTPlan(n, 1)
148 self.
in_fseries = lalfft.prepare_fseries_for_real8tseries(laltypes.REAL8TimeSeries(deltaT = 1.0, data = numpy.zeros((n,), dtype =
"double")))
152 Transform the real-valued time series stored in tseries
153 into a complex-valued time series. The return value is a
154 newly-allocated complex time series. The input time series
155 is stored in the real part of the output time series, and
156 the complex part stores the quadrature phase.
168 tseries = laltypes.COMPLEX16TimeSeries(data = numpy.zeros((self.
n,), dtype =
"cdouble"))
169 lalfft.XLALCOMPLEX16FreqTimeFFT(tseries, add_quadrature_phase(self.
in_fseries, self.
n), self.
revplan)
178 def normalized_autocorrelation(fseries, revplan):
180 fseries = laltypes.COMPLEX16FrequencySeries(
182 epoch = fseries.epoch,
184 deltaF = fseries.deltaF,
185 sampleUnits = fseries.sampleUnits,
186 data = data * numpy.conj(data)
188 tseries = laltypes.COMPLEX16TimeSeries(
189 data = numpy.empty((len(data),), dtype =
"cdouble")
191 lalfft.XLALCOMPLEX16FreqTimeFFT(tseries, fseries, revplan)
193 tseries.data = data / data[0]
199 x = int(math.ceil(x))
202 while n
and (x & (x + 1)):
214 samples_max_256 = 1024,
215 samples_max_64 = 2048,
220 The function time_frequency_boundaries splits a template bank up by
221 times for which different sampling rates are appropriate.
223 The function returns a list of 3-tuples of the form (rate,begin,end)
224 where rate is the sampling rate and begin/end mark the boundaries
225 during which the given rate is guaranteed to be appropriate (no
226 template exceeds a frequency of Nyquist/padding during these times).
228 @param sngl_inspiral_rows The snigle inspiral rows for this sub bank
229 @param flow The low frequency to generate the waveform from
230 @param fhigh The maximum frequency for generating the waveform
231 @param padding Allow a template to be generated up to Nyquist / padding for any slice
232 @param samples_min The minimum number of samples to use in any time slice
233 @param samples_max_256 The maximum number of samples to have in any time slice greater than or equal to 256 Hz
234 @param samples_max_64 The maximum number of samples to have in any time slice greater than or equal to 64 Hz
235 @param samples_max The maximum number of samples in any time slice below 64 Hz
236 @param verbose Be verbose
246 allowed_rates = [16384,8192,4096,2048,1024,512,256,128,64,32]
249 sample_rate_min = ceil_pow_2( 2 * padding * flow )
250 sample_rate_max = ceil_pow_2( 2 * fhigh )
251 while allowed_rates[-1] < sample_rate_min:
252 allowed_rates.pop(-1)
253 while allowed_rates[0] > sample_rate_max:
267 segment_samples_min = max(ceil_pow_2( 2*len(sngl_inspiral_rows) ),samples_min)
275 time_freq_boundaries = []
284 rates_below = [r/(2.*padding)
for r
in allowed_rates[1:]] + [flow]
286 for this_flow, rate
in zip(rates_below, allowed_rates):
288 segment_samples_max = samples_max_256
290 segment_samples_max = samples_max_64
292 segment_samples_max = samples_max
294 if segment_samples_min > segment_samples_max:
295 raise ValueError(
"The input template bank must have fewer than %d templates, but had %d." % (segment_samples_max, 2 * len(sngl_inspiral_rows)))
297 longest_chirp = max(
chirptime.imr_time(this_flow, row.mass1*MSUN_SI ,row.mass2*MSUN_SI, row.spin1z, row.spin2z)
for row
in sngl_inspiral_rows)
302 if longest_chirp > accum_time:
304 number_large_blocks = int(numpy.floor( rate*(longest_chirp-accum_time) / segment_samples_max ))
305 number_small_blocks = int(numpy.ceil( rate*(longest_chirp-accum_time) / segment_samples_min )
306 - number_large_blocks*segment_samples_max/segment_samples_min)
312 while number_small_blocks > 0:
313 if number_small_blocks % 2 == 1:
314 time_freq_boundaries.append((rate,
316 accum_time+float(2**exponent)*segment_samples_min/rate))
317 accum_time += float(2**exponent)*segment_samples_min/rate
319 number_small_blocks = number_small_blocks >> 1
323 for idx
in range(number_large_blocks):
324 time_freq_boundaries.append((rate,
326 accum_time+(1./rate)*segment_samples_max))
327 accum_time += (1./rate)*segment_samples_max
330 print>> sys.stderr,
"Time freq boundaries: "
331 print>> sys.stderr, time_freq_boundaries
333 return numpy.array(time_freq_boundaries,dtype=[(
'rate',
'int'),(
'begin',
'float'),(
'end',
'float')])