def generate_short_inj_from_inj(self, inj_waveform, simulation_id): """Generate and a store a truncated representation of inj_waveform.""" if not self.enabled or not self.match_threshold: # Do nothing! return if simulation_id in self.short_injections: err_msg = "An injection with simulation id " err_msg += str(simulation_id) err_msg += " has already been added. This suggests " err_msg += "that your injection file contains injections with " err_msg += "duplicate simulation_ids. This is not allowed." raise ValueError(err_msg) curr_length = len(inj_waveform) new_length = int(nearest_larger_binary_number(curr_length)) # Don't want length less than 1/delta_f while new_length * inj_waveform.delta_t < 1. / self.coarsematch_deltaf: new_length = new_length * 2 inj_waveform.resize(new_length) inj_tilde = inj_waveform.to_frequencyseries() # Dynamic range is important here! inj_tilde_np = inj_tilde.numpy() * DYN_RANGE_FAC delta_f = inj_tilde.get_delta_f() new_freq_len = int(self.coarsematch_fmax / delta_f + 1) # This shouldn't be a problem if injections are generated at # 16384 Hz ... It is only a problem of injection sample rate # gives a lower Nyquist than the trunc_f_max. If this error is # ever raised one could consider zero-padding the injection. assert (new_freq_len <= len(inj_tilde)) df_ratio = int(self.coarsematch_deltaf / delta_f) inj_tilde_np = inj_tilde_np[:new_freq_len:df_ratio] new_inj = FrequencySeries(inj_tilde_np, dtype=np.complex64, delta_f=self.coarsematch_deltaf) self.short_injections[simulation_id] = new_inj
def get_td_waveform_from_fd(rwrap=0.2, **params): """ Return time domain version of fourier domain approximant. This returns a time domain version of a fourier domain approximant, with padding and tapering at the start of the waveform. Parameters ---------- rwrap: float Cyclic time shift parameter in seconds. A fudge factor to ensure that the entire time series is contiguous in the array and not wrapped around the end. params: dict The parameters defining the waveform to generator. See `get_fd_waveform`. Returns ------- hp: pycbc.types.TimeSeries Plus polarization time series hc: pycbc.types.TimeSeries Cross polarization time series """ # determine the duration to use full_duration = duration = get_waveform_filter_length_in_time(**params) nparams = params.copy() while full_duration < duration * 1.5: full_duration = get_waveform_filter_length_in_time(**nparams) nparams['f_lower'] *= 0.99 if 'f_ref' not in nparams: nparams['f_ref'] = params['f_lower'] # factor to ensure the vectors are all large enough. We don't need to # completely trust our duration estimator in this case, at a small # increase in computational cost fudge_duration = (max(0, full_duration) + .1 + rwrap) * 1.5 fsamples = int(fudge_duration / params['delta_t']) N = pnutils.nearest_larger_binary_number(fsamples) fudge_duration = N * params['delta_t'] nparams['delta_f'] = 1.0 / fudge_duration hp, hc = get_fd_waveform(**nparams) # Resize to the right sample rate tsize = int(1.0 / params['delta_t'] / nparams['delta_f']) fsize = tsize // 2 + 1 hp.resize(fsize) hc.resize(fsize) # avoid wraparound hp = hp.cyclic_time_shift(-rwrap) hc = hc.cyclic_time_shift(-rwrap) hp = wfutils.fd_to_td(hp, left_window=(nparams['f_lower'], params['f_lower'])) hc = wfutils.fd_to_td(hc, left_window=(nparams['f_lower'], params['f_lower'])) return hp, hc
def generate_short_inj_from_inj(self, inj_waveform, simulation_id): """Generate and a store a truncated representation of inj_waveform.""" if not self.enabled: # Do nothing! return if simulation_id in self.short_injections: err_msg = "An injection with simulation id " err_msg += str(simulation_id) err_msg += " has already been added. This suggests " err_msg += "that your injection file contains injections with " err_msg += "duplicate simulation_ids. This is not allowed." raise ValueError(err_msg) curr_length = len(inj_waveform) new_length = int(nearest_larger_binary_number(curr_length)) # Don't want length less than 1/delta_f while new_length * inj_waveform.delta_t < 1./self.coarsematch_deltaf: new_length = new_length * 2 inj_waveform.resize(new_length) inj_tilde = inj_waveform.to_frequencyseries() # Dynamic range is important here! inj_tilde_np = inj_tilde.numpy() * DYN_RANGE_FAC delta_f = inj_tilde.get_delta_f() new_freq_len = int(self.coarsematch_fmax / delta_f + 1) # This shouldn't be a problem if injections are generated at # 16384 Hz ... It is only a problem of injection sample rate # gives a lower Nyquist than the trunc_f_max. If this error is # ever raised one could consider zero-padding the injection. assert(new_freq_len <= len(inj_tilde)) df_ratio = int(self.coarsematch_deltaf/delta_f) inj_tilde_np = inj_tilde_np[:new_freq_len:df_ratio] new_inj = FrequencySeries(inj_tilde_np, dtype=np.complex64, delta_f=self.coarsematch_deltaf) self.short_injections[simulation_id] = new_inj
def td_waveform_to_fd_waveform(waveform, out=None, length=None, buffer_length=100): """ Convert a time domain into a frequency domain waveform by FFT. As a waveform is assumed to "wrap" in the time domain one must be careful to ensure the waveform goes to 0 at both "boundaries". To ensure this is done correctly the waveform must have the epoch set such the merger time is at t=0 and the length of the waveform should be shorter than the desired length of the FrequencySeries (times 2 - 1) so that zeroes can be suitably pre- and post-pended before FFTing. If given, out is a memory array to be used as the output of the FFT. If not given memory is allocated internally. If present the length of the returned FrequencySeries is determined from the length out. If out is not given the length can be provided expicitly, or it will be chosen as the nearest power of 2. If choosing length explicitly the waveform length + buffer_length is used when choosing the nearest binary number so that some zero padding is always added. """ # Figure out lengths and set out if needed if out is None: if length is None: N = pnutils.nearest_larger_binary_number(len(waveform) + \ buffer_length) n = int(N // 2) + 1 else: n = length N = (n - 1) * 2 out = zeros(n, dtype=complex_same_precision_as(waveform)) else: n = len(out) N = (n - 1) * 2 delta_f = 1. / (N * waveform.delta_t) # total duration of the waveform tmplt_length = len(waveform) * waveform.delta_t if len(waveform) > N: err_msg = "The time domain template is longer than the intended " err_msg += "duration in the frequency domain. This situation is " err_msg += "not supported in this function. Please shorten the " err_msg += "waveform appropriately before calling this function or " err_msg += "increase the allowed waveform length. " err_msg += "Waveform length (in samples): {}".format(len(waveform)) err_msg += ". Intended length: {}.".format(N) raise ValueError(err_msg) # for IMR templates the zero of time is at max amplitude (merger) # thus the start time is minus the duration of the template from # lower frequency cutoff to merger, i.e. minus the 'chirp time' tChirp = -float(waveform.start_time) # conversion from LIGOTimeGPS waveform.resize(N) k_zero = int(waveform.start_time / waveform.delta_t) waveform.roll(k_zero) htilde = FrequencySeries(out, delta_f=delta_f, copy=False) fft(waveform.astype(real_same_precision_as(htilde)), htilde) htilde.length_in_time = tmplt_length htilde.chirp_length = tChirp return htilde
def get_td_waveform_from_fd(**params): """ Return time domain version of fourier domain approximant. This returns a time domain version of a fourier domain approximant, with padding and tapering at the start of the waveform. Parameters ---------- params: dict The parameters defining the waveform to generator. See `get_fd_waveform`. Returns ------- hp: pycbc.types.TimeSeries Plus polarization time series hc: pycbc.types.TimeSeries Cross polarization time series """ # determine the duration to use full_duration = duration = get_waveform_filter_length_in_time(**params) nparams = params.copy() while full_duration < duration * 1.5: full_duration = get_waveform_filter_length_in_time(**nparams) nparams['f_lower'] -= 1 if 'f_fref' not in nparams: nparams['f_ref'] = params['f_lower'] # factor to ensure the vectors are all large enough. We don't need to # completely trust our duration estimator in this case, at a small # increase in computational cost rwrap = 0.2 fudge_duration = (max(0, full_duration) + .1 + rwrap) * 1.5 fsamples = int(fudge_duration / params['delta_t']) N = pnutils.nearest_larger_binary_number(fsamples) fudge_duration = N * params['delta_t'] nparams['delta_f'] = 1.0 / fudge_duration hp, hc = get_fd_waveform(**nparams) # Resize to the right sample rate tsize = int(1.0 / params['delta_t'] / nparams['delta_f']) fsize = tsize / 2 + 1 hp.resize(fsize) hc.resize(fsize) # avoid wraparound hp = hp.cyclic_time_shift(-rwrap) hc = hc.cyclic_time_shift(-rwrap) hp = wfutils.fd_to_td(hp, left_window=(nparams['f_lower'], params['f_lower'])) hc = wfutils.fd_to_td(hc, left_window=(nparams['f_lower'], params['f_lower'])) return hp, hc
def td_waveform_to_fd_waveform(waveform, out=None, length=None, buffer_length=100): """ Convert a time domain into a frequency domain waveform by FFT. As a waveform is assumed to "wrap" in the time domain one must be careful to ensure the waveform goes to 0 at both "boundaries". To ensure this is done correctly the waveform must have the epoch set such the merger time is at t=0 and the length of the waveform should be shorter than the desired length of the FrequencySeries (times 2 - 1) so that zeroes can be suitably pre- and post-pended before FFTing. If given, out is a memory array to be used as the output of the FFT. If not given memory is allocated internally. If present the length of the returned FrequencySeries is determined from the length out. If out is not given the length can be provided expicitly, or it will be chosen as the nearest power of 2. If choosing length explicitly the waveform length + buffer_length is used when choosing the nearest binary number so that some zero padding is always added. """ # Figure out lengths and set out if needed if out is None: if length is None: N = pnutils.nearest_larger_binary_number(len(waveform) + \ buffer_length) n = int(N//2) + 1 else: n = length N = (n-1)*2 out = zeros(n, dtype=complex_same_precision_as(waveform)) else: n = len(out) N = (n-1)*2 delta_f = 1. / (N * waveform.delta_t) # total duration of the waveform tmplt_length = len(waveform) * waveform.delta_t if len(waveform) > N: err_msg = "The time domain template is longer than the intended " err_msg += "duration in the frequency domain. This situation is " err_msg += "not supported in this function. Please shorten the " err_msg += "waveform appropriately before calling this function or " err_msg += "increase the allowed waveform length. " err_msg += "Waveform length (in samples): {}".format(len(waveform)) err_msg += ". Intended length: {}.".format(N) raise ValueError(err_msg) # for IMR templates the zero of time is at max amplitude (merger) # thus the start time is minus the duration of the template from # lower frequency cutoff to merger, i.e. minus the 'chirp time' tChirp = - float( waveform.start_time ) # conversion from LIGOTimeGPS waveform.resize(N) k_zero = int(waveform.start_time / waveform.delta_t) waveform.roll(k_zero) htilde = FrequencySeries(out, delta_f=delta_f, copy=False) fft(waveform.astype(real_same_precision_as(htilde)), htilde) htilde.length_in_time = tmplt_length htilde.chirp_length = tChirp return htilde
def __getitem__(self, index): approximant = self.approximant(index) f_end = self.end_frequency(index) # Determine the length of time of the filter, rounded up to # nearest power of two min_buffer = 1.0 + self.minimum_buffer from pycbc.waveform.waveform import props buff_size = pycbc.waveform.get_waveform_filter_length_in_time(approximant, f_lower=self.f_lower, **props(self.table[index])) tlen = nearest_larger_binary_number((buff_size + min_buffer) * self.sample_rate) flen = tlen / 2 + 1 delta_f = self.sample_rate / float(tlen) if f_end is None or f_end >= (flen * delta_f): f_end = (flen-1) * delta_f logging.info("Generating %s, %ss, %i" % (approximant, 1.0/delta_f, index)) # Get the waveform filter distance = 1.0 / DYN_RANGE_FAC htilde = pycbc.waveform.get_waveform_filter( zeros(flen, dtype=numpy.complex64), self.table[index], approximant=approximant, f_lower=self.f_lower, f_final=f_end, delta_f=delta_f, delta_t=1.0/self.sample_rate, distance=distance, **self.extra_args) # If available, record the total duration (which may # include ringdown) and the duration up to merger since they will be # erased by the type conversion below. # NOTE: If these durations are not available the values in self.table # will continue to take the values in the input file. if hasattr(htilde, 'length_in_time'): if htilde.length_in_time is not None: self.table[index].ttotal = htilde.length_in_time if hasattr(htilde, 'chirp_length'): if htilde.chirp_length is not None: self.table[index].template_duration = htilde.chirp_length htilde = htilde.astype(numpy.complex64) htilde.f_lower = self.f_lower htilde.end_frequency = f_end htilde.end_idx = int(htilde.end_frequency / htilde.delta_f) htilde.params = self.table[index] htilde.approximant = approximant htilde.chirp_length = htilde.params.template_duration htilde.length_in_time = htilde.params.ttotal # Add sigmasq as a method of this instance htilde.sigmasq = types.MethodType(sigma_cached, htilde) htilde._sigmasq = {} return htilde
def make_padded_frequency_series(vec, filter_N=None, delta_f=None): """Convert vec (TimeSeries or FrequencySeries) to a FrequencySeries. If filter_N and/or delta_f are given, the output will take those values. If not told otherwise the code will attempt to pad a timeseries first such that the waveform will not wraparound. However, if delta_f is specified to be shorter than the waveform length then wraparound *will* be allowed. """ if filter_N is None: power = ceil(log(len(vec), 2)) + 1 N = 2**power else: N = filter_N n = N / 2 + 1 if isinstance(vec, FrequencySeries): vectilde = FrequencySeries(zeros(n, dtype=complex_same_precision_as(vec)), delta_f=1.0, copy=False) if len(vectilde) < len(vec): cplen = len(vectilde) else: cplen = len(vec) vectilde[0:cplen] = vec[0:cplen] delta_f = vec.delta_f elif isinstance(vec, TimeSeries): # First determine if the timeseries is too short for the specified df # and increase if necessary curr_length = len(vec) new_length = int(nearest_larger_binary_number(curr_length)) while new_length * vec.delta_t < 1. / delta_f: new_length = new_length * 2 vec.resize(new_length) # Then convert to frequencyseries v_tilde = vec.to_frequencyseries() # Then convert frequencyseries to required length and spacing by keeping # only every nth sample if delta_f needs increasing, and cutting at # Nyquist if the max frequency is too high. # NOTE: This assumes that the input and output data is using binary # lengths. i_delta_f = v_tilde.get_delta_f() v_tilde = v_tilde.numpy() df_ratio = int(delta_f / i_delta_f) n_freq_len = int((n - 1) * df_ratio + 1) assert (n <= len(v_tilde)) df_ratio = int(delta_f / i_delta_f) v_tilde = v_tilde[:n_freq_len:df_ratio] vectilde = FrequencySeries(v_tilde, delta_f=delta_f, dtype=complex128) return FrequencySeries(vectilde * DYN_RANGE_FAC, delta_f=delta_f, dtype=complex128)
def make_padded_frequency_series(vec, filter_N=None, delta_f=None): """Convert vec (TimeSeries or FrequencySeries) to a FrequencySeries. If filter_N and/or delta_f are given, the output will take those values. If not told otherwise the code will attempt to pad a timeseries first such that the waveform will not wraparound. However, if delta_f is specified to be shorter than the waveform length then wraparound *will* be allowed. """ if filter_N is None: power = ceil(log(len(vec), 2)) + 1 N = 2 ** power else: N = filter_N n = N / 2 + 1 if isinstance(vec, FrequencySeries): vectilde = FrequencySeries(zeros(n, dtype=complex_same_precision_as(vec)), delta_f=1.0, copy=False) if len(vectilde) < len(vec): cplen = len(vectilde) else: cplen = len(vec) vectilde[0:cplen] = vec[0:cplen] delta_f = vec.delta_f elif isinstance(vec, TimeSeries): # First determine if the timeseries is too short for the specified df # and increase if necessary curr_length = len(vec) new_length = int(nearest_larger_binary_number(curr_length)) while new_length * vec.delta_t < 1./delta_f: new_length = new_length * 2 vec.resize(new_length) # Then convert to frequencyseries v_tilde = vec.to_frequencyseries() # Then convert frequencyseries to required length and spacing by keeping # only every nth sample if delta_f needs increasing, and cutting at # Nyquist if the max frequency is too high. # NOTE: This assumes that the input and output data is using binary # lengths. i_delta_f = v_tilde.get_delta_f() v_tilde = v_tilde.numpy() df_ratio = int(delta_f / i_delta_f) n_freq_len = int((n-1) * df_ratio +1) assert(n <= len(v_tilde)) df_ratio = int(delta_f / i_delta_f) v_tilde = v_tilde[:n_freq_len:df_ratio] vectilde = FrequencySeries(v_tilde, delta_f=delta_f, dtype=complex128) return FrequencySeries(vectilde * DYN_RANGE_FAC, delta_f=delta_f, dtype=complex128)
def make_padded_frequency_series(vec, filter_N=None, delta_f=None): """ Convert vec (TimeSeries or FrequencySeries) to a FrequencySeries. For a TimeSeries input, first it is resized to filter_N and is If filter_N and/or delta_f are given, the output will take those values. If not told otherwise the code will attempt to pad a timeseries first such that the waveform will not wraparound. However, if delta_f is specified to be shorter than the waveform length then wraparound *will* be allowed. """ # {{{ if filter_N is None: filter_N = nearest_larger_binary_number(len(vec)) filter_n = filter_N / 2 + 1 if isinstance(vec, FrequencySeries): vectilde = FrequencySeries(zeros(filter_n), delta_f=vec.get_delta_f(), dtype=complex_same_precision_as(vec)) cplen = min(len(vec), len(vectilde)) vectilde[:cplen] = vec[:cplen] if delta_f is not None: delta_f_ratio = max(1, int(ceil(vectilde.get_delta_f() / delta_f))) vectilde = vectilde[:len(vectilde):delta_f_ratio] elif isinstance(vec, TimeSeries): delta_f_from_filter_N = 1. / filter_N / vec.get_delta_t() vec.resize(filter_N) v_tilde = vec.to_frequencyseries() vectilde = FrequencySeries(v_tilde[:], delta_f=delta_f_from_filter_N, dtype=complex_same_precision_as(vec), copy=True) else: vectilde = None raise IOError("Input is neither a TimeSeries nor a FrequencySeries") return vectilde
def get_chirp_time_region(trigger_params, psd, miss_match, f_lower=30., f_max=2048., f_ref=30.): central_param = copy.deepcopy(trigger_params) # if central_param['approximant'] == 'SPAtmplt': central_param['approximant'] == 'TaylorF2RedSpin' # if not ('tau0' and 'tau3' in central_param): # t0, t3 = pnu.mass1_mass2_to_tau0_tau3(central_param['mass1'], central_param['mass2'], f_ref) # else: # t0 = central_param['tau0'] # t3 = central_param['tau3'] # for tau0 boundary newt0, newt3 = temp_tau0_tau3_with_valid_dtau0(central_param['tau0'], central_param['tau3'], f_ref) temp_param0 = temp_param_from_central_param(central_param, newt0, newt3, f_ref) # for tau3 boundary newt0, newt3 = temp_tau0_tau3_with_valid_dtau3(central_param['tau0'], central_param['tau3'], f_ref) temp_param3 = temp_param_from_central_param(central_param, newt0, newt3, f_ref) tlen = pnu.nearest_larger_binary_number( max([central_param['tau0'], temp_param0['tau0'], temp_param3['tau0']])) df = 1.0 / tlen flen = int(f_max / df) + 1 # hp = pt.zeros(flen, dtype=pt.complex64) # hp0 = pt.zeros(flen, dtype=pt.complex64) # hp3 = pt.zeros(flen, dtype=pt.complex64) # print central_param['approximant'] # if central_param['approximant'] == 'SPAtmplt': # central_param['approximant'] == 'TaylorF2RedSpin' # hp = pw.get_waveform_filter(hp, central_param, delta_f=df, f_lower=f_lower, f_ref=f_ref, f_final=f_max) # hp0 = pw.get_waveform_filter(hp0, temp_param0, delta_f=df, f_lower=f_lower, f_ref=f_ref, f_final=f_max) # hp3 = pw.get_waveform_filter(hp3, temp_param3, delta_f=df, f_lower=f_lower, f_ref=f_ref, f_final=f_max) # else: hp, hc = pw.get_fd_waveform(central_param, delta_f=df, f_lower=f_lower, f_ref=f_ref, f_final=f_max) hp0, hc0 = pw.get_fd_waveform(temp_param0, delta_f=df, f_lower=f_lower, f_ref=f_ref, f_final=f_max) hp3, hc3 = pw.get_fd_waveform(temp_param3, delta_f=df, f_lower=f_lower, f_ref=f_ref, f_final=f_max) # FIXME: currently will using aLIGOZeroDetHighPower # FIXME: add how to make sure, psd numerical problems of psd if psd is not None: ipsd = pp.interpolate(psd, df) else: ipsd = None # ipsd = pp.aLIGOZeroDetHighPower(flen, df, f_lower) # ipsd = pp.interpolate(ipsd, df) # ipsd.data[-1] = 2.0*ipsd.data[-2] # ipsd = ipsd.astype(hp.dtype) mat0, _ = pf.match(hp, hp0, ipsd, f_lower, f_max) mat3, _ = pf.match(hp, hp3, ipsd, f_lower, f_max) # print mat0, mat3, miss_match # print central_param['tau0'], central_param['tau3'] # print temp_param0['tau0'], temp_param0['tau3'] # print temp_param3['tau0'], temp_param3['tau3'] # print float(temp_param0['tau0'])-float(central_param['tau0']) # print temp_param3['tau3']-central_param['tau3'] dtau0_range = miss_match * (temp_param0['tau0'] - central_param['tau0']) / (1.0 - mat0) dtau3_range = miss_match * (temp_param3['tau3'] - central_param['tau3']) / (1.0 - mat3) # print dtau0_range, dtau3_range return dtau0_range, dtau3_range
def get_fd_waveform_from_td(**params): """ Return time domain version of fourier domain approximant. This returns a frequency domain version of a fourier domain approximant, with padding and tapering at the start of the waveform. Parameters ---------- params: dict The parameters defining the waveform to generator. See `get_td_waveform`. Returns ------- hp: pycbc.types.FrequencySeries Plus polarization time series hc: pycbc.types.FrequencySeries Cross polarization time series """ # determine the duration to use full_duration = duration = get_waveform_filter_length_in_time(**params) nparams = params.copy() while full_duration < duration * 1.5: full_duration = get_waveform_filter_length_in_time(**nparams) nparams['f_lower'] -= 1 if 'f_fref' not in nparams: nparams['f_ref'] = params['f_lower'] # We'll try to do the right thing and figure out what the frequency # end is. Otherwise, we'll just assume 2048 Hz. # (consider removing as we hopefully have better estimates for more # approximants try: f_end = get_waveform_end_frequency(**params) delta_t = (0.5 / pnutils.nearest_larger_binary_number(f_end)) except: delta_t = 1.0 / 2048 nparams['delta_t'] = delta_t hp, hc = get_td_waveform(**nparams) # Resize to the right duration tsamples = int(1.0 / params['delta_f'] / delta_t) if tsamples < len(hp): raise ValueError("The frequency spacing (df = {}) is too low to " "generate the {} approximant from the time " "domain".format(params['delta_f'], params['approximant'])) hp.resize(tsamples) hc.resize(tsamples) # apply the tapering, we will use a safety factor here to allow for # somewhat innacurate duration difference estimation. window = (full_duration - duration) * 0.8 hp = wfutils.td_taper(hp, hp.start_time, hp.start_time + window) hc = wfutils.td_taper(hc, hc.start_time, hc.start_time + window) # avoid wraparound hp = hp.to_frequencyseries().cyclic_time_shift(hp.start_time) hc = hc.to_frequencyseries().cyclic_time_shift(hc.start_time) return hp, hc
def __getitem__(self, index): approximant = self.approximant(index) f_end = self.end_frequency(index) # Determine the length of time of the filter, rounded up to # nearest power of two min_buffer = 1.0 + self.minimum_buffer from pycbc.waveform.waveform import props buff_size = pycbc.waveform.get_waveform_filter_length_in_time( approximant, f_lower=self.f_lower, **props(self.table[index])) tlen = nearest_larger_binary_number( (buff_size + min_buffer) * self.sample_rate) flen = tlen / 2 + 1 delta_f = self.sample_rate / float(tlen) if f_end is None or f_end >= (flen * delta_f): f_end = (flen - 1) * delta_f logging.info("Generating %s, %ss, %i" % (approximant, 1.0 / delta_f, index)) # Get the waveform filter distance = 1.0 / DYN_RANGE_FAC htilde = pycbc.waveform.get_waveform_filter( zeros(flen, dtype=numpy.complex64), self.table[index], approximant=approximant, f_lower=self.f_lower, f_final=f_end, delta_f=delta_f, delta_t=1.0 / self.sample_rate, distance=distance, **self.extra_args) # If available, record the total duration (which may # include ringdown) and the duration up to merger since they will be # erased by the type conversion below. # NOTE: If these durations are not available the values in self.table # will continue to take the values in the input file. if hasattr(htilde, 'length_in_time'): if htilde.length_in_time is not None: self.table[index].ttotal = htilde.length_in_time if hasattr(htilde, 'chirp_length'): if htilde.chirp_length is not None: self.table[index].template_duration = htilde.chirp_length htilde = htilde.astype(numpy.complex64) htilde.f_lower = self.f_lower htilde.end_frequency = f_end htilde.end_idx = int(htilde.end_frequency / htilde.delta_f) htilde.params = self.table[index] htilde.approximant = approximant htilde.chirp_length = htilde.params.template_duration htilde.length_in_time = htilde.params.ttotal # Add sigmasq as a method of this instance htilde.sigmasq = types.MethodType(sigma_cached, htilde) htilde._sigmasq = {} return htilde