Ejemplo n.º 1
0
def fd_sequence(taper_start=None, taper_end=None, **kwds):
    from pycbc.waveform import get_fd_waveform_sequence

    if 'approximant' in kwds:
        kwds.pop("approximant")
    hp, hc = get_fd_waveform_sequence(approximant="TaylorF2", **kwds)

    sam = kwds['sample_points'].numpy()
    flow = sam[0]
    fhigh = sam[-1]

    if taper_start:
        l, r = numpy.searchsorted(sam, [flow, flow + taper_start])
        fval = sam[l:r]
        x = (fval - flow) / taper_start
        w = winl(x)
        hp._data[l:r] *= w
        hc._data[l:r] *= w

    if taper_end:
        l, r = numpy.searchsorted(sam, [fhigh - taper_end, fhigh])
        fval = sam[l:r]
        x = (fval - fhigh + taper_end) / taper_end
        w = winr(x)
        hp._data[l:r] *= w
        hc._data[l:r] *= w

    return hp, hc
Ejemplo n.º 2
0
    def _loglr(self):
        r"""Computes the log likelihood ratio,

        .. math::

            \log \mathcal{L}(\Theta) = \sum_i
                \left<h_i(\Theta)|d_i\right> -
                \frac{1}{2}\left<h_i(\Theta)|h_i(\Theta)\right>,

        at the current parameter values :math:`\Theta`.

        Returns
        -------
        float
            The value of the log likelihood ratio.
        """
        # get model params
        p = self.current_params.copy()
        p.update(self.static_params)

        hh = 0.0
        hd = 0j
        for ifo in self.data:
            # get detector antenna pattern
            fp, fc = self.det[ifo].antenna_pattern(
                p["ra"], p["dec"], p["polarization"], self.antenna_time[ifo]
            )
            # get timeshift relative to end of data
            dt = self.det[ifo].time_delay_from_earth_center(
                p["ra"], p["dec"], p["tc"]
            )
            dtc = p["tc"] + dt - self.end_time[ifo]
            tshift = numpy.exp(-2.0j * numpy.pi * self.fedges[ifo] * dtc)
            # generate template and calculate waveform ratio
            hp, hc = get_fd_waveform_sequence(
                sample_points=Array(self.fedges[ifo]), **p
            )
            htilde = numpy.array(fp * hp + fc * hc) * tshift
            r = (htilde / self.h00_sparse[ifo]).astype(numpy.complex128)
            r0 = r[:-1]
            r1 = (r[1:] - r[:-1]) / (
                self.fedges[ifo][1:] - self.fedges[ifo][:-1]
            )

            # <h, d> is sum over bins of A0r0 + A1r1
            hd += numpy.sum(
                self.sdat[ifo]["a0"] * r0 + self.sdat[ifo]["a1"] * r1
            )
            # <h, h> is sum over bins of B0|r0|^2 + 2B1Re(r1r0*)
            hh += numpy.sum(
                self.sdat[ifo]["b0"] * numpy.absolute(r0) ** 2.0
                + 2.0 * self.sdat[ifo]["b1"] * (r1 * numpy.conjugate(r0)).real
            )
        hd = abs(hd)
        llr = numpy.log(special.i0e(hd)) + hd - 0.5 * hh
        return float(llr)
Ejemplo n.º 3
0
 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}
