From 280c740ffe9ee01b6d790aaf73c6aaeb370e74f8 Mon Sep 17 00:00:00 2001 From: WuShichao Date: Wed, 7 Sep 2022 17:48:29 +0200 Subject: [PATCH 01/27] fix waveform_transforms not defined issue --- bin/bank/pycbc_brute_bank | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/bank/pycbc_brute_bank b/bin/bank/pycbc_brute_bank index ef4b3503af9..35d7005c430 100644 --- a/bin/bank/pycbc_brute_bank +++ b/bin/bank/pycbc_brute_bank @@ -46,7 +46,7 @@ parser.add_argument('--approximant', required=True, parser.add_argument('--minimal-match', default=0.97, type=float) parser.add_argument('--buffer-length', default=2, type=float, help='size of waveform buffer in seconds') -parser.add_argument('--sample-rate', default=2048, type=int, +parser.add_argument('--sample-rate', default=2048, type=float, help='sample rate in seconds') parser.add_argument('--low-frequency-cutoff', default=20.0, type=float) parser.add_argument('--enable-sigma-bound', action='store_true') @@ -85,6 +85,8 @@ if args.input_config is not None: if any(config_parser.get_subsections('waveform_transforms')): waveform_transforms = transforms.read_transforms_from_config( config_parser, 'waveform_transforms') + else: + waveform_transforms = None dists_joint = prior_from_config(cp=config_parser) From ed1e8ea6fee1b8b0c114b70b1b64151722ef19e7 Mon Sep 17 00:00:00 2001 From: WuShichao Date: Wed, 7 Sep 2022 17:57:47 +0200 Subject: [PATCH 02/27] add static_args back --- bin/bank/pycbc_brute_bank | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bin/bank/pycbc_brute_bank b/bin/bank/pycbc_brute_bank index 35d7005c430..32e96d6a04c 100644 --- a/bin/bank/pycbc_brute_bank +++ b/bin/bank/pycbc_brute_bank @@ -351,12 +351,13 @@ def draw(rtype): for k, v in zip(p, points): params[k] = v + # Add `static_args` back, some transformations may need them. + if static_args is not None: + for k in static_args.keys(): + params[k] = numpy.array([static_args[k]]*size) + # Apply `waveform_transforms` defined in the .ini file to samples. if args.input_config is not None and waveform_transforms is not None: - # Add `static_args` back, some transformations may need them. - if static_args is not None: - for k in static_args.keys(): - params[k] = numpy.array([static_args[k]]*size) params = transforms.apply_transforms(params, waveform_transforms) params['approximant'] = numpy.array([args.approximant]*size) From 611e517d893f90033cfcb9ed29a30b966f59a44f Mon Sep 17 00:00:00 2001 From: WuShichao Date: Wed, 7 Sep 2022 18:09:36 +0200 Subject: [PATCH 03/27] fix cc issues --- bin/bank/pycbc_brute_bank | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/bank/pycbc_brute_bank b/bin/bank/pycbc_brute_bank index 32e96d6a04c..29274acc082 100644 --- a/bin/bank/pycbc_brute_bank +++ b/bin/bank/pycbc_brute_bank @@ -352,7 +352,7 @@ def draw(rtype): params[k] = v # Add `static_args` back, some transformations may need them. - if static_args is not None: + if args.input_config is not None and static_args is not None: for k in static_args.keys(): params[k] = numpy.array([static_args[k]]*size) From fc97c483a40e3007ae1f3d7b13b0c35634aafb9b Mon Sep 17 00:00:00 2001 From: WuShichao Date: Thu, 8 Sep 2022 13:45:06 +0200 Subject: [PATCH 04/27] adopt Ian's changes for LISA --- pycbc/inference/models/relbin.py | 113 +++++++++++++++++-------- pycbc/psd/__init__.py | 7 +- pycbc/strain/strain.py | 2 +- pycbc/waveform/bbhx_waveform_plugin.py | 70 +++++++++++++++ pycbc/waveform/generator.py | 36 ++++++++ pycbc/waveform/parameters.py | 16 +++- pycbc/waveform/waveform.py | 7 ++ 7 files changed, 210 insertions(+), 41 deletions(-) create mode 100644 pycbc/waveform/bbhx_waveform_plugin.py diff --git a/pycbc/inference/models/relbin.py b/pycbc/inference/models/relbin.py index bb897cd8bf2..65883448177 100644 --- a/pycbc/inference/models/relbin.py +++ b/pycbc/inference/models/relbin.py @@ -169,6 +169,9 @@ def __init__( variable_params, data, low_frequency_cutoff, **kwargs ) + # FIXME: This should be set properly in some way + self.is_lisa = True + # reference waveform and bin edges self.f, self.df, self.end_time, self.det = {}, {}, {}, {} self.h00, self.h00_sparse = {}, {} @@ -181,6 +184,10 @@ def __init__( # store fiducial waveform params self.fid_params = self.static_params.copy() self.fid_params.update(fiducial_params) + + if self.is_lisa: + self.init_tdi_wavs = {} + for k in self.static_params: if self.fid_params[k] == 'REPLACE': self.fid_params.pop(k) @@ -191,7 +198,7 @@ def __init__( self.f[ifo] = numpy.array(d0.sample_frequencies) self.df[ifo] = d0.delta_f self.end_time[ifo] = float(d0.end_time) - self.det[ifo] = Detector(ifo) + # self.det[ifo] = Detector(ifo) # generate fiducial waveform f_lo = self.kmin[ifo] * self.df[ifo] @@ -204,12 +211,24 @@ def __init__( # prune low frequency samples to avoid waveform errors fpoints = Array(self.f[ifo].astype(numpy.float64)) fpoints = fpoints[self.kmin[ifo]:self.kmax[ifo]+1] - fid_hp, fid_hc = get_fd_waveform_sequence(sample_points=fpoints, - **self.fid_params) + + if self.is_lisa: + if ifo not in self.init_tdi_wavs: + la, le, lt = get_fd_waveform_sequence(sample_points=fpoints, + **self.fid_params) + self.init_tdi_wavs['LISA_A'] = la + self.init_tdi_wavs['LISA_E'] = le + self.init_tdi_wavs['LISA_T'] = lt + curr_wav = self.init_tdi_wavs[ifo] + + else: + fid_hp, fid_hc = get_fd_waveform_sequence(sample_points=fpoints, + **self.fid_params) + curr_wav = fid_hp # check for zeros at high frequencies # make sure only nonzero samples are included in bins - numzeros = list(fid_hp[::-1] != 0j).index(True) + numzeros = list(curr_wav[::-1] != 0j).index(True) if numzeros > 0: new_kmax = self.kmax[ifo] - numzeros f_hi = new_kmax * self.df[ifo] @@ -219,27 +238,37 @@ def __init__( "will be %s Hz", f_hi) # make copy of fiducial wfs, adding back in low frequencies - fid_hp.resize(len(self.f[ifo])) - fid_hc.resize(len(self.f[ifo])) - hp0 = numpy.roll(fid_hp, self.kmin[ifo]) - hc0 = numpy.roll(fid_hc, self.kmin[ifo]) + if self.is_lisa: + curr_wav.resize(len(self.f[ifo])) + curr_wav = numpy.roll(curr_wav, self.kmin[ifo]) + tshift = numpy.exp(-2.0j * numpy.pi * self.f[ifo] * self.ta[ifo]) + self.h00[ifo] = numpy.array(curr_wav) * tshift + else: + fid_hp.resize(len(self.f[ifo])) + fid_hc.resize(len(self.f[ifo])) + hp0 = numpy.roll(fid_hp, self.kmin[ifo]) + hc0 = numpy.roll(fid_hc, self.kmin[ifo]) # get detector-specific arrival times relative to end of data - dt = self.det[ifo].time_delay_from_earth_center( - self.fid_params["ra"], - self.fid_params["dec"], - self.fid_params["tc"], - ) + if self.is_lisa: + self.ta[ifo] = -self.end_time[ifo] + else: + self.det[ifo] = Detector(ifo) + dt = self.det[ifo].time_delay_from_earth_center( + self.fid_params["ra"], + self.fid_params["dec"], + self.fid_params["tc"], + ) + self.ta = self.fid_params["tc"] + dt - self.end_time[ifo] - ta = self.fid_params["tc"] + dt - self.end_time[ifo] - tshift = numpy.exp(-2.0j * numpy.pi * self.f[ifo] * ta) + fp, fc = self.det[ifo].antenna_pattern( + self.fid_params["ra"], self.fid_params["dec"], + self.fid_params["polarization"], self.fid_params["tc"]) - 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[ifo] * ta) - h00 = (hp0 * fp + hc0 * fc) * tshift - self.h00[ifo] = h00 + h00 = (hp0 * fp + hc0 * fc) * tshift + self.h00[ifo] = h00 # compute frequency bins logging.info("Computing frequency bins") @@ -340,13 +369,25 @@ def summary_product(self, h1, h2, bins, ifo): def get_waveforms(self, params): """ Get the waveform polarizations for each ifo """ - wfs = [] - for edge in self.edge_unique: - hp, hc = get_fd_waveform_sequence(sample_points=edge, **params) - hp = hp.numpy() - hc = hc.numpy() - wfs.append((hp, hc)) - return {ifo: wfs[self.ifo_map[ifo]] for ifo in self.data} + if self.is_lisa: + wf_ret = {} + la, le, lt = get_fd_waveform_sequence(sample_points=self.edge_unique[0], + **params) + la = la.numpy() + le = le.numpy() + lt = lt.numpy() + wf_ret['LISA_A'] = (la, la) + wf_ret['LISA_E'] = (le, le) + wf_ret['LISA_T'] = (lt, lt) + else: + wfs = [] + for edge in self.edge_unique: + hp, hc = get_fd_waveform_sequence(sample_points=edge, **params) + hp = hp.numpy() + hc = hc.numpy() + wfs.append((hp, hc)) + wf_ret = {ifo: wfs[self.ifo_map[ifo]] for ifo in self.data} + return wf_ret @property def multi_signal_support(self): @@ -440,7 +481,6 @@ def _loglr(self): self._current_wf_parts = {} for ifo in self.data: - det = self.det[ifo] freqs = self.fedges[ifo] sdat = self.sdat[ifo] h00 = self.h00_sparse[ifo] @@ -448,12 +488,19 @@ def _loglr(self): times = self.antenna_time[ifo] # project waveform to detector frame - hp, hc = wfs[ifo] - fp, fc = det.antenna_pattern(p["ra"], p["dec"], - p["polarization"], times) - dt = det.time_delay_from_earth_center(p["ra"], p["dec"], times) - dtc = p["tc"] + dt - end_time + # FIXME: Don't want to do this for LISA!! + if self.is_lisa: + fp, fc = (1, 0) + dt = 0 + dtc = -end_time + else: + det = self.det[ifo] + fp, fc = det.antenna_pattern(p["ra"], p["dec"], + p["polarization"], times) + dt = det.time_delay_from_earth_center(p["ra"], p["dec"], times) + dtc = p["tc"] + dt - end_time + hp, hc = wfs[ifo] hdp, hhp = self.lik(freqs, fp, fc, dtc, hp, hc, h00, sdat['a0'], sdat['a1'], diff --git a/pycbc/psd/__init__.py b/pycbc/psd/__init__.py index 756e8650be5..4738d26e9dc 100644 --- a/pycbc/psd/__init__.py +++ b/pycbc/psd/__init__.py @@ -65,7 +65,7 @@ def from_cli(opt, length, delta_f, low_frequency_cutoff, The frequency series containing the PSD. """ f_low = low_frequency_cutoff - sample_rate = int((length -1) * 2 * delta_f) + sample_rate = (length -1) * 2 * delta_f try: psd_estimation = opt.psd_estimation is not None @@ -109,13 +109,14 @@ def from_cli(opt, length, delta_f, low_frequency_cutoff, elif psd_estimation: # estimate PSD from data psd = welch(strain, avg_method=opt.psd_estimation, - seg_len=int(opt.psd_segment_length * sample_rate), - seg_stride=int(opt.psd_segment_stride * sample_rate), + seg_len=int(opt.psd_segment_length * sample_rate + 0.5), + seg_stride=int(opt.psd_segment_stride * sample_rate + 0.5), num_segments=opt.psd_num_segments, require_exact_data_fit=False) if delta_f != psd.delta_f: psd = interpolate(psd, delta_f) + else: # Shouldn't be possible to get here raise ValueError("Shouldn't be possible to raise this!") diff --git a/pycbc/strain/strain.py b/pycbc/strain/strain.py index 3b204c802a3..ed152eb8625 100644 --- a/pycbc/strain/strain.py +++ b/pycbc/strain/strain.py @@ -844,7 +844,7 @@ def insert_strain_option_group_multi_ifo(parser, gps_times=True): '--hdf-store']) required_opts_list = ['--gps-start-time', '--gps-end-time', - '--strain-high-pass', '--pad-data', '--sample-rate', + '--pad-data', '--sample-rate', '--channel-name'] diff --git a/pycbc/waveform/bbhx_waveform_plugin.py b/pycbc/waveform/bbhx_waveform_plugin.py new file mode 100644 index 00000000000..93ff0b0d314 --- /dev/null +++ b/pycbc/waveform/bbhx_waveform_plugin.py @@ -0,0 +1,70 @@ +import numpy as np +from pycbc.types import FrequencySeries, Array +from pycbc import pnutils, conversions +from .waveform import props +from .parameters import location_params + +from bbhx.waveformbuild import BBHWaveformFD + +def BBHXWaveformFDInterface(run_phenomd=True, nyquist_freq=0.1, + sample_points=None, **params): + # Some of this could go into waveform.py eventually. + tmp_params = props(None, **params) + params = location_params.default_dict().copy() + params.update(tmp_params) + + # Is it slow to do this every time?? Does it need caching?? + wave_gen = BBHWaveformFD(amp_phase_kwargs=dict(run_phenomd=run_phenomd)) + + m1 = params['mass1'] + m2 = params['mass2'] + a1 = params['spin1z'] + a2 = params['spin2z'] + dist = pnutils.megaparsecs_to_meters(params['distance']) + phi_ref = params['coa_phase'] + f_ref = 0 # This is now NOT standard LAL convention! + inc = params['inclination'] + lam = params['eclipticlongitude'] + beta = params['eclipticlatitude'] + psi = params['polarization'] + t_ref = params['tc'] + if sample_points is None: + freqs = np.arange(0, nyquist_freq, params['delta_f']) + else: + freqs = sample_points + # FIXME: Must not hardcode this here!! + params['delta_f'] = 1E-8 + modes = [(2,2)] # More modes if not phenomd + direct = False # See the BBHX documentation + fill = True # See the BBHX documentation + squeeze = True # See the BBHX documentation + length = 1024 # An internal generation parameter, not an output parameter + + shift_t_limits = False # Times are relative to merger + t_obs_start = 0.9*conversions.sec_to_year(1. / params['delta_f']) + t_obs_end = 0.0 # Generates ringdown as well! + + wave = wave_gen(m1, m2, a1, a2, + dist, phi_ref, f_ref, inc, lam, + beta, psi, t_ref, freqs=freqs, + modes=modes, direct=direct, fill=fill, squeeze=squeeze, + length=length,t_obs_start=t_obs_start, + t_obs_end=t_obs_end, + shift_t_limits=shift_t_limits)[0] + + # Convert outputs to PyCBC arrays + if sample_points is None: + # If wave[i] was converted to the time-domain, where would the + # merger be within the timeseries (at end? at start?). This is a weird + # convention in BBHX, and is not trivial! + # FIXME: This has not been tested for relative_binning, and + # may not (probably won't) work there! + length_of_wave = 1. / params['delta_f'] + # I don't know why this is what it is. + loc_of_signal_merger_within_wave = t_ref % length_of_wave + output = [FrequencySeries(wave[i], delta_f=params['delta_f'], + epoch=params['tc'] - loc_of_signal_merger_within_wave) + for i in range(3)] + else: + output = [Array(wave[i]) for i in range(3)] + return output diff --git a/pycbc/waveform/generator.py b/pycbc/waveform/generator.py index 64125ad5a45..1fa137f69d6 100644 --- a/pycbc/waveform/generator.py +++ b/pycbc/waveform/generator.py @@ -30,6 +30,7 @@ from abc import (ABCMeta, abstractmethod) from . import waveform +from . import bbhx_waveform_plugin from .waveform import (FailedWaveformError) from . import ringdown from . import supernovae @@ -1005,6 +1006,41 @@ def select_rframe_generator(approximant): """ return select_waveform_modes_generator(approximant) +# FIXME: For now this is hardcoded to a particular waveform, but there could +# be a more general generate_lisa_aet function with an approximant to +# generate different things +class FDomainLISAAETGenerator(BaseCBCGenerator): + def __init__(self, epoch, ifos=(), variable_args=(), **frozen_params): + self.ifos = ifos + self.set_epoch(epoch) + super().__init__(bbhx_waveform_plugin.BBHXWaveformFDInterface, + variable_args=variable_args, **frozen_params) + + def set_epoch(self, epoch): + """Sets the epoch; epoch should be a float or a LIGOTimeGPS.""" + self._epoch = float(epoch) + + @property + def epoch(self): + return _lal.LIGOTimeGPS(self._epoch) + + def generate(self, **kwargs): + """Generates a waveform from the keyword args. The current params + are updated with the given kwargs, then the generator is called. + """ + waveforms = super().generate(**kwargs) + allowed_names = ['LISA_A', 'LISA_E', 'LISA_T'] + for i in range(3): + old_epoch = waveforms[i]._epoch + tc_within_data = self.current_params['tc'] - old_epoch + waveforms[i]._epoch = self._epoch + waveforms[i] = apply_fd_time_shift(waveforms[i], + self.current_params['tc']-tc_within_data, + copy=False) + + wav_dict = {allowed_names[i]:waveforms[i] for i in range(3) + if allowed_names[i] in self.ifos} + return wav_dict # # ============================================================================= diff --git a/pycbc/waveform/parameters.py b/pycbc/waveform/parameters.py index b0c2ec51093..8b46ce3d5da 100644 --- a/pycbc/waveform/parameters.py +++ b/pycbc/waveform/parameters.py @@ -26,6 +26,7 @@ """ from collections import OrderedDict +from numpy import dtype try: from collections import UserList except ImportError: @@ -418,13 +419,13 @@ def docstr(self, prefix='', include_label=True): label=r"$\Delta t_c~(\rm{s})$", description="Coalesence time offset.") ra = Parameter("ra", - dtype=float, default=None, label=r"$\alpha$", + dtype=float, default=0., label=r"$\alpha$", description="Right ascension (rad).") dec = Parameter("dec", - dtype=float, default=None, label=r"$\delta$", + dtype=float, default=0., label=r"$\delta$", description="Declination (rad).") polarization = Parameter("polarization", - dtype=float, default=None, label=r"$\psi$", + dtype=float, default=0., label=r"$\psi$", description="Polarization (rad).") redshift = Parameter("redshift", dtype=float, default=None, label=r"$z$", @@ -432,6 +433,12 @@ def docstr(self, prefix='', include_label=True): comoving_volume = Parameter("comoving_volume", dtype=float, label=r"$V_C~(\rm{Mpc}^3)$", description="Comoving volume (in cubic Mpc).") +eclipticlatitude = Parameter("eclipticlatitude", + dtype=float, default=0., label=r"$\beta$", + description="eclipticlatitude wrt SSB coords.") +eclipticlongitude = Parameter("eclipticlongitude", + dtype=float, default=0., label=r"$\lambda$", + description="eclipticlongitude wrt SSB coords.") # # Calibration parameters @@ -547,7 +554,8 @@ def docstr(self, prefix='', include_label=True): # passed to the waveform generators in lalsimulation, but are instead applied # after a waveform is generated. Distance, however, is a parameter used by # the waveform generators. -location_params = ParameterList([tc, ra, dec, polarization]) +location_params = ParameterList([tc, ra, dec, polarization, + eclipticlatitude, eclipticlongitude]) # parameters describing the orientation of a binary w.r.t. the radiation # frame. Note: we include distance here, as it is typically used for generating diff --git a/pycbc/waveform/waveform.py b/pycbc/waveform/waveform.py index d4d5887e9d3..acbf0fef4ec 100644 --- a/pycbc/waveform/waveform.py +++ b/pycbc/waveform/waveform.py @@ -490,6 +490,13 @@ def _lalsim_fd_sequence(**p): for apx in _lalsim_enum: fd_sequence[apx] = _lalsim_fd_sequence +try: + from . import bbhx_waveform_plugin + fd_sequence['BBHX_PhenomD'] = bbhx_waveform_plugin.BBHXWaveformFDInterface + cpu_fd['BBHX_PhenomD'] = fd_sequence['BBHX_PhenomD'] +except ImportError: + pass + def get_fd_waveform_sequence(template=None, **kwds): """Return values of the waveform evaluated at the sequence of frequency points. From 550cbb17c6ab729468b7976dcd8ccad390cac49f Mon Sep 17 00:00:00 2001 From: WuShichao Date: Thu, 8 Sep 2022 13:45:43 +0200 Subject: [PATCH 05/27] update for LISA bank --- bin/bank/pycbc_brute_bank | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/bank/pycbc_brute_bank b/bin/bank/pycbc_brute_bank index 29274acc082..3b3ef417674 100644 --- a/bin/bank/pycbc_brute_bank +++ b/bin/bank/pycbc_brute_bank @@ -272,8 +272,10 @@ class GenUniformWaveform(object): def generate(self, **kwds): kwds.update(fdict) if kwds['approximant'] in pycbc.waveform.fd_approximants(): - hp, hc = pycbc.waveform.get_fd_waveform(delta_f=self.delta_f, + ws = pycbc.waveform.get_fd_waveform(delta_f=self.delta_f, f_lower=self.f_lower, **kwds) + hp = ws[0] + hc = ws[1] if 'fratio' in kwds: hp = hc * kwds['fratio'] + hp * (1 - kwds['fratio']) else: From ee8e4ab891684777fd06754056df78f3cbfd1e4e Mon Sep 17 00:00:00 2001 From: WuShichao Date: Thu, 8 Sep 2022 15:02:36 +0200 Subject: [PATCH 06/27] fix self.ta[ifo] issue --- pycbc/inference/models/relbin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pycbc/inference/models/relbin.py b/pycbc/inference/models/relbin.py index 65883448177..96c361e9673 100644 --- a/pycbc/inference/models/relbin.py +++ b/pycbc/inference/models/relbin.py @@ -241,7 +241,6 @@ def __init__( if self.is_lisa: curr_wav.resize(len(self.f[ifo])) curr_wav = numpy.roll(curr_wav, self.kmin[ifo]) - tshift = numpy.exp(-2.0j * numpy.pi * self.f[ifo] * self.ta[ifo]) self.h00[ifo] = numpy.array(curr_wav) * tshift else: fid_hp.resize(len(self.f[ifo])) @@ -252,6 +251,7 @@ def __init__( # get detector-specific arrival times relative to end of data if self.is_lisa: self.ta[ifo] = -self.end_time[ifo] + tshift = numpy.exp(-2.0j * numpy.pi * self.f[ifo] * self.ta[ifo]) else: self.det[ifo] = Detector(ifo) dt = self.det[ifo].time_delay_from_earth_center( From 78cb2bbb321019356eabad79ee661a024d367ea0 Mon Sep 17 00:00:00 2001 From: WuShichao Date: Thu, 8 Sep 2022 16:02:41 +0200 Subject: [PATCH 07/27] fix --- pycbc/inference/models/relbin.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pycbc/inference/models/relbin.py b/pycbc/inference/models/relbin.py index 96c361e9673..5e0f55dab49 100644 --- a/pycbc/inference/models/relbin.py +++ b/pycbc/inference/models/relbin.py @@ -241,6 +241,9 @@ def __init__( if self.is_lisa: curr_wav.resize(len(self.f[ifo])) curr_wav = numpy.roll(curr_wav, self.kmin[ifo]) + # get detector-specific arrival times relative to end of data + self.ta[ifo] = -self.end_time[ifo] + tshift = numpy.exp(-2.0j * numpy.pi * self.f[ifo] * self.ta[ifo]) self.h00[ifo] = numpy.array(curr_wav) * tshift else: fid_hp.resize(len(self.f[ifo])) @@ -248,11 +251,6 @@ def __init__( hp0 = numpy.roll(fid_hp, self.kmin[ifo]) hc0 = numpy.roll(fid_hc, self.kmin[ifo]) - # get detector-specific arrival times relative to end of data - if self.is_lisa: - self.ta[ifo] = -self.end_time[ifo] - tshift = numpy.exp(-2.0j * numpy.pi * self.f[ifo] * self.ta[ifo]) - else: self.det[ifo] = Detector(ifo) dt = self.det[ifo].time_delay_from_earth_center( self.fid_params["ra"], @@ -265,7 +263,7 @@ def __init__( 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[ifo] * ta) + tshift = numpy.exp(-2.0j * numpy.pi * self.f[ifo] * self.ta) h00 = (hp0 * fp + hc0 * fc) * tshift self.h00[ifo] = h00 From f72ca9f9bb8dacd52901795cf6d48098b3052f82 Mon Sep 17 00:00:00 2001 From: WuShichao Date: Thu, 8 Sep 2022 16:42:59 +0200 Subject: [PATCH 08/27] fix ta issue --- pycbc/inference/models/relbin.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pycbc/inference/models/relbin.py b/pycbc/inference/models/relbin.py index 5e0f55dab49..b6d02c1f1f4 100644 --- a/pycbc/inference/models/relbin.py +++ b/pycbc/inference/models/relbin.py @@ -176,6 +176,7 @@ def __init__( self.f, self.df, self.end_time, self.det = {}, {}, {}, {} self.h00, self.h00_sparse = {}, {} self.fedges, self.edges = {}, {} + self.ta = {} self.antenna_time = {} # filtered summary data for linear approximation From 9de05ff9097533f7abf05bf30cf29834df010fca Mon Sep 17 00:00:00 2001 From: WuShichao Date: Thu, 8 Sep 2022 16:49:07 +0200 Subject: [PATCH 09/27] remove all changes --- pycbc/waveform/generator.py | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/pycbc/waveform/generator.py b/pycbc/waveform/generator.py index 1fa137f69d6..64125ad5a45 100644 --- a/pycbc/waveform/generator.py +++ b/pycbc/waveform/generator.py @@ -30,7 +30,6 @@ from abc import (ABCMeta, abstractmethod) from . import waveform -from . import bbhx_waveform_plugin from .waveform import (FailedWaveformError) from . import ringdown from . import supernovae @@ -1006,41 +1005,6 @@ def select_rframe_generator(approximant): """ return select_waveform_modes_generator(approximant) -# FIXME: For now this is hardcoded to a particular waveform, but there could -# be a more general generate_lisa_aet function with an approximant to -# generate different things -class FDomainLISAAETGenerator(BaseCBCGenerator): - def __init__(self, epoch, ifos=(), variable_args=(), **frozen_params): - self.ifos = ifos - self.set_epoch(epoch) - super().__init__(bbhx_waveform_plugin.BBHXWaveformFDInterface, - variable_args=variable_args, **frozen_params) - - def set_epoch(self, epoch): - """Sets the epoch; epoch should be a float or a LIGOTimeGPS.""" - self._epoch = float(epoch) - - @property - def epoch(self): - return _lal.LIGOTimeGPS(self._epoch) - - def generate(self, **kwargs): - """Generates a waveform from the keyword args. The current params - are updated with the given kwargs, then the generator is called. - """ - waveforms = super().generate(**kwargs) - allowed_names = ['LISA_A', 'LISA_E', 'LISA_T'] - for i in range(3): - old_epoch = waveforms[i]._epoch - tc_within_data = self.current_params['tc'] - old_epoch - waveforms[i]._epoch = self._epoch - waveforms[i] = apply_fd_time_shift(waveforms[i], - self.current_params['tc']-tc_within_data, - copy=False) - - wav_dict = {allowed_names[i]:waveforms[i] for i in range(3) - if allowed_names[i] in self.ifos} - return wav_dict # # ============================================================================= From cb01440ef77d171163fe79ccedb67557c16fb1c5 Mon Sep 17 00:00:00 2001 From: Connor Date: Fri, 9 Sep 2022 11:59:40 +0200 Subject: [PATCH 10/27] Plugin testing script --- .../lisa/plugin_test/test_waveform_plugin.py | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 examples/lisa/plugin_test/test_waveform_plugin.py diff --git a/examples/lisa/plugin_test/test_waveform_plugin.py b/examples/lisa/plugin_test/test_waveform_plugin.py new file mode 100644 index 00000000000..118e8ca34e0 --- /dev/null +++ b/examples/lisa/plugin_test/test_waveform_plugin.py @@ -0,0 +1,49 @@ +import numpy as np +import pickle + +import pycbc.waveform + +signals = [] + +def s_ldc2pycbc(mag, pol): + return mag*np.cos(pol) + +with open('../param_files/MBHB_params_v2.pkl', 'rb') as f: + pmbhb = pickle.load(f) + + pMBHB = pmbhb[0] + + modes = [(2,2)] + + params = {'approximant': 'connor_bbhx', + 'mass1': pMBHB['Mass1'], + 'mass2': pMBHB['Mass2'], + 'delta_f':1/31536000, + 'inclination': np.pi/3, + 'tc': pMBHB['CoalescenceTime'], + 'polarization': np.pi/2, + 'spin1z': s_ldc2pycbc(pMBHB['Spin1'], pMBHB['PolarAngleOfSpin1']), + 'spin2z': s_ldc2pycbc(pMBHB['Spin2'], pMBHB['PolarAngleOfSpin2']), + 'coa_phase' : pMBHB['PhaseAtCoalescence'], + 'distance': pMBHB['Distance'], + 'eclipticlatitude': pMBHB['EclipticLatitude'], + 'eclipticlongitude': pMBHB['EclipticLongitude'], + 'mode_array':modes} + + signals.append(params) + +params = signals[0] + + + +A = pycbc.waveform.get_fd_waveform(f_lower=0.0001, **params) + +import matplotlib.pylab as plt + + +td_A = A[0].to_timeseries() + +plt.figure(figsize=(12,6)) +plt.plot(td_A.sample_times,td_A) +plt.xlim(params['tc']-1000, params['tc']+1000) +plt.savefig('test_waveform_plugin.jpg') From 8d18f825dab21051769284b965f316e6a3524bfa Mon Sep 17 00:00:00 2001 From: WuShichao Date: Fri, 9 Sep 2022 15:25:37 +0200 Subject: [PATCH 11/27] remove all hard-coded "BBHx" --- pycbc/waveform/waveform.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pycbc/waveform/waveform.py b/pycbc/waveform/waveform.py index acbf0fef4ec..9ae175a9e10 100644 --- a/pycbc/waveform/waveform.py +++ b/pycbc/waveform/waveform.py @@ -490,12 +490,6 @@ def _lalsim_fd_sequence(**p): for apx in _lalsim_enum: fd_sequence[apx] = _lalsim_fd_sequence -try: - from . import bbhx_waveform_plugin - fd_sequence['BBHX_PhenomD'] = bbhx_waveform_plugin.BBHXWaveformFDInterface - cpu_fd['BBHX_PhenomD'] = fd_sequence['BBHX_PhenomD'] -except ImportError: - pass def get_fd_waveform_sequence(template=None, **kwds): """Return values of the waveform evaluated at the sequence of frequency From cebbf746c88e8ca5d1f0e8312feac82bea21044a Mon Sep 17 00:00:00 2001 From: Connor Date: Fri, 9 Sep 2022 16:28:42 +0200 Subject: [PATCH 12/27] Rel bug fix --- pycbc/inference/models/relbin.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pycbc/inference/models/relbin.py b/pycbc/inference/models/relbin.py index b6d02c1f1f4..486b4ade4a2 100644 --- a/pycbc/inference/models/relbin.py +++ b/pycbc/inference/models/relbin.py @@ -245,7 +245,10 @@ def __init__( # get detector-specific arrival times relative to end of data self.ta[ifo] = -self.end_time[ifo] tshift = numpy.exp(-2.0j * numpy.pi * self.f[ifo] * self.ta[ifo]) - self.h00[ifo] = numpy.array(curr_wav) * tshift + #self.h00[ifo] = numpy.array(curr_wav) * tshift + h00 = numpy.array(curr_wav) * tshift + self.h00[ifo] = h00 + else: fid_hp.resize(len(self.f[ifo])) fid_hc.resize(len(self.f[ifo])) From 03c83cee9ef2b00e6f2d314f3e6f07f550398d2a Mon Sep 17 00:00:00 2001 From: Connor Date: Fri, 9 Sep 2022 17:59:42 +0200 Subject: [PATCH 13/27] Begin no atenna response wf interface --- pycbc/waveform/plugin.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pycbc/waveform/plugin.py b/pycbc/waveform/plugin.py index f47ae9f989b..ea37bf57358 100644 --- a/pycbc/waveform/plugin.py +++ b/pycbc/waveform/plugin.py @@ -18,7 +18,8 @@ def add_custom_waveform(approximant, function, domain, Function evaluates waveform at only chosen points (instead of a equal-spaced grid). """ - from pycbc.waveform.waveform import cpu_fd, cpu_td, fd_sequence + from pycbc.waveform.waveform import cpu_fd, cpu_td, fd_sequence, \ + fd_sequence_no_response used = RuntimeError("Can't load plugin waveform {}, the name is" " already in use.".format(approximant)) From fc787855c3d94b5b7c9e68035d70711b9cdb3c11 Mon Sep 17 00:00:00 2001 From: WuShichao Date: Sat, 10 Sep 2022 22:27:07 +0200 Subject: [PATCH 14/27] remove old bbhx plugin --- pycbc/waveform/bbhx_waveform_plugin.py | 70 -------------------------- 1 file changed, 70 deletions(-) delete mode 100644 pycbc/waveform/bbhx_waveform_plugin.py diff --git a/pycbc/waveform/bbhx_waveform_plugin.py b/pycbc/waveform/bbhx_waveform_plugin.py deleted file mode 100644 index 93ff0b0d314..00000000000 --- a/pycbc/waveform/bbhx_waveform_plugin.py +++ /dev/null @@ -1,70 +0,0 @@ -import numpy as np -from pycbc.types import FrequencySeries, Array -from pycbc import pnutils, conversions -from .waveform import props -from .parameters import location_params - -from bbhx.waveformbuild import BBHWaveformFD - -def BBHXWaveformFDInterface(run_phenomd=True, nyquist_freq=0.1, - sample_points=None, **params): - # Some of this could go into waveform.py eventually. - tmp_params = props(None, **params) - params = location_params.default_dict().copy() - params.update(tmp_params) - - # Is it slow to do this every time?? Does it need caching?? - wave_gen = BBHWaveformFD(amp_phase_kwargs=dict(run_phenomd=run_phenomd)) - - m1 = params['mass1'] - m2 = params['mass2'] - a1 = params['spin1z'] - a2 = params['spin2z'] - dist = pnutils.megaparsecs_to_meters(params['distance']) - phi_ref = params['coa_phase'] - f_ref = 0 # This is now NOT standard LAL convention! - inc = params['inclination'] - lam = params['eclipticlongitude'] - beta = params['eclipticlatitude'] - psi = params['polarization'] - t_ref = params['tc'] - if sample_points is None: - freqs = np.arange(0, nyquist_freq, params['delta_f']) - else: - freqs = sample_points - # FIXME: Must not hardcode this here!! - params['delta_f'] = 1E-8 - modes = [(2,2)] # More modes if not phenomd - direct = False # See the BBHX documentation - fill = True # See the BBHX documentation - squeeze = True # See the BBHX documentation - length = 1024 # An internal generation parameter, not an output parameter - - shift_t_limits = False # Times are relative to merger - t_obs_start = 0.9*conversions.sec_to_year(1. / params['delta_f']) - t_obs_end = 0.0 # Generates ringdown as well! - - wave = wave_gen(m1, m2, a1, a2, - dist, phi_ref, f_ref, inc, lam, - beta, psi, t_ref, freqs=freqs, - modes=modes, direct=direct, fill=fill, squeeze=squeeze, - length=length,t_obs_start=t_obs_start, - t_obs_end=t_obs_end, - shift_t_limits=shift_t_limits)[0] - - # Convert outputs to PyCBC arrays - if sample_points is None: - # If wave[i] was converted to the time-domain, where would the - # merger be within the timeseries (at end? at start?). This is a weird - # convention in BBHX, and is not trivial! - # FIXME: This has not been tested for relative_binning, and - # may not (probably won't) work there! - length_of_wave = 1. / params['delta_f'] - # I don't know why this is what it is. - loc_of_signal_merger_within_wave = t_ref % length_of_wave - output = [FrequencySeries(wave[i], delta_f=params['delta_f'], - epoch=params['tc'] - loc_of_signal_merger_within_wave) - for i in range(3)] - else: - output = [Array(wave[i]) for i in range(3)] - return output From 98786364a8b3dd740b4397f7c4a07f62f52eadf7 Mon Sep 17 00:00:00 2001 From: WuShichao Date: Sat, 10 Sep 2022 22:59:46 +0200 Subject: [PATCH 15/27] add general interface for BBHx --- pycbc/waveform/plugin.py | 25 +++++++++++++++++------ pycbc/waveform/waveform.py | 41 +++++++++++++++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/pycbc/waveform/plugin.py b/pycbc/waveform/plugin.py index f47ae9f989b..1d828c2df7a 100644 --- a/pycbc/waveform/plugin.py +++ b/pycbc/waveform/plugin.py @@ -3,7 +3,8 @@ def add_custom_waveform(approximant, function, domain, - sequence=False, force=False): + sequence=False, has_det_response=False, + force=False,): """ Make custom waveform available to pycbc Parameters @@ -17,8 +18,10 @@ def add_custom_waveform(approximant, function, domain, sequence : bool, False Function evaluates waveform at only chosen points (instead of a equal-spaced grid). + has_det_response : bool, False + Check if waveform generator has built-in detector response. """ - from pycbc.waveform.waveform import cpu_fd, cpu_td, fd_sequence + from pycbc.waveform.waveform import cpu_fd, cpu_td, fd_sequence, fd_det_sequence used = RuntimeError("Can't load plugin waveform {}, the name is" " already in use.".format(approximant)) @@ -29,9 +32,14 @@ def add_custom_waveform(approximant, function, domain, cpu_td[approximant] = function elif domain == 'frequency': if sequence: - if not force and (approximant in fd_sequence): - raise used - fd_sequence[approximant] = function + if has_det_response == False: + if not force and (approximant in fd_sequence): + raise used + fd_sequence[approximant] = function + else: + if not force and (approximant in fd_det_sequence): + raise used + fd_det_sequence[approximant] = function else: if not force and (approximant in cpu_fd): raise used @@ -67,11 +75,16 @@ def retrieve_waveform_plugins(): for plugin in pkg_resources.iter_entry_points('pycbc.waveform.fd'): add_custom_waveform(plugin.name, plugin.resolve(), 'frequency') - # Check for fd sequence waveforms + # Check for fd sequence waveforms (no detector response) for plugin in pkg_resources.iter_entry_points('pycbc.waveform.fd_sequence'): add_custom_waveform(plugin.name, plugin.resolve(), 'frequency', sequence=True) + # Check for fd sequence waveforms (has detector response) + for plugin in pkg_resources.iter_entry_points('pycbc.waveform.fd_det_sequence'): + add_custom_waveform(plugin.name, plugin.resolve(), 'frequency', + sequence=True, has_det_response=True) + # Check for td waveforms for plugin in pkg_resources.iter_entry_points('pycbc.waveform.td'): add_custom_waveform(plugin.name, plugin.resolve(), 'time') diff --git a/pycbc/waveform/waveform.py b/pycbc/waveform/waveform.py index 9ae175a9e10..1370e2187ce 100644 --- a/pycbc/waveform/waveform.py +++ b/pycbc/waveform/waveform.py @@ -467,6 +467,7 @@ def props_sgburst(obj, **kwargs): # Waveform generation ######################################################## fd_sequence = {} +fd_det_sequence = {} def _lalsim_fd_sequence(**p): """ Shim to interface to lalsimulation SimInspiralChooseFDWaveformSequence @@ -493,7 +494,7 @@ def _lalsim_fd_sequence(**p): def get_fd_waveform_sequence(template=None, **kwds): """Return values of the waveform evaluated at the sequence of frequency - points. + points. The waveform generator doesn't include detector response. Parameters ---------- @@ -525,10 +526,43 @@ def get_fd_waveform_sequence(template=None, **kwds): check_args(input_params, required) return wav_gen(**input_params) +def get_fd_det_waveform_sequence(template=None, **kwds): + """Return values of the waveform evaluated at the sequence of frequency + points. The waveform generator includes detector response. + + Parameters + ---------- + template: object + An object that has attached properties. This can be used to substitute + for keyword arguments. A common example would be a row in an xml table. + {params} + + Returns + ------- + htilde: Array + The detector-frame waveform (with detector response) in frequency domain + evaluated at the frequency points. + """ + input_params = props(template, **kwds) + input_params['delta_f'] = -1 + input_params['f_lower'] = -1 + if input_params['approximant'] not in fd_det_sequence: + raise ValueError("Approximant %s not available" % + (input_params['approximant'])) + wav_gen = fd_det_sequence[input_params['approximant']] + if hasattr(wav_gen, 'required'): + required = wav_gen.required + else: + required = parameters.fd_required + check_args(input_params, required) + return wav_gen(**input_params) get_fd_waveform_sequence.__doc__ = get_fd_waveform_sequence.__doc__.format( params=parameters.fd_waveform_sequence_params.docstr(prefix=" ", include_label=False).lstrip(' ')) +get_fd_det_waveform_sequence.__doc__ = get_fd_det_waveform_sequence.__doc__.format( + params=parameters.fd_waveform_sequence_params.docstr(prefix=" ", + include_label=False).lstrip(' ')) def get_td_waveform(template=None, **kwargs): """Return the plus and cross polarizations of a time domain waveform. @@ -1232,7 +1266,7 @@ def get_waveform_filter_length_in_time(approximant, template=None, **kwargs): return None __all__ = ["get_td_waveform", "get_fd_waveform", "get_fd_waveform_sequence", - "get_fd_waveform_from_td", + "get_fd_det_waveform_sequence", "get_fd_waveform_from_td", "print_td_approximants", "print_fd_approximants", "td_approximants", "fd_approximants", "get_waveform_filter", "filter_approximants", @@ -1242,4 +1276,5 @@ def get_waveform_filter_length_in_time(approximant, template=None, **kwargs): "print_sgburst_approximants", "sgburst_approximants", "td_waveform_to_fd_waveform", "get_two_pol_waveform_filter", "NoWaveformError", "FailedWaveformError", "get_td_waveform_from_fd", - 'cpu_fd', 'cpu_td', 'fd_sequence', '_filter_time_lengths'] + 'cpu_fd', 'cpu_td', 'fd_sequence', 'fd_det_sequence', + '_filter_time_lengths'] From 7344620d79629a2d8ffad2e62ef5e1a8f9ca2d0b Mon Sep 17 00:00:00 2001 From: WuShichao Date: Sat, 10 Sep 2022 23:00:25 +0200 Subject: [PATCH 16/27] is_lisa issue not fix yet --- pycbc/inference/models/relbin.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pycbc/inference/models/relbin.py b/pycbc/inference/models/relbin.py index b6d02c1f1f4..98bb9d0ddee 100644 --- a/pycbc/inference/models/relbin.py +++ b/pycbc/inference/models/relbin.py @@ -31,7 +31,7 @@ import itertools from scipy.interpolate import interp1d -from pycbc.waveform import get_fd_waveform_sequence +from pycbc.waveform import get_fd_waveform_sequence,get_fd_det_waveform_sequence from pycbc.detector import Detector from pycbc.types import Array @@ -215,8 +215,8 @@ def __init__( if self.is_lisa: if ifo not in self.init_tdi_wavs: - la, le, lt = get_fd_waveform_sequence(sample_points=fpoints, - **self.fid_params) + la, le, lt = get_fd_det_waveform_sequence(sample_points=fpoints, + **self.fid_params) self.init_tdi_wavs['LISA_A'] = la self.init_tdi_wavs['LISA_E'] = le self.init_tdi_wavs['LISA_T'] = lt @@ -245,7 +245,8 @@ def __init__( # get detector-specific arrival times relative to end of data self.ta[ifo] = -self.end_time[ifo] tshift = numpy.exp(-2.0j * numpy.pi * self.f[ifo] * self.ta[ifo]) - self.h00[ifo] = numpy.array(curr_wav) * tshift + h00 = numpy.array(curr_wav) * tshift + self.h00[ifo] = h00 else: fid_hp.resize(len(self.f[ifo])) fid_hc.resize(len(self.f[ifo])) @@ -370,8 +371,8 @@ def get_waveforms(self, params): """ if self.is_lisa: wf_ret = {} - la, le, lt = get_fd_waveform_sequence(sample_points=self.edge_unique[0], - **params) + la, le, lt = get_fd_det_waveform_sequence(sample_points=self.edge_unique[0], + **params) la = la.numpy() le = le.numpy() lt = lt.numpy() From b619ac68e448262461431da0e6c0a857eaa2438e Mon Sep 17 00:00:00 2001 From: Connor Date: Mon, 12 Sep 2022 11:03:18 +0200 Subject: [PATCH 17/27] Adding test scripts --- examples/lisa/run_inference.sh | 7 +++++++ examples/lisa/simple_inf.sh | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 examples/lisa/run_inference.sh create mode 100644 examples/lisa/simple_inf.sh diff --git a/examples/lisa/run_inference.sh b/examples/lisa/run_inference.sh new file mode 100644 index 00000000000..60c1262213b --- /dev/null +++ b/examples/lisa/run_inference.sh @@ -0,0 +1,7 @@ +#!/bin/sh +pycbc_inference --verbose \ + --config-files configs/0/model_debug-config.ini \ +configs/0/data_debug-config.ini \ +configs/0/sampler_debug-config.ini \ + --output-file inference_test.hdf \ + --force \ No newline at end of file diff --git a/examples/lisa/simple_inf.sh b/examples/lisa/simple_inf.sh new file mode 100644 index 00000000000..c6526bed337 --- /dev/null +++ b/examples/lisa/simple_inf.sh @@ -0,0 +1,7 @@ +#!/bin/sh +pycbc_inference --verbose \ + --config-files simple_run/model_debug-config.ini \ +simple_run/data_debug-config.ini \ +simple_run/sampler_debug-config.ini \ + --output-file simple_test.hdf \ + --force \ No newline at end of file From c3422a7c43c420e5327a67aa3203829a7c20de35 Mon Sep 17 00:00:00 2001 From: Connor Date: Mon, 12 Sep 2022 11:04:41 +0200 Subject: [PATCH 18/27] Plot code for inference --- examples/lisa/plot_gen_mchirp_q.py | 78 ++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 examples/lisa/plot_gen_mchirp_q.py diff --git a/examples/lisa/plot_gen_mchirp_q.py b/examples/lisa/plot_gen_mchirp_q.py new file mode 100644 index 00000000000..42915c0fabd --- /dev/null +++ b/examples/lisa/plot_gen_mchirp_q.py @@ -0,0 +1,78 @@ +import pickle +import numpy as np + +def s_ldc2pycbc(mag, pol): + return mag*np.cos(pol) + +def mr(m1,m2): + return m1/m2 + +def mchi(m1, m2): + return ((m1*m2)**(3/5))/(m1+m2)**(1/5) + +def plt(index): + + with open('param_files/MBHB_params_v2.pkl', 'rb') as f: + pmbhb = pickle.load(f) + + p_index = index + pMBHB = pmbhb[p_index] + + print(pMBHB) + + from ldc.common import tools + + modes = [(2,2)]#, (2,1), (3,3), (3,2), (4,4), (4,3)] + + psi, incl = tools.aziPolAngleL2PsiIncl(pMBHB["EclipticLatitude"], + pMBHB["EclipticLongitude"], + pMBHB['InitialPolarAngleL'], + pMBHB['InitialAzimuthalAngleL']) + + if psi < 0.: + psi = psi + 2*np.pi + + q = mr(pMBHB['Mass1'], pMBHB['Mass2']) + mchirp = mchi(pMBHB['Mass1'],pMBHB['Mass2']) + + params = {'approximant': 'BBHX_PhenomD', + 'mass1': pMBHB['Mass1'], + 'mass2': pMBHB['Mass2'], + 'inclination': incl, + 'tc': pMBHB['CoalescenceTime'], + 'polarization': psi, + 'spin1z': s_ldc2pycbc(pMBHB['Spin1'], pMBHB['PolarAngleOfSpin1']), + 'spin2z': s_ldc2pycbc(pMBHB['Spin2'], pMBHB['PolarAngleOfSpin2']), + 'coa_phase' : pMBHB['PhaseAtCoalescence'], + 'distance': pMBHB['Distance'], + 'eclipticlatitude': pMBHB['EclipticLatitude'], + 'eclipticlongitude': pMBHB['EclipticLongitude'], + 'mchirp':mchirp, + 'q':q, + 'mode_array':modes} + + plot_code = f""" + pycbc_inference_plot_posterior \ + --input-file simple_test.hdf \ + --output-file simple_run_post.png \ + --z-arg snr --plot-scatter --plot-marginal + --parameters \ + mass1_from_mchirp_q(mchirp,q):mass1\ + mass2_from_mchirp_q(mchirp,q):mass2\ + tc\ + --expected-parameters mass1_from_mchirp_q(mchirp,q):{params['mass1']}\ + mass2_from_mchirp_q(mchirp,q):{params['mass2']}\ + tc:{params['tc']} + """ + return plot_code + +import subprocess + +p = [0] + +for i in p:#range(15): + process = subprocess.Popen(plt(i).split(), stdout=subprocess.PIPE) + output, error = process.communicate() + print('rel{} image created'.format(i)) + + From 15ce6d990cd78d7511bb74c69ea869fbc556b094 Mon Sep 17 00:00:00 2001 From: Connor Date: Mon, 12 Sep 2022 15:19:58 +0200 Subject: [PATCH 19/27] Approximant name change --- examples/lisa/plugin_test/test_waveform_plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/lisa/plugin_test/test_waveform_plugin.py b/examples/lisa/plugin_test/test_waveform_plugin.py index 118e8ca34e0..35655ff2337 100644 --- a/examples/lisa/plugin_test/test_waveform_plugin.py +++ b/examples/lisa/plugin_test/test_waveform_plugin.py @@ -15,7 +15,7 @@ def s_ldc2pycbc(mag, pol): modes = [(2,2)] - params = {'approximant': 'connor_bbhx', + params = {'approximant': 'BBHX_PhenomD', 'mass1': pMBHB['Mass1'], 'mass2': pMBHB['Mass2'], 'delta_f':1/31536000, From 01c6265da3b63b159ae12c2546993b3975361f0f Mon Sep 17 00:00:00 2001 From: Connor Date: Tue, 13 Sep 2022 10:52:49 +0200 Subject: [PATCH 20/27] Changed is_lisa flag to checking approximant name against type of waveform being used. --- pycbc/inference/models/relbin.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/pycbc/inference/models/relbin.py b/pycbc/inference/models/relbin.py index 98bb9d0ddee..bd451912975 100644 --- a/pycbc/inference/models/relbin.py +++ b/pycbc/inference/models/relbin.py @@ -31,7 +31,8 @@ import itertools from scipy.interpolate import interp1d -from pycbc.waveform import get_fd_waveform_sequence,get_fd_det_waveform_sequence +from pycbc.waveform import get_fd_waveform_sequence,get_fd_det_waveform_sequence,\ +fd_sequence, fd_det_sequence from pycbc.detector import Detector from pycbc.types import Array @@ -169,8 +170,11 @@ def __init__( variable_params, data, low_frequency_cutoff, **kwargs ) - # FIXME: This should be set properly in some way - self.is_lisa = True + # If the waveform handles the detector response internally, set + # self.det_response = True + self.det_response = False + if self.static_params['approximant'] in fd_det_sequence: + self.det_response = True # reference waveform and bin edges self.f, self.df, self.end_time, self.det = {}, {}, {}, {} @@ -186,7 +190,7 @@ def __init__( self.fid_params = self.static_params.copy() self.fid_params.update(fiducial_params) - if self.is_lisa: + if self.det_response: self.init_tdi_wavs = {} for k in self.static_params: @@ -213,7 +217,7 @@ def __init__( fpoints = Array(self.f[ifo].astype(numpy.float64)) fpoints = fpoints[self.kmin[ifo]:self.kmax[ifo]+1] - if self.is_lisa: + if self.det_response: if ifo not in self.init_tdi_wavs: la, le, lt = get_fd_det_waveform_sequence(sample_points=fpoints, **self.fid_params) @@ -239,7 +243,7 @@ def __init__( "will be %s Hz", f_hi) # make copy of fiducial wfs, adding back in low frequencies - if self.is_lisa: + if self.det_response: curr_wav.resize(len(self.f[ifo])) curr_wav = numpy.roll(curr_wav, self.kmin[ifo]) # get detector-specific arrival times relative to end of data @@ -369,7 +373,7 @@ def summary_product(self, h1, h2, bins, ifo): def get_waveforms(self, params): """ Get the waveform polarizations for each ifo """ - if self.is_lisa: + if self.det_response: wf_ret = {} la, le, lt = get_fd_det_waveform_sequence(sample_points=self.edge_unique[0], **params) @@ -489,7 +493,7 @@ def _loglr(self): # project waveform to detector frame # FIXME: Don't want to do this for LISA!! - if self.is_lisa: + if self.det_response: fp, fc = (1, 0) dt = 0 dtc = -end_time From d571721516e38506e99898a53e57f28e17d1fe07 Mon Sep 17 00:00:00 2001 From: Connor Date: Tue, 13 Sep 2022 11:23:58 +0200 Subject: [PATCH 21/27] Modified cython code with own version of likelihood_parts function for waveforms whcih compute own det response --- pycbc/inference/models/relbin.py | 35 +++++++++++++++++---------- pycbc/inference/models/relbin_cpu.pyx | 32 ++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/pycbc/inference/models/relbin.py b/pycbc/inference/models/relbin.py index bd451912975..d8281d385cb 100644 --- a/pycbc/inference/models/relbin.py +++ b/pycbc/inference/models/relbin.py @@ -38,7 +38,8 @@ from .gaussian_noise import BaseGaussianNoise from .relbin_cpu import (likelihood_parts, likelihood_parts_v, - likelihood_parts_multi, likelihood_parts_multi_v) + likelihood_parts_multi, likelihood_parts_multi_v, + likelihood_parts_det) from .tools import DistMarg @@ -346,7 +347,10 @@ def setup_antenna(self, earth_rotation, fedges): self.mlik = likelihood_parts_multi_v else: atimes = self.fid_params["tc"] - self.lik = likelihood_parts + if self.det_response: + self.lik = likelihood_parts_det + else: + self.lik = likelihood_parts self.mlik = likelihood_parts_multi return atimes @@ -491,12 +495,19 @@ def _loglr(self): end_time = self.end_time[ifo] times = self.antenna_time[ifo] - # project waveform to detector frame - # FIXME: Don't want to do this for LISA!! + # project waveform to detector frame if waveform does not deal + # with detector response. Otherwise, skip detector response. + + hp, hc = wfs[ifo] if self.det_response: - fp, fc = (1, 0) - dt = 0 + fp = 1 dtc = -end_time + hp, hc = wfs[ifo] + hdp, hhp = self.lik(freqs, fp, dtc, + hp, hc, h00, + sdat['a0'], sdat['a1'], + sdat['b0'], sdat['b1']) + self._current_wf_parts[ifo] = (fp, dtc, hp, hc, h00) else: det = self.det[ifo] fp, fc = det.antenna_pattern(p["ra"], p["dec"], @@ -504,13 +515,11 @@ def _loglr(self): dt = det.time_delay_from_earth_center(p["ra"], p["dec"], times) dtc = p["tc"] + dt - end_time - hp, hc = wfs[ifo] - hdp, hhp = self.lik(freqs, fp, fc, dtc, - hp, hc, h00, - sdat['a0'], sdat['a1'], - sdat['b0'], sdat['b1']) - - self._current_wf_parts[ifo] = (fp, fc, dtc, hp, hc, h00) + hdp, hhp = self.lik(freqs, fp, fc, dtc, + hp, hc, h00, + sdat['a0'], sdat['a1'], + sdat['b0'], sdat['b1']) + self._current_wf_parts[ifo] = (fp, fc, dtc, hp, hc, h00) hd += hdp hh += hhp return self.marginalize_loglr(hd, hh) diff --git a/pycbc/inference/models/relbin_cpu.pyx b/pycbc/inference/models/relbin_cpu.pyx index 88f11f49e11..b5ae87ec833 100644 --- a/pycbc/inference/models/relbin_cpu.pyx +++ b/pycbc/inference/models/relbin_cpu.pyx @@ -107,6 +107,38 @@ cpdef likelihood_parts(double [::1] freqs, x0 = x0n return hd, hh +cpdef likelihood_parts_det(double [::1] freqs, + double fp, + double dtc, + double complex[::1] hp, + double complex[::1] hc, + double complex[::1] h00, + double complex[::1] a0, + double complex[::1] a1, + double [::1] b0, + double [::1] b1, + ) : + cdef size_t i + cdef double complex hd=0, r0, r0n, r1, x0, x1, x0n; + cdef double hh=0 + + N = freqs.shape[0] + for i in range(N): + r0n = (exp(-2.0j * 3.141592653 * dtc * freqs[i]) + * (fp * hp[i])) / h00[i] + r1 = r0n - r0 + + x0n = norm(r0n) + x1 = x0n - x0 + + if i > 0: + hd += a0[i-1] * r0 + a1[i-1] * r1 + hh += real(b0[i-1] * x0 + b1[i-1] * x1) + + r0 = r0n + x0 = x0n + return hd, hh + cpdef likelihood_parts_v(double [::1] freqs, double[::1] fp, double[::1] fc, From ada9c53e27a3205cbc4ec8f7b41baf3a2dc4c70d Mon Sep 17 00:00:00 2001 From: Connor Date: Tue, 13 Sep 2022 16:42:04 +0200 Subject: [PATCH 22/27] Error in changing to dictionary output from plugin --- pycbc/inference/models/relbin.py | 34 ++++++++++++--------------- pycbc/inference/models/relbin_cpu.pyx | 1 - pycbc/waveform/waveform.py | 13 +++++----- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/pycbc/inference/models/relbin.py b/pycbc/inference/models/relbin.py index d8281d385cb..70a9a54eb16 100644 --- a/pycbc/inference/models/relbin.py +++ b/pycbc/inference/models/relbin.py @@ -220,12 +220,10 @@ def __init__( if self.det_response: if ifo not in self.init_tdi_wavs: - la, le, lt = get_fd_det_waveform_sequence(sample_points=fpoints, - **self.fid_params) - self.init_tdi_wavs['LISA_A'] = la - self.init_tdi_wavs['LISA_E'] = le - self.init_tdi_wavs['LISA_T'] = lt - curr_wav = self.init_tdi_wavs[ifo] + wave = get_fd_det_waveform_sequence(ifo, + sample_points=fpoints, + **self.fid_params) + curr_wav = wave[ifo] else: fid_hp, fid_hc = get_fd_waveform_sequence(sample_points=fpoints, @@ -378,15 +376,12 @@ def get_waveforms(self, params): """ Get the waveform polarizations for each ifo """ if self.det_response: - wf_ret = {} - la, le, lt = get_fd_det_waveform_sequence(sample_points=self.edge_unique[0], - **params) - la = la.numpy() - le = le.numpy() - lt = lt.numpy() - wf_ret['LISA_A'] = (la, la) - wf_ret['LISA_E'] = (le, le) - wf_ret['LISA_T'] = (lt, lt) + wfs = {} + for ifo in self.data: + wfs = wfs | get_fd_det_waveform_sequence(ifo, + sample_points=self.edge_unique[0], + **params) + return wfs else: wfs = [] for edge in self.edge_unique: @@ -498,17 +493,18 @@ def _loglr(self): # project waveform to detector frame if waveform does not deal # with detector response. Otherwise, skip detector response. - hp, hc = wfs[ifo] if self.det_response: fp = 1 dtc = -end_time - hp, hc = wfs[ifo] + print(wfs[ifo]) + hp = wfs[ifo] hdp, hhp = self.lik(freqs, fp, dtc, - hp, hc, h00, + hp, h00, sdat['a0'], sdat['a1'], sdat['b0'], sdat['b1']) - self._current_wf_parts[ifo] = (fp, dtc, hp, hc, h00) + self._current_wf_parts[ifo] = (fp, dtc, hp, h00) else: + hp, hc = wfs[ifo] det = self.det[ifo] fp, fc = det.antenna_pattern(p["ra"], p["dec"], p["polarization"], times) diff --git a/pycbc/inference/models/relbin_cpu.pyx b/pycbc/inference/models/relbin_cpu.pyx index b5ae87ec833..22cd887e0b2 100644 --- a/pycbc/inference/models/relbin_cpu.pyx +++ b/pycbc/inference/models/relbin_cpu.pyx @@ -111,7 +111,6 @@ cpdef likelihood_parts_det(double [::1] freqs, double fp, double dtc, double complex[::1] hp, - double complex[::1] hc, double complex[::1] h00, double complex[::1] a0, double complex[::1] a1, diff --git a/pycbc/waveform/waveform.py b/pycbc/waveform/waveform.py index 1370e2187ce..8a79b4910ad 100644 --- a/pycbc/waveform/waveform.py +++ b/pycbc/waveform/waveform.py @@ -26,6 +26,7 @@ waveforms. """ +from dataclasses import asdict import os import lal, numpy, copy from pycbc.types import TimeSeries, FrequencySeries, zeros, Array @@ -494,7 +495,7 @@ def _lalsim_fd_sequence(**p): def get_fd_waveform_sequence(template=None, **kwds): """Return values of the waveform evaluated at the sequence of frequency - points. The waveform generator doesn't include detector response. + points. The waveform generator doesn't include detector response. Parameters ---------- @@ -526,9 +527,9 @@ def get_fd_waveform_sequence(template=None, **kwds): check_args(input_params, required) return wav_gen(**input_params) -def get_fd_det_waveform_sequence(template=None, **kwds): +def get_fd_det_waveform_sequence(channel, template=None, **kwds): """Return values of the waveform evaluated at the sequence of frequency - points. The waveform generator includes detector response. + points. The waveform generator includes detector response. Parameters ---------- @@ -539,9 +540,9 @@ def get_fd_det_waveform_sequence(template=None, **kwds): Returns ------- - htilde: Array + dict The detector-frame waveform (with detector response) in frequency domain - evaluated at the frequency points. + evaluated at the frequency points. Keys are requested data channels. """ input_params = props(template, **kwds) input_params['delta_f'] = -1 @@ -555,7 +556,7 @@ def get_fd_det_waveform_sequence(template=None, **kwds): else: required = parameters.fd_required check_args(input_params, required) - return wav_gen(**input_params) + return wav_gen(channel,**input_params) get_fd_waveform_sequence.__doc__ = get_fd_waveform_sequence.__doc__.format( params=parameters.fd_waveform_sequence_params.docstr(prefix=" ", From 327b1f3820f0a90155ab7a5267f3501bc4e88c77 Mon Sep 17 00:00:00 2001 From: Connor Date: Tue, 13 Sep 2022 19:59:28 +0200 Subject: [PATCH 23/27] Fixes to PR request. Mainly reconfiguring due to convention choice of returning data as dict with their data and channel name --- pycbc/inference/models/relbin.py | 20 ++++++++------------ pycbc/inference/models/relbin_cpu.pyx | 4 ++-- pycbc/waveform/waveform.py | 4 ++-- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/pycbc/inference/models/relbin.py b/pycbc/inference/models/relbin.py index 70a9a54eb16..45938c79c12 100644 --- a/pycbc/inference/models/relbin.py +++ b/pycbc/inference/models/relbin.py @@ -31,7 +31,7 @@ import itertools from scipy.interpolate import interp1d -from pycbc.waveform import get_fd_waveform_sequence,get_fd_det_waveform_sequence,\ +from pycbc.waveform import get_fd_waveform_sequence, get_fd_det_waveform_sequence,\ fd_sequence, fd_det_sequence from pycbc.detector import Detector from pycbc.types import Array @@ -192,7 +192,7 @@ def __init__( self.fid_params.update(fiducial_params) if self.det_response: - self.init_tdi_wavs = {} + self.no_det_waves = {} for k in self.static_params: if self.fid_params[k] == 'REPLACE': @@ -219,8 +219,8 @@ def __init__( fpoints = fpoints[self.kmin[ifo]:self.kmax[ifo]+1] if self.det_response: - if ifo not in self.init_tdi_wavs: - wave = get_fd_det_waveform_sequence(ifo, + if ifo not in self.no_det_waves: + wave = get_fd_det_waveform_sequence(ifos=ifo, sample_points=fpoints, **self.fid_params) curr_wav = wave[ifo] @@ -378,8 +378,8 @@ def get_waveforms(self, params): if self.det_response: wfs = {} for ifo in self.data: - wfs = wfs | get_fd_det_waveform_sequence(ifo, - sample_points=self.edge_unique[0], + wfs = wfs | get_fd_det_waveform_sequence(ifos=ifo, + sample_points=self.fedges[ifo], **params) return wfs else: @@ -494,15 +494,11 @@ def _loglr(self): # with detector response. Otherwise, skip detector response. if self.det_response: - fp = 1 dtc = -end_time - print(wfs[ifo]) - hp = wfs[ifo] - hdp, hhp = self.lik(freqs, fp, dtc, - hp, h00, + hp = wfs[ifo].numpy() + hdp, hhp = self.lik(freqs, dtc, hp, h00, sdat['a0'], sdat['a1'], sdat['b0'], sdat['b1']) - self._current_wf_parts[ifo] = (fp, dtc, hp, h00) else: hp, hc = wfs[ifo] det = self.det[ifo] diff --git a/pycbc/inference/models/relbin_cpu.pyx b/pycbc/inference/models/relbin_cpu.pyx index 22cd887e0b2..91541707933 100644 --- a/pycbc/inference/models/relbin_cpu.pyx +++ b/pycbc/inference/models/relbin_cpu.pyx @@ -108,7 +108,6 @@ cpdef likelihood_parts(double [::1] freqs, return hd, hh cpdef likelihood_parts_det(double [::1] freqs, - double fp, double dtc, double complex[::1] hp, double complex[::1] h00, @@ -120,11 +119,12 @@ cpdef likelihood_parts_det(double [::1] freqs, cdef size_t i cdef double complex hd=0, r0, r0n, r1, x0, x1, x0n; cdef double hh=0 + cdef int N N = freqs.shape[0] for i in range(N): r0n = (exp(-2.0j * 3.141592653 * dtc * freqs[i]) - * (fp * hp[i])) / h00[i] + * (hp[i])) / h00[i] r1 = r0n - r0 x0n = norm(r0n) diff --git a/pycbc/waveform/waveform.py b/pycbc/waveform/waveform.py index 8a79b4910ad..6b81efb9a15 100644 --- a/pycbc/waveform/waveform.py +++ b/pycbc/waveform/waveform.py @@ -527,7 +527,7 @@ def get_fd_waveform_sequence(template=None, **kwds): check_args(input_params, required) return wav_gen(**input_params) -def get_fd_det_waveform_sequence(channel, template=None, **kwds): +def get_fd_det_waveform_sequence(template=None, **kwds): """Return values of the waveform evaluated at the sequence of frequency points. The waveform generator includes detector response. @@ -556,7 +556,7 @@ def get_fd_det_waveform_sequence(channel, template=None, **kwds): else: required = parameters.fd_required check_args(input_params, required) - return wav_gen(channel,**input_params) + return wav_gen(**input_params) get_fd_waveform_sequence.__doc__ = get_fd_waveform_sequence.__doc__.format( params=parameters.fd_waveform_sequence_params.docstr(prefix=" ", From d8cacae471e62927dfa0ef3577cc2dd219a2af70 Mon Sep 17 00:00:00 2001 From: Connor Date: Wed, 14 Sep 2022 12:14:46 +0200 Subject: [PATCH 24/27] Code rename conventions --- pycbc/inference/models/relbin.py | 72 ++++++++++++--------------- pycbc/inference/models/relbin_cpu.pyx | 5 +- pycbc/waveform/waveform.py | 9 ++-- 3 files changed, 39 insertions(+), 47 deletions(-) diff --git a/pycbc/inference/models/relbin.py b/pycbc/inference/models/relbin.py index d8281d385cb..a186939dca0 100644 --- a/pycbc/inference/models/relbin.py +++ b/pycbc/inference/models/relbin.py @@ -31,7 +31,7 @@ import itertools from scipy.interpolate import interp1d -from pycbc.waveform import get_fd_waveform_sequence,get_fd_det_waveform_sequence,\ +from pycbc.waveform import get_fd_waveform_sequence, get_fd_det_waveform_sequence,\ fd_sequence, fd_det_sequence from pycbc.detector import Detector from pycbc.types import Array @@ -173,9 +173,9 @@ def __init__( # If the waveform handles the detector response internally, set # self.det_response = True - self.det_response = False + self.no_det_response = False if self.static_params['approximant'] in fd_det_sequence: - self.det_response = True + self.no_det_response = True # reference waveform and bin edges self.f, self.df, self.end_time, self.det = {}, {}, {}, {} @@ -191,8 +191,8 @@ def __init__( self.fid_params = self.static_params.copy() self.fid_params.update(fiducial_params) - if self.det_response: - self.init_tdi_wavs = {} + if self.no_det_response: + self.no_det_waves = {} for k in self.static_params: if self.fid_params[k] == 'REPLACE': @@ -218,14 +218,12 @@ def __init__( fpoints = Array(self.f[ifo].astype(numpy.float64)) fpoints = fpoints[self.kmin[ifo]:self.kmax[ifo]+1] - if self.det_response: - if ifo not in self.init_tdi_wavs: - la, le, lt = get_fd_det_waveform_sequence(sample_points=fpoints, - **self.fid_params) - self.init_tdi_wavs['LISA_A'] = la - self.init_tdi_wavs['LISA_E'] = le - self.init_tdi_wavs['LISA_T'] = lt - curr_wav = self.init_tdi_wavs[ifo] + if self.no_det_response: + if ifo not in self.no_det_waves: + wave = get_fd_det_waveform_sequence(ifos=ifo, + sample_points=fpoints, + **self.fid_params) + curr_wav = wave[ifo] else: fid_hp, fid_hc = get_fd_waveform_sequence(sample_points=fpoints, @@ -244,7 +242,7 @@ def __init__( "will be %s Hz", f_hi) # make copy of fiducial wfs, adding back in low frequencies - if self.det_response: + if self.no_det_response: curr_wav.resize(len(self.f[ifo])) curr_wav = numpy.roll(curr_wav, self.kmin[ifo]) # get detector-specific arrival times relative to end of data @@ -347,7 +345,7 @@ def setup_antenna(self, earth_rotation, fedges): self.mlik = likelihood_parts_multi_v else: atimes = self.fid_params["tc"] - if self.det_response: + if self.no_det_response: self.lik = likelihood_parts_det else: self.lik = likelihood_parts @@ -377,16 +375,13 @@ def summary_product(self, h1, h2, bins, ifo): def get_waveforms(self, params): """ Get the waveform polarizations for each ifo """ - if self.det_response: - wf_ret = {} - la, le, lt = get_fd_det_waveform_sequence(sample_points=self.edge_unique[0], - **params) - la = la.numpy() - le = le.numpy() - lt = lt.numpy() - wf_ret['LISA_A'] = (la, la) - wf_ret['LISA_E'] = (le, le) - wf_ret['LISA_T'] = (lt, lt) + if self.no_det_response: + wfs = {} + for ifo in self.data: + wfs = wfs | get_fd_det_waveform_sequence(ifos=ifo, + sample_points=self.fedges[ifo], + **params) + return wfs else: wfs = [] for edge in self.edge_unique: @@ -484,8 +479,8 @@ def _loglr(self): p.update(self.static_params) wfs = self.get_waveforms(p) - hh = 0.0 - hd = 0j + norm = 0.0 + filter = 0j self._current_wf_parts = {} for ifo in self.data: @@ -498,31 +493,28 @@ def _loglr(self): # project waveform to detector frame if waveform does not deal # with detector response. Otherwise, skip detector response. - hp, hc = wfs[ifo] - if self.det_response: - fp = 1 + if self.no_det_response: dtc = -end_time - hp, hc = wfs[ifo] - hdp, hhp = self.lik(freqs, fp, dtc, - hp, hc, h00, - sdat['a0'], sdat['a1'], - sdat['b0'], sdat['b1']) - self._current_wf_parts[ifo] = (fp, dtc, hp, hc, h00) + channel = wfs[ifo].numpy() + filter_i, norm_i = self.lik(freqs, dtc, channel, h00, + sdat['a0'], sdat['a1'], + sdat['b0'], sdat['b1']) else: + hp, hc = wfs[ifo] det = self.det[ifo] fp, fc = det.antenna_pattern(p["ra"], p["dec"], p["polarization"], times) dt = det.time_delay_from_earth_center(p["ra"], p["dec"], times) dtc = p["tc"] + dt - end_time - hdp, hhp = self.lik(freqs, fp, fc, dtc, + filter_i, norm_i = self.lik(freqs, fp, fc, dtc, hp, hc, h00, sdat['a0'], sdat['a1'], sdat['b0'], sdat['b1']) self._current_wf_parts[ifo] = (fp, fc, dtc, hp, hc, h00) - hd += hdp - hh += hhp - return self.marginalize_loglr(hd, hh) + filter += filter_i + norm += norm_i + return self.marginalize_loglr(filter, norm) def write_metadata(self, fp, group=None): """Adds writing the fiducial parameters and epsilon to file's attrs. diff --git a/pycbc/inference/models/relbin_cpu.pyx b/pycbc/inference/models/relbin_cpu.pyx index b5ae87ec833..91541707933 100644 --- a/pycbc/inference/models/relbin_cpu.pyx +++ b/pycbc/inference/models/relbin_cpu.pyx @@ -108,10 +108,8 @@ cpdef likelihood_parts(double [::1] freqs, return hd, hh cpdef likelihood_parts_det(double [::1] freqs, - double fp, double dtc, double complex[::1] hp, - double complex[::1] hc, double complex[::1] h00, double complex[::1] a0, double complex[::1] a1, @@ -121,11 +119,12 @@ cpdef likelihood_parts_det(double [::1] freqs, cdef size_t i cdef double complex hd=0, r0, r0n, r1, x0, x1, x0n; cdef double hh=0 + cdef int N N = freqs.shape[0] for i in range(N): r0n = (exp(-2.0j * 3.141592653 * dtc * freqs[i]) - * (fp * hp[i])) / h00[i] + * (hp[i])) / h00[i] r1 = r0n - r0 x0n = norm(r0n) diff --git a/pycbc/waveform/waveform.py b/pycbc/waveform/waveform.py index 1370e2187ce..6b81efb9a15 100644 --- a/pycbc/waveform/waveform.py +++ b/pycbc/waveform/waveform.py @@ -26,6 +26,7 @@ waveforms. """ +from dataclasses import asdict import os import lal, numpy, copy from pycbc.types import TimeSeries, FrequencySeries, zeros, Array @@ -494,7 +495,7 @@ def _lalsim_fd_sequence(**p): def get_fd_waveform_sequence(template=None, **kwds): """Return values of the waveform evaluated at the sequence of frequency - points. The waveform generator doesn't include detector response. + points. The waveform generator doesn't include detector response. Parameters ---------- @@ -528,7 +529,7 @@ def get_fd_waveform_sequence(template=None, **kwds): def get_fd_det_waveform_sequence(template=None, **kwds): """Return values of the waveform evaluated at the sequence of frequency - points. The waveform generator includes detector response. + points. The waveform generator includes detector response. Parameters ---------- @@ -539,9 +540,9 @@ def get_fd_det_waveform_sequence(template=None, **kwds): Returns ------- - htilde: Array + dict The detector-frame waveform (with detector response) in frequency domain - evaluated at the frequency points. + evaluated at the frequency points. Keys are requested data channels. """ input_params = props(template, **kwds) input_params['delta_f'] = -1 From b631da5f2be189546194d0457e0126daf4cbce55 Mon Sep 17 00:00:00 2001 From: Connor Date: Wed, 14 Sep 2022 13:29:20 +0200 Subject: [PATCH 25/27] Changes from codeclimate --- pycbc/inference/models/relbin.py | 30 +++++++++++++++--------------- pycbc/waveform/parameters.py | 3 +-- pycbc/waveform/plugin.py | 5 +++-- pycbc/waveform/waveform.py | 6 +++--- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/pycbc/inference/models/relbin.py b/pycbc/inference/models/relbin.py index a186939dca0..883529810eb 100644 --- a/pycbc/inference/models/relbin.py +++ b/pycbc/inference/models/relbin.py @@ -31,8 +31,8 @@ import itertools from scipy.interpolate import interp1d -from pycbc.waveform import get_fd_waveform_sequence, get_fd_det_waveform_sequence,\ -fd_sequence, fd_det_sequence +from pycbc.waveform import get_fd_waveform_sequence,\ +get_fd_det_waveform_sequence, fd_det_sequence from pycbc.detector import Detector from pycbc.types import Array @@ -379,17 +379,17 @@ def get_waveforms(self, params): wfs = {} for ifo in self.data: wfs = wfs | get_fd_det_waveform_sequence(ifos=ifo, - sample_points=self.fedges[ifo], - **params) + sample_points=self.fedges[ifo], + **params) return wfs - else: - wfs = [] - for edge in self.edge_unique: - hp, hc = get_fd_waveform_sequence(sample_points=edge, **params) - hp = hp.numpy() - hc = hc.numpy() - wfs.append((hp, hc)) - wf_ret = {ifo: wfs[self.ifo_map[ifo]] for ifo in self.data} + + wfs = [] + for edge in self.edge_unique: + hp, hc = get_fd_waveform_sequence(sample_points=edge, **params) + hp = hp.numpy() + hc = hc.numpy() + wfs.append((hp, hc)) + wf_ret = {ifo: wfs[self.ifo_map[ifo]] for ifo in self.data} return wf_ret @property @@ -508,9 +508,9 @@ def _loglr(self): dtc = p["tc"] + dt - end_time filter_i, norm_i = self.lik(freqs, fp, fc, dtc, - hp, hc, h00, - sdat['a0'], sdat['a1'], - sdat['b0'], sdat['b1']) + hp, hc, h00, + sdat['a0'], sdat['a1'], + sdat['b0'], sdat['b1']) self._current_wf_parts[ifo] = (fp, fc, dtc, hp, hc, h00) filter += filter_i norm += norm_i diff --git a/pycbc/waveform/parameters.py b/pycbc/waveform/parameters.py index 8b46ce3d5da..925fff39a93 100644 --- a/pycbc/waveform/parameters.py +++ b/pycbc/waveform/parameters.py @@ -26,7 +26,6 @@ """ from collections import OrderedDict -from numpy import dtype try: from collections import UserList except ImportError: @@ -555,7 +554,7 @@ def docstr(self, prefix='', include_label=True): # after a waveform is generated. Distance, however, is a parameter used by # the waveform generators. location_params = ParameterList([tc, ra, dec, polarization, - eclipticlatitude, eclipticlongitude]) + eclipticlatitude, eclipticlongitude]) # parameters describing the orientation of a binary w.r.t. the radiation # frame. Note: we include distance here, as it is typically used for generating diff --git a/pycbc/waveform/plugin.py b/pycbc/waveform/plugin.py index 485bebb46e6..b037519a691 100644 --- a/pycbc/waveform/plugin.py +++ b/pycbc/waveform/plugin.py @@ -21,7 +21,8 @@ def add_custom_waveform(approximant, function, domain, has_det_response : bool, False Check if waveform generator has built-in detector response. """ - from pycbc.waveform.waveform import cpu_fd, cpu_td, fd_sequence, fd_det_sequence + from pycbc.waveform.waveform import cpu_fd, cpu_td, fd_sequence,\ + fd_det_sequence used = RuntimeError("Can't load plugin waveform {}, the name is" " already in use.".format(approximant)) @@ -32,7 +33,7 @@ def add_custom_waveform(approximant, function, domain, cpu_td[approximant] = function elif domain == 'frequency': if sequence: - if has_det_response == False: + if not has_det_response: if not force and (approximant in fd_sequence): raise used fd_sequence[approximant] = function diff --git a/pycbc/waveform/waveform.py b/pycbc/waveform/waveform.py index 6b81efb9a15..7ad0059fe7c 100644 --- a/pycbc/waveform/waveform.py +++ b/pycbc/waveform/waveform.py @@ -26,7 +26,6 @@ waveforms. """ -from dataclasses import asdict import os import lal, numpy, copy from pycbc.types import TimeSeries, FrequencySeries, zeros, Array @@ -541,8 +540,9 @@ def get_fd_det_waveform_sequence(template=None, **kwds): Returns ------- dict - The detector-frame waveform (with detector response) in frequency domain - evaluated at the frequency points. Keys are requested data channels. + The detector-frame waveform (with detector response) in frequency + domain evaluated at the frequency points. Keys are requested data + channels. """ input_params = props(template, **kwds) input_params['delta_f'] = -1 From 3bcf4fa6c0c9c80fa27c10a650dbe0d33143fcbd Mon Sep 17 00:00:00 2001 From: Connor Date: Wed, 14 Sep 2022 14:27:31 +0200 Subject: [PATCH 26/27] More codeclimate changes --- pycbc/inference/models/relbin.py | 25 ++++++++++--------------- pycbc/waveform/plugin.py | 4 ++-- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/pycbc/inference/models/relbin.py b/pycbc/inference/models/relbin.py index 883529810eb..9a95922cf21 100644 --- a/pycbc/inference/models/relbin.py +++ b/pycbc/inference/models/relbin.py @@ -31,8 +31,8 @@ import itertools from scipy.interpolate import interp1d -from pycbc.waveform import get_fd_waveform_sequence,\ -get_fd_det_waveform_sequence, fd_det_sequence +from pycbc.waveform import (get_fd_waveform_sequence, + get_fd_det_waveform_sequence, fd_det_sequence) from pycbc.detector import Detector from pycbc.types import Array @@ -191,9 +191,6 @@ def __init__( self.fid_params = self.static_params.copy() self.fid_params.update(fiducial_params) - if self.no_det_response: - self.no_det_waves = {} - for k in self.static_params: if self.fid_params[k] == 'REPLACE': self.fid_params.pop(k) @@ -219,12 +216,10 @@ def __init__( fpoints = fpoints[self.kmin[ifo]:self.kmax[ifo]+1] if self.no_det_response: - if ifo not in self.no_det_waves: - wave = get_fd_det_waveform_sequence(ifos=ifo, - sample_points=fpoints, - **self.fid_params) + wave = get_fd_det_waveform_sequence(ifos=ifo, + sample_points=fpoints, + **self.fid_params) curr_wav = wave[ifo] - else: fid_hp, fid_hc = get_fd_waveform_sequence(sample_points=fpoints, **self.fid_params) @@ -379,8 +374,8 @@ def get_waveforms(self, params): wfs = {} for ifo in self.data: wfs = wfs | get_fd_det_waveform_sequence(ifos=ifo, - sample_points=self.fedges[ifo], - **params) + sample_points=self.fedges[ifo], + **params) return wfs wfs = [] @@ -480,7 +475,7 @@ def _loglr(self): wfs = self.get_waveforms(p) norm = 0.0 - filter = 0j + filt = 0j self._current_wf_parts = {} for ifo in self.data: @@ -512,9 +507,9 @@ def _loglr(self): sdat['a0'], sdat['a1'], sdat['b0'], sdat['b1']) self._current_wf_parts[ifo] = (fp, fc, dtc, hp, hc, h00) - filter += filter_i + filt += filter_i norm += norm_i - return self.marginalize_loglr(filter, norm) + return self.marginalize_loglr(filt, norm) def write_metadata(self, fp, group=None): """Adds writing the fiducial parameters and epsilon to file's attrs. diff --git a/pycbc/waveform/plugin.py b/pycbc/waveform/plugin.py index b037519a691..9776ca773b4 100644 --- a/pycbc/waveform/plugin.py +++ b/pycbc/waveform/plugin.py @@ -21,8 +21,8 @@ def add_custom_waveform(approximant, function, domain, has_det_response : bool, False Check if waveform generator has built-in detector response. """ - from pycbc.waveform.waveform import cpu_fd, cpu_td, fd_sequence,\ - fd_det_sequence + from pycbc.waveform.waveform import (cpu_fd, cpu_td, fd_sequence, + fd_det_sequence) used = RuntimeError("Can't load plugin waveform {}, the name is" " already in use.".format(approximant)) From 1da6acd22c9ca90cc03e2211369df2928043d2e4 Mon Sep 17 00:00:00 2001 From: Connor Date: Wed, 14 Sep 2022 14:39:25 +0200 Subject: [PATCH 27/27] More codeclimate changes --- pycbc/inference/models/relbin.py | 4 ++-- pycbc/waveform/plugin.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pycbc/inference/models/relbin.py b/pycbc/inference/models/relbin.py index 9a95922cf21..4fe6dd86aa9 100644 --- a/pycbc/inference/models/relbin.py +++ b/pycbc/inference/models/relbin.py @@ -374,8 +374,8 @@ def get_waveforms(self, params): wfs = {} for ifo in self.data: wfs = wfs | get_fd_det_waveform_sequence(ifos=ifo, - sample_points=self.fedges[ifo], - **params) + sample_points=self.fedges[ifo], + **params) return wfs wfs = [] diff --git a/pycbc/waveform/plugin.py b/pycbc/waveform/plugin.py index 9776ca773b4..3f1ccd8901e 100644 --- a/pycbc/waveform/plugin.py +++ b/pycbc/waveform/plugin.py @@ -22,7 +22,7 @@ def add_custom_waveform(approximant, function, domain, Check if waveform generator has built-in detector response. """ from pycbc.waveform.waveform import (cpu_fd, cpu_td, fd_sequence, - fd_det_sequence) + fd_det_sequence) used = RuntimeError("Can't load plugin waveform {}, the name is" " already in use.".format(approximant))