def test_varying_orbital_phase(self): #"""Check that the waveform is consistent under phase changes #""" if self.p.approximant in td_approximants(): sample_attr = 'sample_times' else: sample_attr = 'sample_frequencies' f = pylab.figure() pylab.axes([.1, .2, 0.8, 0.70]) hp_ref, hc_ref = get_waveform(self.p, coa_phase=0) pylab.plot(getattr(hp_ref, sample_attr), hp_ref.real(), label="phiref") hp, hc = get_waveform(self.p, coa_phase=lal.PI / 4) m, i = match(hp_ref, hp) self.assertAlmostEqual(1, m, places=2) o = overlap(hp_ref, hp) pylab.plot(getattr(hp, sample_attr), hp.real(), label="$phiref \pi/4$") hp, hc = get_waveform(self.p, coa_phase=lal.PI / 2) m, i = match(hp_ref, hp) o = overlap(hp_ref, hp) self.assertAlmostEqual(1, m, places=7) self.assertAlmostEqual(-1, o, places=7) pylab.plot(getattr(hp, sample_attr), hp.real(), label="$phiref \pi/2$") hp, hc = get_waveform(self.p, coa_phase=lal.PI) m, i = match(hp_ref, hp) o = overlap(hp_ref, hp) self.assertAlmostEqual(1, m, places=7) self.assertAlmostEqual(1, o, places=7) pylab.plot(getattr(hp, sample_attr), hp.real(), label="$phiref \pi$") pylab.xlim(min(getattr(hp, sample_attr)), max(getattr(hp, sample_attr))) pylab.title("Vary %s oribital phiref, h+" % self.p.approximant) if self.p.approximant in td_approximants(): pylab.xlabel("Time to coalescence (s)") else: pylab.xlabel("GW Frequency (Hz)") pylab.ylabel("GW Strain (real part)") pylab.legend(loc="upper left") info = self.version_txt pylab.figtext(0.05, 0.05, info) if self.save_plots: pname = self.plot_dir + "/%s-vary-phase.png" % self.p.approximant pylab.savefig(pname) if self.show_plots: pylab.show() else: pylab.close(f)
def test_varying_orbital_phase(self): #"""Check that the waveform is consistent under phase changes #""" if self.p.approximant in td_approximants(): sample_attr = 'sample_times' else: sample_attr = 'sample_frequencies' f = pylab.figure() pylab.axes([.1, .2, 0.8, 0.70]) hp_ref, hc_ref = get_waveform(self.p, coa_phase=0) pylab.plot(getattr(hp_ref, sample_attr), hp_ref.real(), label="phiref") hp, hc = get_waveform(self.p, coa_phase=lal.PI/4) m, i = match(hp_ref, hp) self.assertAlmostEqual(1, m, places=2) o = overlap(hp_ref, hp) pylab.plot(getattr(hp, sample_attr), hp.real(), label="$phiref \pi/4$") hp, hc = get_waveform(self.p, coa_phase=lal.PI/2) m, i = match(hp_ref, hp) o = overlap(hp_ref, hp) self.assertAlmostEqual(1, m, places=7) self.assertAlmostEqual(-1, o, places=7) pylab.plot(getattr(hp, sample_attr), hp.real(), label="$phiref \pi/2$") hp, hc = get_waveform(self.p, coa_phase=lal.PI) m, i = match(hp_ref, hp) o = overlap(hp_ref, hp) self.assertAlmostEqual(1, m, places=7) self.assertAlmostEqual(1, o, places=7) pylab.plot(getattr(hp, sample_attr), hp.real(), label="$phiref \pi$") pylab.xlim(min(getattr(hp, sample_attr)), max(getattr(hp, sample_attr))) pylab.title("Vary %s oribital phiref, h+" % self.p.approximant) if self.p.approximant in td_approximants(): pylab.xlabel("Time to coalescence (s)") else: pylab.xlabel("GW Frequency (Hz)") pylab.ylabel("GW Strain (real part)") pylab.legend(loc="upper left") info = self.version_txt pylab.figtext(0.05, 0.05, info) if self.save_plots: pname = self.plot_dir + "/%s-vary-phase.png" % self.p.approximant pylab.savefig(pname) if self.show_plots: pylab.show() else: pylab.close(f)
def match(self): match_result = [] injtau0 = conversions.tau0_from_mass1_mass2(0.1, 0.1, f_lower=self.f_lower) for i in range(self.inj_num): print('i is %s' % i) hpinj, _ = get_fd_waveform(approximant="TaylorF2e", mass1=0.1, mass2=0.1, eccentricity=self.injecc[i], long_asc_nodes=self.injection['pol'][i], inclination=self.injection['inc'][i], delta_f=self.delta_f, f_lower=self.f_lower, f_final=self.f_upper) # scan the template bank to find the maximum match index = np.where(np.abs(injtau0 - self.bank_tau0) < 3) max_match, max_m1, max_m2 = None, None, None for k in index[0]: hpbank, __ = get_fd_waveform(approximant="TaylorF2", mass1=self.bank_m1[k], mass2=self.bank_m2[k], phase_order=6, delta_f=self.delta_f, f_lower=self.f_lower, f_final=self.f_upper) cache_match, _ = match(hpinj, hpbank, psd=self.psd, low_frequency_cutoff=self.f_lower, high_frequency_cutoff=self.f_upper) print('ecc=%f,m1=%f,m2=%f,match=%f' % (self.injecc[i], self.bank_m1[k], self.bank_m2[k], cache_match)) if max_match == None: max_match = cache_match max_m1 = self.bank_m1[k] max_m2 = self.bank_m2[k] elif cache_match > max_match: max_match = cache_match max_m1 = self.bank_m1[k] max_m2 = self.bank_m2[k] match_result.append([ 0.1, 0.1, self.injecc[i], self.injection['pol'][i], self.injection['inc'][i], max_match, max_m1, max_m2 ]) np.savetxt( 'result' + str(sys.argv[1]) + '.txt', match_result, fmt='%f', header='injm1 injm2 injecc injpol injinc maxmatch maxm1 maxm2' ) return match_result
def match(self, other, psd=None, low_frequency_cutoff=None, high_frequency_cutoff=None): """ Return the match between the two TimeSeries or FrequencySeries. Return the match between two waveforms. This is equivalent to the overlap maximized over time and phase. By default, the other vector will be resized to match self. Beware, this may remove high frequency content or the end of the vector. Parameters ---------- other : TimeSeries or FrequencySeries The input vector containing a waveform. psd : Frequency Series A power spectral density to weight the overlap. low_frequency_cutoff : {None, float}, optional The frequency to begin the match. high_frequency_cutoff : {None, float}, optional The frequency to stop the match. index: int The number of samples to shift to get the match. Returns ------- match: float index: int The number of samples to shift to get the match. """ from pycbc.types import TimeSeries from pycbc.filter import match if isinstance(other, TimeSeries): if other.duration != self.duration: other = other.copy() other.resize(int(other.sample_rate * self.duration)) other = other.to_frequencyseries() if len(other) != len(self): other = other.copy() other.resize(len(self)) if psd is not None and len(psd) > len(self): psd = psd.copy() psd.resize(len(self)) return match(self, other, psd=psd, low_frequency_cutoff=low_frequency_cutoff, high_frequency_cutoff=high_frequency_cutoff)
def match(self, other, psd=None, low_frequency_cutoff=None, high_frequency_cutoff=None): """ Return the match between the two TimeSeries or FrequencySeries. Return the match between two waveforms. This is equivelant to the overlap maximized over time and phase. By default, the other vector will be resized to match self. Beware, this may remove high frequency content or the end of the vector. Parameters ---------- other : TimeSeries or FrequencySeries The input vector containing a waveform. psd : Frequency Series A power spectral density to weight the overlap. low_frequency_cutoff : {None, float}, optional The frequency to begin the match. high_frequency_cutoff : {None, float}, optional The frequency to stop the match. index: int The number of samples to shift to get the match. Returns ------- match: float index: int The number of samples to shift to get the match. """ from pycbc.types import TimeSeries from pycbc.filter import match if isinstance(other, TimeSeries): if other.duration != self.duration: other = other.copy() other.resize(int(other.sample_rate * self.duration)) other = other.to_frequencyseries() if len(other) != len(self): other = other.copy() other.resize(len(self)) if psd is not None and len(psd) > len(self): psd = psd.copy() psd.resize(len(self)) return match(self, other, psd=psd, low_frequency_cutoff=low_frequency_cutoff, high_frequency_cutoff=high_frequency_cutoff)
def overlap_between_waveforms(wav1, wav2, psd=None, f_lower=15.): # Return overlap between two TimeSEries with psd needed as a FrequencySeries #{{{ try: if psd == None: psd = self.psd except: raise IOError("Please compute and store PSD") # len1, len2, lenp = len(wav1), len(wav2), len(psd) if len1 != len2: raise IOError("Length of waveforms not equal: %d,%d" % (len1, len2)) if wav1.delta_t != wav2.delta_t: raise IOError("Mismatched wave sample rate") if len1 != 2 * lenp - 2: raise IOError("PSD length inconsistent with waveforms") # return match(wav1, wav2, psd=psd, low_frequency_cutoff=f_lower)[0]
def random_match( sample_rate=4096 * 8, time_length=256, \ mNS=1.35, Qmin=2, Qmax=5, smin=-0.5, smax=+0.75, tLambda=500.,\ f_lower=15., psd=None, outfile='match.dat'): #{{{ N = sample_rate * time_length delta_f = 1./time_length # Choose only ONE mass parameter. Fix NS mass = 1.35Msun rnd = np.random.random() q = rnd*(Qmax - Qmin) + Qmin mBH = q * mNS M = mNS + mBH et = mNS * mBH / M**2 rnd = np.random.random() s1 = rnd * (smax - smin) + smin # hp, hc = tw.getWaveform(M, et, s1, tLambda, f_lower=f_lower) tmp_hp = FrequencySeries( np.zeros(N/2+1), delta_f=delta_f, epoch=hp._epoch,\ dtype=hp.dtype ) tmp_hc = FrequencySeries( np.zeros(N/2+1), delta_f=delta_f, epoch=hp._epoch,\ dtype=hp.dtype ) tmp_hp[:len(hp)] = hp tmp_hc[:len(hc)] = hc hp, hc = tmp_hp, tmp_hc # hppp, hcpp = tw.getWaveform(M, et, s1, tLambda, tidal=False, f_lower=f_lower) tmp_hp = FrequencySeries( np.zeros(N/2+1), delta_f=delta_f, epoch=hp._epoch,\ dtype=hp.dtype ) tmp_hc = FrequencySeries( np.zeros(N/2+1), delta_f=delta_f, epoch=hp._epoch,\ dtype=hp.dtype ) tmp_hp[:len(hppp)] = hppp tmp_hc[:len(hcpp)] = hcpp hppp, hcpp = tmp_hp, tmp_hc # mm, _ = match(hp, hppp, psd=psd, low_frequency_cutoff=f_lower) # out = open(outfile,'a') out.write('%.12e\t%.12e\t%.12e\t%.12e\t%.12e\t%.12e\n' %\ (mBH, mNS, M, et, s1, mm)) out.flush() out.close()
def overlap_between_waveforms(wav1, wav2, psd=None, f_lower=15.): ''' Return overlap between two waveforms: TODO: Add resampling, padding capability. ''' # {{{ try: if psd is None: psd = self.psd except BaseException: raise IOError("Please compute and store PSD") # len1, len2, lenp = len(wav1), len(wav2), len(psd) if len1 != len2: raise IOError("Length of waveforms not equal: %d,%d" % (len1, len2)) if wav1.delta_t != wav2.delta_t: raise IOError("Mismatched wave sample rate") if len1 != 2 * lenp - 2: raise IOError("PSD length inconsistent with waveforms") # return match(wav1, wav2, psd=psd, low_frequency_cutoff=f_lower)[0]
def test_metric_match_prediction(self): mass1a, mass2a, spin1za, spin2za = \ pycbc.tmpltbank.get_random_mass(10, self.massRangeParams) mass1b, mass2b, spin1zb, spin2zb = \ pycbc.tmpltbank.get_random_mass(10, self.massRangeParams) for idx in range(10): masses1 = [mass1a[idx], mass2a[idx], spin1za[idx], spin2za[idx]] masses2 = [mass1b[idx], mass2b[idx], spin1zb[idx], spin2zb[idx]] dist, _, _ = pycbc.tmpltbank.get_point_distance \ (masses1, masses2, self.metricParams, self.f_upper) opt_dist = 0.02 while dist > opt_dist * 1.01 or dist < opt_dist * 0.99: dist_fac = opt_dist / dist dist_fac = dist_fac**0.5 if dist_fac < 0.01: dist_fac = 0.01 if dist_fac > 2: dist_fac = 2 for idx, curr_mass2 in enumerate(masses2): masses2[idx] = masses1[idx] + \ (curr_mass2 - masses1[idx]) * dist_fac dist, _, _ = pycbc.tmpltbank.get_point_distance \ (masses1, masses2, self.metricParams, self.f_upper) self.assertFalse(numpy.isnan(dist)) htilde1, _ = get_fd_waveform\ (approximant='TaylorF2', mass1=masses1[0], mass2=masses1[1], spin1z=masses1[2], spin2z=masses1[3], delta_f=1.0/256, f_lower=15, f_final=2000) htilde2, _ = get_fd_waveform\ (approximant='TaylorF2', mass1=masses2[0], mass2=masses2[1], spin1z=masses2[2], spin2z=masses2[3], delta_f=1.0/256, f_lower=15, f_final=2000) overlap, _ = match(htilde1, htilde2, psd=self.psd_for_match, low_frequency_cutoff=15) self.assertTrue(overlap > 0.97 and overlap < 0.985)
def reject_new_sample_point(new_point, points_table, MM, psd, f_min, dt, N, in_mchirp_window): """This function takes in a new proposed point, and computes its overlaps with all points in the points_table. If the max of these overlaps is > MM, it returns True, else returns False. Which implies that if the new proposed point should be rejected from the set, it returns True, and False if that point should be kept.""" matches = [] hn = get_waveform(new_point, f_min, dt, N) if in_mchirp_window: mchirp_window = in_mchirp_window else: mchirp_window = 1.0 for point in points_table: if within_mchirp_window(new_point, point, mchirp_window): #print "\tComputing overlaps with point number %d" % point.bandpass #sys.stdout.flush() hpt = get_waveform(point, f_min, dt, N) m, idx = match(hn, hpt, psd=psd, low_frequency_cutoff=f_min) matches.append(m) else: matches.append(0) if max(matches) > MM: return True else: return False
hp, hc = get_td_waveform(approximant="EOBNRv2", mass1=10, mass2=10, f_lower=f_low, delta_t=1.0 / 4096) print("waveform is %s seconds long" % hp.duration) print("Generating waveform 2") sp, sc = get_td_waveform(approximant="TaylorT4", mass1=10, mass2=10, f_lower=f_low, delta_t=1.0 / 4096) print("waveform is %s seconds long" % sp.duration) # Ensure that the waveforms are resized to the same length sp.resize(tlen) hp.resize(tlen) print("Calculating analytic PSD") psd = aLIGOZeroDetHighPower(flen, delta_f, f_low) print("Calculating match and overlap") # Note: This takes a while the first time as an FFT plan is generated # subsequent calls within the same program will be faster m, i = match(hp, sp, psd=psd, low_frequency_cutoff=f_low) o = overlap(hp, sp, psd=psd, low_frequency_cutoff=f_low) print("Overlap %s" % o) print("Maximized Overlap %s" % m)
index = 0 # Calculate the overlaps for template_params in template_table: index += 1 update_progress(index*100/len(template_table)) htilde1 = get_waveform(options.template_approximant, options.template_order, template_params, options.template_start_frequency, options.filter_sample_rate, filter_N) htilde2 = get_waveform(options.signal_approximant, options.signal_order, template_params, options.signal_start_frequency, options.filter_sample_rate, filter_N) o,i = match(htilde1, htilde2, psd=psd, low_frequency_cutoff=options.filter_low_frequency_cutoff) print o, i matches.append(o) #Find the maximum overlap in the bank and output to a file for m in matches: match_str= "%5.5f \n" % (m) fout.write(match_str)
# Check if we need to look at this template if options.mchirp_window and outside_mchirp_window(template_params, signal_params, options.mchirp_window): matches.append(-1) continue # Generate htilde if we haven't already done so if htilde is None: htilde = get_waveform(options.template_approximant, options.template_phase_order, options.template_amplitude_order, template_params, options.template_start_frequency, options.filter_sample_rate, filter_N) h_norm = sigmasq(htilde, psd=psd, low_frequency_cutoff=options.filter_low_frequency_cutoff) o,i = match(htilde, stilde, h_norm=h_norm, s_norm=s_norm, low_frequency_cutoff=options.filter_low_frequency_cutoff) matches.append(o) #Find the maximum overlap in the bank and output to a file for stilde, s_norm, matches, sim_template in signals: match_str= "%5.5f \n" % (max(matches)) match_str2=" "+options.bank_file+" "+str(matches.index(max(matches)))+"\n" fout.write(match_str) fout2.write(match_str2)
def log_likelihood_enigma(mass1, mass2, omega_attach, PNO, f_lower, sample_rate, psd, dilation_map_match=False): ''' This function takes in all parameters, including: - masses - omega_attach - PN order and computes the inner product between the sampled ENIGMA waveform and an equivalent EOB waveform m = <h_1|h_2>. Finally returns L = exp(-0.5 x m x m) ''' # extract MCMC parameters PNO = int(np.round(PNO)) omega_attach = float(omega_attach) # Use BASH MAGIC TO PASS MCMC parameters TO ENIGMA os.environ['OMEGA_ATTACH'] = '{0:.12f}'.format(omega_attach) os.environ['PN_ORDER'] = '{0:d}'.format(PNO) dt = 1. / sample_rate df = psd.delta_f N = int(sample_rate / psd.delta_f) # Generate ENIGMA wave try: h1p, h1c = get_td_waveform(approximant='ENIGMA', mass1=mass1, mass2=mass2, f_lower=f_lower, delta_t=dt) except Exception as e: logging.error(traceback.format_exc()) logging.warn( "Could not generate ENIGMA wave..m1={},m2={},omg={},PNO={}".format( mass1, mass2, omega_attach, PNO)) logging.error("\n") return -np.inf h1p = make_padded_frequency_series(h1p, N, df) #h1c = make_padded_frequency_series(h1c, N, df) # Generate EOB wave try: h2p, h2c = get_fd_waveform(approximant='SEOBNRv4_ROM', mass1=mass1, mass2=mass2, f_lower=f_lower, delta_f=df) except: logging.info("Could not generate EOB wave..") return -np.inf h2p = make_padded_frequency_series(h2p, N, df) #h2c = make_padded_frequency_series(h2c, N, df) # Undo BASH MAGIC TO PASS MCMC parameters TO ENIGMA os.environ['OMEGA_ATTACH'] = '' os.environ['PN_ORDER'] = '' # Compute inner prodcut log_like, _ = match(h1p, h2p, psd=psd, low_frequency_cutoff=f_lower) if dilation_map_match: def obj1(m): return np.log(m) def obj2(m, exp=30): return np.sin(m * np.pi / 2)**exp def match_map_for_likelihood(m, exp=30): return obj1(m) + obj2(m, exp=30) return match_map_for_likelihood(log_like) return -(1. - log_like)
def template_segment_checker(self, bank, t_num, segment, start_time): """Test if injections in segment are worth filtering with template. Using the current template, current segment, and injections within that segment. Test if the injections and sufficiently "similar" to any of the injections to justify actually performing a matched-filter call. Ther are two parts to this test: First we check if the chirp time of the template is within a provided window of any of the injections. If not then stop here, it is not worth filtering this template, segment combination for this injection set. If this check passes we compute a match between a coarse representation of the template and a coarse representation of each of the injections. If that match is above a user-provided value for any of the injections then filtering can proceed. This is currently only available if using frequency-domain templates. Parameters ----------- FIXME Returns -------- FIXME """ if not self.enabled: # If disabled, always filter (ie. return True) return True # Get times covered by segment analyze sample_rate = 2. * (len(segment) - 1) * segment.delta_f cum_ind = segment.cumulative_index diff = segment.analyze.stop - segment.analyze.start seg_start_time = cum_ind / sample_rate + start_time seg_end_time = (cum_ind + diff) / sample_rate + start_time # And add buffer seg_start_time = seg_start_time - self.seg_buffer seg_end_time = seg_end_time + self.seg_buffer # Chirp time test if self.chirp_time_window is not None: m1 = bank.table[t_num]['mass1'] m2 = bank.table[t_num]['mass2'] tau0_temp, _ = mass1_mass2_to_tau0_tau3(m1, m2, self.f_lower) for inj in self.injection_params.table: end_time = inj.geocent_end_time + \ 1E-9 * inj.geocent_end_time_ns if not(seg_start_time <= end_time <= seg_end_time): continue tau0_inj, _ = \ mass1_mass2_to_tau0_tau3(inj.mass1, inj.mass2, self.f_lower) tau_diff = abs(tau0_temp - tau0_inj) if tau_diff <= self.chirp_time_window: break else: # Get's here if all injections are outside chirp-time window return False # Coarse match test if self.match_threshold: if self._short_template_mem is None: # Set the memory for the short templates wav_len = 1 + int(self.coarsematch_fmax / self.coarsematch_deltaf) self._short_template_mem = zeros(wav_len, dtype=np.complex64) # Set the current short PSD to red_psd try: red_psd = self._short_psd_storage[id(segment.psd)] except KeyError: # PSD doesn't exist yet, so make it! curr_psd = segment.psd.numpy() step_size = int(self.coarsematch_deltaf / segment.psd.delta_f) max_idx = int(self.coarsematch_fmax / segment.psd.delta_f) + 1 red_psd_data = curr_psd[:max_idx:step_size] red_psd = FrequencySeries(red_psd_data, #copy=False, delta_f=self.coarsematch_deltaf) self._short_psd_storage[id(curr_psd)] = red_psd # Set htilde to be the current short template if not t_num == self._short_template_id: # Set the memory for the short templates if unset if self._short_template_mem is None: wav_len = 1 + int(self.coarsematch_fmax / self.coarsematch_deltaf) self._short_template_mem = zeros(wav_len, dtype=np.complex64) # Generate short waveform htilde = bank.generate_with_delta_f_and_max_freq( t_num, self.coarsematch_fmax, self.coarsematch_deltaf, low_frequency_cutoff=bank.table[t_num].f_lower, cached_mem=self._short_template_mem) self._short_template_id = t_num self._short_template_wav = htilde else: htilde = self._short_template_wav for inj in self.injection_params.table: end_time = inj.geocent_end_time + \ 1E-9 * inj.geocent_end_time_ns if not(seg_start_time < end_time < seg_end_time): continue curr_inj = self.short_injections[inj.simulation_id] o, _ = match(htilde, curr_inj, psd=red_psd, low_frequency_cutoff=self.f_lower) if o > self.match_threshold: break else: # Get's here if all injections are outside match threshold return False return True
def match_inc(par1, par2): # Allow masses to vary as parameters m1_1 = par1 m2_1 = mass2 m1_2 = mass1 m2_2 = par2 # Convert to precessing coords inc_1, s1x, s1y, s1z, s2x, s2y, s2z = SimInspiralTransformPrecessingNewInitialConditions( 0, #theta_JN phi_JL, #phi_JL theta_z1, #theta1 theta_z2, #theta2 phi12, #phi12 abs(spin_z1), #chi1 abs(spin_z2), #chi2 m1_1, m2_1, f_low, phiRef=0) inc_2, s1x_2, s1y_2, s1z_2, s2x_2, s2y_2, s2z_2 = SimInspiralTransformPrecessingNewInitialConditions( 0, #theta_JN phi_JL, #phi_JL theta_z1, #theta1 theta_z2, #theta2 phi12, #phi12 abs(spin_z1), #chi1 spin_z2, #chi2 m1_2, m2_2, f_low, phiRef=0) # Generate the two waveforms to compare hp, hc = get_td_waveform(approximant=approx1, mass1=m1_1, mass2=m2_1, spin1y=s1y, spin1x=s1x, spin1z=s1z, spin2y=s2y, spin2x=s2x, spin2z=s2z, f_lower=f_low, inclination=inc_1, delta_t=1.0 / sample_rate) sp, sc = get_td_waveform(approximant=approx2, mass1=m1_2, mass2=m2_2, spin1y=s1y_2, spin1x=s1x_2, spin1z=s1z_2, spin2y=s2y_2, spin2x=s2x_2, spin2z=s2z_2, f_lower=f_low, inclination=inc_2, delta_t=1.0 / sample_rate) # Resize the waveforms to the same length tlen = max(len(sp), len(hp)) sp.resize(tlen) hp.resize(tlen) # Generate the aLIGO ZDHP PSD delta_f = 1.0 / sp.duration flen = tlen / 2 + 1 psd = aLIGOZeroDetHighPower(flen, delta_f, f_low) # Note: This takes a while the first time as an FFT plan is generated # subsequent calls are much faster. m, i = match(hp, sp, psd=psd, low_frequency_cutoff=f_low) #print 'The match is: %1.3f' % m return m
continue # Generate htilde if we haven't already done so if htilde is None: htilde = get_waveform(options.template_approximant, options.template_phase_order, options.template_amplitude_order, template_params, options.template_start_frequency, options.filter_sample_rate, filter_N) h_norm = sigmasq( htilde, psd=psd, low_frequency_cutoff=options.filter_low_frequency_cutoff) o, i = match( htilde, stilde, h_norm=h_norm, s_norm=s_norm, low_frequency_cutoff=options.filter_low_frequency_cutoff) matches.append(o) #Find the maximum overlap in the bank and output to a file for stilde, s_norm, matches, sim_template in signals: match_str = "%5.5f \n" % (max(matches)) match_str2 = " " + options.bank_file + " " + str( matches.index(max(matches))) + "\n" fout.write(match_str) fout2.write(match_str2)
htilde = None print "\tsub-bank with point %d" % j #sys.stdout.flush() k = 0 for stilde, subbank_point in subbank_sims: # Check if options.mchirp_window and outside_mchirp_window( prop_point, subbank_point, options.mchirp_window): prop_matches.append(0) k += 1 continue if htilde is None: htilde = get_waveform(prop_point, f_min, dt, N) #print "\tcomputing overlap of proposal %d with subbank point %d" % (j,k) m, i = match(stilde, htilde, psd=psd, low_frequency_cutoff=f_min) prop_matches.append(m) k += 1 j += 1 idx += 1 print "Opening results file %s" % options.match_file_name if options.match_file_name: outfile = open(options.match_file_name, "w") else: print "No Match file-name given to write the output in !" raise ValueError("No Match file-name given to write the output for %s" % PROGRAM_NAME) sys.stdout.flush()
m_chirp = np.zeros(1000) for i in M1: p['mass1'] = i q['mass1'] = i pp, pc = pycbc.waveform.waveform.get_td_waveform(**p) qp, qc = pycbc.waveform.waveform.get_td_waveform(**q) # Resize the waveforms to the same length pp.resize(tlen) qp.resize(tlen) # Matching mp, ip = match(hp, pp, psd=psd, low_frequency_cutoff=f_low) mq, iq = match(hp, qp, psd=psd, low_frequency_cutoff=f_low) # Assigning the matches to an array pmatch[j] = mp qmatch[j] = mq # Increasing counting parameter j += 1 m_chirp[j - 1] = ((i * 30.0)**(3.0 / 5.0)) / ((i + 30.0)**(1.0 / 5.0)) # Plotting the points where the curves intersect idx = np.argwhere(np.diff(np.sign(pmatch - qmatch)) != 0).reshape(-1) + 0 # Getting rid of unwanted intersection points
def calculate_faithfulness(m1, m2, s1x=0, s1y=0, s1z=0, s2x=0, s2y=0, s2z=0, tc=0, phic=0, ra=0, dec=0, polarization=0, signal_approx='IMRPhenomD', signal_file=None, tmplt_approx='IMRPhenomC', tmplt_file=None, aligned_spin_tmplt_only=True, non_spin_tmplt_only=False, f_lower=15.0, sample_rate=4096, signal_duration=256, psd_string='aLIGOZeroDetHighPower', verbose=True, debug=False): """ Calculates the match for a signal of given physical parameters, as modelled by a given signal approximant, against templates of another approximant. This function allows turning off x,y components of spin for templates. IN PROGRESS: Adding facility to use "FromDataFile" waveforms """ # {{{ # 0) OPTION CHECKING if aligned_spin_tmplt_only: print( "WARNING: Spin components parallel to L allowed, others set to 0 in templates.") # 1) GENERATE FILTERING META-PARAMETERS filter_N = signal_duration * sample_rate filter_n = filter_N / 2 + 1 delta_t = 1./sample_rate delta_f = 1./signal_duration # LIGO Noise PSD psd = from_string(psd_string, filter_n, delta_f, f_lower) # 2) GENERATE THE TARGET SIGNAL # Get the signal waveform first if signal_approx in pywf.fd_approximants(): generator = pywfg.FDomainDetFrameGenerator(pywfg.FDomainCBCGenerator, 0, variable_args=['mass1', 'mass2', 'spin1x', 'spin1y', 'spin1z', 'spin2x', 'spin2y', 'spin2z', 'coa_phase', 'tc', 'ra', 'dec', 'polarization'], detectors=['H1'], delta_f=delta_f, f_lower=f_lower, approximant=signal_approx) elif signal_approx in pywf.td_approximants(): generator = pywfg.TDomainDetFrameGenerator(pywfg.TDomainCBCGenerator, 0, variable_args=['mass1', 'mass2', 'spin1x', 'spin1y', 'spin1z', 'spin2x', 'spin2y', 'spin2z', 'coa_phase', 'tc', 'ra', 'dec', 'polarization'], detectors=['H1'], delta_t=delta_t, f_lower=f_lower, approximant=signal_approx) elif 'FromDataFile' in signal_approx: if os.path.getsize(signal_file) == 0: raise RuntimeError( " ERROR:...OOPS. Waveform file %s empty!!" % signal_file) try: _ = np.loadtxt(signal_file) except: raise RuntimeError( " WARNING: FAILURE READING DATA FROM %s.." % signal_file) waveform_params = lsctables.SimInspiral() waveform_params.latitude = 0 waveform_params.longitude = 0 waveform_params.polarization = 0 waveform_params.spin1x = 0 waveform_params.spin1y = 0 waveform_params.spin1z = 0 waveform_params.spin2x = 0 waveform_params.spin2y = 0 waveform_params.spin2z = 0 # try: if True: if verbose: print(".. generating signal waveform ") signal_htilde, _params = get_waveform(signal_approx, -1, -1, -1, waveform_params, f_lower, sample_rate, filter_N, datafile=signal_file) print(".. generated signal waveform ") m1, m2, w_value, _ = _params waveform_params.mass1 = m1 waveform_params.mass2 = m2 signal_h = make_frequency_series(signal_htilde) signal_h = extend_waveform_FrequencySeries(signal_h, filter_n) # except: raise IOError("Approximant %s not found.." % signal_approx) else: raise IOError("Signal Approximant %s not found.." % signal_approx) if verbose: print("..Generating signal with masses = %3f, %.3f, spin1 = (%.3f, %.3f, %.3f), and spin2 = (%.3f, %.3f, %.3f)" % (m1, m2, s1x, s1y, s1z, s2x, s2y, s2z)) sys.stdout.flush() if signal_approx in pywf.fd_approximants(): signal = generator.generate_from_args(m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, phic, tc, ra, dec, polarization) # NOTE: SEOBNRv4 has extra high frequency content, it seems.. if 'SEOBNRv4_ROM' in signal_approx or 'SEOBNRv2_ROM' in signal_approx: signal_h = extend_waveform_FrequencySeries( signal['H1'], filter_n, force_fit=True) else: signal_h = extend_waveform_FrequencySeries(signal['H1'], filter_n) elif signal_approx in pywf.td_approximants(): signal = generator.generate_from_args(m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, phic, tc, ra, dec, polarization) signal_h = make_frequency_series(signal['H1']) signal_h = extend_waveform_FrequencySeries(signal_h, filter_n) elif 'FromDataFile' in signal_approx: pass else: raise IOError("Signal Approximant %s not found.." % signal_approx) # 3) GENERATE THE TARGET TEMPLATE # Get the signal waveform first if tmplt_approx in pywf.fd_approximants(): generator = pywfg.FDomainDetFrameGenerator(pywfg.FDomainCBCGenerator, 0, variable_args=['mass1', 'mass2', 'spin1x', 'spin1y', 'spin1z', 'spin2x', 'spin2y', 'spin2z', 'coa_phase', 'tc', 'ra', 'dec', 'polarization'], detectors=['H1'], delta_f=delta_f, f_lower=f_lower, approximant=tmplt_approx) elif tmplt_approx in pywf.td_approximants(): generator = pywfg.TDomainDetFrameGenerator(pywfg.TDomainCBCGenerator, 0, variable_args=['mass1', 'mass2', 'spin1x', 'spin1y', 'spin1z', 'spin2x', 'spin2y', 'spin2z', 'coa_phase', 'tc', 'ra', 'dec', 'polarization'], detectors=['H1'], delta_t=delta_t, f_lower=f_lower, approximant=tmplt_approx) elif 'FromDataFile' in tmplt_approx: if os.path.getsize(tmplt_file) == 0: raise RuntimeError( " ERROR:...OOPS. Waveform file %s empty!!" % tmplt_file) try: _ = np.loadtxt(tmplt_file) except: raise RuntimeError( " WARNING: FAILURE READING DATA FROM %s.." % tmplt_file) waveform_params = lsctables.SimInspiral() waveform_params.latitude = 0 waveform_params.longitude = 0 waveform_params.polarization = 0 waveform_params.spin1x = 0 waveform_params.spin1y = 0 waveform_params.spin1z = 0 waveform_params.spin2x = 0 waveform_params.spin2y = 0 waveform_params.spin2z = 0 # try: if True: if verbose: print(".. generating signal waveform ") tmplt_htilde, _params = get_waveform(tmplt_approx, -1, -1, -1, waveform_params, f_lower, 1./delta_t, filter_N, datafile=tmplt_file) print(".. generated signal waveform ") m1, m2, w_value, _ = _params waveform_params.mass1 = m1 waveform_params.mass2 = m2 tmplt_h = make_frequency_series(tmplt_htilde) tmplt_h = extend_waveform_FrequencySeries(tmplt_h, filter_n) # except: raise IOError("Approximant %s not found.." % tmplt_approx) else: raise IOError("Template Approximant %s not found.." % tmplt_approx) # if aligned_spin_tmplt_only: _m1, _m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z = m1, m2, 0, 0, s1z, 0, 0, s2z elif non_spin_tmplt_only: _m1, _m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z = m1, m2, 0, 0, 0, 0, 0, 0 else: _m1, _m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z = m1, m2, s1x, s1y, s1z, s2x, s2y, s2z # # template = generator.generate_from_args(_m1, _m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z,\ # phic, tc, ra, dec, polarization) # if verbose: print( "..Generating template with masses = %3f, %.3f, spin1 = (%.3f, %.3f, %.3f), and spin2 = (%.3f, %.3f, %.3f)" % (_m1, _m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z)) sys.stdout.flush() if tmplt_approx in pywf.fd_approximants(): try: template = generator.generate_from_args(_m1, _m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z, phic, tc, ra, dec, polarization) except RuntimeError as rerr: print("""FAILED TO GENERATE %s waveform for masses = %.3f, %.3f spins = (%.3f, %.3f, %.3f), (%.3f, %.3f, %.3f) phic, tc, ra, dec, pol = (%.3f, %.3f, %.3f, %.3f, %.3f)""" % (tmplt_approx, _m1, _m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z, phic, tc, ra, dec, polarization)) raise RuntimeError(rerr) # NOTE: SEOBNRv4 has extra high frequency content, it seems.. if 'SEOBNRv4_ROM' in tmplt_approx or 'SEOBNRv2_ROM' in tmplt_approx: template_h = extend_waveform_FrequencySeries( template['H1'], filter_n, force_fit=True) else: template_h = extend_waveform_FrequencySeries( template['H1'], filter_n) elif tmplt_approx in pywf.td_approximants(): try: template = generator.generate_from_args(_m1, _m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z, phic, tc, ra, dec, polarization) except RuntimeError as rerr: print("""FAILED TO GENERATE %s waveform for masses = %.3f, %.3f spins = (%.3f, %.3f, %.3f), (%.3f, %.3f, %.3f) phic, tc, ra, dec, pol = (%.3f, %.3f, %.3f, %.3f, %.3f)""" % (tmplt_approx, _m1, _m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z, phic, tc, ra, dec, polarization)) raise RuntimeError(rerr) template_h = make_frequency_series(template['H1']) template_h = extend_waveform_FrequencySeries(template_h, filter_n) elif 'FromDataFile' in tmplt_approx: pass else: raise IOError("Template Approximant %s not found.." % tmplt_approx) # 4) COMPUTE MATCH m, idx = match(signal_h, template_h, psd=psd, low_frequency_cutoff=f_lower) if debug: print( "MATCH IS %.6f for parameters" % m, m1, m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z) sys.stderr.flush() # # 5) RETURN OPTIMIZED MATCH return m, idx
## Match bit # Resize the waveforms to the same length tlen = max(len(s), len(h), len(g), len(p)) s.resize(tlen) h.resize(tlen) g.resize(tlen) p.resize(tlen) f_low = 20 # Generate the aLIGO ZDHP PSD delta_f = 1.0 / sp.duration flen = tlen / 2 + 1 psd = aLIGOZeroDetHighPower(flen, delta_f, f_low) # ote: This takes a while the first time as an FFT plan is generated # subsequent calls are much faster. # Match the waveforms m1, i = match(h, s, psd=psd, low_frequency_cutoff=f_low) m2, i = match(g, p, psd=psd, low_frequency_cutoff=f_low) lowlim = -0.75 plt.figure(figsize=(10, 4.5)) plt.title("Phase affect on precessing and non-precessing waveforms") plt.subplot(1, 2, 1) plt.plot(hp.sample_times, h, 'r-', label="Phase=0.0") plt.plot(sp.sample_times, s, 'b-', label="Phase=1.5") plt.ylabel('Strain') plt.text(lowlim, min(min(h), min(s)), 'Match=%.2f' % m1, ha='left', va='bottom', fontsize=12)
f_low = 30 sample_rate = 4096 # Generate the two waveforms to compare hp, hc = get_td_waveform(approximant="EOBNRv2", mass1=10, mass2=10, f_lower=f_low, delta_t=1.0/sample_rate) sp, sc = get_td_waveform(approximant="TaylorT4", mass1=10, mass2=10, f_lower=f_low, delta_t=1.0/sample_rate) # Resize the waveforms to the same length tlen = max(len(sp), len(hp)) sp.resize(tlen) hp.resize(tlen) # Generate the aLIGO ZDHP PSD delta_f = 1.0 / sp.duration flen = tlen/2 + 1 psd = aLIGOZeroDetHighPower(flen, delta_f, f_low) # Note: This takes a while the first time as an FFT plan is generated # subsequent calls are much faster. m, i = match(hp, sp, psd=psd, low_frequency_cutoff=f_low) print 'The match is: %1.3f' % m
def align_waveforms_optimally(hplus1, hcross1, hplus2, hcross2, psd='aLIGOZeroDetHighPower', low_frequency_cutoff=None, high_frequency_cutoff=None, tsign=1, phsign=-1, verify=True, phase_tolerance=1e-3, overlap_tolerance=1e-3, trim_leading=False, trim_trailing=False, verbose=False): """ Align waveforms such that their inner product (noise weighted) is optimal without requiring any phase or time shift. The appropriate time and phase shifts are determined iteratively and applied to the second set of (hplus, hcross) vectors. """ ############################################################################# # First copy over data into local memory, ensure lengths of time and # frequency domain vectors are consistent, and compute the maximized overlap # # 1) Cast into time-series h_plus1 = TimeSeries(hplus1, epoch=hplus1._epoch, delta_t=hplus1.delta_t, dtype=hplus1.dtype, copy=True) h_cross1 = TimeSeries(hcross1, epoch=hplus1._epoch, delta_t=hplus1.delta_t, dtype=hplus1.dtype, copy=True) h_plus2 = TimeSeries(hplus2, epoch=hplus2._epoch, delta_t=hplus2.delta_t, dtype=hplus2.dtype, copy=True) h_cross2 = TimeSeries(hcross2, epoch=hplus2._epoch, delta_t=hplus2.delta_t, dtype=hplus2.dtype, copy=True) # # 2) Ensure both input hplus vectors are equal in length if len(hplus2) > len(hplus1): h_plus1.append_zeros(len(hplus2) - len(hplus1)) h_cross1.append_zeros(len(hplus2) - len(hplus1)) elif len(hplus2) < len(hplus1): h_plus2.append_zeros(len(hplus1) - len(hplus2)) h_cross2.append_zeros(len(hplus1) - len(hplus2)) # # 3) Set the upper frequency cutoff to Nyquist if not set by User if high_frequency_cutoff == None: high_frequency_cutoff = 1. / h_plus1.delta_t / 2. # # 4) Compute LIGO noise psd if psd == None: raise IOError("Need compatible psd [or name] as input!") elif type(psd) == str: htilde = make_frequency_series(h_plus1) psd_name = psd psd = from_string(psd_name, len(htilde), htilde.delta_f, low_frequency_cutoff) ## # 5) Calculate Overlap (maximized) before alignment m = match(h_plus1, h_plus2, psd=psd, low_frequency_cutoff=low_frequency_cutoff, high_frequency_cutoff=high_frequency_cutoff) optimal_overlap = m[0] # FIXME if verbose: print(("Overlap BEFORE ALIGNMENT:", overlap_cplx(h_plus1, h_plus2, psd=psd, low_frequency_cutoff=low_frequency_cutoff, high_frequency_cutoff=high_frequency_cutoff, normalized=True))) print(("Match BEFORE ALIGNMENT:", m)) ############################################################################# # Iterate to obtain the correct phase and time shifts, using which we # align the two waveforms such that their unmaximized and maximized overlaps # agree. # # 1) Initialize phase/time offset counters t_shift_counter = 0 ph_shift_counter = 0 # # 2) Initialize initial garbage values to enter the while loop idx = 0 ph_shift = t_shift = 1e9 olap = 0 + 0j # # 3) Iteration begins # >>>>>> while np.abs(ph_shift) > phase_tolerance or \ np.abs(t_shift) > h_plus1.delta_t or \ np.abs(np.abs(olap.real) - optimal_overlap) > overlap_tolerance: if idx == 0: hp2, hc2 = h_plus2, h_cross2 # # 1) Determine the phase and time shifts for optimal match # by comparing hplus1/hcross1 with hp2/hc2 which is phase/time shifted # in previous iteration snr, corr, snr_norm = matched_filter_core(h_plus1, hp2, psd, low_frequency_cutoff, high_frequency_cutoff, None) max_snr, max_id = snr.abs_max_loc() if max_id != 0: t_shift = snr.delta_t * (len(snr) - max_id) else: t_shift = snr.delta_t * max_id ph_shift = np.angle(snr[max_id]) # # 2) Add them to running time/phase offset counter t_shift_counter += t_shift ph_shift_counter += ph_shift # if verbose: print((" >> Iteration %d\n" % (idx + 1))) print(("max_id = %d, id_shift = %d" % (max_id, int(t_shift / snr.delta_t)))) print(("t_shift = %f,\n ph_shift = %f" % (t_shift, ph_shift))) # #### # 3) Shift the second hp/hc pair (ORIGINAL) by cumulative phase/time offset hp2, hc2 = shift_waveform_phase_time(h_plus2, h_cross2, tsign * t_shift_counter, phsign * ph_shift_counter, verbose=verbose) # ### # 4) As time shifting can change array lengths, equalize again, compute psd ## if len(h_plus1) > len(hp2): hp2.append_zeros(len(h_plus1) - len(hp2)) htilde = make_frequency_series(h_plus1) psd = from_string(psd_name, len(htilde), htilde.delta_f, low_frequency_cutoff) elif len(h_plus1) < len(hp2): h_plus1.append_zeros(len(hp2) - len(h_plus1)) htilde = make_frequency_series(h_plus1) psd = from_string(psd_name, len(htilde), htilde.delta_f, low_frequency_cutoff) # # 5) Compute UNMAXIMIZED overlap. olap = overlap_cplx(h_plus1, hp2, psd=psd, low_frequency_cutoff=low_frequency_cutoff, high_frequency_cutoff=high_frequency_cutoff, normalized=True) if verbose: print(("Overlap AFTER ALIGNMENT = ", olap)) print(("Optimal Overlap = ", optimal_overlap)) # idx += 1 if verbose: print("\n") # >>>>>> # 3) Iteration ended. ############################################################################# # Verify the alignment ### if verify: # print("Verifying time alignment...") # # 1) Determine the phase and time shifts for optimal match snr, corr, snr_norm = matched_filter_core(h_plus1, hp2, psd, low_frequency_cutoff, high_frequency_cutoff, None) max_snr, max_id = snr.abs_max_loc() if verbose: print( ("Post-Alignment Index of MAX SNR (should be 0 or 1 or %d): %d" % (len(snr) - 1, max_id))) print(("Length of whole SNR time-series: ", len(snr))) # # 2) Test if current time shift is within tolerance if max_id != 0 and max_id != 1 and \ max_id != (len(snr)-1) and max_id != (len(snr)-2): raise RuntimeError("Warning: ALIGNMENT NOT CORRECT (see above)") else: print("Alignment in time correct..") # # 3) Test if current phase shift is within tolerance print("Verifying phase alignment...") ph_shift = np.angle(snr[max_id]) if np.abs(ph_shift) > phase_tolerance: if verbose: print(("dphi, dphi+pi, dphi-pi: ", ph_shift, ph_shift + np.pi, ph_shift - np.pi)) print( ("dphi/pi, dphi*pi: ", ph_shift / np.pi, ph_shift * np.pi)) raise RuntimeError( "Warning: Phasing alignment possibly incorrect.") else: if verbose: print(("Post-Alignmend Phase shift (should be < %.2e): %.2e" % (phase_tolerance, np.abs(ph_shift)))) print(("Alignment in phasing correct.. (within tol %.2e)" % phase_tolerance)) # ############################################################################# # TRIM the output arrays and return if trim_trailing: hp2 = trim_trailing_zeros(hp2) hc2 = trim_trailing_zeros(hc2) if trim_leading: hp2 = trim_leading_zeros(hp2) hc2 = trim_leading_zeros(hc2) # return hplus1, hcross1, hp2, hc2
ifo, f_lower=gen.current_params['f_lower']) fi = ti.to_frequencyseries(delta_f=gen.current_params['delta_f']) if len(fi) < len(psd): fi.resize(len(psd)) elif len(psd) < len(fi): fi = fi[:len(psd)] fi /= asd ti = fi.to_timeseries() ax.plot(ti.sample_times.numpy() - gps_time, ti.data, 'b-', lw=2, zorder=2) m, i = match(ti, ts, psd=psd, low_frequency_cutoff=gen.current_params['f_lower']) print "Match between map and injected is %.2f" % m ax.set_xlim(xmin, xmax) ax.set_ylim(ylim) ax.text(xmin, ylim[0], 'Match=%.2f' % m, ha='left', va='bottom', fontsize=12) ax.set_ylabel('{} whitened strain'.format(ifo)) if ii == 2: ax.set_xlabel('GPS time - {} (s)'.format(gps_time)) ## Find and save SNR
def match_inc(inc, spin_1, mass2): # Allow masses to vary as parameters m1_1 = mass1 m2_1 = 15 m1_2 = mass1 m2_2 = 15 # Phases phase1 = mass2 phase2 = mass2 # Convert to precessing coords inc_1, s1x, s1y, s1z, s2x, s2y, s2z = SimInspiralTransformPrecessingNewInitialConditions( inc, #theta_JN phi_JL, #phi_JL theta_z1, #theta1 theta_z2, #theta2 phi12, #phi12 spin_1, #chi1 - this parameter varies spin_2, #chi2 m1_1, m2_1, f_low, phiRef=0) #This is our 'spin1=0' waveform that we match the precessing one with inc_2, s1x_2, s1y_2, s1z_2, s2x_2, s2y_2, s2z_2 = SimInspiralTransformPrecessingNewInitialConditions( inc, #theta_JN phi_JL, #phi_JL theta_z1, #theta1 theta_z2, #theta2 phi12, #phi12 0, #chi1 spin_2, #chi2 m1_2, m2_2, f_low, phiRef=0) # Generate the two waveforms to compare hp, hc = get_td_waveform(approximant=approx1, mass1=m1_1, mass2=m2_1, spin1y=s1y, spin1x=s1x, spin1z=s1z, spin2y=s2y, spin2x=s2x, spin2z=s2z, f_lower=f_low, inclination=inc_1, coa_phase=phase1, delta_t=1.0 / sample_rate) sp, sc = get_td_waveform(approximant=approx2, mass1=m1_2, mass2=m2_2, spin1y=s1y_2, spin1x=s1x_2, spin1z=s1z_2, spin2y=s2y_2, spin2x=s2x_2, spin2z=s2z_2, f_lower=f_low, inclination=inc_2, coa_phase=phase2, delta_t=1.0 / sample_rate) # Add polarisation mixing h = hp * np.cos(2 * psi_1) + hc * np.sin(2 * psi_1) s = sp * np.cos(2 * psi_2) + sc * np.sin(2 * psi_2) # Resize the waveforms to the same length tlen = max(len(s), len(h)) s.resize(tlen) h.resize(tlen) # Generate the aLIGO ZDHP PSD delta_f = 1.0 / s.duration flen = tlen / 2 + 1 psd = aLIGOZeroDetHighPower(flen, delta_f, f_low) # Note: This takes a while the first time as an FFT plan is generated # subsequent calls are much faster. m, i = match(h, s, psd=psd, low_frequency_cutoff=f_low) #print 'The match is: %1.3f' % m return m
def align_waveforms_suboptimally(hplus1, hcross1, hplus2, hcross2, psd='aLIGOZeroDetHighPower', low_frequency_cutoff=None, high_frequency_cutoff=None, tsign=1, phsign=1, verify=True, trim_leading=False, trim_trailing=False, verbose=False): # Cast into time-series h_plus1 = TimeSeries(hplus1, epoch=hplus1._epoch, delta_t=hplus1.delta_t, dtype=hplus1.dtype) h_cross1 = TimeSeries(hcross1, epoch=hplus1._epoch, delta_t=hplus1.delta_t, dtype=hplus1.dtype) h_plus2 = TimeSeries(hplus2, epoch=hplus2._epoch, delta_t=hplus2.delta_t, dtype=hplus2.dtype) h_cross2 = TimeSeries(hcross2, epoch=hplus2._epoch, delta_t=hplus2.delta_t, dtype=hplus2.dtype) # # Ensure both input hplus vectors are equal in length if len(hplus2) > len(hplus1): h_plus1.append_zeros(len(hplus2) - len(hplus1)) h_cross1.append_zeros(len(hplus2) - len(hplus1)) elif len(hplus2) < len(hplus1): h_plus2.append_zeros(len(hplus1) - len(hplus2)) h_cross2.append_zeros(len(hplus1) - len(hplus2)) # htilde = make_frequency_series(h_plus1) stilde = make_frequency_series(h_plus2) # if high_frequency_cutoff == None: high_frequency_cutoff = 1. / h_plus1.delta_t / 2. # if psd == None: raise IOError("Need compatible psd [or name] as input!") elif type(psd) == str: psd_name = psd psd = from_string(psd_name, len(htilde), htilde.delta_f, low_frequency_cutoff) # # Determine the phase and time shifts for optimal match snr, corr, snr_norm = matched_filter_core( htilde, stilde, # h_plus1, h_plus2, psd, low_frequency_cutoff, high_frequency_cutoff, None) max_snr, max_id = snr.abs_max_loc() if max_id != 0: t_shift = snr.delta_t * (len(snr) - max_id) else: t_shift = snr.delta_t * max_id ph_shift = np.angle(snr[max_id]) - 0.24850315030 - 0.0465881735639 # if verbose: print(("max_id = %d, id_shift = %d" % (max_id, int(t_shift / snr.delta_t)))) print(("t_shift = %f,\n ph_shift = %f" % (t_shift, ph_shift))) # # print(OVERLAPS if verbose: print(("Overlap BEFORE ALIGNMENT:", overlap_cplx(h_plus1, h_plus2, psd=psd, low_frequency_cutoff=low_frequency_cutoff, high_frequency_cutoff=high_frequency_cutoff, normalized=True))) print(("Match BEFORE ALIGNMENT:", match(h_plus1, h_plus2, psd=psd, low_frequency_cutoff=low_frequency_cutoff, high_frequency_cutoff=high_frequency_cutoff))) # Shift whichever needs to be shifted to future time. # Shifting back in time is tricky. if t_shift >= 0: hp2, hc2 = shift_waveform_phase_time(h_plus2, h_cross2, tsign * t_shift, phsign * ph_shift, verbose=verbose) else: hp2, hc2 = shift_waveform_phase_time(h_plus2, h_cross2, tsign * t_shift, phsign * ph_shift, verbose=verbose) # # Ensure both input hplus vectors are equal in length if len(h_plus1) > len(hp2): hp2.append_zeros(len(h_plus1) - len(hp2)) elif len(h_plus1) < len(hp2): h_plus1.append_zeros(len(hp2) - len(h_plus1)) if verbose: htilde = make_frequency_series(h_plus1) psd = from_string(psd_name, len(htilde), htilde.delta_f, low_frequency_cutoff) print(("Overlap AFTER ALIGNMENT:", overlap_cplx(h_plus1, hp2, psd=psd, low_frequency_cutoff=low_frequency_cutoff, high_frequency_cutoff=high_frequency_cutoff, normalized=True))) print(("Match AFTER ALIGNMENT:", match(h_plus1, hp2, psd=psd, low_frequency_cutoff=low_frequency_cutoff, high_frequency_cutoff=high_frequency_cutoff))) if verify: # print("Verifying time alignment...") # Determine the phase and time shifts for optimal match snr, corr, snr_norm = matched_filter_core( # htilde, stilde, h_plus1, hp2, psd, low_frequency_cutoff, high_frequency_cutoff, None) max_snr, max_id = snr.abs_max_loc() print(("Post-Alignment Index of MAX SNR (should be 0 or 1 or %d): %d" % (len(snr) - 1, max_id))) print(("Length of whole SNR time-series: ", len(snr))) if max_id != 0 and max_id != 1 and max_id != ( len(snr) - 1) and max_id != (len(snr) - 2): # raise RuntimeError( "Warning: ALIGNMENT NOT CORRECT (see above)" ) print("Warning: ALIGNMENT NOT CORRECT (see above)") else: print("Alignment in time correct..") # print("Verifying phase alignment...") ph_shift = np.angle(snr[max_id]) if ph_shift != 0: print("Warning: Phasing alignment possibly incorrect.") print(("dphi, dphi+pi, dphi-pi: ", ph_shift, ph_shift + np.pi, ph_shift - np.pi)) print(("dphi/pi, dphi*pi: ", ph_shift / np.pi, ph_shift * np.pi)) # # if trim_trailing: hp1 = trim_trailing_zeros(hp1) hc1 = trim_trailing_zeros(hc1) hp2 = trim_trailing_zeros(hp2) hc2 = trim_trailing_zeros(hc2) if trim_leading: hp1 = trim_leading_zeros(hp1) hc1 = trim_leading_zeros(hc1) hp2 = trim_leading_zeros(hp2) hc2 = trim_leading_zeros(hc2) # return hplus1, hcross1, hp2, hc2
def test_mismatch(self): fmin = 5 fmax = 15 # Invalid noise with self.assertRaises(TypeError): gwm.network_mismatch(self.ts1, self.ts2, 8, -70, "2015-09-14 09:50:45", noises=1) # No noise, three detectors antennas = gwu.antenna_responses_from_sky_localization( 8, -70, "2015-09-14 09:50:45") self.assertAlmostEqual( gwm.mismatch_from_strains( self.ts1, self.ts2, fmin=fmin, fmax=fmax, noises=None, antenna_patterns=list(antennas), num_polarization_shifts=30, num_time_shifts=30, time_shift_start=-70, time_shift_end=70, )[0], gwm.network_mismatch( self.ts1, self.ts2, 8, -70, "2015-09-14 09:50:45", fmin=fmin, fmax=fmax, noises=None, num_polarization_shifts=30, num_time_shifts=30, time_shift_start=-70, time_shift_end=70, )[0], ) # Only one active detector only_virgo = gwu.Detectors(hanford=-1, livingston=-1, virgo=None) self.assertAlmostEqual( gwm.mismatch_from_strains( self.ts1, self.ts2, fmin=fmin, fmax=fmax, noises=None, antenna_patterns=[antennas.virgo], num_polarization_shifts=30, num_time_shifts=30, time_shift_start=-70, time_shift_end=70, )[0], gwm.network_mismatch( self.ts1, self.ts2, 8, -70, "2015-09-14 09:50:45", fmin=fmin, fmax=fmax, noises=only_virgo, num_polarization_shifts=30, num_time_shifts=30, time_shift_start=-70, time_shift_end=70, )[0], ) # Test with a "gw-looking" singal from PyCBC # # First, we test the overlap by giving num_polarizations, # num_time_shifts=1 try: with warnings.catch_warnings(): warnings.simplefilter("ignore") from pycbc.filter import match, overlap from pycbc.types import timeseries as pycbcts from pycbc.waveform import get_td_waveform fmin_gw = 50 fmax_gw = 100 delta_t = 1 / 4096 hp1, hc1 = get_td_waveform( approximant="IMRPhenomPv2", mass1=10, mass2=10, spin1z=0.9, delta_t=delta_t, f_lower=40, ) hp2, hc2 = get_td_waveform( approximant="IMRPhenomPv2", mass1=10, mass2=25, spin1z=-0.5, delta_t=delta_t, f_lower=40, ) # PyCBC does not work well with series with different length. So, we # crop the longer one to the length of the shorter one. For the choice # of paramters, it is 2 that is shorter than 1. 1 starts earlier in the # past. However, they have the same frequencies, so we can simply crop # away the part we are not interested in. time_offset = 2 # Manually computed looking at the times hp1 = hp1.crop(time_offset, 0) hc1 = hc1.crop(time_offset, 0) # We apply the "antenna pattern" h1_pycbc = pycbcts.TimeSeries(0.33 * hp1 + 0.66 * hc1, delta_t=hp1.delta_t) h2_pycbc = pycbcts.TimeSeries(0.33 * hp2 + 0.66 * hc2, delta_t=hp2.delta_t) overlap_m = overlap( h1_pycbc, h2_pycbc, psd=None, low_frequency_cutoff=fmin_gw, high_frequency_cutoff=fmax_gw, ) h1_postcac = ts.TimeSeries(h1_pycbc.sample_times, hp1 - 1j * hc1) h2_postcac = ts.TimeSeries(h2_pycbc.sample_times, hp2 - 1j * hc2) o = gwm.mismatch_from_strains( h1_postcac, h2_postcac, fmin=fmin_gw, fmax=fmax_gw, noises=None, antenna_patterns=[(0.66, 0.33)], num_polarization_shifts=1, num_time_shifts=1, time_shift_start=0, time_shift_end=0, force_numba=False, ) self.assertAlmostEqual(1 - o[0], overlap_m, places=2) # Now we can test the mismatch pycbc_m, _ = match( h1_pycbc, h2_pycbc, psd=None, low_frequency_cutoff=fmin_gw, high_frequency_cutoff=fmax_gw, ) pycbc_m = 1 - pycbc_m mat = gwm.mismatch_from_strains( h1_postcac, h2_postcac, fmin=fmin_gw, fmax=fmax_gw, noises=None, antenna_patterns=[(0.66, 0.33)], num_polarization_shifts=100, num_time_shifts=800, time_shift_start=-0.3, time_shift_end=0.3, force_numba=False, ) self.assertAlmostEqual(mat[0], pycbc_m, places=2) except ImportError: # pragma: no cover pass
def template_segment_checker(self, bank, t_num, segment, start_time): """Test if injections in segment are worth filtering with template. Using the current template, current segment, and injections within that segment. Test if the injections and sufficiently "similar" to any of the injections to justify actually performing a matched-filter call. Ther are two parts to this test: First we check if the chirp time of the template is within a provided window of any of the injections. If not then stop here, it is not worth filtering this template, segment combination for this injection set. If this check passes we compute a match between a coarse representation of the template and a coarse representation of each of the injections. If that match is above a user-provided value for any of the injections then filtering can proceed. This is currently only available if using frequency-domain templates. Parameters ----------- FIXME Returns -------- FIXME """ if not self.enabled: # If disabled, always filter (ie. return True) return True # Get times covered by segment analyze sample_rate = 2. * (len(segment) - 1) * segment.delta_f cum_ind = segment.cumulative_index diff = segment.analyze.stop - segment.analyze.start seg_start_time = cum_ind / sample_rate + start_time seg_end_time = (cum_ind + diff) / sample_rate + start_time # And add buffer seg_start_time = seg_start_time - self.seg_buffer seg_end_time = seg_end_time + self.seg_buffer # Chirp time test if self.chirp_time_window is not None: m1 = bank.table[t_num]['mass1'] m2 = bank.table[t_num]['mass2'] tau0_temp, _ = mass1_mass2_to_tau0_tau3(m1, m2, self.f_lower) for inj in self.injection_params.table: end_time = inj.geocent_end_time + \ 1E-9 * inj.geocent_end_time_ns if not (seg_start_time <= end_time <= seg_end_time): continue tau0_inj, _ = \ mass1_mass2_to_tau0_tau3(inj.mass1, inj.mass2, self.f_lower) tau_diff = abs(tau0_temp - tau0_inj) if tau_diff <= self.chirp_time_window: break else: # Get's here if all injections are outside chirp-time window return False # Coarse match test if self.match_threshold: if self._short_template_mem is None: # Set the memory for the short templates wav_len = 1 + int( self.coarsematch_fmax / self.coarsematch_deltaf) self._short_template_mem = zeros(wav_len, dtype=np.complex64) # Set the current short PSD to red_psd try: red_psd = self._short_psd_storage[id(segment.psd)] except KeyError: # PSD doesn't exist yet, so make it! curr_psd = segment.psd.numpy() step_size = int(self.coarsematch_deltaf / segment.psd.delta_f) max_idx = int(self.coarsematch_fmax / segment.psd.delta_f) + 1 red_psd_data = curr_psd[:max_idx:step_size] red_psd = FrequencySeries( red_psd_data, #copy=False, delta_f=self.coarsematch_deltaf) self._short_psd_storage[id(curr_psd)] = red_psd # Set htilde to be the current short template if not t_num == self._short_template_id: # Set the memory for the short templates if unset if self._short_template_mem is None: wav_len = 1 + int( self.coarsematch_fmax / self.coarsematch_deltaf) self._short_template_mem = zeros(wav_len, dtype=np.complex64) # Generate short waveform htilde = bank.generate_with_delta_f_and_max_freq( t_num, self.coarsematch_fmax, self.coarsematch_deltaf, low_frequency_cutoff=bank.table[t_num].f_lower, cached_mem=self._short_template_mem) self._short_template_id = t_num self._short_template_wav = htilde else: htilde = self._short_template_wav for inj in self.injection_params.table: end_time = inj.geocent_end_time + \ 1E-9 * inj.geocent_end_time_ns if not (seg_start_time < end_time < seg_end_time): continue curr_inj = self.short_injections[inj.simulation_id] o, _ = match(htilde, curr_inj, psd=red_psd, low_frequency_cutoff=self.f_lower) if o > self.match_threshold: break else: # Get's here if all injections are outside match threshold return False return True
def objective_function_fitting_factor(x, *args): """ This function is to be minimized if the fitting factor is to be found """ objective_function_fitting_factor.counter += 1 # 1) OBTAIN THE TEMPLATE PARAMETERS FROM X. ASSUME THAT ONLY # THOSE ARE PASSED THAT ARE NEEDED BY THE GENERATOR if len(x) == 2: m1, m2 = x if vary_masses_only: _s1x = _s1y = _s1z = _s2x = _s2y = _s2z = 0 else: _s1x, _s1y, _s1z = s1x, s1y, s1z _s2x, _s2y, _s2z = s2x, s2y, s2z elif len(x) == 4: m1, m2, _s1z, _s2z = x if vary_masses_and_aligned_spin_only: _s1x = _s1y = _s2x = _s2y = 0 else: _s1x, _s1y = s1x, s1y _s2x, _s2y = s2x, s2y elif len(x) == 8: m1, m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z = x else: raise IOError( "No of vars %d not supported (should be 2 or 4 or 8)" % len(x)) # 2) CHECK FOR CONSISTENCY if (_s1x**2 + _s1y**2 + _s1z**2) > s_max or (_s2x**2 + _s2y**2 + _s2z**2) > s_max: return 1e99 # 2) ASSUME THAT signal_h, tmplt_generator = args tmplt = tmplt_generator.generate_from_args( m1, m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z) tmplt_h = make_frequency_series(tmplt['H1']) if debug: print("IN FF Objective-> for parameters:", m1, m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z) if debug: print("IN FF Objective-> Length(tmplt) = %d, making it %d" % (len(tmplt['H1']), filter_n)) # NOTE: SEOBNRv4 has extra high frequency content, it seems.. if 'SEOBNRv4_ROM' in tmplt_approx or 'SEOBNRv2_ROM' in tmplt_approx: tmplt_h = extend_waveform_FrequencySeries( tmplt_h, filter_n, force_fit=True) else: tmplt_h = extend_waveform_FrequencySeries(tmplt_h, filter_n) # 3) COMPUTE MATCH m, _ = match(signal_h, tmplt_h, psd=psd, low_frequency_cutoff=f_lower) if debug: print("MATCH IS %.6f for parameters:" % m, m1, m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z) retval = np.log10(1. - m) # We do not want PSO to go berserk, so we stop when FF = 0.999999 if retval <= -6.0: retval = -6.0 return retval
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
from pycbc.types.timeseries import TimeSeries from pycbc.types.frequencyseries import FrequencySeries from pycbc.filter import match import numpy import matplotlib.pyplot as plt data = numpy.sin(numpy.arange(0, 100, 100 / (4096.0 * 64))) # data += numpy.random.normal(scale=.01, size=data.shape) # plt.plot(data) # plt.show() filtD = TimeSeries(data, dtype=numpy.float64, delta_t=1.0 / 4096) frequency_series_filt = filtD.to_frequencyseries() dt_fraction = .5 filtD_offset_subsample = ( frequency_series_filt * numpy.exp(2j * numpy.pi * frequency_series_filt.sample_frequencies * frequency_series_filt.delta_t * dt_fraction)) o, _ = match(filtD, filtD_offset_subsample, subsample_interpolation=True) print(1 - o) # assert numpy.isclose(1, o, rtol=0, atol=1e-8)