Skip to content

Commit

Permalink
Lisa dev merge (gwastro#4128)
Browse files Browse the repository at this point in the history
* fix waveform_transforms not defined issue

* add static_args back

* fix cc issues

* adopt Ian's changes for LISA

* update for LISA bank

* fix self.ta[ifo] issue

* fix

* fix ta issue

* remove all changes

* Plugin testing script

* remove all hard-coded "BBHx"

* Rel bug fix

* Begin no atenna response wf interface

* remove old bbhx plugin

* add general interface for BBHx

* is_lisa issue not fix yet

* Adding test scripts

* Plot code for inference

* Approximant name change

* Changed is_lisa flag to checking approximant name against type of waveform being used.

* Modified cython code with own version of likelihood_parts function for waveforms whcih compute own det response

* Error in changing to dictionary output from plugin

* Fixes to PR request. Mainly reconfiguring due to convention choice of returning data as dict with their data and channel name

* Code rename conventions

* Changes from codeclimate

* More codeclimate changes

* More codeclimate changes

Co-authored-by: WuShichao <wushichao@mail.bnu.edu.cn>
  • Loading branch information
2 people authored and connor-mcisaac committed Oct 12, 2022
1 parent 44c301c commit b4049d4
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 63 deletions.
4 changes: 3 additions & 1 deletion bin/bank/pycbc_brute_bank
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
137 changes: 92 additions & 45 deletions pycbc/inference/models/relbin.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@
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, fd_det_sequence)
from pycbc.detector import Detector
from pycbc.types import Array

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


Expand Down Expand Up @@ -169,10 +171,17 @@ def __init__(
variable_params, data, low_frequency_cutoff, **kwargs
)

# If the waveform handles the detector response internally, set
# self.det_response = True
self.no_det_response = False
if self.static_params['approximant'] in fd_det_sequence:
self.no_det_response = True

# reference waveform and bin edges
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
Expand All @@ -181,6 +190,7 @@ def __init__(
# store fiducial waveform params
self.fid_params = self.static_params.copy()
self.fid_params.update(fiducial_params)

for k in self.static_params:
if self.fid_params[k] == 'REPLACE':
self.fid_params.pop(k)
Expand All @@ -191,7 +201,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]
Expand All @@ -204,12 +214,20 @@ 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.no_det_response:
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)
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]
Expand All @@ -219,27 +237,36 @@ 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])

# 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.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
self.ta[ifo] = -self.end_time[ifo]
tshift = numpy.exp(-2.0j * numpy.pi * self.f[ifo] * self.ta[ifo])
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]))
hp0 = numpy.roll(fid_hp, self.kmin[ifo])
hc0 = numpy.roll(fid_hc, self.kmin[ifo])

ta = self.fid_params["tc"] + dt - self.end_time[ifo]
tshift = numpy.exp(-2.0j * numpy.pi * self.f[ifo] * ta)
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]

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"])

h00 = (hp0 * fp + hc0 * fc) * tshift
self.h00[ifo] = h00
tshift = numpy.exp(-2.0j * numpy.pi * self.f[ifo] * self.ta)

h00 = (hp0 * fp + hc0 * fc) * tshift
self.h00[ifo] = h00

# compute frequency bins
logging.info("Computing frequency bins")
Expand Down Expand Up @@ -313,7 +340,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.no_det_response:
self.lik = likelihood_parts_det
else:
self.lik = likelihood_parts
self.mlik = likelihood_parts_multi
return atimes

Expand All @@ -340,13 +370,22 @@ def summary_product(self, h1, h2, bins, ifo):
def get_waveforms(self, params):
""" Get the waveform polarizations for each ifo
"""
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

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}
wf_ret = {ifo: wfs[self.ifo_map[ifo]] for ifo in self.data}
return wf_ret

@property
def multi_signal_support(self):
Expand Down Expand Up @@ -435,34 +474,42 @@ def _loglr(self):
p.update(self.static_params)
wfs = self.get_waveforms(p)

hh = 0.0
hd = 0j
norm = 0.0
filt = 0j
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]
end_time = self.end_time[ifo]
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

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)
# project waveform to detector frame if waveform does not deal
# with detector response. Otherwise, skip detector response.

if self.no_det_response:
dtc = -end_time
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

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)
filt += filter_i
norm += norm_i
return self.marginalize_loglr(filt, norm)

def write_metadata(self, fp, group=None):
"""Adds writing the fiducial parameters and epsilon to file's attrs.
Expand Down
31 changes: 31 additions & 0 deletions pycbc/inference/models/relbin_cpu.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,37 @@ cpdef likelihood_parts(double [::1] freqs,
x0 = x0n
return hd, hh

cpdef likelihood_parts_det(double [::1] freqs,
double dtc,
double complex[::1] hp,
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
cdef int N

N = freqs.shape[0]
for i in range(N):
r0n = (exp(-2.0j * 3.141592653 * dtc * freqs[i])
* (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,
Expand Down
7 changes: 4 additions & 3 deletions pycbc/psd/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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!")
Expand Down
2 changes: 1 addition & 1 deletion pycbc/strain/strain.py
Original file line number Diff line number Diff line change
Expand Up @@ -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']


Expand Down
15 changes: 11 additions & 4 deletions pycbc/waveform/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,20 +418,26 @@ 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$",
description="Redshift.")
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
Expand Down Expand Up @@ -547,7 +553,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
Expand Down
Loading

0 comments on commit b4049d4

Please sign in to comment.