Ejemplo n.º 4
0
    def __init__(self,
                 variable_params,
                 data,
                 low_frequency_cutoff,
                 fiducial_params=None,
                 epsilon=0.5,
                 **kwargs):
        super(Relative, self).__init__(variable_params, data,
                                       low_frequency_cutoff, **kwargs)
        # check that all of the frequency cutoffs are the same
        # FIXME: this can probably be loosened at some point
        kmins = list(self.kmin.values())
        kmaxs = list(self.kmax.values())
        if any(kk != kmins[0] for kk in kmins):
            raise ValueError("All lower frequency cutoffs must be the same")
        if any(kk != kmaxs[0] for kk in kmaxs):
            raise ValueError("All high frequency cutoffs must be the same")
        # store data and frequencies
        d0 = list(self.data.values())[0]
        self.f = numpy.array(d0.sample_frequencies)
        self.df = d0.delta_f
        self.end_time = float(d0.end_time)
        self.det = {ifo: Detector(ifo) for ifo in self.data}
        self.epsilon = float(epsilon)
        # store data and psds as arrays for faster computation
        self.comp_data = {ifo: d.numpy() for ifo, d in self.data.items()}
        self.comp_psds = {ifo: p.numpy() for ifo, p in self.psds.items()}
        # store fiducial waveform params
        self.fid_params = fiducial_params

        # get detector-specific arrival times relative to end of data
        dt = {
            ifo:
            self.det[ifo].time_delay_from_earth_center(self.fid_params['ra'],
                                                       self.fid_params['dec'],
                                                       self.fid_params['tc'])
            for ifo in self.data
        }
        self.ta = {
            ifo: self.fid_params['tc'] + dt[ifo] - self.end_time
            for ifo in self.data
        }

        # generate fiducial waveform
        f_lo = kmins[0] * self.df
        f_hi = kmaxs[0] * self.df
        logging.info("Generating fiducial waveform from %s to %s Hz", f_lo,
                     f_hi)
        # prune low frequency samples to avoid waveform errors
        nbelow = sum(self.f < 10)
        fpoints = Array(self.f.astype(numpy.float64))[nbelow:]
        approx = self.static_params['approximant']
        fid_hp, fid_hc = get_fd_waveform_sequence(approximant=approx,
                                                  sample_points=fpoints,
                                                  **self.fid_params)
        self.h00 = {}
        for ifo in self.data:
            # make copy of fiducial wfs, adding back in low frequencies
            hp0 = numpy.concatenate([[0j] * nbelow, fid_hp.copy()])
            hc0 = numpy.concatenate([[0j] * nbelow, fid_hc.copy()])
            fp, fc = self.det[ifo].antenna_pattern(
                self.fid_params['ra'], self.fid_params['dec'],
                self.fid_params['polarization'], self.fid_params['tc'])
            tshift = numpy.exp(-2.0j * numpy.pi * self.f * self.ta[ifo])
            self.h00[ifo] = numpy.array(hp0 * fp + hc0 * fc) * tshift

        # compute frequency bins
        logging.info("Computing frequency bins")
        nbin, fbin, fbin_ind = setup_bins(f_full=self.f,
                                          f_lo=kmins[0] * self.df,
                                          f_hi=kmaxs[0] * self.df,
                                          eps=self.epsilon)
        logging.info("Using %s bins for this model", nbin)
        # store bins and edges in sample and frequency space
        self.edges = fbin_ind
        self.fedges = numpy.array(fbin).astype(numpy.float64)
        self.bins = numpy.array([(self.edges[i], self.edges[i + 1])
                                 for i in range(len(self.edges) - 1)])
        self.fbins = numpy.array([(fbin[i], fbin[i + 1])
                                  for i in range(len(fbin) - 1)])
        # store low res copy of fiducial waveform
        self.h00_sparse = {
            ifo: self.h00[ifo].copy().take(self.edges)
            for ifo in self.h00
        }

        # compute summary data
        logging.info("Calculating summary data at frequency resolution %s Hz",
                     self.df)
        self.sdat = self.summary_data()
