示例#1
0
def test_trivial_multiplication(multiplication_function):
    """Test 1*g and g*1

    We test trivial multiplication by 1.  The modes of the `1` function are just sqrt(4*pi) for the
    (ell,m)=(0,0) mode, and 0 for everything else.  Even though this can be described by just the
    first element, we test this for each ellmax_f up to 8 just to make sure the multiplication
    function works as expected.  This is multiplied by a function with random values input for its
    modes.

    """
    np.random.seed(1234)
    atol = 2e-15
    rtol = 2e-15
    ellmax_g = 8
    for ellmax_f in range(1, ellmax_g):
        f = np.zeros(sf.LM_total_size(0, ellmax_f), dtype=np.complex)
        f[0] = np.sqrt(4*np.pi)
        ellmin_f = 0
        s_f = 0
        ellmin_g = 0
        for s_g in range(1-ellmax_g, ellmax_g):
            i_max = sf.LM_index(ellmax_g, ellmax_g, ellmin_g)
            g = np.random.rand(sf.LM_total_size(0, ellmax_g)) + 1j*np.random.rand(sf.LM_total_size(0, ellmax_g))
            g[:sf.LM_total_size(0, abs(s_g)-1)+1] = 0.0
            fg, ellmin_fg, ellmax_fg, s_fg = multiplication_function(f, ellmin_f, ellmax_f, s_f, g, ellmin_g, ellmax_g, s_g)
            assert s_fg == s_f + s_g
            assert ellmin_fg == 0
            assert ellmax_fg == ellmax_f + ellmax_g
            assert np.allclose(fg[:i_max+1], g[:i_max+1], atol=atol, rtol=rtol)
            gf, ellmin_gf, ellmax_gf, s_gf = multiplication_function(g, ellmin_g, ellmax_g, s_g, f, ellmin_f, ellmax_f, s_f)
            assert s_gf == s_g + s_f
            assert ellmin_gf == 0
            assert ellmax_gf == ellmax_g + ellmax_f
            assert np.allclose(gf[:i_max+1], g[:i_max+1], atol=atol, rtol=rtol)
