Exemplo n.º 1
0
 def test_spline_with_sph_harms(self):
     """Test spline projection the same as spherical harmonics."""
     odg = OneDGrid(np.arange(10) + 1, np.ones(10), (0, np.inf))
     rad = IdentityRTransform().transform_1d_grid(odg)
     atgrid = AtomGrid.from_pruned(rad, 1, sectors_r=[], sectors_degree=[7])
     sph_coor = atgrid.convert_cart_to_sph()
     values = self.helper_func_power(atgrid.points)
     l_max = atgrid.l_max // 2
     r_sph = generate_real_sph_harms(l_max, sph_coor[:, 1], sph_coor[:, 2])
     result = spline_with_sph_harms(r_sph, values, atgrid.weights,
                                    atgrid.indices, rad)
     # generate ref
     for shell in range(1, 11):
         sh_grid = atgrid.get_shell_grid(shell - 1, r_sq=False)
         # Convert to spherical harmonics
         r = np.linalg.norm(sh_grid._points, axis=1)
         theta = np.arctan2(sh_grid._points[:, 1], sh_grid._points[:, 0])
         phi = np.arccos(sh_grid._points[:, 2] / r)
         # General all spherical harmonics up to l_max
         r_sph = generate_real_sph_harms(l_max, theta, phi)
         # Project the function 2x^2 + 3y^2 + 4z^2
         r_sph_proj = np.sum(
             r_sph * self.helper_func_power(sh_grid.points) *
             sh_grid.weights,
             axis=-1,
         )
         # Check the actual projection against the cubic spline interpolation.
         assert_allclose(r_sph_proj, result(shell), atol=1e-10)
Exemplo n.º 2
0
 def test_spline_with_sph_harms(self):
     """Test spline projection the same as spherical harmonics."""
     rad = IdentityRTransform().transform_grid(HortonLinear(10))
     rad._points += 1
     atgrid = AtomicGrid.special_init(rad, 1, scales=[], degs=[7])
     sph_coor = atgrid.convert_cart_to_sph()
     values = self.helper_func_power(atgrid.points)
     l_max = atgrid.l_max // 2
     r_sph = generate_real_sph_harms(l_max, sph_coor[:, 0], sph_coor[:, 1])
     result = spline_with_sph_harms(
         r_sph, values, atgrid.weights, atgrid.indices, rad.points
     )
     # generate ref
     # for shell in range(1, 11):
     for shell in range(1, 11):
         sh_grid = atgrid.get_shell_grid(shell - 1, r_sq=False)
         r = np.linalg.norm(sh_grid._points, axis=1)
         theta = np.arctan2(sh_grid._points[:, 1], sh_grid._points[:, 0])
         phi = np.arccos(sh_grid._points[:, 2] / r)
         r_sph = generate_real_sph_harms(l_max, theta, phi)
         r_sph_proj = np.sum(
             r_sph * self.helper_func_power(sh_grid.points) * sh_grid.weights,
             axis=-1,
         )
         assert_allclose(r_sph_proj, result(shell), atol=1e-10)
Exemplo n.º 3
0
 def test_generate_real_sph_harms(self):
     """Test generated real spherical harmonics values."""
     pts = self.ang_grid.points
     wts = self.ang_grid.weights
     r = np.linalg.norm(pts, axis=1)
     # polar
     phi = np.arccos(pts[:, 2] / r)
     # azimuthal
     theta = np.arctan2(pts[:, 1], pts[:, 0])
     # generate spherical harmonics
     sph_h = generate_real_sph_harms(3, theta, phi)  # l_max = 3
     assert sph_h.shape == (7, 4, 26)
     for _ in range(20):
         n = np.random.randint(0, 4, 2)
         m1 = np.random.randint(-n[0], n[0] + 1)
         m2 = np.random.randint(-n[1], n[1] + 1)
         re = sum(sph_h[m1, n[0]] * sph_h[m2, n[1]] * wts)
         if n[0] != n[1] or m1 != m2:
             print(n, m1, m2, re)
             assert_almost_equal(re, 0)
         else:
             print(n, m1, m2, re)
             assert_almost_equal(re, 1)
         # no nan in the final result
         assert np.sum(np.isnan(re)) == 0
