def _det_tc(detector_name, ra, dec, tc, ref_frame='geocentric'): """Returns the coalescence time of a signal in the given detector. Parameters ---------- detector_name : string The name of the detector, e.g., 'H1'. ra : float The right ascension of the signal, in radians. dec : float The declination of the signal, in radians. tc : float The GPS time of the coalescence of the signal in the `ref_frame`. ref_frame : {'geocentric', string} The reference frame that the given coalescence time is defined in. May specify 'geocentric', or a detector name; default is 'geocentric'. Returns ------- float : The GPS time of the coalescence in detector `detector_name`. """ if ref_frame == detector_name: return tc detector = Detector(detector_name) if ref_frame == 'geocentric': return tc + detector.time_delay_from_earth_center(ra, dec, tc) else: other = Detector(ref_frame) return tc + detector.time_delay_from_detector(other, ra, dec, tc)
def generate_signal(param_set): hp, hc = get_td_waveform( approximant= 'SEOBNRv4', #This approximant is only appropriate for BBH mergers mass1=param_set['m1'], mass2=param_set['m2'], spin1z=param_set['x1'], spin2z=param_set['x2'], inclination_range=param_set['inc'], coa_phase=param_set['coa'], distance=param_set['dist'], delta_t=1.0 / param_set['f'], f_lower=30) time = 100000000 det_h1 = Detector('H1') det_l1 = Detector('L1') det_v1 = Detector('V1') hp = fade_on(hp, 0.25) hc = fade_on(hc, 0.25) sig_h1 = det_h1.project_wave(hp, hc, param_set['ra'], param_set['dec'], param_set['pol']) sig_l1 = det_l1.project_wave(hp, hc, param_set['ra'], param_set['dec'], param_set['pol']) sig_v1 = det_v1.project_wave(hp, hc, param_set['ra'], param_set['dec'], param_set['pol']) return {'H1': sig_h1, 'L1': sig_l1, 'V1': sig_v1}
def __init__(self, num_templates, analysis_block, background_statistic, stat_files, ifos, ifar_limit=100, timeslide_interval=.035, coinc_threshold=.002, return_background=False): """ Parameters ---------- num_templates: int The size of the template bank analysis_block: int The number of seconds in each analysis segment background_statistic: str The name of the statistic to rank coincident events. stat_files: list of strs List of filenames that contain information used to construct various coincident statistics. ifos: list of strs List of ifo names that are being analyzed. At the moment this must be two items such as ['H1', 'L1']. ifar_limit: float The largest inverse false alarm rate in years that we would like to calculate. timeslide_interval: float The time in seconds between consecutive timeslide offsets. coinc_threshold: float Amount of time allowed to form a coincidence in addition to the time of flight in seconds. return_background: boolean If true, background triggers will also be included in the file output. """ from . import stat self.num_templates = num_templates self.analysis_block = analysis_block stat_class = stat.get_statistic(background_statistic) self.stat_calculator = stat_class(stat_files, ifos) self.timeslide_interval = timeslide_interval self.return_background = return_background self.ifos = ifos if len(self.ifos) != 2: raise ValueError("Only a two ifo analysis is supported at this time") self.lookback_time = (ifar_limit * lal.YRJUL_SI * timeslide_interval) ** 0.5 self.buffer_size = int(numpy.ceil(self.lookback_time / analysis_block)) det0, det1 = Detector(ifos[0]), Detector(ifos[1]) self.time_window = det0.light_travel_time_to_detector(det1) + coinc_threshold self.coincs = CoincExpireBuffer(self.buffer_size, self.ifos) self.singles = {}
def make_strain_from_inj_object(self, inj, delta_t, detector_name): """Make a h(t) strain time-series from an injection object as read from an hdf file. Parameters ----------- inj : injection object The injection object to turn into a strain h(t). delta_t : float Sample rate to make injection at. detector_name : string Name of the detector used for projecting injections. Returns -------- signal : float h(t) corresponding to the injection. """ detector = Detector(detector_name) # compute the waveform time series hp, hc = ringdown_td_approximants[inj['approximant']](delta_t=delta_t, **inj) hp._epoch += inj['tc'] hc._epoch += inj['tc'] # compute the detector response and add it to the strain signal = detector.project_wave(hp, hc, inj['ra'], inj['dec'], inj['polarization']) return signal
def __init__(self, rFrameGeneratorClass, epoch, detectors=None, variable_args=(), **frozen_params): # initialize frozen & current parameters: self.current_params = frozen_params.copy() self._static_args = frozen_params.copy() # we'll separate out frozen location parameters from the frozen # parameters that are sent to the rframe generator self.frozen_location_args = {} loc_params = set(frozen_params.keys()) & self.location_args for param in loc_params: self.frozen_location_args[param] = frozen_params.pop(param) # set the order of the variable parameters self.variable_args = tuple(variable_args) # variables that are sent to the rFrame generator rframe_variables = list(set(self.variable_args) - self.location_args) # initialize the radiation frame generator self.rframe_generator = rFrameGeneratorClass( variable_args=rframe_variables, **frozen_params) self.set_epoch(epoch) # if detectors are provided, convert to detector type; also ensure that # location variables are specified if detectors is not None: # FIXME: use the following when we switch to 2.7 #self.detectors = {det: Detector(det) for det in detectors} self.detectors = dict([(det, Detector(det)) for det in detectors]) missing_args = [arg for arg in self.location_args if not (arg in self.current_params or arg in self.variable_args)] if any(missing_args): raise ValueError("detectors provided, but missing location " "parameters %s. " %(', '.join(missing_args)) + "These must be either in the frozen params or the " "variable args.") else: self.detectors = {'RF': None} self.detector_names = sorted(self.detectors.keys())
def make_strain_from_inj_object(self, inj, delta_t, detector_name, f_lower=None, distance_scale=1): """Make a h(t) strain time-series from an injection object as read from a sim_inspiral table, for example. Parameters ----------- inj : injection object The injection object to turn into a strain h(t). delta_t : float Sample rate to make injection at. detector_name : string Name of the detector used for projecting injections. f_lower : {None, float}, optional Low-frequency cutoff for injected signals. If None, use value provided by each injection. distance_scale: {1, float}, optional Factor to scale the distance of an injection with. The default is no scaling. Returns -------- signal : float h(t) corresponding to the injection. """ detector = Detector(detector_name) if f_lower is None: f_l = inj.f_lower else: f_l = f_lower name, phase_order = legacy_approximant_name(inj.waveform) # compute the waveform time series hp, hc = get_td_waveform(inj, approximant=name, delta_t=delta_t, phase_order=phase_order, f_lower=f_l, distance=inj.distance, **self.extra_args) hp /= distance_scale hc /= distance_scale hp._epoch += inj.get_time_geocent() hc._epoch += inj.get_time_geocent() # taper the polarizations hp_tapered = wfutils.taper_timeseries(hp, inj.taper) hc_tapered = wfutils.taper_timeseries(hc, inj.taper) # compute the detector response and add it to the strain signal = detector.project_wave(hp_tapered, hc_tapered, inj.longitude, inj.latitude, inj.polarization) return signal
def _worker_init_fn(self, worker_id: int = None): self.detectors = {ifo: Detector(ifo) for ifo in self.ifos} self.data = np.load(self.data_dir / self.data_file, mmap_mode='r') # save asds as stacked numpy array for faster compute if self.psd_dir is not None: asds = [] for ifo in self.ifos: psd = load_psd_from_file(self.psd_dir / f'{ifo}_PSD.npy') asds.append(psd[:self.static_args['fd_length']]**0.5) self.asds = np.stack(asds) if self.ref_ifo is not None: # psd = load_psd_from_file(self.psd_dir / f'{self.ref_ifo}_PSD.npy') self.asds /= self.asds[self.ifos.index(self.ref_ifo)] self.asds = self.asds.astype(self.real_dtype) self.parameters = self.parameters.astype(self.real_dtype) self.mean = self.mean.astype(self.real_dtype) self.std = self.std.astype(self.real_dtype) # reduced basis encoder self.encoder.load(n=self.n, mmap_mode='r', verbose=True) for param in self.encoder.parameters(): param.requires_grad = False
def _optimal_orientation_from_detector(detector_name, tc): """ Low-level function to be called from _optimal_dec_from_detector and _optimal_ra_from_detector""" d = Detector(detector_name) ra, dec = d.optimal_orientation(tc) return ra, dec
def __init__(self, variable_params, data, low_frequency_cutoff, sample_rate=32768, polarization_samples=None, **kwargs): variable_params, kwargs = self.setup_distance_marginalization( variable_params, marginalize_phase=True, **kwargs) super(SingleTemplate, self).__init__(variable_params, data, low_frequency_cutoff, **kwargs) # Generate template waveforms df = data[self.detectors[0]].delta_f p = self.static_params.copy() if 'distance' in p: _ = p.pop('distance') if 'inclination' in p: _ = p.pop('inclination') hp, _ = get_fd_waveform(delta_f=df, distance=1, inclination=0, **p) # Extend template to high sample rate flen = int(int(sample_rate) / df) / 2 + 1 hp.resize(flen) #polarization array to marginalize over if num_samples given self.pflag = 0 if polarization_samples is not None: self.polarization = numpy.linspace(0, 2 * numpy.pi, int(polarization_samples)) self.pflag = 1 # Calculate high sample rate SNR time series self.sh = {} self.hh = {} self.det = {} for ifo in self.data: flow = self.kmin[ifo] * df fhigh = self.kmax[ifo] * df # Extend data to high sample rate self.data[ifo].resize(flen) self.det[ifo] = Detector(ifo) snr, _, _ = pyfilter.matched_filter_core( hp, self.data[ifo], psd=self.psds[ifo], low_frequency_cutoff=flow, high_frequency_cutoff=fhigh) self.sh[ifo] = 4 * df * snr self.hh[ifo] = pyfilter.sigmasq(hp, psd=self.psds[ifo], low_frequency_cutoff=flow, high_frequency_cutoff=fhigh) self.time = None
def __init__(self, data, psds, low_frequency_cutoff=None, high_frequency_cutoff=None, sample_rate=32768, **kwargs): super(SingleTemplate, self).__init__(data=data, **kwargs) if low_frequency_cutoff is not None: low_frequency_cutoff = float(low_frequency_cutoff) if high_frequency_cutoff is not None: high_frequency_cutoff = float(high_frequency_cutoff) # Generate template waveforms df = data[tuple(data.keys())[0]].delta_f p = self.static_params.copy() if 'distance' in p: p.pop('distance') if 'inclination' in p: p.pop('inclination') hp, _ = get_fd_waveform(delta_f=df, distance=1, inclination=0, **p) if high_frequency_cutoff is None: high_frequency_cutoff = len(data[tuple(data.keys())[0]] - 1) * df # Extend data and template to high sample rate flen = int(sample_rate / df) / 2 + 1 hp.resize(flen) for ifo in data: data[ifo].resize(flen) # Calculate high sample rate SNR time series self.sh = {} self.hh = {} self.det = {} for ifo in data: self.det[ifo] = Detector(ifo) snr, _, _ = pyfilter.matched_filter_core( hp, data[ifo], psd=psds[ifo], low_frequency_cutoff=low_frequency_cutoff, high_frequency_cutoff=high_frequency_cutoff) self.sh[ifo] = 4 * df * snr self.hh[ifo] = -0.5 * pyfilter.sigmasq( hp, psd=psds[ifo], low_frequency_cutoff=low_frequency_cutoff, high_frequency_cutoff=high_frequency_cutoff) self.time = None
def make_strain_from_inj_object(self, inj, delta_t, detector_name, f_lower=None, distance_scale=1): """Make a h(t) strain time-series from an injection object. Parameters ----------- inj : injection object The injection object to turn into a strain h(t). Can be any object which has waveform parameters as attributes, such as an element in a ``WaveformArray``. delta_t : float Sample rate to make injection at. detector_name : string Name of the detector used for projecting injections. f_lower : {None, float}, optional Low-frequency cutoff for injected signals. If None, use value provided by each injection. distance_scale: {1, float}, optional Factor to scale the distance of an injection with. The default is no scaling. Returns -------- signal : float h(t) corresponding to the injection. """ detector = Detector(detector_name) if f_lower is None: f_l = inj.f_lower else: f_l = f_lower # compute the waveform time series hp, hc = get_td_waveform(inj, delta_t=delta_t, f_lower=f_l, **self.extra_args) hp /= distance_scale hc /= distance_scale hp._epoch += inj.tc hc._epoch += inj.tc # taper the polarizations try: hp_tapered = wfutils.taper_timeseries(hp, inj.taper) hc_tapered = wfutils.taper_timeseries(hc, inj.taper) except AttributeError: hp_tapered = hp hc_tapered = hc # compute the detector response and add it to the strain signal = detector.project_wave(hp_tapered, hc_tapered, inj.ra, inj.dec, inj.polarization) return signal
def finalize_template_events(self, perform_coincidence=True, coinc_window=0.0): # Set ids for ifo in self.ifos: num_events = len(self.template_event_dict[ifo]) new_event_ids = numpy.arange(self.event_index, self.event_index + num_events) self.template_event_dict[ifo]['event_id'] = new_event_ids self.event_index = self.event_index + num_events if perform_coincidence: if not len(self.ifos) == 2: err_msg = "Coincidence currently only supported for 2 ifos." raise ValueError(err_msg) ifo1 = self.ifos[0] ifo2 = self.ifos[1] end_times1 = self.template_event_dict[ifo1]['time_index'] /\ float(self.opt.sample_rate[ifo1]) + self.opt.gps_start_time[ifo1] end_times2 = self.template_event_dict[ifo2]['time_index'] /\ float(self.opt.sample_rate[ifo2]) + self.opt.gps_start_time[ifo2] light_travel_time = Detector(ifo1).light_travel_time_to_detector( Detector(ifo2)) coinc_window = coinc_window + light_travel_time # FIXME: Remove!!! coinc_window = 2.0 if len(end_times1) and len(end_times2): idx_list1, idx_list2, _ = \ coinc.time_coincidence(end_times1, end_times2, coinc_window) if len(idx_list1): for idx1, idx2 in zip(idx_list1, idx_list2): event1 = self.template_event_dict[ifo1][idx1] event2 = self.template_event_dict[ifo2][idx2] self.coinc_list.append((event1, event2)) for ifo in self.ifos: self.events = numpy.append(self.events, self.template_event_dict[ifo]) self.template_event_dict[ifo] = numpy.array([], dtype=self.event_dtype)
def _worker_init_fn(self, worker_id: int = None): self.detectors = {ifo: Detector(ifo) for ifo in self.ifos} self.data = np.load(self.data_dir / self.data_file, mmap_mode='c') # save asds as stacked numpy array for faster compute if self.psd_dir is not None: asds = [] for ifo in self.ifos: psd = load_psd_from_file(self.psd_dir / f'{ifo}_PSD.npy') asds.append(psd[:self.static_args['fd_length']]**0.5) self.asds = np.stack(asds).astype(self.complex_dtype)
def setUp(self): available_detectors = get_available_detectors() available_detectors = [a[0] for a in available_detectors] self.assertTrue('H1' in available_detectors) self.assertTrue('L1' in available_detectors) self.assertTrue('V1' in available_detectors) self.detectors = [Detector(d) for d in ['H1', 'L1', 'V1']] self.sample_rate = 4096. self.earth_time = lal.REARTH_SI / lal.C_SI # create a few random injections self.injections = [] start_time = float(lal.GPSTimeNow()) taper_choices = ('TAPER_NONE', 'TAPER_START', 'TAPER_END', 'TAPER_STARTEND') for i, taper in zip(xrange(20), itertools.cycle(taper_choices)): inj = MyInjection() inj.end_time = start_time + 40000 * i + \ numpy.random.normal(scale=3600) random = numpy.random.uniform inj.mass1 = random(low=1., high=20.) inj.mass2 = random(low=1., high=20.) inj.distance = random(low=0.9, high=1.1) * 1e6 * lal.PC_SI inj.latitude = numpy.arccos(random(low=-1, high=1)) inj.longitude = random(low=0, high=2 * lal.PI) inj.inclination = numpy.arccos(random(low=-1, high=1)) inj.polarization = random(low=0, high=2 * lal.PI) inj.taper = taper self.injections.append(inj) # create LIGOLW document xmldoc = ligolw.Document() xmldoc.appendChild(ligolw.LIGO_LW()) # create sim inspiral table, link it to document and fill it sim_table = lsctables.New(lsctables.SimInspiralTable) xmldoc.childNodes[-1].appendChild(sim_table) for i in xrange(len(self.injections)): row = sim_table.RowType() self.injections[i].fill_sim_inspiral_row(row) row.process_id = 'process:process_id:0' row.simulation_id = 'sim_inspiral:simulation_id:%d' % i sim_table.append(row) # write document to temp file self.inj_file = tempfile.NamedTemporaryFile(suffix='.xml') ligolw_utils.write_fileobj(xmldoc, self.inj_file)
def projector(detector_name, inj, hp, hc, distance_scale=1): """ Use the injection row to project the polarizations into the detector frame """ detector = Detector(detector_name) hp /= distance_scale hc /= distance_scale try: tc = inj.tc ra = inj.ra dec = inj.dec except: tc = inj.get_time_geocent() ra = inj.longitude dec = inj.latitude hp.start_time += tc hc.start_time += tc # taper the polarizations try: hp_tapered = wfutils.taper_timeseries(hp, inj.taper) hc_tapered = wfutils.taper_timeseries(hc, inj.taper) except AttributeError: hp_tapered = hp hc_tapered = hc projection_method = 'lal' if hasattr(inj, 'detector_projection_method'): projection_method = inj.detector_projection_method logging.info('Injecting at %s, method is %s', tc, projection_method) # compute the detector response and add it to the strain signal = detector.project_wave( hp_tapered, hc_tapered, ra, dec, inj.polarization, method=projection_method, reference_time=tc, ) return signal
def __init__(self, variable_params, data, low_frequency_cutoff, sample_rate=32768, **kwargs): super(SingleTemplate, self).__init__(variable_params, data, low_frequency_cutoff, **kwargs) # Generate template waveforms df = data[self.detectors[0]].delta_f p = self.static_params.copy() if 'distance' in p: _ = p.pop('distance') if 'inclination' in p: _ = p.pop('inclination') hp, _ = get_fd_waveform(delta_f=df, distance=1, inclination=0, **p) # Extend template to high sample rate flen = int(int(sample_rate) / df) / 2 + 1 hp.resize(flen) # Calculate high sample rate SNR time series self.sh = {} self.hh = {} self.det = {} for ifo in self.data: flow = self.kmin[ifo] * df fhigh = self.kmax[ifo] * df # Extend data to high sample rate self.data[ifo].resize(flen) self.det[ifo] = Detector(ifo) snr, _, _ = pyfilter.matched_filter_core( hp, self.data[ifo], psd=self.psds[ifo], low_frequency_cutoff=flow, high_frequency_cutoff=fhigh) self.sh[ifo] = 4 * df * snr self.hh[ifo] = -0.5 * pyfilter.sigmasq(hp, psd=self.psds[ifo], low_frequency_cutoff=flow, high_frequency_cutoff=fhigh) self.time = None
def get_gate_times(self): """Gets the time to apply a gate based on the current sky position. If the parameter ``gatefunc`` is set to ``'hmeco'``, the gate times will be calculated based on the hybrid MECO of the given set of parameters; see ``get_gate_times_hmeco`` for details. Otherwise, the gate times will just be retrieved from the ``t_gate_start`` and ``t_gate_end`` parameters. .. warning:: Since the normalization of the likelihood is currently not being calculated, it is recommended that you do not use ``gatefunc``, instead using fixed gate times. Returns ------- dict : Dictionary of detector names -> (gate start, gate width) """ params = self.current_params try: gatefunc = self.current_params['gatefunc'] except KeyError: gatefunc = None if gatefunc == 'hmeco': return self.get_gate_times_hmeco() # gate input for ringdown analysis which consideres a start time # and an end time gatestart = params['t_gate_start'] gateend = params['t_gate_end'] # we'll need the sky location for determining time shifts ra = self.current_params['ra'] dec = self.current_params['dec'] gatetimes = {} for det in self._invpsds: thisdet = Detector(det) # account for the time delay between the waveforms of the # different detectors gatestartdelay = gatestart + thisdet.time_delay_from_earth_center( ra, dec, gatestart) gateenddelay = gateend + thisdet.time_delay_from_earth_center( ra, dec, gateend) dgatedelay = gateenddelay - gatestartdelay gatetimes[det] = (gatestartdelay, dgatedelay) return gatetimes
def make_strain_from_inj_object(self, inj, delta_t, detector_name, distance_scale=1): """Make a h(t) strain time-series from an injection object as read from an hdf file. Parameters ----------- inj : injection object The injection object to turn into a strain h(t). delta_t : float Sample rate to make injection at. detector_name : string Name of the detector used for projecting injections. distance_scale: float, optional Factor to scale the distance of an injection with. The default (=1) is no scaling. Returns -------- signal : float h(t) corresponding to the injection. """ detector = Detector(detector_name) # compute the waveform time series hp, hc = ringdown_td_approximants[inj['approximant']]( inj, delta_t=delta_t, **self.extra_args) hp._epoch += inj['tc'] hc._epoch += inj['tc'] if distance_scale != 1: hp /= distance_scale hc /= distance_scale # compute the detector response and add it to the strain signal = detector.project_wave(hp, hc, inj['ra'], inj['dec'], inj['polarization']) return signal
def detector_projection(hp, hc, **kwargs): """Returns the waveform projected onto different detectors. Arguments --------- hp : TimeSeries TimeSeries object containing the "plus" polarization of a GW hc : TimeSeries TimeSeries object containing the "cross" polarization of a GW Returns ------- list A list containing the signals projected onto the detectors specified in in kwargs['detectors]. """ end_time = kwargs['end_time'] detectors = kwargs['detectors'] declination = kwargs['declination'] right_ascension = kwargs['right_ascension'] polarization = kwargs['polarization'] del kwargs['end_time'] del kwargs['detectors'] del kwargs['declination'] del kwargs['right_ascension'] del kwargs['polarization'] detectors = [Detector(d) for d in detectors] hp.start_time += end_time hc.start_time += end_time ret = [ d.project_wave(TimeSeries(hp), TimeSeries(hc), right_ascension, declination, polarization) for d in detectors ] return (ret)
def apply(self, strain, detector_name, f_lower=None, distance_scale=1): """Add injections (as seen by a particular detector) to a time series. Parameters ---------- strain : TimeSeries Time series to inject signals into, of type float32 or float64. detector_name : string Name of the detector used for projecting injections. f_lower : {None, float}, optional Low-frequency cutoff for injected signals. If None, use value provided by each injection. distance_scale: {1, foat}, optional Factor to scale the distance of an injection with. The default is no scaling. Returns ------- None Raises ------ TypeError For invalid types of `strain`. """ if strain.dtype not in (float32, float64): raise TypeError("Strain dtype must be float32 or float64, not " \ + str(strain.dtype)) lalstrain = strain.lal() detector = Detector(detector_name) earth_travel_time = lal.REARTH_SI / lal.C_SI t0 = float(strain.start_time) - earth_travel_time t1 = float(strain.end_time) + earth_travel_time # pick lalsimulation injection function add_injection = injection_func_map[strain.dtype] for inj in self.table: # roughly estimate if the injection may overlap with the segment end_time = inj.get_time_geocent() #CHECK: This is a hack (10.0s); replace with an accurate estimate inj_length = 10.0 eccentricity = 0.0 polarization = 0.0 start_time = end_time - 2 * inj_length if end_time < t0 or start_time > t1: continue # compute the waveform time series hp, hc = sim.SimBurstSineGaussian(float(inj.q), float(inj.frequency), float(inj.hrss), float(eccentricity), float(polarization), float(strain.delta_t)) hp = TimeSeries(hp.data.data[:], delta_t=hp.deltaT, epoch=hp.epoch) hc = TimeSeries(hc.data.data[:], delta_t=hc.deltaT, epoch=hc.epoch) hp._epoch += float(end_time) hc._epoch += float(end_time) if float(hp.start_time) > t1: continue # compute the detector response, taper it if requested # and add it to the strain strain = wfutils.taper_timeseries(strain, inj.taper) signal_lal = hp.astype(strain.dtype).lal() add_injection(lalstrain, signal_lal, None) strain.data[:] = lalstrain.data.data[:]
def load_inject_condition_ccsn(t_i, t_f, t_inj, ra, dec, pol, hp, hc, local=False, Tc=16, To=2, fw=2048, window='tukey', detector='H', qtrans=False, qsplit=False, dT=2.0, save=False, data_path=None): """Fucntion to load a chunk, inject a waveform and condition, created to enable parallelizing. """ vmem = psutil.virtual_memory() free_mem = vmem.free >> 20 avail_mem = vmem.available >> 20 # if free_mem < 3e5: if avail_mem < 3e5: return if local: files = get_files(detector) try: data = TimeSeries.read(files, start=t_i, end=t_f, format='hdf5.losc') # load data locally except: return else: # load data from losc try: data = TimeSeries.fetch_open_data(detector + '1', *(t_i, t_f), sample_rate=fw, verbose=False, cache=True) except: return if np.isnan(data.value).any(): return det_obj = Detector(detector + '1') delay = det_obj.time_delay_from_detector(Detector('H1'), ra, dec, t_inj) t_inj += delay fp, fc = det_obj.antenna_pattern(ra, dec, pol, t_inj) # wfs_path = Path(git_path + '/shared/ccsn_wfs/' + ccsn_paper) # sim_data = [i.strip().split() for i in open(join(wfs_path, ccsn_file)).readlines()] # if ccsn_paper == 'radice': # line_s = 1 # else: # line_s = 0 # D = D_kpc * 3.086e+21 # cm # sim_times = np.asarray([float(dat[0]) for dat in sim_data[line_s:]]) # hp = np.asarray([float(dat[1]) for dat in sim_data[line_s:]]) / D # if ccsn_paper == 'abdikamalov': # hc = np.zeros(hp.shape) # else: # hc = np.asarray([float(dat[2]) for dat in sim_data[line_s:]]) / D # dt = sim_times[1] - sim_times[0] h = fp * hp + fc * hc # h = TimeSeries(h, t0=sim_times[0], dt=dt) # h = h.resample(rate=fw, ftype = 'iir', n=20) # downsample to working frequency fw # h = h.highpass(frequency=11, filtfilt=True) # filter out frequencies below 20Hz # inj_window = scisig.tukey(M=len(h), alpha=0.08, sym=True) # h = h * inj_window # h = h.pad(int((fw * Tc - len(h)) / 2)) wf_times = data.times.value shift = int((t_inj - (wf_times[0] + Tc / 2)) * fw) h = np.roll(h.value, shift) h = TimeSeries(h, t0=wf_times[0], dt=data.dt) try: h = h.taper() except: pass injected_data = data.inject(h) del data gc.collect() cond_data = condition_data(injected_data, To, fw, window, qtrans, qsplit, dT) del injected_data gc.collect() x = [] times = [] for dat in cond_data: x.append(dat.values) times.append(dat.t0) del cond_data gc.collect() x = np.asarray(x) times = np.asarray(times) idx = find_closest_index(t_inj, times) x = x[idx] times = times[idx] return x, times
def _loglr(self, return_unmarginalized=False): r"""Computes the log likelihood ratio, .. math:: \log \mathcal{L}(\Theta) = \sum_i \left<h_i(\Theta)|d_i\right> - \frac{1}{2}\left<h_i(\Theta)|h_i(\Theta)\right>, at the current parameter values :math:`\Theta`. Returns ------- float The value of the log likelihood ratio. """ params = self.current_params try: wfs = self.waveform_generator.generate(**params) except NoWaveformError: return self._nowaveform_loglr() except FailedWaveformError as e: if self.ignore_failed_waveforms: return self._nowaveform_loglr() else: raise e # --------------------------------------------------------------------- # Some optimizations not yet taken: # * higher m calculations could have a lot of redundancy # * fp/fc need not be calculated except where polarization is different # * may be possible to simplify this by making smarter use of real/imag # --------------------------------------------------------------------- lr = 0. hds = {} hhs = {} for det, modes in wfs.items(): if det not in self.dets: self.dets[det] = Detector(det) fp, fc = self.dets[det].antenna_pattern(self.current_params['ra'], self.current_params['dec'], self.pol, self.current_params['tc']) # loop over modes and prepare the waveform modes # we will sum up zetalm = glm <ulm, d> + i glm <vlm, d> # over all common m so that we can apply the phase once zetas = {} rlms = {} slms = {} for mode in modes: l, m = mode ulm, vlm = modes[mode] # whiten the waveforms # the kmax of the waveforms may be different than internal kmax kmax = min(max(len(ulm), len(vlm)), self._kmax[det]) slc = slice(self._kmin[det], kmax) ulm[self._kmin[det]:kmax] *= self._weight[det][slc] vlm[self._kmin[det]:kmax] *= self._weight[det][slc] # the inner products # <ulm, d> ulmd = ulm[slc].inner(self._whitened_data[det][slc]).real # <vlm, d> vlmd = vlm[slc].inner(self._whitened_data[det][slc]).real # add inclination, and pack into a complex number import lal glm = lal.SpinWeightedSphericalHarmonic( self.current_params['inclination'], 0, -2, l, m).real if m not in zetas: zetas[m] = 0j zetas[m] += glm * (ulmd + 1j*vlmd) # Get condense set of the parts of the waveform that only diff # by m, this is used next to help calculate <h, h> r = glm * ulm s = glm * vlm if m not in rlms: rlms[m] = r slms[m] = s else: rlms[m] += r slms[m] += s # now compute all possible <hlm, hlm> rr_m = {} ss_m = {} rs_m = {} sr_m = {} combos = itertools.combinations_with_replacement(rlms.keys(), 2) for m, mprime in combos: r = rlms[m] s = slms[m] rprime = rlms[mprime] sprime = slms[mprime] rr_m[mprime, m] = r[slc].inner(rprime[slc]).real ss_m[mprime, m] = s[slc].inner(sprime[slc]).real rs_m[mprime, m] = s[slc].inner(rprime[slc]).real sr_m[mprime, m] = r[slc].inner(sprime[slc]).real # store the conjugate for easy retrieval later rr_m[m, mprime] = rr_m[mprime, m] ss_m[m, mprime] = ss_m[mprime, m] rs_m[m, mprime] = sr_m[mprime, m] sr_m[m, mprime] = rs_m[mprime, m] # now apply the phase to all the common ms hpd = 0. hcd = 0. hphp = 0. hchc = 0. hphc = 0. for m, zeta in zetas.items(): phase_coeff = self.phase_fac(m) # <h+, d> = (exp[i m phi] * zeta).real() # <hx, d> = -(exp[i m phi] * zeta).imag() z = phase_coeff * zeta hpd += z.real hcd -= z.imag # now calculate the contribution to <h, h> cosm = phase_coeff.real sinm = phase_coeff.imag for mprime in zetas: pcprime = self.phase_fac(mprime) cosmprime = pcprime.real sinmprime = pcprime.imag # needed components rr = rr_m[m, mprime] ss = ss_m[m, mprime] rs = rs_m[m, mprime] sr = sr_m[m, mprime] # <hp, hp> hphp += rr * cosm * cosmprime \ + ss * sinm * sinmprime \ - rs * cosm * sinmprime \ - sr * sinm * cosmprime # <hc, hc> hchc += rr * sinm * sinmprime \ + ss * cosm * cosmprime \ + rs * sinm * cosmprime \ + sr * cosm * sinmprime # <hp, hc> hphc += -rr * cosm * sinmprime \ + ss * sinm * cosmprime \ + sr * sinm * sinmprime \ - rs * cosm * cosmprime # Now apply the polarizations and calculate the loglr # We have h = Fp * hp + Fc * hc # loglr = <h, d> - <h, h>/2 # = Fp*<hp, d> + Fc*<hc, d> # - (1/2)*(Fp*Fp*<hp, hp> + Fc*Fc*<hc, hc> # + 2*Fp*Fc<hp, hc>) # (in the last line we have made use of the time series being # real, so that <a, b> = <b, a>). hd = fp * hpd + fc * hcd hh = fp * fp * hphp + fc * fc * hchc + 2 * fp * fc * hphc hds[det] = hd hhs[det] = hh lr += hd - 0.5 * hh if return_unmarginalized: return self.pol, self.phase, lr, hds, hhs lr_total = special.logsumexp(lr) - numpy.log(self.nsamples) # store the maxl values idx = lr.argmax() setattr(self._current_stats, 'maxl_polarization', self.pol[idx]) setattr(self._current_stats, 'maxl_phase', self.phase[idx]) return float(lr_total)
def get_detector_signals(static_arguments, waveform_params, event_time, waveform): """ Project the raw `waveform` (i.e., the tuple `(h_plus, h_cross)` returned by :func:`get_waveform()`) onto the antenna patterns of the detectors in Hanford and Livingston. This requires the position of the source in the sky, which is contained in `waveform_params`. Args: static_arguments (dict): The static arguments (e.g., the waveform approximant and the sampling rate) defined in the `*.ini` configuration file. waveform_params (dict): The parameters that were used as inputs for the waveform simulation, although this method will only require the following parameters to be present: - ``ra`` = Right ascension of the source - ``dec`` = Declination of the source - ``polarization`` = Polarization angle of the source event_time (int): The GPS time for the event, which, by convention, is the time at which the simulated signal reaches its maximum amplitude in the `H1` channel. waveform (tuple): The pure simulated wavefrom, represented by a tuple `(h_plus, h_cross)`, which is usually generated by :func:`get_waveform()`. Returns: A dictionary with keys `{'H1'}` that contains the pure signal as it would be observed at Hanford and Livingston. """ # Retrieve the two polarization modes from the waveform tuple h_plus, h_cross = waveform # Extract the parameters we will need later for the projection right_ascension = 2 * np.pi * waveform_params['ra'] declination = np.arcsin(1 - 2 * waveform_params['dec']) polarization = waveform_params['polarization'] # Store the detector signals we will get through projection detector_signals = {} # Set up detectors detectors = {'H1': Detector('H1')} # Set up the detector based on its name detector = detectors['H1'] # Calculate the antenna pattern for this detector f_plus, f_cross = \ detector.antenna_pattern(right_ascension=right_ascension, declination=declination, polarization=polarization, t_gps=100) # Calculate the time offset from H1 for this detector delta_t_h1 = \ detector.time_delay_from_detector(other_detector=detectors['H1'], right_ascension=right_ascension, declination=declination, t_gps=100) # Project the waveform onto the antenna pattern detector_signal = f_plus * h_plus + f_cross * h_cross # Map the signal from geocentric coordinates to the specific # reference frame of the detector. This depends on whether we have # simulated the waveform in the time or frequency domain: if static_arguments['domain'] == 'time': offset = 100 + delta_t_h1 + detector_signal.start_time detector_signal = detector_signal.cyclic_time_shift(offset) detector_signal.start_time = event_time - 100 elif static_arguments['domain'] == 'frequency': offset = 100 + delta_t_h1 detector_signal = detector_signal.cyclic_time_shift(offset) detector_signal.start_time = event_time - 100 detector_signal = detector_signal.to_timeseries() else: raise ValueError('Invalid domain! Must be "time" or "frequency"!') # Store the result detector_signals['H1'] = detector_signal return detector_signals
def win(ifo1, ifo2): d1 = Detector(ifo1) d2 = Detector(ifo2) return d1.light_travel_time_to_detector(d2) + slop
def _loglr(self): r"""Computes the log likelihood ratio, .. math:: \log \mathcal{L}(\Theta) = \sum_i \left<h_i(\Theta)|d_i\right> - \frac{1}{2}\left<h_i(\Theta)|h_i(\Theta)\right>, at the current parameter values :math:`\Theta`. Returns ------- float The value of the log likelihood ratio. """ params = self.current_params try: if self.all_ifodata_same_rate_length: wfs = self.waveform_generator.generate(**params) else: wfs = {} for det in self.data: wfs.update(self.waveform_generator[det].generate(**params)) except NoWaveformError: return self._nowaveform_loglr() except FailedWaveformError as e: if self.ignore_failed_waveforms: return self._nowaveform_loglr() else: raise e lr = sh_total = hh_total = 0. for det, (hp, hc) in wfs.items(): if det not in self.dets: self.dets[det] = Detector(det) fp, fc = self.dets[det].antenna_pattern(self.current_params['ra'], self.current_params['dec'], self.pol, self.current_params['tc']) # the kmax of the waveforms may be different than internal kmax kmax = min(max(len(hp), len(hc)), self._kmax[det]) slc = slice(self._kmin[det], kmax) # whiten both polarizations hp[self._kmin[det]:kmax] *= self._weight[det][slc] hc[self._kmin[det]:kmax] *= self._weight[det][slc] # h = fp * hp + hc * hc # <h, d> = fp * <hp,d> + fc * <hc,d> # the inner products cplx_hpd = self._whitened_data[det][slc].inner(hp[slc]) # <hp, d> cplx_hcd = self._whitened_data[det][slc].inner(hc[slc]) # <hc, d> cplx_hd = fp * cplx_hpd + fc * cplx_hcd # <h, h> = <fp * hp + fc * hc, fp * hp + fc * hc> # = Real(fpfp * <hp,hp> + fcfc * <hc,hc> + \ # fphc * (<hp, hc> + <hc, hp>)) hphp = hp[slc].inner(hp[slc]).real # < hp, hp> hchc = hc[slc].inner(hc[slc]).real # <hc, hc> # Below could be combined, but too tired to figure out # if there should be a sign applied if so hphc = hp[slc].inner(hc[slc]).real # <hp, hc> hchp = hc[slc].inner(hp[slc]).real # <hc, hp> hh = fp * fp * hphp + fc * fc * hchc + fp * fc * (hphc + hchp) # store setattr(self._current_stats, '{}_optimal_snrsq'.format(det), hh) sh_total += cplx_hd hh_total += hh lr = self.marginalize_loglr(sh_total, hh_total, skip_vector=True) lr_total = special.logsumexp(lr) - numpy.log(len(self.pol)) # store the maxl polarization idx = lr.argmax() setattr(self._current_stats, 'maxl_polarization', self.pol[idx]) setattr(self._current_stats, 'maxl_loglr', lr[idx]) # just store the maxl optimal snrsq for det in wfs: p = '{}_optimal_snrsq'.format(det) setattr(self._current_stats, p, getattr(self._current_stats, p)[idx]) return float(lr_total)
def __init__(self, variable_params, data, low_frequency_cutoff, fiducial_params=None, epsilon=0.5, **kwargs): super(Relative, self).__init__(variable_params, data, low_frequency_cutoff, **kwargs) # check that all of the frequency cutoffs are the same # FIXME: this can probably be loosened at some point kmins = list(self.kmin.values()) kmaxs = list(self.kmax.values()) if any(kk != kmins[0] for kk in kmins): raise ValueError("All lower frequency cutoffs must be the same") if any(kk != kmaxs[0] for kk in kmaxs): raise ValueError("All high frequency cutoffs must be the same") # store data and frequencies d0 = list(self.data.values())[0] self.f = numpy.array(d0.sample_frequencies) self.df = d0.delta_f self.end_time = float(d0.end_time) self.det = {ifo: Detector(ifo) for ifo in self.data} self.epsilon = float(epsilon) # store data and psds as arrays for faster computation self.comp_data = {ifo: d.numpy() for ifo, d in self.data.items()} self.comp_psds = {ifo: p.numpy() for ifo, p in self.psds.items()} # store fiducial waveform params self.fid_params = fiducial_params # get detector-specific arrival times relative to end of data dt = { ifo: self.det[ifo].time_delay_from_earth_center(self.fid_params['ra'], self.fid_params['dec'], self.fid_params['tc']) for ifo in self.data } self.ta = { ifo: self.fid_params['tc'] + dt[ifo] - self.end_time for ifo in self.data } # generate fiducial waveform f_lo = kmins[0] * self.df f_hi = kmaxs[0] * self.df logging.info("Generating fiducial waveform from %s to %s Hz", f_lo, f_hi) # prune low frequency samples to avoid waveform errors nbelow = sum(self.f < 10) fpoints = Array(self.f.astype(numpy.float64))[nbelow:] approx = self.static_params['approximant'] fid_hp, fid_hc = get_fd_waveform_sequence(approximant=approx, sample_points=fpoints, **self.fid_params) self.h00 = {} for ifo in self.data: # make copy of fiducial wfs, adding back in low frequencies hp0 = numpy.concatenate([[0j] * nbelow, fid_hp.copy()]) hc0 = numpy.concatenate([[0j] * nbelow, fid_hc.copy()]) fp, fc = self.det[ifo].antenna_pattern( self.fid_params['ra'], self.fid_params['dec'], self.fid_params['polarization'], self.fid_params['tc']) tshift = numpy.exp(-2.0j * numpy.pi * self.f * self.ta[ifo]) self.h00[ifo] = numpy.array(hp0 * fp + hc0 * fc) * tshift # compute frequency bins logging.info("Computing frequency bins") nbin, fbin, fbin_ind = setup_bins(f_full=self.f, f_lo=kmins[0] * self.df, f_hi=kmaxs[0] * self.df, eps=self.epsilon) logging.info("Using %s bins for this model", nbin) # store bins and edges in sample and frequency space self.edges = fbin_ind self.fedges = numpy.array(fbin).astype(numpy.float64) self.bins = numpy.array([(self.edges[i], self.edges[i + 1]) for i in range(len(self.edges) - 1)]) self.fbins = numpy.array([(fbin[i], fbin[i + 1]) for i in range(len(fbin) - 1)]) # store low res copy of fiducial waveform self.h00_sparse = { ifo: self.h00[ifo].copy().take(self.edges) for ifo in self.h00 } # compute summary data logging.info("Calculating summary data at frequency resolution %s Hz", self.df) self.sdat = self.summary_data()
def _loglikelihood(self): r"""Computes the log likelihood after removing the power within the given time window, .. math:: \log p(d|\Theta) = -\frac{1}{2} \sum_i \left< d_i - h_i(\Theta) | d_i - h_i(\Theta) \right>, at the current parameter values :math:`\Theta`. Returns ------- float The value of the log likelihood. """ # generate the template waveform try: wfs = self.get_waveforms() except NoWaveformError: return self._nowaveform_logl() except FailedWaveformError as e: if self.ignore_failed_waveforms: return self._nowaveform_logl() raise e # get the gated waveforms and data gated_wfs = self.get_gated_waveforms() gated_data = self.get_gated_data() # cycle over loglr = 0. lognl = 0. for det, (hp, hc) in wfs.items(): # get the antenna patterns if det not in self.dets: self.dets[det] = Detector(det) fp, fc = self.dets[det].antenna_pattern(self.current_params['ra'], self.current_params['dec'], self.pol, self.current_params['tc']) norm = self.det_lognorm(det) # we always filter the entire segment starting from kmin, since the # gated series may have high frequency components slc = slice(self._kmin[det], self._kmax[det]) # get the gated values gated_hp, gated_hc = gated_wfs[det] gated_d = gated_data[det] # we'll overwhiten the ungated data and waveforms for computing # inner products d = self._overwhitened_data[det] # overwhiten the hp and hc # we'll do this in place for computational efficiency, but as a # result we'll clear the current waveforms cache so a repeated call # to get_waveforms does not return the overwhitened versions self._current_wfs = None invpsd = self._invpsds[det] hp *= invpsd hc *= invpsd # get the various gated inner products hpd = hp[slc].inner(gated_d[slc]).real # <hp, d> hcd = hc[slc].inner(gated_d[slc]).real # <hc, d> dhp = d[slc].inner(gated_hp[slc]).real # <d, hp> dhc = d[slc].inner(gated_hc[slc]).real # <d, hc> hphp = hp[slc].inner(gated_hp[slc]).real # <hp, hp> hchc = hc[slc].inner(gated_hc[slc]).real # <hc, hc> hphc = hp[slc].inner(gated_hc[slc]).real # <hp, hc> hchp = hc[slc].inner(gated_hp[slc]).real # <hc, hp> dd = d[slc].inner(gated_d[slc]).real # <d, d> # since the antenna patterns are real, # <h, d>/2 + <d, h>/2 = fp*(<hp, d>/2 + <d, hp>/2) # + fc*(<hc, d>/2 + <d, hc>/2) hd = fp * (hpd + dhp) + fc * (hcd + dhc) # <h, h>/2 = <fp*hp + fc*hc, fp*hp + fc*hc>/2 # = fp*fp*<hp, hp>/2 + fc*fc*<hc, hc>/2 # + fp*fc*<hp, hc>/2 + fc*fp*<hc, hp>/2 hh = fp * fp * hphp + fc * fc * hchc + fp * fc * (hphc + hchp) # sum up; note that the factor is 2df instead of 4df to account # for the factor of 1/2 loglr += norm + 2 * invpsd.delta_f * (hd - hh) lognl += -2 * invpsd.delta_f * dd # store the maxl polarization idx = loglr.argmax() setattr(self._current_stats, 'maxl_polarization', self.pol[idx]) setattr(self._current_stats, 'maxl_logl', loglr[idx] + lognl) # compute the marginalized log likelihood marglogl = special.logsumexp(loglr) + lognl - numpy.log(len(self.pol)) return float(marglogl)
# coding: utf-8 # In[4]: from pycbc.detector import Detector # In[5]: det_h1 = Detector('H1') det_l1 = Detector('L1') det_v1 = Detector('V1') # In[6]: end_time = 1192529720 declination = 0.65 right_ascension = 4.67 polarization = 2.34 # In[7]: det_h1.antenna_pattern(right_ascension, declination, polarization, end_time)
from pycbc.detector import Detector from astropy.utils import iers # Make sure the documentation can be built without an internet connection iers.conf.auto_download = False # The source of the gravitational waves right_ascension = 0.7 declination = -0.5 # Reference location will be the Hanford detector # see the `time_delay_from_earth_center` method to use use geocentric time # as the reference dref = Detector("H1") # Time in GPS seconds that the GW passes time = 100000000 # Time that the GW will (or has) passed through the given detector for ifo in ["H1", "L1", "V1"]: d = Detector(ifo) dt = d.time_delay_from_detector(dref, right_ascension, declination, time) st = "GW passed through {} {} seconds relative to passing by Hanford" print(st.format(ifo, dt))
def get_td_waveform_resp(params): """ Generate time domain data of gw detector response This function will produce data of a gw detector response based on a numerical relativity waveform. Parameters ---------- params: object The fields of this object correspond to the kwargs of the `pycbc.waveform.get_td_waveform()` method and the positional arguments of `pycbc.detector.Detector.antenna_pattern()`. For the later the fields should be supplied as `params.ra`, `.dec`, `.polarization` and `.geocentric_end_time` Returns ------- h_plus: pycbc.Types.TimeSeries h_cross: pycbc.Types.TimeSeries pats: dictionary Dictionary containing 'H1' and 'L1' keys. Each key maps to an object of containing the field `.f_plus` and `.f_cross` corresponding to the plus and cross antenna patterns for the two ifos 'H1' and 'L1'. """ # # construct waveform string that can be parsed by lalsimulation waveform_string = params.approximant if not pn_orders[params.order] == -1: waveform_string += params.order name, phase_order = legacy_approximant_name(waveform_string) # Populate additional fields of params object params.mchirp, params.eta = pnutils.mass1_mass2_to_mchirp_eta( params.mass1, params.mass2) params.waveform = waveform_string params.approximant = name params.phase_order = phase_order # generate waveform h_plus, h_cross = get_td_waveform(params) # Generate antenna patterns for all ifos pats = {} for ifo in params.instruments: # get Detector instance for IFO det = Detector(ifo) # get antenna pattern f_plus, f_cross = det.antenna_pattern( params.ra, params.dec, params.polarization, params.geocentric_end_time) # Populate antenna patterns with new pattern pat = type('AntennaPattern', (object,), {}) pat.f_plus = f_plus pat.f_cross = f_cross pats[ifo] = pat return h_plus, h_cross, pats