Ejemplo n.º 5
0
    def __init__(self,
                 variable_params,
                 data,
                 low_frequency_cutoff,
                 fiducial_params=None,
                 gammas=None,
                 epsilon=0.5,
                 vary_polarization=False,
                 **kwargs):
        super(Relative, self).__init__(variable_params, data,
                                       low_frequency_cutoff, **kwargs)

        # check that all of the frequency cutoffs are the same
        # FIXME: this can probably be loosened at some point
        kmins = list(self.kmin.values())
        kmaxs = list(self.kmax.values())
        if any(kk != kmins[0] for kk in kmins):
            raise ValueError("All lower frequency cutoffs must be the same")
        if any(kk != kmaxs[0] for kk in kmaxs):
            raise ValueError("All high frequency cutoffs must be the same")

        # store data and frequencies
        d0 = list(self.data.values())[0]
        self.f = numpy.array(d0.sample_frequencies)
        self.df = d0.delta_f
        self.end_time = float(d0.end_time)
        self.det = {ifo: Detector(ifo) for ifo in self.data}
        self.epsilon = float(epsilon)

        # store data and psds as arrays for faster computation
        self.comp_data = {ifo: d.numpy() for ifo, d in self.data.items()}
        self.comp_psds = {ifo: p.numpy() for ifo, p in self.psds.items()}

        # store fiducial waveform params
        self.fid_params = fiducial_params

        # get detector-specific arrival times relative to end of data
        dt = {
            ifo:
            self.det[ifo].time_delay_from_earth_center(self.fid_params['ra'],
                                                       self.fid_params['dec'],
                                                       self.fid_params['tc'])
            for ifo in self.data
        }
        self.ta = {
            ifo: self.fid_params['tc'] + dt[ifo] - self.end_time
            for ifo in self.data
        }

        # generate fiducial waveform
        f_lo = kmins[0] * self.df
        f_hi = kmaxs[0] * self.df
        logging.info("Generating fiducial waveform from %s to %s Hz", f_lo,
                     f_hi)

        # prune low frequency samples to avoid waveform errors
        nbelow = sum(self.f < f_lo)
        fpoints = Array(self.f.astype(numpy.float64))[nbelow:]
        approx = self.static_params['approximant']
        fid_hp, fid_hc = get_fd_waveform_sequence(approximant=approx,
                                                  sample_points=fpoints,
                                                  **self.fid_params)
        # check for zeros at high frequencies
        numzeros = list(fid_hp[::-1] != 0j).index(True)
        n_above_fhi = (len(self.f) - 1) - kmaxs[0]
        # make sure only nonzero samples are included in bins
        if numzeros > n_above_fhi:
            nremove = numzeros - n_above_fhi
            new_kmax = kmaxs[0] - nremove
            f_hi = new_kmax * self.df
            logging.info(
                "WARNING! Fiducial waveform terminates below "
                "high-frequency-cutoff, final bin frequency "
                "will be %s Hz", f_hi)
        self.h00 = {}
        for ifo in self.data:
            # make copy of fiducial wfs, adding back in low frequencies
            hp0 = numpy.concatenate([[0j] * nbelow, fid_hp.copy()])
            hc0 = numpy.concatenate([[0j] * nbelow, fid_hc.copy()])
            fp, fc = self.det[ifo].antenna_pattern(
                self.fid_params['ra'], self.fid_params['dec'],
                self.fid_params['polarization'], self.fid_params['tc'])
            tshift = numpy.exp(-2.0j * numpy.pi * self.f * self.ta[ifo])
            self.h00[ifo] = numpy.array(hp0 * fp + hc0 * fc) * tshift

        # compute frequency bins
        logging.info("Computing frequency bins")
        nbin, fbin, fbin_ind = setup_bins(f_full=self.f,
                                          f_lo=f_lo,
                                          f_hi=f_hi,
                                          gammas=gammas,
                                          eps=self.epsilon)
        logging.info("Using %s bins for this model", nbin)

        # store bins and edges in sample and frequency space
        self.edges = fbin_ind
        self.fedges = numpy.array(fbin).astype(numpy.float64)
        self.bins = numpy.array([(self.edges[i], self.edges[i + 1])
                                 for i in range(len(self.edges) - 1)])
        self.fbins = numpy.array([(fbin[i], fbin[i + 1])
                                  for i in range(len(fbin) - 1)])
        # store low res copy of fiducial waveform
        self.h00_sparse = {
            ifo: self.h00[ifo].copy().take(self.edges)
            for ifo in self.h00
        }

        # compute summary data
        logging.info("Calculating summary data at frequency resolution %s Hz",
                     self.df)
        self.sdat = self.summary_data()

        # Calculate the times to evaluate fp/fc
        if vary_polarization is not False:
            logging.info('Enabling frequency-dependent polarization')
            from pycbc.waveform.spa_tmplt import spa_length_in_time
            times = spa_length_in_time(phase_order=-1,
                                       mass1=self.fid_params['mass1'],
                                       mass2=self.fid_params['mass2'],
                                       f_lower=self.fedges)
            self.antenna_time = self.fid_params['tc'] - times
        else:
            self.antenna_time = self.fid_params['tc']