Exemplo n.º 4
0
    def interpolate(spls_mtr, rad, theta, phi, deriv=0):
        """Inperpolate points on any 3d space.

        Parameters
        ----------
        spls_mtr : np.ndadrray(M, L)
            An array of solved spline for poisson ODE
        rad : float
            Radial value to be interpolated
        theta : np.ndarray(N,)
            An array of azimuthal angles
        phi : np.ndarray(N,)
            An array of polar angles
        deriv : int, optional
            0 for function value, 1 for its first order deriv

        Returns
        -------
        np.ndarray(N,)
            Interpolated value on each point
        """
        ms, ls = spls_mtr.shape
        # (M, L, N)
        sph_harm = generate_real_sph_harms(ls - 1, theta, phi)
        r_value = Poisson.interpolate_radial(spls_mtr, rad, deriv)
        return np.sum(r_value[..., None] * sph_harm, axis=(0, 1))
Exemplo n.º 5
0
 def test_project_function_onto_spherical_expansion(self):
     r"""Test projecting a spherical harmonic onto itself and check if it's the same."""
     l_max = 4
     angular_grid = AngularGrid(degree=10)
     # Convert Cartesian points to spherical coordinates
     r = np.linalg.norm(angular_grid.points, axis=1)
     phi = np.arccos(angular_grid.points[:, 2] / r)
     theta = np.arctan2(angular_grid.points[:, 1], angular_grid.points[:,
                                                                       0])
     # Generate the real spherical harmonics up to degree l_max for all orders m.
     sph_harms = generate_real_sph_harms(l_max, theta, phi)
     # Go through each degree l and order m
     for l_deg in range(0, l_max + 1):
         for m_ord in range(-l_deg, l_deg + 1):
             # Get spherical harmonic with order m and degree l
             sph_harm_l_m = sph_harms[m_ord, l_deg, :]
             # Project sph_harm_l_m onto the spherical harmonic expnasion
             #   Returns (1, l_{max}* 2 + 1, l_{max})
             proj_coeffs = project_function_onto_spherical_expansion(
                 sph_harms,
                 sph_harm_l_m,
                 angular_grid.weights,
                 [0, angular_grid.size],
             )
             # Fourier coefficients from projection onto itself should be one.
             assert np.abs(proj_coeffs[0, m_ord, l_deg] - 1.0) < 1e-8
             for l2 in range(0, l_max + 1):
                 for m2 in range(-l2, l2 + 1):
                     if l2 != l_deg or m_ord != m2:
                         # Spherical harmonic forms an orthogonal system.
                         assert np.abs(proj_coeffs[0, m2, l2]) < 1e-8
Exemplo n.º 6
0
    def test_integration_of_spherical_harmonic_not_accurate_beyond_degree(
            self):
        r"""Test integration of spherical harmonic of degree higher than grid is not accurate."""
        grid = AngularGrid(degree=3)
        r = np.linalg.norm(grid.points, axis=1)
        phi = np.arccos(grid.points[:, 2] / r)
        theta = np.arctan2(grid.points[:, 1], grid.points[:, 0])

        sph_harm = generate_real_sph_harms(l_max=6, theta=theta, phi=phi)
        # Check that l=4,m=0 gives inaccurate results
        assert np.abs(grid.integrate(sph_harm[0, 4, :])) > 1e-8
        # Check that l=6,m=0 gives inaccurate results
        assert np.abs(grid.integrate(sph_harm[0, 6, :])) > 1e-8
