Пример #1
0
    def test_coordinate_retarded_times(self):

        # Schwarzschild_radius_to_tortoise
        self.assertAlmostEqual(gwu.Schwarzschild_radius_to_tortoise(2, 0.5), 2)

        # Test with array
        rr = np.array([2, 2])
        self.assertCountEqual(gwu.Schwarzschild_radius_to_tortoise(rr, 0.5),
                              rr)

        # retarded_times_to_coordinate_times
        # Scalar
        self.assertAlmostEqual(
            gwu.retarded_times_to_coordinate_times(1, 2, 0.5), 3)

        # Array
        ones = np.ones(2)
        self.assertCountEqual(
            gwu.retarded_times_to_coordinate_times(ones, rr, 0.5), rr + 1)

        # coordinate_times_to_retarded_times
        #
        # To test this, we just check that the composition with
        # retarded_times_to_coordinate_times is the identity
        self.assertCountEqual(
            gwu._coordinate_times_to_retarded_times(
                gwu.retarded_times_to_coordinate_times(ones, rr, 0.5), rr,
                0.5),
            ones,
        )
Пример #2
0
    def extrapolate_strain_lm_to_infinity(
        self,
        mult_l,
        mult_m,
        pcut,
        detectors_distances,
        retarded_times,
        *args,
        window_function=None,
        trim_ends=True,
        mass=1,
        order=2,
        extrapolate_amplitude_phase=False,
        **kwargs,
    ):
        """Extrapolate strains to spatial infinity with the method described in 1307.5307.

        If ``extrapolate_amplitude_phase`` is True, extrapolate amplitude and
        phase of the complex strain instead of real and imaginary parts.

        TODO: Test this function!

        [Equation (29)]

        :param mult_l: Multipolar component l.
        :type mult_l: int
        :param mult_m: Multipolar component m.
        :type mult_m: int
        :param pcut: Period that enters the fixed-frequency integration.
                     Typically, the longest physical period in the signal.
        :type pcut: float
        :param retarded_times: Times at which the waves have to be evaluated
        :type retarded_times: float or 1D NumPy array
        :param detectors_distances: Extraction radii
        :type detectors_distances: 1D NumPy array
        :param mass: ADM mass of the system
        :type mass: float
        :param order: Order of the extrapolation.
        :type order: int
        :param window_function: If not None, apply window_function to the
                                series before computing the strain.
        :type window_function: callable, str, or None
        :param trim_ends: If True, a portion of the resulting strain is removed
                          at both the initial and final times. The amount removed
                          is equal to pcut.
        :type trim_ends: bool
        :param extrapolate_amplitude_phase: If True, extrapolate phase and amplitude, if
                                            False, extrapolate real and imaginary parts.
        :type extrapolate_amplitude_phase: int

        :returns: Waves evaluated at the retarded times.
        :rtype: List of :py:class:`~.TimeSeries`

        """

        dists = np.sort(detectors_distances)

        # Strains are in the form r * h_+ - i r * h_cross
        strains = [
            self[dist].get_strain_lm(
                mult_l,
                mult_m,
                pcut,
                *args,
                window_function=window_function,
                trim_ends=trim_ends,
                **kwargs,
            ) for dist in dists
        ]

        # Resample the waves to have all the same retarded times
        strains_resampled = [
            strain.resampled(
                gw_utils.retarded_times_to_coordinate_times(
                    retarded_times, dist, mass))
            for strain, dist in zip(strains, dists)
        ]

        if not extrapolate_amplitude_phase:
            extrapolated = self._extrapolate_waves_to_infinity(
                strains_resampled,
                retarded_times,
                dists,
                mass,
                order=order,
            )
        else:
            strains_amplitudes = [s.abs() for s in strains_resampled]
            strains_phases = [s.unfolded_phase() for s in strains_resampled]

            extrapolated_amp = self._extrapolate_waves_to_infinity(
                strains_amplitudes,
                retarded_times,
                dists,
                mass,
                order=order,
            )
            extrapolated_phase = self._extrapolate_waves_to_infinity(
                strains_phases,
                retarded_times,
                dists,
                mass,
                order=order,
            )

            extrapolated = extrapolated_amp * np.exp(1j * extrapolated_phase)

        return extrapolated
Пример #3
0
    def _extrapolate_waves_to_infinity(waves, times, radii, mass=1, order=2):
        """Extrapolate ``waves`` to infinity and evaluate the result on the given
        ``times``.

        We follow what described in 1307.5307.

        In practice, ``waves`` is a list of strains at the extraction radii ``radii``.

        :param waves: Waves that have to be extrapolated (strains computed at
                      different radii).
        :type waves: list of :py:class:`~.TimeSeries`
        :param times: Times at which the waves have to be evaluated
        :type times: float or 1D NumPy array
        :param radii: Extraction radii. It has to be that radii[i] correspond to
                      waves[i].
        :type radii: float or 1D NumPy array
        :param mass: ADM mass of the system.
        :type mass: float
        :param order: Order of the extrapolation.
        :type order: int

        :returns: Waves evaluated at the retarded times.
        :rtype: List of :py:class:`~.TimeSeries`

        """

        # Follows what done in the NRAR collaboration (1307.5307)
        # This is what we are going to do:

        # 1. Assume that the spacetime is almost Schwarzschild with mass mass.
        # 2. Choose a set of retarded times u_i where GWs have to be evaluated
        # 3. Compute the coordinate times t_i that correspond to the retarded
        #    times u_i at the radius r. This uses tortoise coordinates.
        # 4. Interpolate the waveforms at the coordinate times corresponding to
        #    the retarded times u_i for different extraction radii.
        #    Now our waves are so that they are evaluated at different t_i but
        #    at the same u_i.
        # 5. We do this process for a bunch of extraction radii
        #    (rex1, rex2, rex3, ...)
        #    So, we should have wave1, wave2, wave3, with all the same number
        #    of points that correspond to the same retarded time.
        # 6. For each element in u_i, fit all the waves (wave1, wave2, ...)
        #    with a polynomial of the form a_n/r^n.

        if order >= len(radii):
            raise RuntimeError(
                "Order too high for the number of extraction radii provided")

        if len(radii) != len(waves):
            raise RuntimeError(
                "Numbers of extraction radii and waves do not agree")
        # Make sure radii is an array
        radii = np.array(radii)

        # First, we resample the waves so that they have all the same retarded
        # times.
        #
        # Take the timeseries w, and return a timeseries evaluated at
        # coordinate times that correspond to the retarded times ui at the
        # coordinate extraction radius rex. mass is the ADM mass (needed to
        # compute tortoise radius).
        waves_retarded = [
            w.resampled(
                gw_utils.retarded_times_to_coordinate_times(times, r, mass))
            for w, r in zip(waves, radii)
        ]

        # We perform the fit in ir=1/r instead of r
        # So, technically, we are fitting sum^p_n=0 a_n * ir^n
        inverse_radii = 1.0 / radii

        # waves_matrix is a table. Each line is a different time, each column
        # is a different extraction radius. We will polyfit on every fixed line
        # to get the extrapolated waves.
        waves_matrix = np.vstack([w.y for w in waves_retarded]).T

        # Polyfit returns coefficient ordered from the highest to the lowest
        # This is why we take the [-1]
        extrapolated_wave = [
            np.polyfit(inverse_radii, waves_at_t, order)[-1]
            for waves_at_t in waves_matrix
        ]

        return ts.TimeSeries(times, extrapolated_wave)