def __getitem__(self, index): if isinstance(index, slice): return self.getslice(index) approximant = self.approximant(index) f_end = self.end_frequency(index) # Determine the length of time of the filter, rounded up to # nearest power of two min_buffer = .5 + self.minimum_buffer from pycbc.waveform.waveform import props buff_size = pycbc.waveform.get_waveform_filter_length_in_time(approximant, f_lower=self.f_lower, **props(self.table[index])) tlen = self.round_up((buff_size + min_buffer) * self.sample_rate) flen = tlen / 2 + 1 delta_f = self.sample_rate / float(tlen) if f_end is None or f_end >= (flen * delta_f): f_end = (flen-1) * delta_f logging.info("Generating %s, %ss, %i" % (approximant, 1.0/delta_f, index)) # Get the waveform filter distance = 1.0 / DYN_RANGE_FAC htilde = pycbc.waveform.get_waveform_filter( zeros(flen, dtype=numpy.complex64), self.table[index], approximant=approximant, f_lower=self.f_lower, f_final=f_end, delta_f=delta_f, delta_t=1.0/self.sample_rate, distance=distance, **self.extra_args) # If available, record the total duration (which may # include ringdown) and the duration up to merger since they will be # erased by the type conversion below. ttotal = template_duration = -1 if hasattr(htilde, 'length_in_time'): ttotal = htilde.length_in_time if hasattr(htilde, 'chirp_length'): template_duration = htilde.chirp_length self.table[index].template_duration = template_duration htilde = htilde.astype(numpy.complex64) htilde.f_lower = self.f_lower htilde.end_frequency = f_end htilde.end_idx = int(htilde.end_frequency / htilde.delta_f) htilde.params = self.table[index] htilde.approximant = approximant htilde.chirp_length = template_duration htilde.length_in_time = ttotal # Add sigmasq as a method of this instance htilde.sigmasq = types.MethodType(sigma_cached, htilde) htilde._sigmasq = {} htilde.id = self.id_from_hash(hash((htilde.params.mass1, htilde.params.mass2, htilde.params.spin1z, htilde.params.spin2z))) return htilde
def get_decompressed_waveform(self, tempout, index, f_lower=None, approximant=None, df=None): """Returns a frequency domain decompressed waveform for the template in the bank corresponding to the index taken in as an argument. The decompressed waveform is obtained by interpolating in frequency space, the amplitude and phase points for the compressed template that are read in from the bank.""" from pycbc.waveform.waveform import props from pycbc.waveform import get_waveform_filter_length_in_time # Get the template hash corresponding to the template index taken in as argument tmplt_hash = self.table.template_hash[index] # Read the compressed waveform from the bank file compressed_waveform = pycbc.waveform.compress.CompressedWaveform.from_hdf( self.filehandler, tmplt_hash, load_now=True) # Get the interpolation method to be used to decompress the waveform if self.waveform_decompression_method is not None: decompression_method = self.waveform_decompression_method else: decompression_method = compressed_waveform.interpolation logging.info("Decompressing waveform using %s", decompression_method) if df is not None: delta_f = df else: delta_f = self.delta_f # Create memory space for writing the decompressed waveform decomp_scratch = FrequencySeries(tempout[0:self.filter_length], delta_f=delta_f, copy=False) # Get the decompressed waveform hdecomp = compressed_waveform.decompress( out=decomp_scratch, f_lower=f_lower, interpolation=decompression_method) p = props(self.table[index]) p.pop('approximant') try: tmpltdur = self.table[index].template_duration except AttributeError: tmpltdur = None if tmpltdur is None or tmpltdur == 0.0: tmpltdur = get_waveform_filter_length_in_time(approximant, **p) hdecomp.chirp_length = tmpltdur hdecomp.length_in_time = hdecomp.chirp_length return hdecomp
def get_decompressed_waveform(self, tempout, index, f_lower=None, approximant=None, df=None): """Returns a frequency domain decompressed waveform for the template in the bank corresponding to the index taken in as an argument. The decompressed waveform is obtained by interpolating in frequency space, the amplitude and phase points for the compressed template that are read in from the bank.""" from pycbc.waveform.waveform import props from pycbc.waveform import get_waveform_filter_length_in_time # Get the template hash corresponding to the template index taken in as argument tmplt_hash = self.table.template_hash[index] # Read the compressed waveform from the bank file compressed_waveform = pycbc.waveform.compress.CompressedWaveform.from_hdf( self.filehandler, tmplt_hash, load_now=True) # Get the interpolation method to be used to decompress the waveform if self.waveform_decompression_method is not None : decompression_method = self.waveform_decompression_method else : decompression_method = compressed_waveform.interpolation logging.info("Decompressing waveform using %s", decompression_method) if df is not None : delta_f = df else : delta_f = self.delta_f # Create memory space for writing the decompressed waveform decomp_scratch = FrequencySeries(tempout[0:self.filter_length], delta_f=delta_f, copy=False) # Get the decompressed waveform hdecomp = compressed_waveform.decompress(out=decomp_scratch, f_lower=f_lower, interpolation=decompression_method) p = props(self.table[index]) p.pop('approximant') try: tmpltdur = self.table[index].template_duration except AttributeError: tmpltdur = None if tmpltdur is None or tmpltdur==0.0 : tmpltdur = get_waveform_filter_length_in_time(approximant, **p) hdecomp.chirp_length = tmpltdur hdecomp.length_in_time = hdecomp.chirp_length return hdecomp
def __getitem__(self, index): if isinstance(index, slice): return self.getslice(index) approximant = self.approximant(index) f_end = self.end_frequency(index) flow = self.table[index].f_lower # Determine the length of time of the filter, rounded up to # nearest power of two min_buffer = .5 + self.minimum_buffer from pycbc.waveform.waveform import props p = props(self.table[index]) p.pop('approximant') buff_size = pycbc.waveform.get_waveform_filter_length_in_time(approximant, **p) tlen = self.round_up((buff_size + min_buffer) * self.sample_rate) flen = tlen / 2 + 1 delta_f = self.sample_rate / float(tlen) if f_end is None or f_end >= (flen * delta_f): f_end = (flen-1) * delta_f logging.info("Generating %s, %ss, %i" % (approximant, 1.0/delta_f, index)) # Get the waveform filter distance = 1.0 / DYN_RANGE_FAC htilde = pycbc.waveform.get_waveform_filter( zeros(flen, dtype=numpy.complex64), self.table[index], approximant=approximant, f_lower=flow, f_final=f_end, delta_f=delta_f, delta_t=1.0/self.sample_rate, distance=distance, **self.extra_args) # If available, record the total duration (which may # include ringdown) and the duration up to merger since they will be # erased by the type conversion below. ttotal = template_duration = -1 if hasattr(htilde, 'length_in_time'): ttotal = htilde.length_in_time if hasattr(htilde, 'chirp_length'): template_duration = htilde.chirp_length self.table[index].template_duration = template_duration htilde = htilde.astype(numpy.complex64) htilde.f_lower = flow htilde.end_idx = int(htilde.f_end / htilde.delta_f) htilde.params = self.table[index] htilde.chirp_length = template_duration htilde.length_in_time = ttotal htilde.approximant = approximant htilde.end_frequency = f_end # Add sigmasq as a method of this instance htilde.sigmasq = types.MethodType(sigma_cached, htilde) htilde._sigmasq = {} htilde.id = self.id_from_hash(hash((htilde.params.mass1, htilde.params.mass2, htilde.params.spin1z, htilde.params.spin2z))) return htilde
def __getitem__(self, index): approximant = self.approximant(index) f_end = self.end_frequency(index) # Determine the length of time of the filter, rounded up to # nearest power of two min_buffer = 1.0 + self.minimum_buffer from pycbc.waveform.waveform import props buff_size = pycbc.waveform.get_waveform_filter_length_in_time( approximant, f_lower=self.f_lower, **props(self.table[index])) tlen = nearest_larger_binary_number( (buff_size + min_buffer) * self.sample_rate) flen = tlen / 2 + 1 delta_f = self.sample_rate / float(tlen) if f_end is None or f_end >= (flen * delta_f): f_end = (flen - 1) * delta_f logging.info("Generating %s, %ss, %i" % (approximant, 1.0 / delta_f, index)) # Get the waveform filter distance = 1.0 / DYN_RANGE_FAC htilde = pycbc.waveform.get_waveform_filter( zeros(flen, dtype=numpy.complex64), self.table[index], approximant=approximant, f_lower=self.f_lower, f_final=f_end, delta_f=delta_f, delta_t=1.0 / self.sample_rate, distance=distance, **self.extra_args) # If available, record the total duration (which may # include ringdown) and the duration up to merger since they will be # erased by the type conversion below. # NOTE: If these durations are not available the values in self.table # will continue to take the values in the input file. if hasattr(htilde, 'length_in_time'): if htilde.length_in_time is not None: self.table[index].ttotal = htilde.length_in_time if hasattr(htilde, 'chirp_length'): if htilde.chirp_length is not None: self.table[index].template_duration = htilde.chirp_length htilde = htilde.astype(numpy.complex64) htilde.f_lower = self.f_lower htilde.end_frequency = f_end htilde.end_idx = int(htilde.end_frequency / htilde.delta_f) htilde.params = self.table[index] htilde.approximant = approximant htilde.chirp_length = htilde.params.template_duration htilde.length_in_time = htilde.params.ttotal # Add sigmasq as a method of this instance htilde.sigmasq = types.MethodType(sigma_cached, htilde) htilde._sigmasq = {} return htilde
def modhm_fd(**kwargs): r"""Allows a waveform to be generated with different parameters for the sub-dominant modes. Modified parameters may be specified in one of two ways. For parameter ``{parameter}`` and mode ``{mode}`` you can either provide ``mod_{mode}_{parameter}`` or ``fdiff_{mode}_{parameter}``. If the former, the given value will be used for the parameter for the given mode. If the latter, the parameter will be scaled by 1 + the given value for the specified mode. Special combinations of parameters are recognized. They are: * ``mchirp``, ``eta`` : if either of these are modified, then ``mass1`` and ``mass2`` wil be adjusted accordingly. If the resulting ``eta`` is unphysical (not in [0, 0.25]) or chirp mass (not > 0) is unphysical, a ``NoWaveformError`` is raised. * ``chi_eff``, ``chi_a``: if either of these are modified, then ``spin1z`` and ``spin2z`` will be adjusted accordingly, using the modified ``mass1`` and ``mass2``. * ``spin1_perp``, ``spin1_azimuthal`` : if either of these are modified, then ``spin1x`` and ``spin1y`` will be adjusted accordingly. * ``spin2_perp``, ``spin2_azimuthal``: same as above, but for the second object. If the resulting modified spins yield a magnitude > 1, a ``NoWaveformError`` is raised. Parameters ---------- base_approximant : str The waveform approximant to use. mode_array : array of tuples The modes to generate, e.g., ``[(2, 2), (3, 3)]``. fdiff_{mode}_{parameter} : float, optional Adjust the parameter ``{parameter}`` for mode ``{mode}`` by the given fractional difference. absdiff_{mode}_{parameter} : float, optional Adjust the parameter ``{parameter}`` for mode ``{mode}`` by the given absolute difference. replace_{mode}_{parameter} : float, optional Use the given value for ``{parameter}`` for mode ``{mode}``. amp_{mode} : float, optional Modify the amplitude of mode ``{mode}`` by the given scale factor. other kwargs : All other keyword argument are passed to :py:func:`pycbc.waveform.waveform.get_fd_waveform`. Returns ------- hp : FrequencySeries The plus polarization. hc : FrequencySeries The cross polarization. """ # pull out the base wavefrom try: apprx = kwargs.pop("base_approximant") except KeyError: raise ValueError("Must provide a base_approximant") try: mode_array = kwargs.pop("mode_array") except KeyError: raise ValueError("Must provide a mode_array") # ensure mode array is a list of modes if isinstance(mode_array, str): mode_array = [tuple(int(m) for m in mode) for mode in shlex.split(mode_array)] # set the approximant to the base kwargs["approximant"] = apprx # add default values, check for other required values kwargs = props(None, **kwargs) # pull out the modification arguments modargs = [p for p in kwargs if p.startswith("fdiff_") or p.startswith("absdiff_") or p.startswith("replace_")] modargs = dict((p, kwargs.pop(p)) for p in modargs) # parse the parameters modparams = {} for p, val in modargs.items(): # template is (fdiff|mod)_mode_param diffarg, mode, param = p.split('_', 2) mode = tuple(int(x) for x in mode) try: addto = modparams[mode] except KeyError: addto = modparams[mode] = {} if param in addto: # the parameter is already there; means multiple args were given raise ValueError("Provide only one of absdiff_{m}_{p}, " "fdiff_{m}_{p}, or replace_{m}_{p}".format( m=''.join(map(str, mode)), p=param)) addto[param] = (val, diffarg) # cycle over the modes, generating the waveform one at a time hps = [] hcs = [] wfargs = kwargs.copy() size = 0 for mode in mode_array: # make sure mode is a tuple mode = tuple(mode) if mode in modparams: # convert mchirp, eta to mass1, mass2 if they are provided mchirp_mod = modparams[mode].pop('mchirp', None) eta_mod = modparams[mode].pop('eta', None) if mchirp_mod is not None or eta_mod is not None: m1, m2 = transform_masses(kwargs['mass1'], kwargs['mass2'], mchirp_mod, eta_mod) wfargs['mass1'] = m1 wfargs['mass2'] = m2 # convert spins chieff_mod = modparams[mode].pop('chi_eff', None) chia_mod = modparams[mode].pop('chi_a', None) if chieff_mod is not None or chia_mod is not None: s1z, s2z = transform_spinzs(wfargs['mass1'], wfargs['mass2'], kwargs['spin1z'], kwargs['spin2z'], chieff_mod, chia_mod) wfargs['spin1z'] = s1z wfargs['spin2z'] = s2z spin1_perp_mod = modparams[mode].pop('spin1_perp', None) spin1_az_mod = modparams[mode].pop('spin1_azimuthal', None) if spin1_perp_mod is not None or spin1_az_mod is not None: s1x, s1y = transform_spin_perp(kwargs['spin1x'], kwargs['spin1y'], spin1_perp_mod, spin1_az_mod) wfargs['spin1x'] = s1x wfargs['spin1y'] = s1y spin2_perp_mod = modparams[mode].pop('spin2_perp', None) spin2_az_mod = modparams[mode].pop('spin2_azimuthal', None) if spin2_perp_mod is not None or spin2_az_mod is not None: s2x, s2y = transform_spin_perp(kwargs['spin2x'], kwargs['spin2y'], spin2_perp_mod, spin2_az_mod) wfargs['spin2x'] = s2x wfargs['spin2y'] = s2y # update all other parameters for p in list(modparams[mode].keys()): diff, modtype = modparams[mode].pop(p) wfargs[p] = apply_mod(kwargs[p], diff, modtype) # check that we still have physical spins for obj in [1, 2]: mag = (wfargs['spin{}x'.format(obj)]**2 + wfargs['spin{}y'.format(obj)]**2 + wfargs['spin{}z'.format(obj)]**2)**0.5 if mag >= 1: raise NoWaveformError("unphysical spins") wfargs['mode_array'] = [mode] # pull out any amplitude scaling scalefac = wfargs.pop('amp_{}'.format(''.join(map(str, mode))), 1.) hp, hc = get_fd_waveform(**wfargs) if scalefac != 1.: hp *= scalefac hc *= scalefac hps.append(hp) hcs.append(hc) size = max(size, len(hp)) # make sure everything is the same size for ii, hp in enumerate(hps): hp.resize(size) hcs[ii].resize(size) return sum(hps), sum(hcs)