Ejemplo n.º 6
0
    def __init__(
        self,
        variable_params,
        data,
        low_frequency_cutoff,
        fiducial_params=None,
        gammas=None,
        epsilon=0.5,
        vary_polarization=False,
        **kwargs
    ):
        super(Relative, self).__init__(
            variable_params, data, low_frequency_cutoff, **kwargs
        )

        self.epsilon = float(epsilon)

        # reference waveform and bin edges
        self.h00, self.h00_sparse = {}, {}
        self.f, self.df, self.end_time, self.det = {}, {}, {}, {}
        self.edges, self.fedges, self.bins, self.fbins = {}, {}, {}, {}
        self.ta = {}
        self.antenna_time = {}

        # filtered summary data for linear approximation
        self.sdat = {}

        # store data and psds as arrays for faster computation
        self.comp_data = {ifo: d.numpy() for ifo, d in self.data.items()}
        self.comp_psds = {ifo: p.numpy() for ifo, p in self.psds.items()}

        # store fiducial waveform params
        self.fid_params = fiducial_params

        for ifo in data:
            # store data and frequencies
            d0 = self.data[ifo]
            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)

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

            self.ta[ifo] = self.fid_params["tc"] + dt - self.end_time[ifo]

            # generate fiducial waveform
            f_lo = self.kmin[ifo] * self.df[ifo]
            f_hi = self.kmax[ifo] * self.df[ifo]
            logging.info(
                "%s: Generating fiducial waveform from %s to %s Hz",
                ifo,
                f_lo,
                f_hi,
            )

            # prune low frequency samples to avoid waveform errors
            nbelow = sum(self.f[ifo] < f_lo)
            fpoints = Array(self.f[ifo].astype(numpy.float64))[nbelow:]
            approx = self.static_params["approximant"]
            fid_hp, fid_hc = get_fd_waveform_sequence(
                approximant=approx, sample_points=fpoints, **self.fid_params
            )
            # check for zeros at high frequencies
            numzeros = list(fid_hp[::-1] != 0j).index(True)
            n_above_fhi = (len(self.f[ifo]) - 1) - self.kmax[ifo]
            # make sure only nonzero samples are included in bins
            if numzeros > n_above_fhi:
                nremove = numzeros - n_above_fhi
                new_kmax = self.kmax[ifo] - nremove
                f_hi = new_kmax * self.df[ifo]
                logging.info(
                    "WARNING! Fiducial waveform terminates below "
                    "high-frequency-cutoff, final bin frequency "
                    "will be %s Hz",
                    f_hi,
                )

            # make copy of fiducial wfs, adding back in low frequencies
            hp0 = numpy.concatenate([[0j] * nbelow, fid_hp.copy()])
            hc0 = numpy.concatenate([[0j] * nbelow, fid_hc.copy()])
            fp, fc = self.det[ifo].antenna_pattern(
                self.fid_params["ra"],
                self.fid_params["dec"],
                self.fid_params["polarization"],
                self.fid_params["tc"],
            )
            tshift = numpy.exp(-2.0j * numpy.pi * self.f[ifo] * self.ta[ifo])
            self.h00[ifo] = numpy.array(hp0 * fp + hc0 * fc) * tshift

            # compute frequency bins
            logging.info("Computing frequency bins")
            nbin, fbin, fbin_ind = setup_bins(
                f_full=self.f[ifo],
                f_lo=f_lo,
                f_hi=f_hi,
                gammas=gammas,
                eps=self.epsilon,
            )
            logging.info("Using %s bins for this model", nbin)

            # store bins and edges in sample and frequency space
            self.edges[ifo] = fbin_ind
            self.fedges[ifo] = numpy.array(fbin).astype(numpy.float64)
            self.bins[ifo] = numpy.array(
                [
                    (self.edges[ifo][i], self.edges[ifo][i + 1])
                    for i in range(len(self.edges[ifo]) - 1)
                ]
            )
            self.fbins[ifo] = numpy.array(
                [(fbin[i], fbin[i + 1]) for i in range(len(fbin) - 1)]
            )

            # store low res copy of fiducial waveform
            self.h00_sparse[ifo] = self.h00[ifo].copy().take(self.edges[ifo])

            # compute summary data
            logging.info(
                "Calculating summary data at frequency resolution %s Hz",
                self.df[ifo],
            )
            self.sdat[ifo] = self.summary_data(ifo)

            # Calculate the times to evaluate fp/fc
            if vary_polarization is not False:
                logging.info("Enabling frequency-dependent polarization")
                from pycbc.waveform.spa_tmplt import spa_length_in_time

                times = spa_length_in_time(
                    phase_order=-1,
                    mass1=self.fid_params["mass1"],
                    mass2=self.fid_params["mass2"],
                    f_lower=self.fedges[ifo],
                )
                self.antenna_time[ifo] = self.fid_params["tc"] - times
            else:
                self.antenna_time[ifo] = self.fid_params["tc"]
