From 92c7845ee1a54a61dd6e41fe95c72ddbe3200c7e Mon Sep 17 00:00:00 2001 From: Thomas Dent Date: Wed, 3 Jul 2019 10:02:59 -0700 Subject: [PATCH] first cut at coinc rate stat with p/t/a --- pycbc/events/coinc_rate.py | 24 +++++++-------- pycbc/events/stat.py | 62 ++++++++++++++++++++++++++++++++++---- 2 files changed, 68 insertions(+), 18 deletions(-) diff --git a/pycbc/events/coinc_rate.py b/pycbc/events/coinc_rate.py index 7edea8f83ff..eb6487e0354 100644 --- a/pycbc/events/coinc_rate.py +++ b/pycbc/events/coinc_rate.py @@ -15,7 +15,7 @@ import pycbc.detector -def multiifo_noise_coinc_lograte(log_rates, slop): +def multiifo_noise_lograte(log_rates, slop): """ Calculate the expected rate of noise coincidences for multiple combinations of detectors @@ -31,19 +31,19 @@ def multiifo_noise_coinc_lograte(log_rates, slop): Returns ------- - expected_coinc_log_rates: dict + expected_log_rates: dict Key: ifo combination string Value: expected log coincidence rate in the combination, units log Hz """ - expected_coinc_log_rates = {} + expected_coinc_logrates = {} # Order of ifos must be stable in output dict keys, so sort them ifos = sorted(list(log_rates.keys())) ifostring = ' '.join(ifos) # Calculate coincidence for all-ifo combination - expected_coinc_log_rates[ifostring] = \ - combination_noise_coinc_lograte(log_rates, slop) + expected_coinc_logrates[ifostring] = \ + combination_noise_lograte(log_rates, slop) # If more than one possible coincidence type exists, # calculate coincidence for subsets through recursion @@ -54,16 +54,16 @@ def multiifo_noise_coinc_lograte(log_rates, slop): rates_subset = {} for ifo in subset: rates_subset[ifo] = log_rates[ifo] - sub_coinc_rates = multiifo_noise_coinc_lograte(rates_subset, slop) + sub_coinc_rates = multiifo_noise_lograte(rates_subset, slop) # add these sub-coincidences to the overall dictionary for sub_coinc in sub_coinc_rates: - expected_coinc_log_rates[sub_coinc] = \ + expected_coinc_logrates[sub_coinc] = \ sub_coinc_rates[sub_coinc] - return expected_coinc_log_rates + return expected_coinc_logrates -def combination_noise_coinc_rate(rates, slop): +def combination_noise_rate(rates, slop): """ Calculate the expected rate of noise coincidences for a combination of detectors @@ -88,10 +88,10 @@ def combination_noise_coinc_rate(rates, slop): 'instead') log_rates = {k: numpy.log(r) for (k, r) in rates.items()} # exp may underflow - return numpy.exp(combination_noise_coinc_lograte(log_rates, slop)) + return numpy.exp(combination_noise_lograte(log_rates, slop)) -def combination_noise_coinc_lograte(log_rates, slop): +def combination_noise_lograte(log_rates, slop): """ Calculate the expected rate of noise coincidences for a combination of detectors given log of single detector noise rates @@ -107,7 +107,7 @@ def combination_noise_coinc_lograte(log_rates, slop): Returns ------- - combo_coinc_rate: numpy array + return value: numpy array Expected log coincidence rate in the combination, units Hz """ # multiply product of trigger rates by the overlap time diff --git a/pycbc/events/stat.py b/pycbc/events/stat.py index 7f9a50a9ae3..5aa6e0e3dfd 100644 --- a/pycbc/events/stat.py +++ b/pycbc/events/stat.py @@ -569,7 +569,7 @@ def single(self, trigs): dtype=numpy.float32), ndmin=1, copy=False) -class ExpFitSGCoincRateStatistic(ExpFitStatistic): +class ExpFitSGBgRateStatistic(ExpFitStatistic): """Detection statistic using an exponential falloff noise model. Statistic calculates the log noise coinc rate for each @@ -579,7 +579,7 @@ class ExpFitSGCoincRateStatistic(ExpFitStatistic): def __init__(self, files, benchmark_lograte=-14.6): # benchmark_lograte is log of a representative noise trigger rate # This comes from H1L1 (O2) and is 4.5e-7 Hz - super(ExpFitSGCoincRateStatistic, self).__init__(files) + super(ExpFitSGBgRateStatistic, self).__init__(files) self.benchmark_lograte = benchmark_lograte self.get_newsnr = ranking.get_newsnr_sgveto # Reassign the rate as it is now number per time rather than an @@ -599,10 +599,59 @@ def reassign_rate(self, ifo): def coinc_multiifo(self, s, slide, step, **kwargs): # pylint:disable=unused-argument - """Calculate the final coinc ranking statistic""" - ln_coinc_rate = coinc_rate.combination_noise_coinc_lograte( + # ranking statistic is -ln(expected rate density of noise triggers) + # plus normalization constant + ln_noise_rate = coinc_rate.combination_noise_lograte( s, kwargs['time_addition']) - loglr = - ln_coinc_rate + self.benchmark_lograte + loglr = - ln_noise_rate + self.benchmark_lograte + return loglr + + +class ExpFitSGFgBgRateStatistic(PhaseTDStatistic, ExpFitSGBgRateStatistic): + + def __init__(self, files): + # read in background fit info and store it, also use newsnr_sgveto + ExpFitSGBgRateStatistic.__init__(self, files) + # also use PhaseTD statistic single.dtype + PhaseTDStatistic.__init__(self, files) + + def single(self, trigs): + # single-ifo stat = log of noise rate + sngl_stat = self.lognoiserate(trigs) + # populate other fields to calculate phase/time/amp consistency + singles = numpy.zeros(len(sngl_stat), dtype=self.single_dtype) + singles['snglstat'] = sngl_stat + singles['coa_phase'] = trigs['coa_phase'][:] + singles['end_time'] = trigs['end_time'][:] + singles['sigmasq'] = trigs['sigmasq'][:] + singles['snr'] = trigs['snr'][:] + return numpy.array(singles, ndmin=1) + + def coinc_multiifo(self, s, slide, + step, **kwargs): # pylint:disable=unused-argument + sngl_rates = {ifo: sngl_data['snglstat'] for ifo, sngl_data in + s.items()} + ln_noise_rate = coinc_rate.combination_noise_lograte(sngl_rates, + kwargs['time_addition']) + yesprint = False + if len(ln_noise_rate): + yesprint = True + print(ln_noise_rate) # diagnostic for testing + # logsignalrate function inherited from PhaseTDStatistic + # - for now, only use H-L consistency + ifos = s.keys() + if 'H1' in ifos and 'L1' in ifos: + if yesprint: + print('Applying HL phase/time/amp consistency') + logr_s = self.logsignalrate(s['H1'], s['L1'], slide, step) + else: + if yesprint: + print('HV or LV coinc, no phase/time-amp/consistency') + logr_s = numpy.zeros_like(s['V1']['snr']) + + if yesprint: + print(logr_s) + loglr = logr_s - ln_noise_rate + self.benchmark_lograte return loglr @@ -622,7 +671,8 @@ def coinc_multiifo(self, s, slide, 'newsnr_sgveto': NewSNRSGStatistic, 'newsnr_sgveto_psdvar': NewSNRSGPSDStatistic, 'phasetd_exp_fit_stat_sgveto_psdvar': PhaseTDExpFitSGPSDStatistic, - 'exp_fit_sg_coinc_rate': ExpFitSGCoincRateStatistic + 'exp_fit_sg_bg_rate': ExpFitSGBgRateStatistic, + 'exp_fit_sg_fgbg_rate': ExpFitSGFgBgRateStatistic } sngl_statistic_dict = {