Exemplo n.º 7
0
    def test_derivative_of_interpolate_given_splines(self):
        """Test the spline interpolating derivative of function in radial coordinate."""
        odg = OneDGrid(np.arange(10) + 1, np.ones(10), (0, np.inf))
        rad = IdentityRTransform().transform_1d_grid(odg)
        atgrid = AtomGrid.from_pruned(rad, 1, sectors_r=[], sectors_degree=[7])
        sph_coor = atgrid.convert_cart_to_sph()
        values = self.helper_func_power(atgrid.points)
        l_max = atgrid.l_max // 2
        r_sph = generate_real_sph_harms(l_max, sph_coor[:, 1], sph_coor[:, 2])
        result = spline_with_sph_harms(r_sph, values, atgrid.weights,
                                       atgrid.indices, rad)
        semi_sph_c = sph_coor[atgrid.indices[5]:atgrid.indices[6]]
        interp = interpolate_given_splines(result,
                                           6,
                                           semi_sph_c[:, 1],
                                           semi_sph_c[:, 2],
                                           deriv=1)
        # same result from points and interpolation
        ref_deriv = self.helper_func_power_deriv(
            atgrid.points[atgrid.indices[5]:atgrid.indices[6]])
        assert_allclose(interp, ref_deriv)

        # test random x, y, z with fd
        xyz = np.random.rand(1, 3)
        xyz /= np.linalg.norm(xyz, axis=-1)[:, None]
        rad = np.random.normal() * np.random.randint(1, 11)
        xyz *= rad
        ref_value = self.helper_func_power_deriv(xyz)

        r = np.linalg.norm(xyz, axis=-1)
        theta = np.arctan2(xyz[:, 1], xyz[:, 0])
        phi = np.arccos(xyz[:, 2] / r)
        interp = interpolate_given_splines(result,
                                           np.abs(rad),
                                           theta,
                                           phi,
                                           deriv=1)
        assert_allclose(interp, ref_value)

        with self.assertRaises(ValueError):
            interpolate_given_splines(result,
                                      6,
                                      semi_sph_c[:, 1],
                                      semi_sph_c[:, 2],
                                      deriv=4)
        with self.assertRaises(ValueError):
            interpolate_given_splines(result,
                                      6,
                                      semi_sph_c[:, 1],
                                      semi_sph_c[:, 2],
                                      deriv=-1)
Exemplo n.º 8
0
    def _proj_sph_value(radial, atcoords, l_max, value_array, weights,
                        indices):
        """Compute the spline for target function on each spherical harmonics.

        Parameters
        ----------
        radial : RadialGrid
            Radial grids for compute coeffs on each Real Spherical Harmonics.
        atcoords : numpy.ndarray(N, 2)
            Spherical coordinates for comput coeff. [azimuthal, polar]
        l_max : int, >= 0
            The maximum value l in generated real spherical harmonics
        value_array : np.ndarray(N)
            Function value need to be projected onto real spherical harmonics
        weights : np.ndarray
            Weight of each point on the integration grid
        indices : np.ndarray
            Array of indices indicate the beginning and ending of each
            radial point

        Returns
        -------
        np.ndarray[scipy.PPoly], shape(2L - 1, L + 1)
            scipy cubic spline instance of each harmonic shell
        """
        if atcoords.shape[1] > 2:
            raise ValueError(
                f"Input coordinates contains too many columns\n"
                f"Only 2 columns needed, got coors shape:{atcoords.shape}")
        theta, phi = atcoords[:, 0], atcoords[:, 1]
        real_sph = generate_real_sph_harms(l_max, theta, phi)
        # real_sph shape: (m, l, n)
        ms, ls = real_sph.shape[:-1]
        # store spline for each p^{lm}
        spls_mtr = np.zeros((ms, ls), dtype=object)
        ml_sph_value = compute_spline_point_value(real_sph, value_array,
                                                  weights, indices)
        ml_sph_value /= (radial.points**2 * radial.weights)[:, None, None]
        for l_value in range(ls):
            for m_value in range(-l_value, l_value + 1):
                spls_mtr[m_value,
                         l_value] = CubicSpline(x=radial.points,
                                                y=ml_sph_value[:, m_value,
                                                               l_value])
        return spls_mtr
Exemplo n.º 9
0
 def test_integration_of_spherical_harmonic_up_to_degree_three(self):
     r"""Test integration of spherical harmonic up to degree three is accurate."""
     degree = 3
     grid = AngularGrid(degree=100)
     # Concert to spherical coordinates from Cartesian.
     r = np.linalg.norm(grid.points, axis=1)
     phi = np.arccos(grid.points[:, 2] / r)
     theta = np.arctan2(grid.points[:, 1], grid.points[:, 0])
     # Generate All Spherical Harmonics Up To Degree = 3
     #   Returns a three dimensional array where [order m, degree l, points]
     sph_harm = generate_real_sph_harms(degree, theta, phi)
     for l_deg in range(0, 4):
         for m_ord in range(-l_deg, l_deg):
             if l_deg == 0 and m_ord == 0:
                 actual = np.sqrt(4.0 * np.pi)
                 assert_equal(actual,
                              grid.integrate(sph_harm[m_ord, l_deg, :]))
             else:
                 assert_almost_equal(
                     0.0, grid.integrate(sph_harm[m_ord, l_deg, :]))