Ejemplo n.º 7
0
    def __init__(self,
                 variable_params,
                 data,
                 low_frequency_cutoff,
                 fiducial_params=None,
                 gammas=None,
                 epsilon=0.5,
                 earth_rotation=False,
                 marginalize_phase=True,
                 **kwargs):

        variable_params, kwargs = self.setup_distance_marginalization(
            variable_params, marginalize_phase=marginalize_phase, **kwargs)

        super(Relative, self).__init__(variable_params, data,
                                       low_frequency_cutoff, **kwargs)

        self.epsilon = float(epsilon)

        # reference waveform and bin edges
        self.h00, self.h00_sparse = {}, {}
        self.f, self.df, self.end_time, self.det = {}, {}, {}, {}
        self.edges, self.fedges, self.bins, self.fbins = {}, {}, {}, {}
        self.ta = {}
        self.antenna_time = {}

        # filtered summary data for linear approximation
        self.sdat = {}

        # store data and psds as arrays for faster computation
        self.comp_data = {ifo: d.numpy() for ifo, d in self.data.items()}
        self.comp_psds = {ifo: p.numpy() for ifo, p in self.psds.items()}

        # store fiducial waveform params
        self.fid_params = self.static_params.copy()
        self.fid_params.update(fiducial_params)

        for ifo in data:
            # store data and frequencies
            d0 = self.data[ifo]
            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)

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

            self.ta[ifo] = self.fid_params["tc"] + dt - self.end_time[ifo]

            # generate fiducial waveform
            f_lo = self.kmin[ifo] * self.df[ifo]
            f_hi = self.kmax[ifo] * self.df[ifo]
            logging.info(
                "%s: Generating fiducial waveform from %s to %s Hz",
                ifo,
                f_lo,
                f_hi,
            )

            # 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)

            # check for zeros at high frequencies
            # make sure only nonzero samples are included in bins
            numzeros = list(fid_hp[::-1] != 0j).index(True)
            if numzeros > 0:
                new_kmax = self.kmax[ifo] - numzeros
                f_hi = new_kmax * self.df[ifo]
                logging.info(
                    "WARNING! Fiducial waveform terminates below "
                    "high-frequency-cutoff, final bin frequency "
                    "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])

            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] * self.ta[ifo])
            self.h00[ifo] = numpy.array(hp0 * fp + hc0 * fc) * tshift

            # compute frequency bins
            logging.info("Computing frequency bins")
            nbin, fbin, fbin_ind = setup_bins(
                f_full=self.f[ifo],
                f_lo=f_lo,
                f_hi=f_hi,
                gammas=gammas,
                eps=self.epsilon,
            )
            logging.info("Using %s bins for this model", nbin)

            # store bins and edges in sample and frequency space
            self.edges[ifo] = fbin_ind
            self.fedges[ifo] = numpy.array(fbin).astype(numpy.float64)
            self.bins[ifo] = numpy.array([
                (self.edges[ifo][i], self.edges[ifo][i + 1])
                for i in range(len(self.edges[ifo]) - 1)
            ])
            self.fbins[ifo] = numpy.array([(fbin[i], fbin[i + 1])
                                           for i in range(len(fbin) - 1)])

            # store low res copy of fiducial waveform
            self.h00_sparse[ifo] = self.h00[ifo].copy().take(self.edges[ifo])

            # compute summary data
            logging.info(
                "Calculating summary data at frequency resolution %s Hz",
                self.df[ifo],
            )
            self.sdat[ifo] = self.summary_data(ifo)

            # Calculate the times to evaluate fp/fc
            if earth_rotation is not False:
                logging.info("Enabling frequency-dependent earth rotation")
                from pycbc.waveform.spa_tmplt import spa_length_in_time

                times = spa_length_in_time(
                    phase_order=-1,
                    mass1=self.fid_params["mass1"],
                    mass2=self.fid_params["mass2"],
                    f_lower=self.fedges[ifo],
                )
                self.antenna_time[ifo] = self.fid_params["tc"] - times
                self.lik = likelihood_parts_v
            else:
                self.antenna_time[ifo] = self.fid_params["tc"]
                self.lik = likelihood_parts

        # determine the unique ifo layouts
        self.edge_unique = []
        self.ifo_map = {}
        for ifo in self.fedges:
            if len(self.edge_unique) == 0:
                self.ifo_map[ifo] = 0
                self.edge_unique.append(Array(self.fedges[ifo]))
            else:
                for i, edge in enumerate(self.edge_unique):
                    if numpy.array_equal(edge, self.fedges[ifo]):
                        self.ifo_map[ifo] = i
                        break
                else:
                    self.ifo_map[ifo] = len(self.edge_unique)
                    self.edge_unique.append(Array(self.fedges[ifo]))
        logging.info("%s unique ifo layouts", len(self.edge_unique))