示例#2
0
    def to_modes(self, ell_max=None, ell_min=None):
        """Transform to modes of a spin-weighted spherical harmonic expansion

        Parameters
        ----------
        self : WaveformGrid object
            This is the object to be transformed to SWSH modes
        ell_max : int, optional
            The largest ell value to include in the output data.  Default value
            is deduced from n_theta and n_phi.
        ell_min : int, optional
            The smallest ell value to include in the output data.  Default value
            is abs(spin_weight).

        """
        s = SpinWeights[self.dataType]
        if ell_max is None:
            ell_max = int((max(self.n_theta, self.n_phi) - 1) // 2)
        if ell_min is None:
            ell_min = abs(s)
        if not isinstance(ell_max, numbers.Integral) or ell_max < 0:
            raise ValueError(f"Input `ell_max` should be a nonnegative integer; got `{ell_max}`.")
        if not isinstance(ell_min, numbers.Integral) or ell_min < 0 or ell_min > ell_max:
            raise ValueError(f"Input `ell_min` should be an integer between 0 and {ell_max}; got `{ell_min}`.")

        final_dim = int(np.prod(self.data.shape[2:]))
        old_data = self.data.reshape((self.n_times, self.n_theta, self.n_phi, final_dim))
        new_data = np.empty((self.n_times, sf.LM_total_size(ell_min, ell_max), final_dim), dtype=complex)
        # Note that spinsfast returns all modes, including ell<abs(s).  So we just chop those off
        for i_time in range(self.n_times):
            for i_final in range(final_dim):
                new_data[i_time, :, i_final] = spinsfast.map2salm(old_data[i_time, :, :, i_final], s, ell_max)[
                    sf.LM_index(ell_min, -ell_min, 0) :
                ]
        new_data = new_data.reshape((self.n_times, sf.LM_total_size(ell_min, ell_max)) + self.data.shape[2:])

        # old_data = self.data.reshape((self.n_times, self.n_theta, self.n_phi)+self.data.shape[2:])
        # new_data = np.empty((self.n_times, sf.LM_total_size(ell_min, ell_max))+self.data.shape[2:], dtype=complex)
        # # Note that spinsfast returns all modes, including ell<abs(s).  So we just chop those off
        # for i_time in range(self.n_times):
        #     new_data[i_time, :] = spinsfast.map2salm(old_data[i_time, :, :], s, ell_max)\
        #         [sf.LM_index(ell_min, -ell_min, 0):]

        m = WaveformModes(
            t=self.t,
            data=new_data,
            history=self.history,
            ell_min=ell_min,
            ell_max=ell_max,
            frameType=self.frameType,
            dataType=self.dataType,
            r_is_scaled_out=self.r_is_scaled_out,
            m_is_scaled_out=self.m_is_scaled_out,
            constructor_statement=f"{self}.to_modes({ell_max})",
        )
        return m
示例#3
0
def kerr_schild(mass, spin, ell_max=8):
    psi2 = np.zeros(sf.LM_total_size(0, ell_max), dtype=complex)
    psi1 = np.zeros(sf.LM_total_size(0, ell_max), dtype=complex)
    psi0 = np.zeros(sf.LM_total_size(0, ell_max), dtype=complex)

    # In the Moreschi-Boyle convention
    psi2[0] = -sf.constant_as_ell_0_mode(mass)
    psi1[2] = -np.sqrt(2) * (3j * spin / 2) * (np.sqrt((8 / 3) * np.pi))
    psi0[6] = 2 * (3 * spin ** 2 / mass / 2) * (np.sqrt((32 / 15) * np.pi))

    return psi2, psi1, psi0
def test_eth_derivation(eth, spin_weight_of_eth):
    """Ensure that the various `eth` operators are derivations -- i.e., they obey the Leibniz product law

    Given two spin-weighted functions `f` and `g`, we need to test that

        eth(f * g) = eth(f) * g + f * eth(g)

    This test generates a set of random modes with equal power for `f` and `g` (though more realistic functions can
    be expected to have exponentially decaying mode amplitudes).  Because of the large power in high-ell modes,
    we need to double the number of modes in the representation of their product, which is why we use

        n_theta = n_phi = 4 * ell_max + 1

    These `f` and `g` functions must be transformed to the physical-space representation, multiplied there,
    the product transformed back to spectral space, the eth operator evaluated, and then transformed back again to
    physical space for comparison.

    We test both the Newman-Penrose and Geroch-Held-Penrose versions of eth, as well as their conjugates.

    """
    import spinsfast
    ell_max = 16
    n_modes = sf.LM_total_size(0, ell_max)
    n_theta = n_phi = 4 * ell_max + 1
    for s1 in range(-2, 2 + 1):
        for s2 in range(-s1, s1 + 1):
            np.random.seed(1234)
            ell_min1 = abs(s1)
            ell_min2 = abs(s2)
            f = np.random.rand(n_modes) + 1j * np.random.rand(n_modes)
            f[:sf.LM_total_size(0, ell_min1 - 1)] = 0j
            f_j_k = spinsfast.salm2map(f, s1, ell_max, n_theta, n_phi)
            g = np.random.rand(n_modes) + 1j * np.random.rand(n_modes)
            g[:sf.LM_total_size(0, ell_min2 - 1)] = 0j
            g_j_k = spinsfast.salm2map(g, s2, ell_max, n_theta, n_phi)
            fg_j_k = f_j_k * g_j_k
            fg = spinsfast.map2salm(fg_j_k, s1 + s2, 2 * ell_max)
            ethf = eth(f, s1, ell_min=0)
            ethg = eth(g, s2, ell_min=0)
            ethfg = eth(fg, s1 + s2, ell_min=0)
            ethf_j_k = spinsfast.salm2map(ethf, s1 + spin_weight_of_eth,
                                          ell_max, n_theta, n_phi)
            ethg_j_k = spinsfast.salm2map(ethg, s2 + spin_weight_of_eth,
                                          ell_max, n_theta, n_phi)
            ethfg_j_k = spinsfast.salm2map(ethfg, s1 + s2 + spin_weight_of_eth,
                                           2 * ell_max, n_theta, n_phi)
            assert np.allclose(ethfg_j_k,
                               ethf_j_k * g_j_k + f_j_k * ethg_j_k,
                               rtol=1e-10,
                               atol=1e-10)
示例#5
0
def test_modes_squared_angular_momenta():
    tolerance = 1e-13
    np.random.seed(1234)
    L2 = sf.Modes.Lsquared
    Lz = sf.Modes.Lz
    Lp = sf.Modes.Lplus
    Lm = sf.Modes.Lminus
    R2 = sf.Modes.Rsquared
    Rz = sf.Modes.Rz
    Rp = sf.Modes.Rplus
    Rm = sf.Modes.Rminus
    for s in range(-2, 2 + 1):
        ell_min = abs(s)
        ell_max = 8
        a = np.random.rand(3, 7,
                           sf.LM_total_size(ell_min, ell_max) *
                           2).view(complex)
        m = sf.Modes(a, spin_weight=s, ell_min=ell_min, ell_max=ell_max)

        # Test L^2 = 0.5(L+L- + L-L+) + LzLz
        m1 = L2(m)
        m2 = 0.5 * (Lp(Lm(m)) + Lm(Lp(m))) + Lz(Lz(m))
        assert np.allclose(m1, m2, rtol=tolerance, atol=tolerance)

        # Test R^2 = 0.5(R+R- + R-R+) + RzRz
        m1 = R2(m)
        m2 = 0.5 * (Rp(Rm(m)) + Rm(Rp(m))) + Rz(Rz(m))
        assert np.allclose(m1, m2, rtol=tolerance, atol=tolerance)

        # Test L^2 = R^2
        m1 = L2(m)
        m2 = R2(m)
        assert np.allclose(m1, m2, rtol=tolerance, atol=tolerance)
示例#6
0
def test_modes_conjugate():
    tolerance = 1e-15
    np.random.seed(1234)
    for inplace in [False, True]:
        for s in range(-2, 2 + 1):
            ell_min = abs(s)
            ell_max = 8
            a = np.random.rand(3, 7,
                               sf.LM_total_size(ell_min, ell_max) *
                               2).view(complex)
            m = sf.Modes(a, spin_weight=s, ell_min=ell_min, ell_max=ell_max)
            g = m.grid()
            s = m.s
            ell_min = m.ell_min
            ell_max = m.ell_max
            shape = m.shape
            mbar = m.conjugate(inplace)
            gbar = mbar.grid()
            assert s == -mbar.s
            assert ell_min == mbar.ell_min
            assert ell_max == mbar.ell_max
            assert shape == mbar.shape
            assert np.allclose(g,
                               np.conjugate(gbar),
                               rtol=tolerance,
                               atol=tolerance)
示例#7
0
def single_mode_proportional_to_time(**kwargs):
    """Return WaveformModes object a single nonzero mode, proportional to time

    The waveform output by this function will have just one nonzero mode.  The behavior of that mode will be
    particularly simple; it will just be proportional to time.

    Parameters
    ----------
    s : int, optional
        Spin weight of the waveform field.  Default is -2.
    ell, m : int, optional
        The (ell, m) values of the nonzero mode in the returned waveform.  Default value is (abs(s), -abs(s)).
    ell_min, ell_max : int, optional
        Smallest and largest ell values present in the output.  Default values are abs(s) and 8.
    data_type : int, optional
        Default value is whichever psi_n corresponds to the input spin.  It is important to choose these, rather than
        `h` or `sigma` for the analytical solution to translations, which doesn't account for the direct contribution
        of supertranslations (as opposed to the indirect contribution, which involves moving points around).
    t_0, t_1 : float, optional
        Beginning and end of time.  Default values are -20. and 20.
    dt : float, optional
        Time step.  Default value is 0.1.
    beta : complex, optional
        Constant of proportionality such that nonzero mode is beta*t.  Default is 1.

    """
    s = kwargs.pop("s", -2)
    ell = kwargs.pop("ell", abs(s))
    m = kwargs.pop("m", -ell)
    ell_min = kwargs.pop("ell_min", abs(s))
    ell_max = kwargs.pop("ell_max", 8)
    data_type = kwargs.pop("data_type",
                           scri.DataType[scri.SpinWeights.index(s)])
    t_0 = kwargs.pop("t_0", -20.0)
    t_1 = kwargs.pop("t_1", 20.0)
    dt = kwargs.pop("dt", 1.0 / 10.0)
    t = np.arange(t_0, t_1 + dt, dt)
    n_times = t.size
    beta = kwargs.pop("beta", 1.0)
    data = np.zeros((n_times, sf.LM_total_size(ell_min, ell_max)),
                    dtype=complex)
    data[:, sf.LM_index(ell, m, ell_min)] = beta * t

    if kwargs:
        import pprint

        warnings.warn(
            f"\nUnused kwargs passed to this function:\n{pprint.pformat(kwargs, width=1)}"
        )

    return scri.WaveformModes(
        t=t,
        data=data,
        ell_min=ell_min,
        ell_max=ell_max,
        frameType=scri.Inertial,
        dataType=data_type,
        r_is_scaled_out=True,
        m_is_scaled_out=True,
    )
示例#8
0
def read_from_h5(file_name, **kwargs):
    """Read data from an H5 file in LVC format"""
    import re
    import h5py
    from scipy.interpolate import InterpolatedUnivariateSpline as Spline

    phase_re = re.compile('phase_l(?P<ell>.*)_m(?P<m>.*)')
    amp_re = re.compile('amp_l(?P<ell>.*)_m(?P<m>.*)')
    
    with h5py.File(file_name) as f:
        t = f['NRtimes'][:]
        ell_m = np.array([[int(match['ell']), int(match['m'])] for key in f for match in [phase_re.match(key)] if match])
        ell_min = np.min(ell_m[:, 0])
        ell_max = np.max(ell_m[:, 0])
        data = np.empty((t.size, sf.LM_total_size(ell_min, ell_max)), dtype=complex)
        for ell in range(ell_min, ell_max+1):
            for m in range(-ell, ell+1):
                amp = Spline(f['amp_l{0}_m{1}/X'.format(ell, m)][:],
                             f['amp_l{0}_m{1}/Y'.format(ell, m)][:],
                             k=int(f['amp_l{0}_m{1}/deg'.format(ell, m)][()]))(t)
                phase = Spline(f['phase_l{0}_m{1}/X'.format(ell, m)][:],
                               f['phase_l{0}_m{1}/Y'.format(ell, m)][:],
                               k=int(f['phase_l{0}_m{1}/deg'.format(ell, m)][()]))(t)
                data[:, sf.LM_index(ell, m, ell_min)] = amp * np.exp(1j * phase)
        if 'auxiliary-info' in f and 'history.txt' in f['auxiliary-info']:
            history = ("### " + f['auxiliary-info/history.txt'][()].decode().replace('\n', '\n### ')).split('\n')
        else:
            history = [""]
        constructor_statement = "scri.LVC.read_from_h5('{0}')".format(file_name)
        w = WaveformModes(t=t, data=data, ell_min=ell_min, ell_max=ell_max,
                          frameType=Inertial, dataType=h,
                          history=history, constructor_statement=constructor_statement,
                          r_is_scaled_out=True, m_is_scaled_out=True)

    return w
示例#9
0
def single_mode_constant_rotation(**kwargs):
    """Return WaveformModes object a single nonzero mode, with phase proportional to time

    The waveform output by this function will have just one nonzero mode.  The behavior of that mode will be fairly
    simple; it will be given by exp(i*omega*t).  Note that omega can be complex, which gives damping.

    Parameters
    ----------
    s : int, optional
        Spin weight of the waveform field.  Default is -2.
    ell, m : int, optional
        The (ell, m) values of the nonzero mode in the returned waveform.  Default value is (abs(s), -abs(s)).
    ell_min, ell_max : int, optional
        Smallest and largest ell values present in the output.  Default values are abs(s) and 8.
    data_type : int, optional
        Default value is whichever psi_n corresponds to the input spin.  It is important to choose these, rather than
        `h` or `sigma` for the analytical solution to translations, which doesn't account for the direct contribution
        of supertranslations (as opposed to the indirect contribution, which involves moving points around).
    t_0, t_1 : float, optional
        Beginning and end of time.  Default values are -20. and 20.
    dt : float, optional
        Time step.  Default value is 0.1.
    omega : complex, optional
        Constant of proportionality such that nonzero mode is exp(i*omega*t).  Note that this can be complex, which
        implies damping.  Default is 0.5.

    """
    s = kwargs.pop('s', -2)
    ell = kwargs.pop('ell', abs(s))
    m = kwargs.pop('m', -ell)
    ell_min = kwargs.pop('ell_min', abs(s))
    ell_max = kwargs.pop('ell_max', 8)
    data_type = kwargs.pop('data_type',
                           scri.DataType[scri.SpinWeights.index(s)])
    t_0 = kwargs.pop('t_0', -20.0)
    t_1 = kwargs.pop('t_1', 20.0)
    dt = kwargs.pop('dt', 1. / 10.)
    t = np.arange(t_0, t_1 + dt, dt)
    n_times = t.size
    omega = complex(kwargs.pop('omega', 0.5))
    data = np.zeros((n_times, sf.LM_total_size(ell_min, ell_max)),
                    dtype=complex)
    data[:, sf.LM_index(ell, m, ell_min)] = np.exp(1j * omega * t)

    if kwargs:
        import pprint
        warnings.warn("\nUnused kwargs passed to this function:\n{0}".format(
            pprint.pformat(kwargs, width=1)))

    return scri.WaveformModes(t=t,
                              data=data,
                              ell_min=ell_min,
                              ell_max=ell_max,
                              frameType=scri.Inertial,
                              dataType=data_type,
                              r_is_scaled_out=True,
                              m_is_scaled_out=True)
示例#10
0
def construct_and_validate(modifier, validator, ell_max=8):
    time = np.linspace(-100, 100, num=2001)
    sigma, sigmadot, sigmaddot, psi2, psi1, psi0 = np.zeros(
        (6, sf.LM_total_size(0, ell_max)), dtype=complex)
    modifier(sigma, sigmadot, sigmaddot, psi2, psi1, psi0)
    abd = ABD.from_initial_values(time, ell_max, sigma, sigmadot, sigmaddot,
                                  psi2, psi1, psi0)
    validator(abd)
    return True
示例#11
0
def test_supertranslation_inverses():
    w1 = samples.random_waveform_proportional_to_time(rotating=False)
    ell_max = 4
    for ellpp, mpp in sf.LM_range(0, ell_max):
        supertranslation = np.zeros((sf.LM_total_size(0, ell_max), ),
                                    dtype=complex)
        if mpp == 0:
            supertranslation[sf.LM_index(ellpp, mpp, 0)] = 1.0
        elif mpp < 0:
            supertranslation[sf.LM_index(ellpp, mpp, 0)] = 1.0
            supertranslation[sf.LM_index(ellpp, -mpp, 0)] = (-1.0)**mpp
        elif mpp > 0:
            supertranslation[sf.LM_index(ellpp, mpp, 0)] = 1.0j
            supertranslation[sf.LM_index(ellpp, -mpp, 0)] = (-1.0)**mpp * -1.0j
        max_displacement = abs(
            spinsfast.salm2map(supertranslation, 0, ell_max, 4 * ell_max + 1,
                               4 * ell_max + 1)).max()
        w2 = copy.deepcopy(w1)
        w2 = w2.transform(supertranslation=supertranslation)
        w2 = w2.transform(supertranslation=-supertranslation)

        i1A = np.argmin(abs(w1.t - (w1.t[0] + 3 * max_displacement)))
        i1B = np.argmin(abs(w1.t - (w1.t[-1] - 3 * max_displacement)))
        i2A = np.argmin(abs(w2.t - w1.t[i1A]))
        i2B = np.argmin(abs(w2.t - w1.t[i1B]))
        try:
            assert np.allclose(w1.t[i1A:i1B + 1],
                               w2.t[i2A:i2B + 1],
                               rtol=0.0,
                               atol=1e-15), (
                                   w1.t[i1A],
                                   w2.t[i2A],
                                   w1.t[i1B],
                                   w2.t[i2B],
                                   w1.t[i1A:i1B + 1].shape,
                                   w2.t[i2A:i2B + 1].shape,
                               )
        except ValueError:
            print("Indices:\n\t", i1A, i1B, i2A, i2B)
            print("Times:\n\t", w1.t[i1A], w1.t[i1B], w2.t[i2A], w2.t[i2B])
            raise
        data1 = w1.data[i1A:i1B + 1]
        data2 = w2.data[i2A:i2B + 1]
        try:
            assert np.allclose(data1, data2, rtol=5e-10, atol=5e-14), [
                abs(data1 - data2).max(),
                data1.ravel()[np.argmax(abs(data1 - data2))],
                data2.ravel()[np.argmax(abs(data1 - data2))],
                np.unravel_index(np.argmax(abs(data1 - data2)), data1.shape),
            ]
            # list(sf.LM_range(0, ell_max)[np.unravel_index(np.argmax(abs(data1-data2)),
            #                                               data1.shape)[1]])])
        except:
            print("Indices:\n\t", i1A, i1B, i2A, i2B)
            print("Times:\n\t", w1.t[i1A], w1.t[i1B], w2.t[i2A], w2.t[i2B])
            raise
示例#12
0
def test_modes_ufuncs():
    for s1 in range(-2, 2 + 1):
        ell_min1 = abs(s1)
        ell_max1 = 8
        a1 = np.random.rand(11,
                            sf.LM_total_size(ell_min1, ell_max1) *
                            2).view(complex)
        m1 = sf.Modes(a1, spin_weight=s1, ell_min=ell_min1, ell_max=ell_max1)
        positivem1 = +m1
        assert np.array_equal(m1.view(np.ndarray), positivem1.view(np.ndarray))
        negativem1 = -m1
        assert np.array_equal(-(m1.view(np.ndarray)),
                              negativem1.view(np.ndarray))
示例#13
0
def test_rotations_of_each_mode_individually(Rs):
    ell_min = 0
    ell_max = 8  # sf.ell_max is just too much; this test is too slow, and ell=8 should be fine
    R_basis = Rs
    Ds = np.empty((len(Rs), sf.LMpM_total_size(ell_min, ell_max)),
                  dtype=complex)
    for i, R in enumerate(Rs):
        Ds[i, :] = sf.Wigner_D_matrices(R, ell_min, ell_max)
    for ell in range(ell_max + 1):
        first_zeros = np.zeros((len(Rs), sf.LM_total_size(ell_min, ell - 1)),
                               dtype=complex)
        later_zeros = np.zeros((len(Rs), sf.LM_total_size(ell + 1, ell_max)),
                               dtype=complex)
        for Mp in range(-ell, ell):
            W_in = delta_waveform(ell,
                                  Mp,
                                  begin=-10.0,
                                  end=100.0,
                                  n_times=len(Rs),
                                  ell_min=ell_min,
                                  ell_max=ell_max)
            # Now, the modes are f^{\ell,m[} = \delta^{\ell,mp}_{L,Mp}
            assert W_in.ensure_validity(alter=False)
            W_out = scri.WaveformModes(W_in)
            W_out.rotate_decomposition_basis(Rs)
            assert W_out.ensure_validity(alter=False)
            assert np.array_equal(W_out.t, W_in.t)
            assert np.max(np.abs(W_out.frame - R_basis)) == 0.0
            i_D0 = sf.LMpM_index(ell, Mp, -ell, ell_min)
            assert np.array_equal(
                W_out.data[:, :sf.LM_total_size(ell_min, ell - 1)],
                first_zeros)
            if ell < ell_max:
                assert np.array_equal(
                    W_out.data[:,
                               sf.LM_total_size(ell_min, ell - 1):-sf.
                               LM_total_size(ell + 1, ell_max)],
                    Ds[:, i_D0:i_D0 + (2 * ell + 1)],
                )
                assert np.array_equal(
                    W_out.data[:, -sf.LM_total_size(ell + 1, ell_max):],
                    later_zeros)
            else:
                assert np.array_equal(
                    W_out.data[:, sf.LM_total_size(ell_min, ell - 1):],
                    Ds[:, i_D0:i_D0 + (2 * ell + 1)])
            assert W_out.ell_min == W_in.ell_min
            assert W_out.ell_max == W_in.ell_max
            assert np.array_equal(W_out.LM, W_in.LM)
            for h_in, h_out in zip(W_in.history, W_out.history[:-1]):
                assert h_in == h_out.replace(
                    type(W_out).__name__ + str(W_out.num),
                    type(W_in).__name__ + str(W_in.num))
            assert W_out.frameType == W_in.frameType
            assert W_out.dataType == W_in.dataType
            assert W_out.r_is_scaled_out == W_in.r_is_scaled_out
            assert W_out.m_is_scaled_out == W_in.m_is_scaled_out
            assert W_out.num != W_in.num
示例#14
0
def test_modes_norm():
    tolerance = 1e-15
    np.random.seed(1234)
    for s in range(-2, 2 + 1):
        ell_min = abs(s)
        ell_max = 8
        a = np.random.rand(3, 7,
                           sf.LM_total_size(ell_min, ell_max) *
                           2).view(complex)
        m = sf.Modes(a, spin_weight=s, ell_min=ell_min, ell_max=ell_max)
        mmbar = m.multiply(m.conjugate())
        norm = np.sqrt(2 * math.sqrt(np.pi) *
                       mmbar[..., 0].view(np.ndarray).real)
        assert np.allclose(norm, m.norm(), rtol=tolerance, atol=tolerance)
示例#15
0
def read_from_h5(file_name, **kwargs):
    """Read data from an H5 file in LVC format"""
    import re
    import h5py
    from scipy.interpolate import InterpolatedUnivariateSpline as Spline

    phase_re = re.compile("phase_l(?P<ell>.*)_m(?P<m>.*)")
    amp_re = re.compile("amp_l(?P<ell>.*)_m(?P<m>.*)")

    with h5py.File(file_name, "r") as f:
        t = f["NRtimes"][:]
        ell_m = np.array([[int(match["ell"]),
                           int(match["m"])] for key in f
                          for match in [phase_re.match(key)] if match])
        ell_min = np.min(ell_m[:, 0])
        ell_max = np.max(ell_m[:, 0])
        data = np.empty((t.size, sf.LM_total_size(ell_min, ell_max)),
                        dtype=complex)
        for ell in range(ell_min, ell_max + 1):
            for m in range(-ell, ell + 1):
                amp = Spline(f[f"amp_l{ell}_m{m}/X"][:],
                             f[f"amp_l{ell}_m{m}/Y"][:],
                             k=int(f[f"amp_l{ell}_m{m}/deg"][()]))(t)
                phase = Spline(f[f"phase_l{ell}_m{m}/X"][:],
                               f[f"phase_l{ell}_m{m}/Y"][:],
                               k=int(f[f"phase_l{ell}_m{m}/deg"][()]))(t)
                data[:,
                     sf.LM_index(ell, m, ell_min)] = amp * np.exp(1j * phase)
        if "auxiliary-info" in f and "history.txt" in f["auxiliary-info"]:
            history = ("### " +
                       f["auxiliary-info/history.txt"][()].decode().replace(
                           "\n", "\n### ")).split("\n")
        else:
            history = [""]
        constructor_statement = f"scri.LVC.read_from_h5('{file_name}')"
        w = WaveformModes(
            t=t,
            data=data,
            ell_min=ell_min,
            ell_max=ell_max,
            frameType=Inertial,
            dataType=h,
            history=history,
            constructor_statement=constructor_statement,
            r_is_scaled_out=True,
            m_is_scaled_out=True,
        )

    return w
示例#16
0
def test_modes_copying_and_pickling(copier):
    for s in range(-2, 2 + 1):
        ell_min = abs(s)
        ell_max = 8
        a = np.random.rand(3, 7,
                           sf.LM_total_size(ell_min, ell_max) *
                           2).view(complex)
        m = sf.Modes(a, spin_weight=s, ell_min=ell_min, ell_max=ell_max)
        c = copier(m)
        assert m is not c
        assert np.array_equal(c, m)
        assert isinstance(c, type(m))
        assert c.s == m.s
        assert c.ell_min == m.ell_min
        assert c.ell_max == m.ell_max
示例#17
0
def check_modes(modes, nonzero_ℓm):
    import numpy as np
    import spherical_functions as sf

    non_zero_indices = np.array([modes.index(ℓ, m) for ℓ, m in nonzero_ℓm],
                                dtype=int)
    zero_indices = np.array(list(
        set(range(sf.LM_total_size(0, modes.ell_max))) -
        set(non_zero_indices)),
                            dtype=int)
    assert not np.any(
        modes[...,
              zero_indices]), f"nonzero values among indices {zero_indices}"
    for non_zero_index in non_zero_indices:
        assert np.any(modes[
            ...,
            non_zero_index]), f"no nonzero values at index {non_zero_index}"
示例#18
0
def test_modes_grid():
    for s in range(-2, 2 + 1):
        ell_min = abs(s)
        ell_max = 8
        a = np.random.rand(3, 7,
                           sf.LM_total_size(ell_min, ell_max) *
                           2).view(complex)
        m = sf.Modes(a, spin_weight=s, ell_min=ell_min, ell_max=ell_max)
        n = 2 * ell_max + 1
        for n_theta, n_phi in [[None, None], [n, None], [None, n], [n, n],
                               [n + 1, n], [n, n + 1], [n + 1, n + 1]]:
            g = m.grid(n_theta=n_theta, n_phi=n_phi)
            assert g.dtype == np.complex
            assert g.shape[:-2] == a.shape[:-1]
            if n_theta is None:
                n_theta = n
            if n_phi is None:
                n_phi = n
            assert g.shape[-2:] == (n_theta, n_phi)
示例#19
0
def test_hyper_translation():
    """Compare code-transformed waveform to analytically transformed waveform"""
    print("")
    ell_max = 4
    for s in range(-2, 2+1):
        for ell in range(abs(s), ell_max+1):
            for m in range(-ell, ell+1):
                print("\tWorking on spin s =", s, ", ell =", ell, ", m =", m)
                for ellpp, mpp in sf.LM_range(2, ell_max):
                    supertranslation = np.zeros((sf.LM_total_size(0, ell_max),), dtype=complex)
                    if mpp == 0:
                        supertranslation[sf.LM_index(ellpp, mpp, 0)] = 1.0
                    elif mpp < 0:
                        supertranslation[sf.LM_index(ellpp, mpp, 0)] = 1.0
                        supertranslation[sf.LM_index(ellpp, -mpp, 0)] = (-1.0)**mpp
                    elif mpp > 0:
                        supertranslation[sf.LM_index(ellpp, mpp, 0)] = 1.0j
                        supertranslation[sf.LM_index(ellpp, -mpp, 0)] = (-1.0)**mpp * -1.0j
                    max_displacement = abs(spinsfast.salm2map(supertranslation, 0,
                                                              ell_max, 4*ell_max+1, 4*ell_max+1)).max()
                    w_m1 = (samples.single_mode_proportional_to_time(s=s, ell=ell, m=m)
                            .transform(supertranslation=supertranslation))
                    w_m2 = samples.single_mode_proportional_to_time_supertranslated(s=s, ell=ell, m=m,
                                                                                    supertranslation=supertranslation)
                    i1A = np.argmin(abs(w_m1.t-(w_m1.t[0]+2*max_displacement)))
                    i1B = np.argmin(abs(w_m1.t-(w_m1.t[-1]-2*max_displacement)))
                    i2A = np.argmin(abs(w_m2.t-w_m1.t[i1A]))
                    i2B = np.argmin(abs(w_m2.t-w_m1.t[i1B]))
                    assert np.allclose(w_m1.t[i1A:i1B+1], w_m2.t[i2A:i2B+1], rtol=0.0, atol=1e-16), \
                        (w_m1.t[i1A], w_m2.t[i2A], w_m1.t[i1B], w_m2.t[i2B],
                         w_m1.t[i1A:i1B+1].shape, w_m2.t[i2A:i2B+1].shape)
                    data1 = w_m1.data[i1A:i1B+1]
                    data2 = w_m2.data[i2A:i2B+1]
                    assert np.allclose(data1, data2, rtol=0.0, atol=5e-14), \
                        ([s, ell, m],
                         supertranslation,
                         [abs(data1-data2).max(),
                          data1.ravel()[np.argmax(abs(data1-data2))], data2.ravel()[np.argmax(abs(data1-data2))]],
                         [np.unravel_index(np.argmax(abs(data1-data2)), data1.shape)[0],
                          list(sf.LM_range(abs(s), ell_max)[np.unravel_index(np.argmax(abs(data1-data2)),
                                                                             data1.shape)[1]])])
示例#20
0
def test_modes_real():
    tolerance = 1e-14
    np.random.seed(1234)
    for inplace in [False, True]:
        s = 0
        ell_min = abs(s)
        ell_max = 8
        a = np.random.rand(3, 7,
                           sf.LM_total_size(ell_min, ell_max) *
                           2).view(complex)
        # Test success with spin_weight==0
        m = sf.Modes(a, spin_weight=s, ell_min=ell_min, ell_max=ell_max)
        g = m.grid()
        s = m.s
        ell_min = m.ell_min
        ell_max = m.ell_max
        shape = m.shape
        mreal = m._real_func(inplace)
        greal = mreal.grid()
        assert s == mreal.s
        assert ell_min == mreal.ell_min
        assert ell_max == mreal.ell_max
        assert shape == mreal.shape
        assert np.allclose(greal,
                           np.real(greal) + 0.0j,
                           rtol=tolerance,
                           atol=tolerance)
        assert np.allclose(np.real(g),
                           np.real(greal),
                           rtol=tolerance,
                           atol=tolerance)
        assert np.allclose(np.zeros_like(g, dtype=float),
                           np.imag(greal),
                           rtol=tolerance,
                           atol=tolerance)
        # Test failure with s!=0
        for s in [-3, -2, -1, 1, 2, 3]:
            m = sf.Modes(a, spin_weight=s, ell_min=ell_min, ell_max=ell_max)
            with pytest.raises(ValueError):
                mreal = m._real_func(inplace)
示例#21
0
def test_modes_imag():
    tolerance = 1e-14
    np.random.seed(1234)
    for inplace in [False, True]:
        s = 0
        ell_min = abs(s)
        ell_max = 8
        a = np.random.rand(3, 7,
                           sf.LM_total_size(ell_min, ell_max) *
                           2).view(complex)
        # Test success with spin_weight==0
        m = sf.Modes(a, spin_weight=s, ell_min=ell_min, ell_max=ell_max)
        g = m.grid()
        s = m.s
        ell_min = m.ell_min
        ell_max = m.ell_max
        shape = m.shape
        mimag = m._imag_func(inplace)
        gimag = mimag.grid()
        assert s == mimag.s
        assert ell_min == mimag.ell_min
        assert ell_max == mimag.ell_max
        assert shape == mimag.shape
        assert np.allclose(gimag,
                           np.real(gimag),
                           rtol=tolerance,
                           atol=tolerance)  # gimag is purely real
        assert np.allclose(np.array(np.imag(g.ndarray), dtype=complex),
                           gimag.ndarray,
                           rtol=tolerance,
                           atol=tolerance)  # imag(g) == gimag
        assert np.allclose(np.imag(gimag.ndarray),
                           np.zeros_like(g.ndarray, dtype=float),
                           rtol=tolerance,
                           atol=tolerance)  # imag(gimag) == 0
        # Test failure with s!=0
        for s in [-3, -2, -1, 1, 2, 3]:
            m = sf.Modes(a, spin_weight=s, ell_min=ell_min, ell_max=ell_max)
            with pytest.raises(ValueError):
                mimag = m._imag_func(inplace)
 def specialized_multiplication(f, ellmin_f, ellmax_f, s_f, g, ellmin_g,
                                ellmax_g, s_g):
     ellmin_fg = 0
     ellmax_fg = ellmax_f + ellmax_g
     s_fg = s_f + s_g
     fg = np.zeros(sf.LM_total_size(0, ellmax_fg), dtype=np.complex)
     # for ell in range(ellmin_g, ellmax_g+1):
     #     for m in range(-ell, ell+1):
     #         i_g = sf.LM_index(ell, m, ellmin_g)
     #         for ellprime in [ell-1, ell, ell+1]:
     #             if ellprime < ellmin_g or ellprime > ellmax_g or ellprime < abs(s_g):
     #                 continue
     #             for mprime in [m-1, m, m+1]:
     #                 if mprime < -ellprime or mprime > ellprime:
     #                     continue
     #                 i_fg = sf.LM_index(ellprime, mprime, ellmin_fg)
     #                 m1 = mprime - m
     #                 fg[i_fg] += (
     #                     # (-1)**(s_g+m+1)
     #                     # * np.sqrt(3*(2*ell+1)/(4*np.pi))
     #                     # * (-1)**(m1)
     #                     # * np.sqrt(2*ellprime+1)
     #                     (-1)**(1 + ell + ellprime + s_g + m + m1)
     #                     * np.sqrt(3*(2*ell+1)*(2*ellprime+1)/(4*np.pi))
     #                     * sf.Wigner3j(1, ell, ellprime, 0, s_g, -s_g)
     #                     * sf.Wigner3j(1, ell, ellprime, m1, m, -mprime)
     #                     * f[sf.LM_index(1, m1, 0)]
     #                     * g[i_g]
     #                 )
     ####################################################################################
     # for ell in range(ellmin_g, ellmax_g+1):
     #     for m in range(-ell, ell+1):
     #         i_g = sf.LM_index(ell, m, ellmin_g)
     #         coefficient = (-1)**(s_g + m) * np.sqrt(3*(2*ell+1)/(4*np.pi))
     #         for ellprime in [ell-1, ell, ell+1]:
     #             if ellprime < ellmin_g or ellprime > ellmax_g or ellprime < abs(s_g):
     #                 continue
     #             if m-1 >= -ellprime and m-1 <= ellprime:
     #                 i_fg = sf.LM_index(ellprime, m-1, ellmin_fg)
     #                 fg[i_fg] += (
     #                     coefficient
     #                     * (-1)**(ell + ellprime)
     #                     * np.sqrt((2*ellprime+1))
     #                     * sf.Wigner3j(1, ell, ellprime, 0, s_g, -s_g)
     #                     * sf.Wigner3j(1, ell, ellprime, -1, m, -m+1)
     #                     * f[sf.LM_index(1, -1, 0)]
     #                     * g[i_g]
     #                 )
     #             if m >= -ellprime and m <= ellprime:
     #                 i_fg = sf.LM_index(ellprime, m, ellmin_fg)
     #                 fg[i_fg] += (
     #                     coefficient
     #                     * (-1)**(ell + ellprime)
     #                     * -np.sqrt(2*ellprime+1)
     #                     * sf.Wigner3j(1, ell, ellprime, 0, s_g, -s_g)
     #                     * sf.Wigner3j(1, ell, ellprime, 0, m, -m)
     #                     * f[sf.LM_index(1, 0, 0)]
     #                     * g[i_g]
     #                 )
     #             if m+1 >= -ellprime and m+1 <= ellprime:
     #                 i_fg = sf.LM_index(ellprime, m+1, ellmin_fg)
     #                 fg[i_fg] += (
     #                     coefficient
     #                     * (-1)**(ell + ellprime)
     #                     * np.sqrt(2*ellprime+1)
     #                     * sf.Wigner3j(1, ell, ellprime, 0, s_g, -s_g)
     #                     * sf.Wigner3j(1, ell, ellprime, 1, m, -m-1)
     #                     * f[sf.LM_index(1, 1, 0)]
     #                     * g[i_g]
     #                 )
     ####################################################################################
     # for ell in range(ellmin_g, ellmax_g+1):
     #     for m in range(-ell, ell+1):
     #         i_g = sf.LM_index(ell, m, ellmin_g)
     #         coefficient = (-1)**(s_g + m + 1) * np.sqrt(3*(2*ell+1)/(4*np.pi))
     #         if ell-1 >= ellmin_g and ell-1 <= ellmax_g and ell-1 >= abs(s_g):
     #             if m-1 >= -ell+1 and m-1 <= ell-1:
     #                 i_fg = sf.LM_index(ell-1, m-1, ellmin_fg)
     #                 fg[i_fg] += (
     #                     coefficient
     #                     * np.sqrt(2*ell-1)
     #                     * sf.Wigner3j(1, ell, ell-1, 0, s_g, -s_g)
     #                     * sf.Wigner3j(1, ell, ell-1, -1, m, -m+1)
     #                     * f[sf.LM_index(1, -1, 0)]
     #                     * g[i_g]
     #                 )
     #             if m >= -ell+1 and m <= ell-1:
     #                 i_fg = sf.LM_index(ell-1, m, ellmin_fg)
     #                 fg[i_fg] += (
     #                     -coefficient
     #                     * np.sqrt(2*ell-1)
     #                     * sf.Wigner3j(1, ell, ell-1, 0, s_g, -s_g)
     #                     * sf.Wigner3j(1, ell, ell-1, 0, m, -m)
     #                     * f[sf.LM_index(1, 0, 0)]
     #                     * g[i_g]
     #                 )
     #             if m+1 >= -ell+1 and m+1 <= ell-1:
     #                 i_fg = sf.LM_index(ell-1, m+1, ellmin_fg)
     #                 fg[i_fg] += (
     #                     coefficient
     #                     * np.sqrt(2*ell-1)
     #                     * sf.Wigner3j(1, ell, ell-1, 0, s_g, -s_g)
     #                     * sf.Wigner3j(1, ell, ell-1, 1, m, -m-1)
     #                     * f[sf.LM_index(1, 1, 0)]
     #                     * g[i_g]
     #                 )
     #         if ell >= ellmin_g and ell <= ellmax_g and ell >= abs(s_g):
     #             if m-1 >= -ell and m-1 <= ell:
     #                 i_fg = sf.LM_index(ell, m-1, ellmin_fg)
     #                 fg[i_fg] += (
     #                     -coefficient
     #                     * np.sqrt(2*ell+1)
     #                     * sf.Wigner3j(1, ell, ell, 0, s_g, -s_g)
     #                     * sf.Wigner3j(1, ell, ell, -1, m, -m+1)
     #                     * f[sf.LM_index(1, -1, 0)]
     #                     * g[i_g]
     #                 )
     #             if m >= -ell and m <= ell:
     #                 i_fg = sf.LM_index(ell, m, ellmin_fg)
     #                 fg[i_fg] += (
     #                     coefficient
     #                     * np.sqrt(2*ell+1)
     #                     * sf.Wigner3j(1, ell, ell, 0, s_g, -s_g)
     #                     * sf.Wigner3j(1, ell, ell, 0, m, -m)
     #                     * f[sf.LM_index(1, 0, 0)]
     #                     * g[i_g]
     #                 )
     #             if m+1 >= -ell and m+1 <= ell:
     #                 i_fg = sf.LM_index(ell, m+1, ellmin_fg)
     #                 fg[i_fg] += (
     #                     -coefficient
     #                     * np.sqrt(2*ell+1)
     #                     * sf.Wigner3j(1, ell, ell, 0, s_g, -s_g)
     #                     * sf.Wigner3j(1, ell, ell, 1, m, -m-1)
     #                     * f[sf.LM_index(1, 1, 0)]
     #                     * g[i_g]
     #                 )
     #         if ell+1 >= ellmin_g and ell+1 <= ellmax_g and ell+1 >= abs(s_g):
     #             if m-1 >= -ell-1 and m-1 <= ell+1:
     #                 i_fg = sf.LM_index(ell+1, m-1, ellmin_fg)
     #                 fg[i_fg] += (
     #                     coefficient
     #                     * np.sqrt(2*ell+3)
     #                     * sf.Wigner3j(1, ell, ell+1, 0, s_g, -s_g)
     #                     * sf.Wigner3j(1, ell, ell+1, -1, m, -m+1)
     #                     * f[sf.LM_index(1, -1, 0)]
     #                     * g[i_g]
     #                 )
     #             if m >= -ell-1 and m <= ell+1:
     #                 i_fg = sf.LM_index(ell+1, m, ellmin_fg)
     #                 fg[i_fg] += (
     #                     -coefficient
     #                     * np.sqrt(2*ell+3)
     #                     * sf.Wigner3j(1, ell, ell+1, 0, s_g, -s_g)
     #                     * sf.Wigner3j(1, ell, ell+1, 0, m, -m)
     #                     * f[sf.LM_index(1, 0, 0)]
     #                     * g[i_g]
     #                 )
     #             if m+1 >= -ell-1 and m+1 <= ell+1:
     #                 i_fg = sf.LM_index(ell+1, m+1, ellmin_fg)
     #                 fg[i_fg] += (
     #                     coefficient
     #                     * np.sqrt(2*ell+3)
     #                     * sf.Wigner3j(1, ell, ell+1, 0, s_g, -s_g)
     #                     * sf.Wigner3j(1, ell, ell+1, 1, m, -m-1)
     #                     * f[sf.LM_index(1, 1, 0)]
     #                     * g[i_g]
     #                 )
     ####################################################################################
     for ell in range(ellmin_g, ellmax_g + 1):
         for m in range(-ell, ell + 1):
             i_fg = sf.LM_index(ell, m, ellmin_fg)
             coefficient = (-1)**(s_g + m) * np.sqrt(3 * (2 * ell + 1) /
                                                     (4 * np.pi))
             if ell + 1 >= ellmin_g and ell + 1 <= ellmax_g and ell + 1 >= abs(
                     s_g):
                 if m + 1 >= -ell - 1 and m + 1 <= ell + 1:
                     fg[i_fg] += (
                         coefficient * np.sqrt(2 * ell + 3) *
                         sf.Wigner3j(1, ell + 1, ell, 0, s_g, -s_g) *
                         sf.Wigner3j(1, ell + 1, ell, -1, m + 1, -m) *
                         f[sf.LM_index(1, -1, 0)] *
                         g[sf.LM_index(ell + 1, m + 1, ellmin_g)])
                 if m >= -ell - 1 and m <= ell + 1:
                     fg[i_fg] += (
                         coefficient * np.sqrt(2 * ell + 3) *
                         sf.Wigner3j(1, ell + 1, ell, 0, s_g, -s_g) *
                         sf.Wigner3j(1, ell + 1, ell, 0, m, -m) *
                         f[sf.LM_index(1, 0, 0)] *
                         g[sf.LM_index(ell + 1, m, ellmin_g)])
                 if m - 1 >= -ell - 1 and m - 1 <= ell + 1:
                     fg[i_fg] += (
                         coefficient * np.sqrt(2 * ell + 3) *
                         sf.Wigner3j(1, ell + 1, ell, 0, s_g, -s_g) *
                         sf.Wigner3j(1, ell + 1, ell, 1, m - 1, -m) *
                         f[sf.LM_index(1, 1, 0)] *
                         g[sf.LM_index(ell + 1, m - 1, ellmin_g)])
             if ell >= ellmin_g and ell <= ellmax_g and ell >= abs(s_g):
                 if m + 1 >= -ell and m + 1 <= ell:
                     fg[i_fg] += (-coefficient * np.sqrt(2 * ell + 1) *
                                  sf.Wigner3j(1, ell, ell, 0, s_g, -s_g) *
                                  sf.Wigner3j(1, ell, ell, -1, m + 1, -m) *
                                  f[sf.LM_index(1, -1, 0)] *
                                  g[sf.LM_index(ell, m + 1, ellmin_g)])
                 if m >= -ell and m <= ell:
                     fg[i_fg] += (-coefficient * np.sqrt(2 * ell + 1) *
                                  sf.Wigner3j(1, ell, ell, 0, s_g, -s_g) *
                                  sf.Wigner3j(1, ell, ell, 0, m, -m) *
                                  f[sf.LM_index(1, 0, 0)] *
                                  g[sf.LM_index(ell, m, ellmin_g)])
                 if m - 1 >= -ell and m - 1 <= ell:
                     fg[i_fg] += (-coefficient * np.sqrt(2 * ell + 1) *
                                  sf.Wigner3j(1, ell, ell, 0, s_g, -s_g) *
                                  sf.Wigner3j(1, ell, ell, 1, m - 1, -m) *
                                  f[sf.LM_index(1, 1, 0)] *
                                  g[sf.LM_index(ell, m - 1, ellmin_g)])
             if ell - 1 >= ellmin_g and ell - 1 <= ellmax_g and ell - 1 >= abs(
                     s_g):
                 if m + 1 >= -ell + 1 and m + 1 <= ell - 1:
                     fg[i_fg] += (
                         coefficient * np.sqrt(2 * ell - 1) *
                         sf.Wigner3j(1, ell - 1, ell, 0, s_g, -s_g) *
                         sf.Wigner3j(1, ell - 1, ell, -1, m + 1, -m) *
                         f[sf.LM_index(1, -1, 0)] *
                         g[sf.LM_index(ell - 1, m + 1, ellmin_g)])
                 if m >= -ell + 1 and m <= ell - 1:
                     fg[i_fg] += (
                         coefficient * np.sqrt(2 * ell - 1) *
                         sf.Wigner3j(1, ell - 1, ell, 0, s_g, -s_g) *
                         sf.Wigner3j(1, ell - 1, ell, 0, m, -m) *
                         f[sf.LM_index(1, 0, 0)] *
                         g[sf.LM_index(ell - 1, m, ellmin_g)])
                 if m - 1 >= -ell + 1 and m - 1 <= ell - 1:
                     fg[i_fg] += (
                         coefficient * np.sqrt(2 * ell - 1) *
                         sf.Wigner3j(1, ell - 1, ell, 0, s_g, -s_g) *
                         sf.Wigner3j(1, ell - 1, ell, 1, m - 1, -m) *
                         f[sf.LM_index(1, 1, 0)] *
                         g[sf.LM_index(ell - 1, m - 1, ellmin_g)])
     return fg, ellmin_fg, ellmax_fg, s_fg
示例#23
0
def single_mode_proportional_to_time_supertranslated(**kwargs):
    """Return WaveformModes as in single_mode_proportional_to_time, with analytical supertranslation

    This function constructs the same basic object as the `single_mode_proportional_to_time`, but then applies an
    analytical supertranslation.  The arguments to this function are the same as to the other, with two additions:

    Additional parameters
    ---------------------
    supertranslation : complex array, optional
        Spherical-harmonic modes of the supertranslation to apply to the waveform.  This is overwritten by
         `space_translation` if present.  Default value is `None`.
    space_translation : float array of length 3, optional
        This is just the 3-vector representing the displacement to apply to the waveform.  Note that if
        `supertranslation`, this parameter overwrites it.  Default value is [1.0, 0.0, 0.0].

    """
    s = kwargs.pop("s", -2)
    ell = kwargs.pop("ell", abs(s))
    m = kwargs.pop("m", -ell)
    ell_min = kwargs.pop("ell_min", abs(s))
    ell_max = kwargs.pop("ell_max", 8)
    data_type = kwargs.pop("data_type",
                           scri.DataType[scri.SpinWeights.index(s)])
    t_0 = kwargs.pop("t_0", -20.0)
    t_1 = kwargs.pop("t_1", 20.0)
    dt = kwargs.pop("dt", 1.0 / 10.0)
    t = np.arange(t_0, t_1 + dt, dt)
    n_times = t.size
    beta = kwargs.pop("beta", 1.0)
    data = np.zeros((n_times, sf.LM_total_size(ell_min, ell_max)),
                    dtype=complex)
    data[:, sf.LM_index(ell, m, ell_min)] = beta * t
    supertranslation = np.array(kwargs.pop("supertranslation",
                                           np.array([], dtype=complex)),
                                dtype=complex)
    if "space_translation" in kwargs:
        if supertranslation.size < 4:
            supertranslation.resize((4, ))
        supertranslation[1:4] = -sf.vector_as_ell_1_modes(
            kwargs.pop("space_translation"))
    supertranslation_ell_max = int(math.sqrt(supertranslation.size) - 1)
    if supertranslation_ell_max * (supertranslation_ell_max +
                                   2) + 1 != supertranslation.size:
        raise ValueError(
            f"Bad number of elements in supertranslation: {supertranslation.size}"
        )
    for i, (ellpp, mpp) in enumerate(sf.LM_range(0, supertranslation_ell_max)):
        if supertranslation[i] != 0.0:
            mp = m + mpp
            for ellp in range(ell_min, min(ell_max, (ell + ellpp)) + 1):
                if ellp >= abs(mp):
                    addition = (beta * supertranslation[i] * math.sqrt(
                        ((2 * ellpp + 1) * (2 * ell + 1) *
                         (2 * ellp + 1)) / (4 * math.pi)) *
                                sf.Wigner3j(ellpp, ell, ellp, 0, -s, s) *
                                sf.Wigner3j(ellpp, ell, ellp, mpp, m, -mp))
                    if (s + mp) % 2 == 1:
                        addition *= -1
                    data[:, sf.LM_index(ellp, mp, ell_min)] += addition

    if kwargs:
        import pprint

        warnings.warn(
            f"\nUnused kwargs passed to this function:\n{pprint.pformat(kwargs, width=1)}"
        )

    return scri.WaveformModes(
        t=t,
        data=data,
        ell_min=ell_min,
        ell_max=ell_max,
        frameType=scri.Inertial,
        dataType=data_type,
        r_is_scaled_out=True,
        m_is_scaled_out=True,
    )
示例#24
0
        mass_ratio = 1.0 / mass_ratio

    s = -2
    ell_min = abs(s)
    data_type = scri.h

    nu = mass_ratio / (1 + mass_ratio)**2
    t = np.arange(t_0, t_1 + 0.99 * dt, dt)
    t_merger = t_1 - 100.0
    i_merger = np.argmin(abs(t - t_merger))
    if i_merger < 20:
        raise ValueError(
            f"Insufficient space between initial time (t={t_merger}) and merger (t={t_0})."
        )
    n_times = t.size
    data = np.zeros((n_times, sf.LM_total_size(ell_min, ell_max)),
                    dtype=complex)

    # Get a rough approximation to the phasing through merger
    tau = nu * (t_merger - t) / 5
    with warnings.catch_warnings(
    ):  # phi and omega will have NaNs after t_merger for now
        warnings.simplefilter("ignore")
        phi = -4 * tau**(5 / 8)
        omega = (nu / 2) * tau**(-3 / 8)

    # Now, transition omega smoothly up to a constant value of 0.25
    omega_transition_width = 5.0
    i1 = np.argmin(np.abs(omega[~np.isnan(omega)] - 0.25))
    i0 = np.argmin(np.abs(t - (t[i1] - omega_transition_width)))
    transition = transition_function(t, t[i0], t[i1])
示例#25
0
def test_modes_multiplication():
    tolerance = 1e-13
    np.random.seed(1234)
    # Test without truncation
    for i_mul, mul in enumerate([
            np.multiply, lambda a, b: a.multiply(b),
            lambda a, b: a.multiply(b, truncator=max)
    ]):
        for s1 in range(-2, 2 + 1):
            ell_min1 = abs(s1)
            ell_max1 = 8
            a1 = np.random.rand(3, 7,
                                sf.LM_total_size(ell_min1, ell_max1) *
                                2).view(complex)
            m1 = sf.Modes(a1,
                          spin_weight=s1,
                          ell_min=ell_min1,
                          ell_max=ell_max1)
            # Check scalar multiplications
            s = np.random.rand()
            m1s = mul(m1, s)
            assert m1.s == s1
            assert m1s.ell_max == m1.ell_max
            g1s = m1s.grid()
            n_theta, n_phi = g1s.shape[-2:]
            g1 = m1.grid(n_theta, n_phi)
            assert np.allclose(g1 * s, g1s, rtol=tolerance, atol=tolerance)
            if mul is np.multiply:
                sm1 = mul(s, m1)
                assert sm1.s == s1
                assert sm1.ell_max == m1.ell_max
                sg1 = sm1.grid()
                n_theta, n_phi = sg1.shape[-2:]
                g1 = m1.grid(n_theta, n_phi)
                assert np.allclose(s * g1, sg1, rtol=tolerance, atol=tolerance)
            # Check scalar-array multiplications
            s = np.random.rand(3, 7)
            m1s = mul(m1, s)
            assert m1.s == s1
            assert m1s.ell_max == m1.ell_max
            g1s = m1s.grid()
            n_theta, n_phi = g1s.shape[-2:]
            g1 = m1.grid(n_theta, n_phi)
            assert np.allclose(g1 * s, g1s, rtol=tolerance, atol=tolerance)
            if mul is np.multiply:
                sm1 = mul(s, m1)
                assert sm1.s == s1
                assert sm1.ell_max == m1.ell_max
                sg1 = sm1.grid()
                n_theta, n_phi = sg1.shape[-2:]
                g1 = m1.grid(n_theta, n_phi)
                assert np.allclose(s * g1, sg1, rtol=tolerance, atol=tolerance)
            # Check spin-weighted multiplications
            for s2 in range(-s1, s1 + 1):
                ell_min2 = ell_min1 + 1
                ell_max2 = ell_max1 - 1
                a2 = np.random.rand(3, 7,
                                    sf.LM_total_size(ell_min2, ell_max2) *
                                    2).view(complex)
                m2 = sf.Modes(a2,
                              spin_weight=s2,
                              ell_min=ell_min2,
                              ell_max=ell_max2)
                m1m2 = mul(m1, m2)
                assert m1m2.s == s1 + s2
                if i_mul == 2:
                    assert m1m2.ell_max == max(m1.ell_max, m2.ell_max)
                else:
                    assert m1m2.ell_max == m1.ell_max + m2.ell_max
                    g12 = m1m2.grid()
                    n_theta, n_phi = g12.shape[-2:]
                    g1 = m1.grid(n_theta, n_phi)
                    g2 = m2.grid(n_theta, n_phi)
                    assert np.allclose(g1 * g2,
                                       g12,
                                       rtol=tolerance,
                                       atol=tolerance)
示例#26
0
def test_LM_total_size(ell_max):
    for l_min in range(ell_max + 1):
        for l_max in range(l_min, ell_max + 1):
            assert sf.LM_index(l_max + 1, -(l_max + 1),
                               l_min) == sf.LM_total_size(l_min, l_max)
def test_SWSH_multiplication_formula(multiplication_function):
    """Test formula for multiplication of SWSHs

    Much of the analysis is based on the formula

    s1Yl1m1 * s2Yl2m2 = sum([
        s3Yl3m3 * (-1)**(l1+l2+l3+s3+m3) * sqrt((2*l1+1)*(2*l2+1)*(2*l3+1)/(4*pi))
            * Wigner3j(l1, l2, l3, s1, s2, -s3) * Wigner3j(l1, l2, l3, m1, m2, -m3)
        for s3 in [s1+s2]
        for l3 in range(abs(l1-l2), l1+l2+1)
        for m3 in [m1+m2]
    ])

    This test evaluates each side of this formula, and compares the values at all collocation points
    on the sphere.  This is tested for each possible value of (s1, l1, m1, s2, l2, m2) up to l1=4
    and l2=4 [the number of items to test scales very rapidly with ell], and tested again for each
    (0, 1, m1, s2, l2, m2) up to l2=8.

    """
    atol = 2e-15
    rtol = 2e-15
    ell_max = 4
    for ell1 in range(ell_max + 1):
        for s1 in range(-ell1, ell1 + 1):
            for m1 in range(-ell1, ell1 + 1):
                for ell2 in range(ell_max + 1):
                    for s2 in range(-ell2, ell2 + 1):
                        for m2 in range(-ell2, ell2 + 1):
                            swsh1 = np.zeros(sf.LM_total_size(0, ell_max),
                                             dtype=np.complex)
                            swsh1[sf.LM_index(ell1, m1, 0)] = 1.0
                            swsh2 = np.zeros(sf.LM_total_size(0, ell_max),
                                             dtype=np.complex)
                            swsh2[sf.LM_index(ell2, m2, 0)] = 1.0
                            swsh3, ell_min_3, ell_max_3, s3 = multiplication_function(
                                swsh1, 0, ell_max, s1, swsh2, 0, ell_max, s2)
                            assert s3 == s1 + s2
                            assert ell_min_3 == 0
                            assert ell_max_3 == 2 * ell_max
                            n_theta = 2 * ell_max_3 + 1
                            n_phi = n_theta
                            swsh3_map = spinsfast.salm2map(
                                swsh3, s3, ell_max_3, n_theta, n_phi)
                            swsh4_map = np.zeros_like(swsh3_map)
                            for ell4 in range(abs(ell1 - ell2),
                                              ell1 + ell2 + 1):
                                for s4 in [s1 + s2]:
                                    for m4 in [m1 + m2]:
                                        swsh4_k = np.zeros_like(swsh3)
                                        swsh4_k[sf.LM_index(ell4, m4, 0)] = (
                                            (-1)
                                            **(ell1 + ell2 + ell4 + s4 + m4) *
                                            np.sqrt(
                                                (2 * ell1 + 1) *
                                                (2 * ell2 + 1) *
                                                (2 * ell4 + 1) / (4 * np.pi)) *
                                            sf.Wigner3j(
                                                ell1, ell2, ell4, s1, s2, -s4)
                                            * sf.Wigner3j(
                                                ell1, ell2, ell4, m1, m2, -m4))
                                        swsh4_map[:] += spinsfast.salm2map(
                                            swsh4_k, s4, ell_max_3, n_theta,
                                            n_phi)
                            assert np.allclose(swsh3_map,
                                               swsh4_map,
                                               atol=atol,
                                               rtol=rtol)

    atol = 8e-15
    rtol = 8e-15
    ell_max = 8
    for ell1 in [1]:
        for s1 in [0]:
            for m1 in [-1, 0, 1]:
                for ell2 in range(ell_max + 1):
                    for s2 in range(-ell2, ell2 + 1):
                        for m2 in range(-ell2, ell2 + 1):
                            swsh1 = np.zeros(sf.LM_total_size(0, ell_max),
                                             dtype=np.complex)
                            swsh1[sf.LM_index(ell1, m1, 0)] = 1.0
                            swsh2 = np.zeros(sf.LM_total_size(0, ell_max),
                                             dtype=np.complex)
                            swsh2[sf.LM_index(ell2, m2, 0)] = 1.0
                            swsh3, ell_min_3, ell_max_3, s3 = multiplication_function(
                                swsh1, 0, ell_max, s1, swsh2, 0, ell_max, s2)
                            assert s3 == s1 + s2
                            assert ell_min_3 == 0
                            assert ell_max_3 == 2 * ell_max
                            n_theta = 2 * ell_max_3 + 1
                            n_phi = n_theta
                            swsh3_map = spinsfast.salm2map(
                                swsh3, s3, ell_max_3, n_theta, n_phi)
                            swsh4_map = np.zeros_like(swsh3_map)
                            for ell4 in [ell2 - 1, ell2, ell2 + 1]:
                                if ell4 < 0:
                                    continue
                                swsh4_k = np.zeros_like(swsh3)
                                # swsh4_k[sf.LM_index(ell4, m1+m2, 0)] = (
                                #     (-1)**(1+ell2+ell4+s2+m1+m2)
                                #     * np.sqrt(3*(2*ell2+1)*(2*ell4+1)/(4*np.pi))
                                #     * sf.Wigner3j(1, ell2, ell4, 0, s2, -s2)
                                #     * sf.Wigner3j(1, ell2, ell4, m1, m2, -m1-m2)
                                # )
                                # swsh4_map[:] += (
                                #     spinsfast.salm2map(swsh4_k, s2, ell_max_3, n_theta, n_phi)
                                # )
                                swsh4_k[sf.LM_index(ell4, m1 + m2, 0)] = (
                                    (-1)**(ell2 + ell4 + m1) * np.sqrt(
                                        (2 * ell4 + 1)) *
                                    sf.Wigner3j(1, ell2, ell4, 0, s2, -s2) *
                                    sf.Wigner3j(1, ell2, ell4, m1, m2,
                                                -m1 - m2))
                                swsh4_map[:] += (
                                    (-1)**(s2 + m2 + 1) *
                                    np.sqrt(3 * (2 * ell2 + 1) / (4 * np.pi)) *
                                    spinsfast.salm2map(swsh4_k, s2, ell_max_3,
                                                       n_theta, n_phi))
                            assert np.allclose(swsh3_map,
                                               swsh4_map,
                                               atol=atol,
                                               rtol=rtol), np.max(
                                                   np.abs(swsh3_map -
                                                          swsh4_map))
示例#28
0
def test_modes_derivatives_on_grids():
    # Test various SWSH-derivative expressions on grids
    tolerance = 2e-14
    np.random.seed(1234)
    for s in range(-2, 2 + 1):
        ell_min = 0
        ell_max = abs(s) + 5
        zeros = lambda: np.zeros(sf.LM_total_size(ell_min, ell_max),
                                 dtype=complex)
        for ell in range(abs(s), ell_max + 1):
            for m in range(-ell, ell + 1):
                sYlm = sf.Modes(zeros(),
                                spin_weight=s,
                                ell_min=ell_min,
                                ell_max=ell_max)
                sYlm[sYlm.index(ell, m)] = 1.0
                g_sYlm = sYlm.grid()
                n_theta, n_phi = g_sYlm.shape[-2:]

                # Test Lsquared {s}Y{l,m} = l * (l+1) * {s}Y{l,m}
                L2_sYlm = sYlm.Lsquared()
                g_L2_sYlm = L2_sYlm.grid(n_theta, n_phi)
                factor = ell * (ell + 1)
                assert np.allclose(g_L2_sYlm,
                                   factor * g_sYlm,
                                   rtol=tolerance,
                                   atol=tolerance)

                # Test Lz {s}Y{l,m} = m * {s}Y{l,m}
                Lz_sYlm = sYlm.Lz()
                g_Lz_sYlm = Lz_sYlm.grid(n_theta, n_phi)
                factor = m
                assert np.allclose(g_Lz_sYlm,
                                   factor * g_sYlm,
                                   rtol=tolerance,
                                   atol=tolerance)

                # Test Lplus {s}Y{l,m} = sqrt((l-m)*(l+m+1)) {s}Y{l,m+1}
                invalid = abs(m + 1) > ell
                sYlmp1 = sf.Modes(zeros(),
                                  spin_weight=s,
                                  ell_min=ell_min,
                                  ell_max=ell_max)
                if invalid:
                    with pytest.raises(ValueError):
                        sYlmp1.index(ell, m + 1)
                else:
                    sYlmp1[sYlmp1.index(ell, m + 1)] = 1.0
                g_sYlmp1 = sYlmp1.grid(n_theta, n_phi)
                Lp_sYlm = sYlm.Lplus()
                g_Lp_sYlm = Lp_sYlm.grid(n_theta, n_phi)
                factor = 0.0 if invalid else math.sqrt(
                    (ell - m) * (ell + m + 1))
                assert np.allclose(g_Lp_sYlm,
                                   factor * g_sYlmp1,
                                   rtol=tolerance,
                                   atol=tolerance)

                # Test Lminus {s}Y{l,m} = sqrt((l+m)*(l-m+1)) * {s}Y{l,m-1}
                invalid = abs(m - 1) > ell
                sYlmm1 = sf.Modes(zeros(),
                                  spin_weight=s,
                                  ell_min=ell_min,
                                  ell_max=ell_max)
                if invalid:
                    with pytest.raises(ValueError):
                        sYlmm1.index(ell, m - 1)
                else:
                    sYlmm1[sYlmm1.index(ell, m - 1)] = 1.0
                g_sYlmm1 = sYlmm1.grid(n_theta, n_phi)
                Lm_sYlm = sYlm.Lminus()
                g_Lm_sYlm = Lm_sYlm.grid(n_theta, n_phi)
                factor = 0.0 if invalid else math.sqrt(
                    (ell + m) * (ell - m + 1))
                assert np.allclose(g_Lm_sYlm,
                                   factor * g_sYlmm1,
                                   rtol=tolerance,
                                   atol=tolerance)

                # Test Rsquared {s}Y{l,m} = l * (l+1) * {s}Y{l,m}
                R2_sYlm = sYlm.Rsquared()
                g_R2_sYlm = R2_sYlm.grid(n_theta, n_phi)
                factor = ell * (ell + 1)
                assert np.allclose(g_R2_sYlm,
                                   factor * g_sYlm,
                                   rtol=tolerance,
                                   atol=tolerance)

                # Test Rz {s}Y{l,m} = -s * {s}Y{l,m}
                Rz_sYlm = sYlm.Rz()
                g_Rz_sYlm = Rz_sYlm.grid(n_theta, n_phi)
                factor = -s
                assert np.allclose(g_Rz_sYlm,
                                   factor * g_sYlm,
                                   rtol=tolerance,
                                   atol=tolerance)

                # Test Rplus {s}Y{l,m} = sqrt((l+s)(l-s+1)) {s-1}Y{l,m}
                invalid = abs(s - 1) > ell
                sm1Ylm = sf.Modes(zeros(),
                                  spin_weight=s - 1,
                                  ell_min=ell_min,
                                  ell_max=ell_max)
                if invalid:
                    with pytest.raises(ValueError):
                        sm1Ylm.index(ell, m)
                else:
                    sm1Ylm[sm1Ylm.index(ell, m)] = 1.0
                g_sm1Ylm = sm1Ylm.grid(n_theta, n_phi)
                Rp_sYlm = sYlm.Rplus()
                g_Rp_sYlm = Rp_sYlm.grid(n_theta, n_phi)
                factor = 0.0 if invalid else math.sqrt(
                    (ell + s) * (ell - s + 1))
                assert np.allclose(g_Rp_sYlm,
                                   factor * g_sm1Ylm,
                                   rtol=tolerance,
                                   atol=tolerance)

                # Test Rminus {s}Y{l,m} = sqrt((l-s)(l+s+1)) {s+1}Y{l,m}
                invalid = abs(s + 1) > ell
                sp1Ylm = sf.Modes(zeros(),
                                  spin_weight=s + 1,
                                  ell_min=ell_min,
                                  ell_max=ell_max)
                if invalid:
                    with pytest.raises(ValueError):
                        sp1Ylm.index(ell, m)
                else:
                    sp1Ylm[sp1Ylm.index(ell, m)] = 1.0
                Rm_sYlm = sYlm.Rminus()
                g_sp1Ylm = sp1Ylm.grid(n_theta, n_phi)
                g_Rm_sYlm = Rm_sYlm.grid(n_theta, n_phi)
                factor = 0.0 if invalid else math.sqrt(
                    (ell - s) * (ell + s + 1))
                assert np.allclose(g_Rm_sYlm,
                                   factor * g_sp1Ylm,
                                   rtol=tolerance,
                                   atol=tolerance)

                # Test eth {s}Y{l,m} = sqrt((l-s)(l+s+1)) {s+1}Y{l,m}
                invalid = abs(s + 1) > ell
                sp1Ylm = sf.Modes(zeros(),
                                  spin_weight=s + 1,
                                  ell_min=ell_min,
                                  ell_max=ell_max)
                if invalid:
                    with pytest.raises(ValueError):
                        sp1Ylm.index(ell, m)
                else:
                    sp1Ylm[sp1Ylm.index(ell, m)] = 1.0
                eth_sYlm = sYlm.eth
                g_sp1Ylm = sp1Ylm.grid(n_theta, n_phi)
                g_eth_sYlm = eth_sYlm.grid(n_theta, n_phi)
                factor = 0.0 if invalid else math.sqrt(
                    (ell - s) * (ell + s + 1))
                assert np.allclose(g_eth_sYlm,
                                   factor * g_sp1Ylm,
                                   rtol=tolerance,
                                   atol=tolerance)

                # Test ethbar {s}Y{l,m} = -sqrt((l+s)(l-s+1)) {s-1}Y{l,m}
                invalid = abs(s - 1) > ell
                sm1Ylm = sf.Modes(zeros(),
                                  spin_weight=s - 1,
                                  ell_min=ell_min,
                                  ell_max=ell_max)
                if invalid:
                    with pytest.raises(ValueError):
                        sm1Ylm.index(ell, m)
                else:
                    sm1Ylm[sm1Ylm.index(ell, m)] = 1.0
                g_sm1Ylm = sm1Ylm.grid(n_theta, n_phi)
                ethbar_sYlm = sYlm.ethbar
                g_ethbar_sYlm = ethbar_sYlm.grid(n_theta, n_phi)
                factor = 0.0 if invalid else -math.sqrt(
                    (ell + s) * (ell - s + 1))
                assert np.allclose(g_ethbar_sYlm,
                                   factor * g_sm1Ylm,
                                   rtol=tolerance,
                                   atol=tolerance)

                # Test ethbar eth sYlm = -(l-s)(l+s+1) sYlm
                ethbar_eth_sYlm = sYlm.eth.ethbar
                g_ethbar_eth_sYlm = ethbar_eth_sYlm.grid(n_theta, n_phi)
                factor = 0.0 if (abs(s + 1) > ell or
                                 abs(s) > ell) else -(ell - s) * (ell + s + 1)
                assert np.allclose(g_ethbar_eth_sYlm,
                                   factor * g_sYlm,
                                   rtol=tolerance,
                                   atol=tolerance)
def test_first_nontrivial_multiplication(multiplication_function):
    """Test f*g where f is an ell=1, s=0 function

    We can write out the expression for f*g in the case where f is a pure ell=1 function, so we can
    check the multiplication function against that formula.  As in `test_trivial_multiplication`, we
    test with multiple values of ellmax_f, and construct `g` from random values.

    """
    def specialized_multiplication(f, ellmin_f, ellmax_f, s_f, g, ellmin_g,
                                   ellmax_g, s_g):
        ellmin_fg = 0
        ellmax_fg = ellmax_f + ellmax_g
        s_fg = s_f + s_g
        fg = np.zeros(sf.LM_total_size(0, ellmax_fg), dtype=np.complex)
        # for ell in range(ellmin_g, ellmax_g+1):
        #     for m in range(-ell, ell+1):
        #         i_g = sf.LM_index(ell, m, ellmin_g)
        #         for ellprime in [ell-1, ell, ell+1]:
        #             if ellprime < ellmin_g or ellprime > ellmax_g or ellprime < abs(s_g):
        #                 continue
        #             for mprime in [m-1, m, m+1]:
        #                 if mprime < -ellprime or mprime > ellprime:
        #                     continue
        #                 i_fg = sf.LM_index(ellprime, mprime, ellmin_fg)
        #                 m1 = mprime - m
        #                 fg[i_fg] += (
        #                     # (-1)**(s_g+m+1)
        #                     # * np.sqrt(3*(2*ell+1)/(4*np.pi))
        #                     # * (-1)**(m1)
        #                     # * np.sqrt(2*ellprime+1)
        #                     (-1)**(1 + ell + ellprime + s_g + m + m1)
        #                     * np.sqrt(3*(2*ell+1)*(2*ellprime+1)/(4*np.pi))
        #                     * sf.Wigner3j(1, ell, ellprime, 0, s_g, -s_g)
        #                     * sf.Wigner3j(1, ell, ellprime, m1, m, -mprime)
        #                     * f[sf.LM_index(1, m1, 0)]
        #                     * g[i_g]
        #                 )
        ####################################################################################
        # for ell in range(ellmin_g, ellmax_g+1):
        #     for m in range(-ell, ell+1):
        #         i_g = sf.LM_index(ell, m, ellmin_g)
        #         coefficient = (-1)**(s_g + m) * np.sqrt(3*(2*ell+1)/(4*np.pi))
        #         for ellprime in [ell-1, ell, ell+1]:
        #             if ellprime < ellmin_g or ellprime > ellmax_g or ellprime < abs(s_g):
        #                 continue
        #             if m-1 >= -ellprime and m-1 <= ellprime:
        #                 i_fg = sf.LM_index(ellprime, m-1, ellmin_fg)
        #                 fg[i_fg] += (
        #                     coefficient
        #                     * (-1)**(ell + ellprime)
        #                     * np.sqrt((2*ellprime+1))
        #                     * sf.Wigner3j(1, ell, ellprime, 0, s_g, -s_g)
        #                     * sf.Wigner3j(1, ell, ellprime, -1, m, -m+1)
        #                     * f[sf.LM_index(1, -1, 0)]
        #                     * g[i_g]
        #                 )
        #             if m >= -ellprime and m <= ellprime:
        #                 i_fg = sf.LM_index(ellprime, m, ellmin_fg)
        #                 fg[i_fg] += (
        #                     coefficient
        #                     * (-1)**(ell + ellprime)
        #                     * -np.sqrt(2*ellprime+1)
        #                     * sf.Wigner3j(1, ell, ellprime, 0, s_g, -s_g)
        #                     * sf.Wigner3j(1, ell, ellprime, 0, m, -m)
        #                     * f[sf.LM_index(1, 0, 0)]
        #                     * g[i_g]
        #                 )
        #             if m+1 >= -ellprime and m+1 <= ellprime:
        #                 i_fg = sf.LM_index(ellprime, m+1, ellmin_fg)
        #                 fg[i_fg] += (
        #                     coefficient
        #                     * (-1)**(ell + ellprime)
        #                     * np.sqrt(2*ellprime+1)
        #                     * sf.Wigner3j(1, ell, ellprime, 0, s_g, -s_g)
        #                     * sf.Wigner3j(1, ell, ellprime, 1, m, -m-1)
        #                     * f[sf.LM_index(1, 1, 0)]
        #                     * g[i_g]
        #                 )
        ####################################################################################
        # for ell in range(ellmin_g, ellmax_g+1):
        #     for m in range(-ell, ell+1):
        #         i_g = sf.LM_index(ell, m, ellmin_g)
        #         coefficient = (-1)**(s_g + m + 1) * np.sqrt(3*(2*ell+1)/(4*np.pi))
        #         if ell-1 >= ellmin_g and ell-1 <= ellmax_g and ell-1 >= abs(s_g):
        #             if m-1 >= -ell+1 and m-1 <= ell-1:
        #                 i_fg = sf.LM_index(ell-1, m-1, ellmin_fg)
        #                 fg[i_fg] += (
        #                     coefficient
        #                     * np.sqrt(2*ell-1)
        #                     * sf.Wigner3j(1, ell, ell-1, 0, s_g, -s_g)
        #                     * sf.Wigner3j(1, ell, ell-1, -1, m, -m+1)
        #                     * f[sf.LM_index(1, -1, 0)]
        #                     * g[i_g]
        #                 )
        #             if m >= -ell+1 and m <= ell-1:
        #                 i_fg = sf.LM_index(ell-1, m, ellmin_fg)
        #                 fg[i_fg] += (
        #                     -coefficient
        #                     * np.sqrt(2*ell-1)
        #                     * sf.Wigner3j(1, ell, ell-1, 0, s_g, -s_g)
        #                     * sf.Wigner3j(1, ell, ell-1, 0, m, -m)
        #                     * f[sf.LM_index(1, 0, 0)]
        #                     * g[i_g]
        #                 )
        #             if m+1 >= -ell+1 and m+1 <= ell-1:
        #                 i_fg = sf.LM_index(ell-1, m+1, ellmin_fg)
        #                 fg[i_fg] += (
        #                     coefficient
        #                     * np.sqrt(2*ell-1)
        #                     * sf.Wigner3j(1, ell, ell-1, 0, s_g, -s_g)
        #                     * sf.Wigner3j(1, ell, ell-1, 1, m, -m-1)
        #                     * f[sf.LM_index(1, 1, 0)]
        #                     * g[i_g]
        #                 )
        #         if ell >= ellmin_g and ell <= ellmax_g and ell >= abs(s_g):
        #             if m-1 >= -ell and m-1 <= ell:
        #                 i_fg = sf.LM_index(ell, m-1, ellmin_fg)
        #                 fg[i_fg] += (
        #                     -coefficient
        #                     * np.sqrt(2*ell+1)
        #                     * sf.Wigner3j(1, ell, ell, 0, s_g, -s_g)
        #                     * sf.Wigner3j(1, ell, ell, -1, m, -m+1)
        #                     * f[sf.LM_index(1, -1, 0)]
        #                     * g[i_g]
        #                 )
        #             if m >= -ell and m <= ell:
        #                 i_fg = sf.LM_index(ell, m, ellmin_fg)
        #                 fg[i_fg] += (
        #                     coefficient
        #                     * np.sqrt(2*ell+1)
        #                     * sf.Wigner3j(1, ell, ell, 0, s_g, -s_g)
        #                     * sf.Wigner3j(1, ell, ell, 0, m, -m)
        #                     * f[sf.LM_index(1, 0, 0)]
        #                     * g[i_g]
        #                 )
        #             if m+1 >= -ell and m+1 <= ell:
        #                 i_fg = sf.LM_index(ell, m+1, ellmin_fg)
        #                 fg[i_fg] += (
        #                     -coefficient
        #                     * np.sqrt(2*ell+1)
        #                     * sf.Wigner3j(1, ell, ell, 0, s_g, -s_g)
        #                     * sf.Wigner3j(1, ell, ell, 1, m, -m-1)
        #                     * f[sf.LM_index(1, 1, 0)]
        #                     * g[i_g]
        #                 )
        #         if ell+1 >= ellmin_g and ell+1 <= ellmax_g and ell+1 >= abs(s_g):
        #             if m-1 >= -ell-1 and m-1 <= ell+1:
        #                 i_fg = sf.LM_index(ell+1, m-1, ellmin_fg)
        #                 fg[i_fg] += (
        #                     coefficient
        #                     * np.sqrt(2*ell+3)
        #                     * sf.Wigner3j(1, ell, ell+1, 0, s_g, -s_g)
        #                     * sf.Wigner3j(1, ell, ell+1, -1, m, -m+1)
        #                     * f[sf.LM_index(1, -1, 0)]
        #                     * g[i_g]
        #                 )
        #             if m >= -ell-1 and m <= ell+1:
        #                 i_fg = sf.LM_index(ell+1, m, ellmin_fg)
        #                 fg[i_fg] += (
        #                     -coefficient
        #                     * np.sqrt(2*ell+3)
        #                     * sf.Wigner3j(1, ell, ell+1, 0, s_g, -s_g)
        #                     * sf.Wigner3j(1, ell, ell+1, 0, m, -m)
        #                     * f[sf.LM_index(1, 0, 0)]
        #                     * g[i_g]
        #                 )
        #             if m+1 >= -ell-1 and m+1 <= ell+1:
        #                 i_fg = sf.LM_index(ell+1, m+1, ellmin_fg)
        #                 fg[i_fg] += (
        #                     coefficient
        #                     * np.sqrt(2*ell+3)
        #                     * sf.Wigner3j(1, ell, ell+1, 0, s_g, -s_g)
        #                     * sf.Wigner3j(1, ell, ell+1, 1, m, -m-1)
        #                     * f[sf.LM_index(1, 1, 0)]
        #                     * g[i_g]
        #                 )
        ####################################################################################
        for ell in range(ellmin_g, ellmax_g + 1):
            for m in range(-ell, ell + 1):
                i_fg = sf.LM_index(ell, m, ellmin_fg)
                coefficient = (-1)**(s_g + m) * np.sqrt(3 * (2 * ell + 1) /
                                                        (4 * np.pi))
                if ell + 1 >= ellmin_g and ell + 1 <= ellmax_g and ell + 1 >= abs(
                        s_g):
                    if m + 1 >= -ell - 1 and m + 1 <= ell + 1:
                        fg[i_fg] += (
                            coefficient * np.sqrt(2 * ell + 3) *
                            sf.Wigner3j(1, ell + 1, ell, 0, s_g, -s_g) *
                            sf.Wigner3j(1, ell + 1, ell, -1, m + 1, -m) *
                            f[sf.LM_index(1, -1, 0)] *
                            g[sf.LM_index(ell + 1, m + 1, ellmin_g)])
                    if m >= -ell - 1 and m <= ell + 1:
                        fg[i_fg] += (
                            coefficient * np.sqrt(2 * ell + 3) *
                            sf.Wigner3j(1, ell + 1, ell, 0, s_g, -s_g) *
                            sf.Wigner3j(1, ell + 1, ell, 0, m, -m) *
                            f[sf.LM_index(1, 0, 0)] *
                            g[sf.LM_index(ell + 1, m, ellmin_g)])
                    if m - 1 >= -ell - 1 and m - 1 <= ell + 1:
                        fg[i_fg] += (
                            coefficient * np.sqrt(2 * ell + 3) *
                            sf.Wigner3j(1, ell + 1, ell, 0, s_g, -s_g) *
                            sf.Wigner3j(1, ell + 1, ell, 1, m - 1, -m) *
                            f[sf.LM_index(1, 1, 0)] *
                            g[sf.LM_index(ell + 1, m - 1, ellmin_g)])
                if ell >= ellmin_g and ell <= ellmax_g and ell >= abs(s_g):
                    if m + 1 >= -ell and m + 1 <= ell:
                        fg[i_fg] += (-coefficient * np.sqrt(2 * ell + 1) *
                                     sf.Wigner3j(1, ell, ell, 0, s_g, -s_g) *
                                     sf.Wigner3j(1, ell, ell, -1, m + 1, -m) *
                                     f[sf.LM_index(1, -1, 0)] *
                                     g[sf.LM_index(ell, m + 1, ellmin_g)])
                    if m >= -ell and m <= ell:
                        fg[i_fg] += (-coefficient * np.sqrt(2 * ell + 1) *
                                     sf.Wigner3j(1, ell, ell, 0, s_g, -s_g) *
                                     sf.Wigner3j(1, ell, ell, 0, m, -m) *
                                     f[sf.LM_index(1, 0, 0)] *
                                     g[sf.LM_index(ell, m, ellmin_g)])
                    if m - 1 >= -ell and m - 1 <= ell:
                        fg[i_fg] += (-coefficient * np.sqrt(2 * ell + 1) *
                                     sf.Wigner3j(1, ell, ell, 0, s_g, -s_g) *
                                     sf.Wigner3j(1, ell, ell, 1, m - 1, -m) *
                                     f[sf.LM_index(1, 1, 0)] *
                                     g[sf.LM_index(ell, m - 1, ellmin_g)])
                if ell - 1 >= ellmin_g and ell - 1 <= ellmax_g and ell - 1 >= abs(
                        s_g):
                    if m + 1 >= -ell + 1 and m + 1 <= ell - 1:
                        fg[i_fg] += (
                            coefficient * np.sqrt(2 * ell - 1) *
                            sf.Wigner3j(1, ell - 1, ell, 0, s_g, -s_g) *
                            sf.Wigner3j(1, ell - 1, ell, -1, m + 1, -m) *
                            f[sf.LM_index(1, -1, 0)] *
                            g[sf.LM_index(ell - 1, m + 1, ellmin_g)])
                    if m >= -ell + 1 and m <= ell - 1:
                        fg[i_fg] += (
                            coefficient * np.sqrt(2 * ell - 1) *
                            sf.Wigner3j(1, ell - 1, ell, 0, s_g, -s_g) *
                            sf.Wigner3j(1, ell - 1, ell, 0, m, -m) *
                            f[sf.LM_index(1, 0, 0)] *
                            g[sf.LM_index(ell - 1, m, ellmin_g)])
                    if m - 1 >= -ell + 1 and m - 1 <= ell - 1:
                        fg[i_fg] += (
                            coefficient * np.sqrt(2 * ell - 1) *
                            sf.Wigner3j(1, ell - 1, ell, 0, s_g, -s_g) *
                            sf.Wigner3j(1, ell - 1, ell, 1, m - 1, -m) *
                            f[sf.LM_index(1, 1, 0)] *
                            g[sf.LM_index(ell - 1, m - 1, ellmin_g)])
        return fg, ellmin_fg, ellmax_fg, s_fg

    np.random.seed(1234)
    atol = 2e-15
    rtol = 2e-15
    ellmax_g = 8
    print()
    for ellmax_f in range(1, ellmax_g + 1):
        # print(ellmax_f)
        f = np.zeros(sf.LM_total_size(0, ellmax_f), dtype=np.complex)
        f[1:4] = np.random.rand(3) + 1j * np.random.rand(3)
        ellmin_f = 0
        s_f = 0
        ellmin_g = 0
        for s_g in range(1 - ellmax_g, ellmax_g):
            # print('\t', s_g)
            i_max = sf.LM_index(ellmax_g, ellmax_g, ellmin_g)
            g = np.random.rand(sf.LM_total_size(
                0,
                ellmax_g)) + 1j * np.random.rand(sf.LM_total_size(0, ellmax_g))
            g[:sf.LM_total_size(0, abs(s_g) - 1) + 1] = 0.0
            fg, ellmin_fg, ellmax_fg, s_fg = multiplication_function(
                f, ellmin_f, ellmax_f, s_f, g, ellmin_g, ellmax_g, s_g)
            fg2, ellmin_fg2, ellmax_fg2, s_fg2 = specialized_multiplication(
                f, ellmin_f, ellmax_f, s_f, g, ellmin_g, ellmax_g, s_g)
            assert s_fg == s_f + s_g
            assert ellmin_fg == 0
            assert ellmax_fg == ellmax_f + ellmax_g
            import pprint
            assert np.allclose(
                fg[:i_max + 1], fg2[:i_max + 1], atol=atol,
                rtol=rtol), pprint.pformat(list(fg)) + '\n\n' + pprint.pformat(
                    list(fg2))
            gf, ellmin_gf, ellmax_gf, s_gf = multiplication_function(
                g, ellmin_g, ellmax_g, s_g, f, ellmin_f, ellmax_f, s_f)
            assert s_gf == s_g + s_f
            assert ellmin_gf == 0
            assert ellmax_gf == ellmax_g + ellmax_f
            assert np.allclose(gf[:i_max + 1],
                               fg2[:i_max + 1],
                               atol=atol,
                               rtol=rtol)
示例#30
0
def test_modes_derivative_commutators():
    tolerance = 1e-13
    np.random.seed(1234)
    # Note that post-fix operators are in the opposite order compared
    # to prefixed commutators, so we pull the post-fix operators out
    # as functions to make things look right.
    np.random.seed(1234)
    L2 = sf.Modes.Lsquared
    Lz = sf.Modes.Lz
    Lp = sf.Modes.Lplus
    Lm = sf.Modes.Lminus
    R2 = sf.Modes.Rsquared
    Rz = sf.Modes.Rz
    Rp = sf.Modes.Rplus
    Rm = sf.Modes.Rminus
    eth = lambda modes: modes.eth
    ethbar = lambda modes: modes.ethbar
    for s in range(-2, 2 + 1):
        ell_min = abs(s)
        ell_max = 8
        a = np.random.rand(3, 7,
                           sf.LM_total_size(ell_min, ell_max) *
                           2).view(complex)
        m = sf.Modes(a, spin_weight=s, ell_min=ell_min, ell_max=ell_max)
        # Test [Ri, Lj] = 0
        for R in [Rz, Rp, Rm]:
            for L in [Lz, Lp, Lm]:
                assert np.max(np.abs(L(R(m)) - R(L(m)))) < tolerance
        # Test [L2, Lj] = 0
        for L in [Lz, Lp, Lm]:
            assert np.max(np.abs(L2(L(m)) - L(L2(m)))) < 5 * tolerance
        # Test [R2, Rj] = 0
        for R in [Rz, Rp, Rm]:
            assert np.max(np.abs(R2(R(m)) - R(R2(m)))) < 5 * tolerance
        # Test [Lz, Lp] = Lp
        assert np.allclose(Lz(Lp(m)) - Lp(Lz(m)),
                           Lp(m),
                           rtol=tolerance,
                           atol=tolerance)
        # Test [Lz, Lm] = -Lm
        assert np.allclose(Lz(Lm(m)) - Lm(Lz(m)),
                           -Lm(m),
                           rtol=tolerance,
                           atol=tolerance)
        # Test [Lp, Lm] = 2Lz
        assert np.allclose(Lp(Lm(m)) - Lm(Lp(m)),
                           2 * Lz(m),
                           rtol=tolerance,
                           atol=tolerance)
        # Test [Rz, Rp] = Rp
        assert np.allclose(Rz(Rp(m)) - Rp(Rz(m)),
                           Rp(m),
                           rtol=tolerance,
                           atol=tolerance)
        # Test [Rz, Rm] = -Rm
        assert np.allclose(Rz(Rm(m)) - Rm(Rz(m)),
                           -Rm(m),
                           rtol=tolerance,
                           atol=tolerance)
        # Test [Rp, Rm] = 2Rz
        assert np.allclose(Rp(Rm(m)) - Rm(Rp(m)),
                           2 * Rz(m),
                           rtol=tolerance,
                           atol=tolerance)
        # Test [ethbar, eth] = 2s
        assert np.allclose(ethbar(eth(m)) - eth(ethbar(m)),
                           2 * m.s * m,
                           rtol=tolerance,
                           atol=tolerance)