Exemplo n.º 10
0
 def test_orthogonality_of_spherical_harmonic_up_to_degree_three(self):
     r"""Test orthogonality of spherical harmonic up to degree 3 is accurate."""
     degree = 3
     grid = AngularGrid(degree=10)
     # Concert to spherical coordinates from Cartesian.
     r = np.linalg.norm(grid.points, axis=1)
     phi = np.arccos(grid.points[:, 2] / r)
     theta = np.arctan2(grid.points[:, 1], grid.points[:, 0])
     # Generate All Spherical Harmonics Up To Degree = 3
     #   Returns a three dimensional array where [order m, degree l, points]
     sph_harm = generate_real_sph_harms(degree, theta, phi)
     for l_deg in range(0, 4):
         for m_ord in range(-l_deg, l_deg + 1):
             for l2 in range(0, 4):
                 for m2 in range(-l_deg, l_deg + 1):
                     integral = grid.integrate(sph_harm[m_ord, l_deg, :] *
                                               sph_harm[m2, l2, :])
                     if l2 != l_deg or m2 != m_ord:
                         assert np.abs(integral) < 1e-8
                     else:
                         assert np.abs(integral - 1.0) < 1e-8
Exemplo n.º 11
0
    def test_cubicspline_and_deriv(self):
        """Test spline for derivation."""
        rad = IdentityRTransform().transform_grid(HortonLinear(10))
        rad._points += 1
        atgrid = AtomicGrid.special_init(rad, 1, scales=[], degs=[7])
        sph_coor = atgrid.convert_cart_to_sph()
        values = self.helper_func_power(atgrid.points)
        l_max = atgrid.l_max // 2
        r_sph = generate_real_sph_harms(l_max, sph_coor[:, 0], sph_coor[:, 1])
        result = spline_with_sph_harms(
            r_sph, values, atgrid.weights, atgrid.indices, rad.points
        )
        semi_sph_c = sph_coor[atgrid.indices[5] : atgrid.indices[6]]
        interp = interpolate(result, 6, semi_sph_c[:, 0], semi_sph_c[:, 1], deriv=1)
        # same result from points and interpolation
        ref_deriv = self.helper_func_power_deriv(
            atgrid.points[atgrid.indices[5] : atgrid.indices[6]]
        )
        assert_allclose(interp, ref_deriv)

        # test random x, y, z with fd
        xyz = np.random.rand(1, 3)
        xyz /= np.linalg.norm(xyz, axis=-1)[:, None]
        rad = np.random.normal() * np.random.randint(1, 11)
        xyz *= rad
        ref_value = self.helper_func_power_deriv(xyz)

        r = np.linalg.norm(xyz, axis=-1)
        theta = np.arctan2(xyz[:, 1], xyz[:, 0])
        phi = np.arccos(xyz[:, 2] / r)
        interp = interpolate(result, np.abs(rad), theta, phi, deriv=1)
        assert_allclose(interp, ref_value)

        with self.assertRaises(ValueError):
            interp = interpolate(result, 6, semi_sph_c[:, 0], semi_sph_c[:, 1], deriv=4)
        with self.assertRaises(ValueError):
            interp = interpolate(
                result, 6, semi_sph_c[:, 0], semi_sph_c[:, 1], deriv=-1
            )
Exemplo n.º 12
0
    def test_interpolate_given_splines_at_random_points(self):
        """Test interpolation given splines at random points."""
        odg = OneDGrid(np.arange(10) + 1, np.ones(10), (0, np.inf))
        rad = IdentityRTransform().transform_1d_grid(odg)
        atgrid = AtomGrid.from_pruned(rad, 1, sectors_r=[], sectors_degree=[7])
        sph_coor = atgrid.convert_cart_to_sph()
        values = self.helper_func_power(atgrid.points)
        l_max = atgrid.l_max // 2
        r_sph = generate_real_sph_harms(l_max, sph_coor[:, 1], sph_coor[:, 2])
        result = spline_with_sph_harms(r_sph, values, atgrid.weights,
                                       atgrid.indices, rad)
        semi_sph_c = sph_coor[atgrid.indices[5]:atgrid.indices[6]]
        interp = interpolate_given_splines(result, 6, semi_sph_c[:, 1],
                                           semi_sph_c[:, 2])
        # same result from points and interpolation
        assert_allclose(interp, values[atgrid.indices[5]:atgrid.indices[6]])

        # random multiple interpolation test
        for _ in range(100):
            indices = np.random.randint(1, 11, np.random.randint(1, 10))
            interp = interpolate_given_splines(result, indices,
                                               semi_sph_c[:, 1], semi_sph_c[:,
                                                                            2])
            for i, j in enumerate(indices):
                assert_allclose(
                    interp[i], values[atgrid.indices[j - 1]:atgrid.indices[j]])

        # test random x, y, z
        xyz = np.random.rand(10, 3)
        xyz /= np.linalg.norm(xyz, axis=-1)[:, None]
        rad = np.random.normal() * np.random.randint(1, 11)
        xyz *= rad
        ref_value = self.helper_func_power(xyz)

        r = np.linalg.norm(xyz, axis=-1)
        theta = np.arctan2(xyz[:, 1], xyz[:, 0])
        phi = np.arccos(xyz[:, 2] / r)
        interp = interpolate_given_splines(result, np.abs(rad), theta, phi)
        assert_allclose(interp, ref_value)