Ejemplo n.º 8
0
    def __init__(
        self,
        variable_params,
        data,
        low_frequency_cutoff,
        fiducial_params=None,
        gammas=None,
        epsilon=0.5,
        earth_rotation=False,
        marginalize_phase=True,
        **kwargs
    ):

        variable_params, kwargs = self.setup_distance_marginalization(
                               variable_params,
                               marginalize_phase=marginalize_phase,
                               **kwargs)

        super(Relative, self).__init__(
            variable_params, data, low_frequency_cutoff, **kwargs
        )

        # reference waveform and bin edges
        self.f, self.df, self.end_time, self.det = {}, {}, {}, {}
        self.h00, self.h00_sparse = {}, {}
        self.fedges, self.edges = {}, {}
        self.antenna_time = {}

        # filtered summary data for linear approximation
        self.sdat = {}

        # 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)

        for ifo in data:
            # store data and frequencies
            d0 = self.data[ifo]
            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)

            # generate fiducial waveform
            f_lo = self.kmin[ifo] * self.df[ifo]
            f_hi = self.kmax[ifo] * self.df[ifo]
            logging.info(
                "%s: Generating fiducial waveform from %s to %s Hz",
                ifo, f_lo, f_hi,
            )

            # 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)

            # check for zeros at high frequencies
            # make sure only nonzero samples are included in bins
            numzeros = list(fid_hp[::-1] != 0j).index(True)
            if numzeros > 0:
                new_kmax = self.kmax[ifo] - numzeros
                f_hi = new_kmax * self.df[ifo]
                logging.info(
                    "WARNING! Fiducial waveform terminates below "
                    "high-frequency-cutoff, final bin frequency "
                    "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"],
            )

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

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

            # compute frequency bins
            logging.info("Computing frequency bins")
            fbin_ind = setup_bins(
                f_full=self.f[ifo], f_lo=f_lo, f_hi=f_hi,
                gammas=gammas, eps=float(epsilon),
            )
            logging.info("Using %s bins for this model", len(fbin_ind))

            self.fedges[ifo] = self.f[ifo][fbin_ind]
            self.edges[ifo] = fbin_ind

            self.init_from_frequencies(h00, fbin_ind, ifo)
            self.antenna_time[ifo] = self.setup_antenna(earth_rotation,
                                                        self.fedges[ifo])
        self.combine_layout()