Exemplo n.º 13
0
    def test_cubicspline_and_interp(self):
        """Test cubicspline interpolation values."""
        rad = IdentityRTransform().transform_grid(HortonLinear(10))
        rad._points += 1
        atgrid = AtomicGrid.special_init(rad, 1, scales=[], degs=[7])
        sph_coor = atgrid.convert_cart_to_sph()
        values = self.helper_func_power(atgrid.points)
        l_max = atgrid.l_max // 2
        r_sph = generate_real_sph_harms(l_max, sph_coor[:, 0], sph_coor[:, 1])
        result = spline_with_sph_harms(
            r_sph, values, atgrid.weights, atgrid.indices, rad.points
        )
        semi_sph_c = sph_coor[atgrid.indices[5] : atgrid.indices[6]]
        interp = interpolate(result, 6, semi_sph_c[:, 0], semi_sph_c[:, 1])
        # same result from points and interpolation
        assert_allclose(interp, values[atgrid.indices[5] : atgrid.indices[6]])

        # random multiple interpolation test
        for _ in range(100):
            indices = np.random.randint(1, 11, np.random.randint(1, 10))
            interp = interpolate(result, indices, semi_sph_c[:, 0], semi_sph_c[:, 1])
            for i, j in enumerate(indices):
                assert_allclose(
                    interp[i], values[atgrid.indices[j - 1] : atgrid.indices[j]]
                )

        # test random x, y, z
        xyz = np.random.rand(10, 3)
        xyz /= np.linalg.norm(xyz, axis=-1)[:, None]
        rad = np.random.normal() * np.random.randint(1, 11)
        xyz *= rad
        ref_value = self.helper_func_power(xyz)

        r = np.linalg.norm(xyz, axis=-1)
        theta = np.arctan2(xyz[:, 1], xyz[:, 0])
        phi = np.arccos(xyz[:, 2] / r)
        interp = interpolate(result, np.abs(rad), theta, phi)
        assert_allclose(interp, ref_value)
Exemplo n.º 14
0
    def test_cubicpline_and_interp(self):
        """Test cubicspline interpolation values."""
        rad = HortonLinear(10)
        rad._points += 1
        atgrid = AtomicGrid(rad, 1, scales=[], degs=[7])
        sph_coor = atgrid.convert_cart_to_sph()
        values = self.helper_func_power(atgrid.points)
        l_max = atgrid.l_max // 2
        r_sph = generate_real_sph_harms(l_max, sph_coor[:, 0], sph_coor[:, 1])
        result = spline_with_sph_harms(r_sph, values, atgrid.weights,
                                       atgrid.indices, rad.points)
        semi_sph_c = sph_coor[atgrid.indices[5]:atgrid.indices[6]]
        interp = interpelate(result, 6, semi_sph_c[:, 0], semi_sph_c[:, 1])
        # same result from points and interpolation
        assert_allclose(interp, values[atgrid.indices[5]:atgrid.indices[6]])

        # random multiple interpolation test
        for _ in range(100):
            indices = np.random.randint(1, 11, np.random.randint(1, 10))
            interp = interpelate(result, indices, semi_sph_c[:, 0],
                                 semi_sph_c[:, 1])
            for i, j in enumerate(indices):
                assert_allclose(
                    interp[i], values[atgrid.indices[j - 1]:atgrid.indices[j]])