Exemplo n.º 1
0
    def test_cubicspline_and_deriv(self):
        """Test spline for derivation."""
        odg = OneDGrid(np.arange(10) + 1, np.ones(10), (0, np.inf))
        rad = IdentityRTransform().transform_1d_grid(odg)
        for _ in range(10):
            degree = np.random.randint(5, 20)
            atgrid = AtomGrid.from_pruned(rad,
                                          1,
                                          sectors_r=[],
                                          sectors_degree=[degree])
            values = self.helper_func_power(atgrid.points)
            # spls = atgrid.fit_values(values)

            for i in range(10):
                interp = atgrid.interpolate(
                    atgrid.points[atgrid.indices[i]:atgrid.indices[i + 1]],
                    values,
                    deriv=1,
                )
                # same result from points and interpolation
                ref_deriv = self.helper_func_power_deriv(
                    atgrid.points[atgrid.indices[i]:atgrid.indices[i + 1]])
                assert_allclose(interp, ref_deriv)

            # test random x, y, z with fd
            for _ in range(10):
                xyz = np.random.rand(10, 3) * np.random.uniform(1, 6)
                ref_value = self.helper_func_power_deriv(xyz)
                interp = atgrid.interpolate(xyz, values, deriv=1)
                assert_allclose(interp, ref_value)
Exemplo n.º 2
0
 def setUp(self):
     """Set up radial grid for integral tests."""
     pts = HortonLinear(100)
     tf = ExpRTransform(1e-3, 1e1)
     rad_pts = tf.transform(pts.points)
     rad_wts = tf.deriv(pts.points) * pts.weights
     self.rgrid = OneDGrid(rad_pts, rad_wts)
Exemplo n.º 3
0
def GaussChebyshev(npoints):
    r"""Generate a grid based on Gauss-Chebyshev grid.

    Gauss Chebyshev grid is defined as:
    .. math::
        \int_{-1}^{1} \frac{f(x)}{\sqrt{1-x^2}}dx \approx \sum_{i=1}^n w_i f(x_i)

    This integration grid is defined as :
    .. math::
        \int_{-1}^{1}f(x)dx\approx\sum_{i=1}^n  w_i \sqrt{1-x_i^2} f(x_i)
        = \sum_{i=1}^n  w_i' f(x_i)
    Parameters
    ----------
    npoints : int
        Number of points in the grid

    Returns
    -------
    OneDGrid
        A grid instance with points and weights, [-1, 1]
    """
    # points are generated in decreasing order
    # weights are pi/n, all weights are the same
    points, weights = np.polynomial.chebyshev.chebgauss(npoints)
    weights = weights * np.sqrt(1 - np.power(points, 2))
    return OneDGrid(points[::-1], weights)
Exemplo n.º 4
0
 def test_atomic_rotate(self):
     """Test random rotation for atomic grid."""
     rad_pts = np.array([0.1, 0.5, 1])
     rad_wts = np.array([0.3, 0.4, 0.3])
     rad_grid = OneDGrid(rad_pts, rad_wts)
     degs = [3, 5, 7]
     atgrid = AtomGrid(rad_grid, degrees=degs)
     # make sure True and 1 is not the same result
     atgrid1 = AtomGrid(rad_grid, degrees=degs, rotate=True)
     atgrid2 = AtomGrid(rad_grid, degrees=degs, rotate=1)
     # test diff points, same weights
     assert not np.allclose(atgrid.points, atgrid1.points)
     assert not np.allclose(atgrid.points, atgrid2.points)
     assert not np.allclose(atgrid1.points, atgrid2.points)
     assert_allclose(atgrid.weights, atgrid1.weights)
     assert_allclose(atgrid.weights, atgrid2.weights)
     assert_allclose(atgrid1.weights, atgrid2.weights)
     # test same integral
     value = np.prod(atgrid.points**2, axis=-1)
     value1 = np.prod(atgrid.points**2, axis=-1)
     value2 = np.prod(atgrid.points**2, axis=-1)
     res = atgrid.integrate(value)
     res1 = atgrid1.integrate(value1)
     res2 = atgrid2.integrate(value2)
     assert_almost_equal(res, res1)
     assert_almost_equal(res1, res2)
     # test rotated shells
     for i in range(len(degs)):
         non_rot_shell = atgrid.get_shell_grid(i).points
         rot_shell = atgrid2.get_shell_grid(i).points
         rot_mt = R.random(random_state=1 + i).as_matrix()
         assert_allclose(rot_shell, non_rot_shell @ rot_mt)
Exemplo n.º 5
0
def GaussChebyshev(npoints):
    r"""Generate 1D grid on [-1, 1] interval based on Gauss-Chebyshev quadrature.

    The fundamental definition of Gauss-Chebyshev quadrature is:

    .. math::
        \int_{-1}^{1} \frac{f(x)}{\sqrt{1-x^2}} dx \approx \sum_{i=1}^n w_i f(x_i)

    However, to integrate function :math:`g(x)` over [-1, 1], this is re-written as:

    .. math::
        \int_{-1}^{1}g(x) dx \approx \sum_{i=1}^n w_i \sqrt{1-x_i^2} g(x_i)
        = \sum_{i=1}^n w_i' g(x_i)

    Parameters
    ----------
    npoints : int
        Number of grid points.

    Returns
    -------
    OneDGrid
        A 1D grid instance.

    """
    # points are generated in decreasing order
    # weights are pi/n, all weights are the same
    points, weights = np.polynomial.chebyshev.chebgauss(npoints)
    weights = weights * np.sqrt(1 - np.power(points, 2))
    return OneDGrid(points[::-1], weights, (-1, 1))
Exemplo n.º 6
0
def TrefethenGeneral(npoints, quadrature, d=3):
    r"""Generate 1D grid on [-1,1] interval based on Trefethen-General.

    Parameters
    ----------
    npoints : int
        Number of points in the grid.

    Returns
    -------
    OneDGrid
        A 1D grid instance.
    """
    grid = quadrature(npoints)

    points = np.zeros(npoints)
    weights = np.zeros(npoints)

    if d == 2:
        points = _g2(grid.points)
        weights = _derg2(grid.points) * grid.weights
    elif d == 3:
        points = _g3(grid.points)
        weights = _derg3(grid.points) * grid.weights
    else:
        points = grid.points
        weights = grid.weights

    return OneDGrid(points, weights, (-1, 1))
Exemplo n.º 7
0
    def transform_1d_grid(self, oned_grid):
        r"""Generate a new integral grid by transforming given the OneDGrid.

        .. math::
            \int^{\inf}_0 g(r) d r &= \int^b_a g(r(x)) \frac{dr}{dx} dx \\
                                   &= \int^b_a f(x) \frac{dr}{dx} dx \\
            w^r_n = w^x_n \cdot \frac{dr}{dx} \vert_{x_n}

        Parameters
        ----------
        oned_grid : OneDGrid
            An instance of 1D grid.

        Returns
        -------
        OneDGrid
            Transformed 1D grid spanning a different domain.

        """
        if not isinstance(oned_grid, OneDGrid):
            raise TypeError(
                f"Input grid is not OneDGrid, got {type(oned_grid)}")
        # check domain
        if oned_grid.domain[0] < self.domain[0] or oned_grid.domain[
                1] > self.domain[1]:
            raise ValueError(
                "Given 1D grid domain does not match the transformation domain.\n"
                f"grid domain: {oned_grid.domain}, tf domain: {self.domain}")
        new_points = self.transform(oned_grid.points)
        new_weights = self.deriv(oned_grid.points) * oned_grid.weights
        new_domain = oned_grid.domain
        if new_domain is not None:
            new_domain = self.transform(np.array(oned_grid.domain))
        return OneDGrid(new_points, new_weights, new_domain)
Exemplo n.º 8
0
    def test_integrating_angular_components(self):
        """Test radial points that contain zero."""
        odg = OneDGrid(np.array([0.0, 1e-16, 1e-8, 1e-4, 1e-2]), np.ones(5),
                       (0, np.inf))
        atom_grid = AtomGrid(odg, degrees=[3])
        spherical = atom_grid.convert_cartesian_to_spherical()
        # Evaluate all spherical harmonics on the atomic grid points (r_i, theta_j, phi_j).
        spherical_harmonics = generate_real_spherical_harmonics(
            3,
            spherical[:, 1],
            spherical[:, 2]  # theta, phi points
        )
        # Convert to three-dimensional array (Degrees, Order, Points)
        spherical_array = np.zeros((3, 2 * 3 + 1, len(atom_grid.points)))
        spherical_array[0, 0, :] = spherical_harmonics[0, :]  # (l,m) = (0,0)
        spherical_array[1, 0, :] = spherical_harmonics[1, :]  # = (1, 0)
        spherical_array[1, 1, :] = spherical_harmonics[2, :]  # = (1, 1)
        spherical_array[1, 2, :] = spherical_harmonics[3, :]  # = (1, -1)
        spherical_array[2, 0, :] = spherical_harmonics[4, :]  # = (2, 0)
        spherical_array[2, 1, :] = spherical_harmonics[5, :]  # = (2, 2)
        spherical_array[2, 2, :] = spherical_harmonics[6, :]  # = (2, 1)
        spherical_array[2, 3, :] = spherical_harmonics[7, :]  # = (2, -2)
        spherical_array[2, 4, :] = spherical_harmonics[8, :]  # = (2, -1)

        integral = atom_grid.integrate_angular_coordinates(spherical_array)
        assert integral.shape == (3, 2 * 3 + 1, 5)
        # Assert that all spherical harmonics except when l=0,m=0 are all zero.
        assert_almost_equal(integral[0, 0, :], np.sqrt(4.0 * np.pi))
        assert_almost_equal(integral[0, 1:, :], 0.0)
        assert_almost_equal(integral[1:, :, :], 0.0)
Exemplo n.º 9
0
    def test_interpolation_of_laplacian_of_exponential(self):
        r"""Test the interpolation of Laplacian of exponential."""
        odg = OneDGrid(np.linspace(0.01, 1, num=1000), np.ones(1000),
                       (0, np.inf))
        degree = 10
        atgrid = AtomGrid.from_pruned(odg,
                                      1,
                                      sectors_r=[],
                                      sectors_degree=[degree])

        def func(cart_pts):
            radius = np.linalg.norm(cart_pts, axis=1)
            return np.exp(-radius)

        func_values = func(atgrid.points)

        laplacian = atgrid.interpolate_laplacian(func_values)

        # Test on the same points used for interpolation and random points.
        for grid in [atgrid.points, np.random.uniform(-0.5, 0.5, (250, 3))]:
            actual = laplacian(grid)
            spherical_pts = atgrid.convert_cartesian_to_spherical(grid)
            # Laplacian of exponential is e^-x (x - 2) / x
            desired = (np.exp(-spherical_pts[:, 0]) *
                       (spherical_pts[:, 0] - 2.0) / spherical_pts[:, 0])
            assert_almost_equal(actual, desired, decimal=3)
Exemplo n.º 10
0
    def test_spherical_average_of_spherical_harmonic(self):
        r"""Test spherical average of spherical harmonic is zero."""

        # construct helper function
        def func(sph_points):
            # Spherical harmonic of order 6 and magnetic 0
            r, phi, theta = sph_points.T
            return (np.sqrt(13) / (np.sqrt(np.pi) * 32) *
                    (231 * np.cos(theta)**6.0 - 315 * np.cos(theta)**4.0 +
                     105 * np.cos(theta)**2.0 - 5.0))

        # Construct Radial Grid and atomic grid with spherical harmonics of degree 10
        #   for all points.
        oned_grid = np.arange(0.0, 5.0, 0.001)
        rad = OneDGrid(oned_grid, np.ones(len(oned_grid)), (0, np.inf))
        atgrid = AtomGrid(rad, degrees=[10])
        spherical_pts = atgrid.convert_cartesian_to_spherical(atgrid.points)
        func_values = func(spherical_pts)

        spherical_avg = atgrid.spherical_average(func_values)

        # Test that the spherical average of a spherical harmonic is zero.
        numb_pts = 1000
        random_rad_pts = np.random.uniform(0.02, np.pi, size=(numb_pts, 3))
        spherical_avg2 = spherical_avg(random_rad_pts[:, 0])
        assert_allclose(spherical_avg2, 0.0, atol=1e-4)
Exemplo n.º 11
0
    def test_interpolation_of_laplacian_with_spherical_harmonic(self):
        r"""Test the interpolation of Laplacian of spherical harmonic is eigenvector."""
        odg = OneDGrid(np.linspace(0.0, 10, num=2000), np.ones(2000),
                       (0, np.inf))
        rad = IdentityRTransform().transform_1d_grid(odg)
        degree = 6 * 2 + 2
        atgrid = AtomGrid.from_pruned(rad,
                                      1,
                                      sectors_r=[],
                                      sectors_degree=[degree])

        def func(sph_points):
            # Spherical harmonic of order 6 and magnetic 0
            r, phi, theta = sph_points.T
            return (np.sqrt(2.0) * np.sqrt(13) / (np.sqrt(np.pi) * 32) *
                    (231 * np.cos(theta)**6.0 - 315 * np.cos(theta)**4.0 +
                     105 * np.cos(theta)**2.0 - 5.0))

        # Get spherical points from atomic grid
        spherical_pts = atgrid.convert_cartesian_to_spherical(atgrid.points)
        func_values = func(spherical_pts)

        laplacian = atgrid.interpolate_laplacian(func_values)

        # Test on the same points used for interpolation and random points.
        for grid in [atgrid.points, np.random.uniform(-0.75, 0.75, (250, 3))]:
            actual = laplacian(grid)
            spherical_pts = atgrid.convert_cartesian_to_spherical(grid)
            # Eigenvector spherical harmonic times l(l + 1) / r^2
            with np.errstate(divide="ignore", invalid="ignore"):
                desired = (-func(spherical_pts) * 6 * (6 + 1) /
                           spherical_pts[:, 0]**2.0)
            desired[spherical_pts[:, 0]**2.0 < 1e-10] = 0.0
            assert_almost_equal(actual, desired, decimal=3)
Exemplo n.º 12
0
    def test_fitting_product_of_spherical_harmonic(self):
        r"""Test fitting the radial components of r**2 times spherical harmonic."""
        max_degree = 7  # Maximum degree
        rad = OneDGrid(np.linspace(0.0, 1.0, num=10), np.ones(10), (0, np.inf))
        atom_grid = AtomGrid(rad, degrees=[max_degree])
        max_degree = atom_grid.l_max
        spherical = atom_grid.convert_cartesian_to_spherical()

        spherical_harmonic = generate_real_spherical_harmonics(
            4,
            spherical[:, 1],
            spherical[:, 2]  # theta, phi points
        )
        # Test on the function r^2 * Y^1_3
        func_vals = spherical[:,
                              0]**2.0 * spherical_harmonic[(3 + 1)**2 + 1, :]
        # Fit radial components
        fit = atom_grid.radial_component_splines(func_vals)
        radial_pts = np.arange(0.0, 1.0, 0.01)
        i = 0
        for l_value in range(0, max_degree // 2):
            for m in ([0] + [x for x in range(1, l_value + 1)] +
                      [x for x in range(-l_value, 0)]):
                if i != (3 + 1)**2 + 1:
                    assert_almost_equal(fit[i](radial_pts), 0.0, decimal=8)
                else:
                    # Test that on the right spherical harmonic the function r* Y^1_3 projects
                    # to \rho^{1,3}(r) = r
                    assert_almost_equal(fit[i](radial_pts), radial_pts**2.0)
                i += 1
Exemplo n.º 13
0
    def test_spherical_average_of_gaussian(self):
        r"""Test spherical average of a Gaussian (radial) function is itself and its integral."""

        # construct helper function
        def func(sph_points):
            return np.exp(-sph_points[:, 0]**2.0)

        # Construct Radial Grid and atomic grid with spherical harmonics of degree 10
        #   for all points.
        oned_grid = np.arange(0.0, 5.0, 0.001)
        rad = OneDGrid(oned_grid, np.ones(len(oned_grid)), (0, np.inf))
        atgrid = AtomGrid(rad, degrees=[5])
        spherical_pts = atgrid.convert_cartesian_to_spherical(atgrid.points)
        func_values = func(spherical_pts)

        spherical_avg = atgrid.spherical_average(func_values)

        # Test that the spherical average of a Gaussian is itself
        numb_pts = 1000
        random_rad_pts = np.random.uniform(0.0, 1.5, size=(numb_pts, 3))
        spherical_avg2 = spherical_avg(random_rad_pts[:, 0])
        func_vals = func(random_rad_pts)
        assert_allclose(spherical_avg2, func_vals, atol=1e-4)

        # Test the integral of spherical average is the integral of Gaussian e^(-x^2)e^(-y^2)...
        #   from -infinity to infinity which is equal to pi^(3/2)
        integral = (
            4.0 * np.pi *
            np.trapz(y=spherical_avg(oned_grid) * oned_grid**2.0, x=oned_grid))
        actual_integral = np.sqrt(np.pi)**3.0
        assert_allclose(actual_integral, integral)
Exemplo n.º 14
0
    def test_cubicspline_and_interp(self):
        """Test cubicspline interpolation values."""
        odg = OneDGrid(np.arange(10) + 1, np.ones(10), (0, np.inf))
        rad_grid = IdentityRTransform().transform_1d_grid(odg)
        for _ in range(10):
            degree = np.random.randint(5, 20)
            atgrid = AtomGrid.from_pruned(rad_grid,
                                          1,
                                          sectors_r=[],
                                          sectors_degree=[degree])
            values = self.helper_func_power(atgrid.points)
            # spls = atgrid.fit_values(values)

            for i in range(10):
                interp = atgrid.interpolate(
                    atgrid.points[atgrid.indices[i]:atgrid.indices[i + 1]],
                    values)
                # same result from points and interpolation
                assert_allclose(
                    interp, values[atgrid.indices[i]:atgrid.indices[i + 1]])

            # test random x, y, z
            for _ in range(10):
                xyz = np.random.rand(10, 3) * np.random.uniform(1, 6)
                # 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)

                interp = atgrid.interpolate(xyz, values)
                assert_allclose(interp, ref_value)
Exemplo n.º 15
0
def GaussLaguerre(npoints, alpha=0):
    r"""Generate 1D grid on [0, inf) interval based on Generalized Gauss-Laguerre quadrature.

    The fundamental definition of Generalized Gauss-Laguerre quadrature is:

    .. math::
        \int_{0}^{\infty} x^\alpha e^{-x} f(x) dx \approx \sum_{i=1}^n w_i f(x_i)

    However, to integrate function :math:`g(x)` over [0, inf), this is re-written as:

    .. math::
        \int_{0}^{\infty} g(x)dx \approx
        \sum_{i=1}^n \frac{w_i}{x_i^\alpha e^{-x_i}} g(x_i) = \sum_{i=1}^n w_i' g(x_i)

    Parameters
    ----------
    npoints : int
        Number of grid points.
    alpha : float, optional
        Value of parameter :math:`alpha` which should be larger than -1.

    Returns
    -------
    OneDGrid
        A 1D grid instance.

    """
    if alpha <= -1:
        raise ValueError(f"Alpha need to be bigger than -1, given {alpha}")
    points, weights = roots_genlaguerre(npoints, alpha)
    weights = weights * np.exp(points) * np.power(points, -alpha)
    return OneDGrid(points, weights, (0, np.inf))
Exemplo n.º 16
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.º 17
0
    def test_convert_points_to_sph(self):
        """Test convert random points to spherical based on atomic structure."""
        rad_pts = np.array([0.1, 0.5, 1])
        rad_wts = np.array([0.3, 0.4, 0.3])
        rad_grid = OneDGrid(rad_pts, rad_wts)
        center = np.random.rand(3)
        atgrid = AtomGrid(rad_grid, degrees=[7], center=center)
        points = np.random.rand(100, 3)
        calc_sph = atgrid.convert_cart_to_sph(points)
        # compute ref result
        ref_coor = points - center
        # radius
        r = np.linalg.norm(ref_coor, axis=-1)
        # azimuthal
        theta = np.arctan2(ref_coor[:, 1], ref_coor[:, 0])
        # polar
        phi = np.arccos(ref_coor[:, 2] / r)
        assert_allclose(np.stack([r, theta, phi]).T, calc_sph)
        assert_equal(calc_sph.shape, (100, 3))

        # test single point
        point = np.random.rand(3)
        calc_sph = atgrid.convert_cart_to_sph(point)
        ref_coor = point - center
        r = np.linalg.norm(ref_coor)
        theta = np.arctan2(ref_coor[1], ref_coor[0])
        phi = np.arccos(ref_coor[2] / r)
        assert_allclose(np.array([r, theta, phi]).reshape(-1, 3), calc_sph)
Exemplo n.º 18
0
def GaussLaguerre(npoints, alpha=0):
    r"""Generate a grid based on generalized Gauss-Laguerre grid.

    Generalizeed Gauss Laguerre grid is defined as:
    .. math::
        \int_{0}^{\infty} x^{\alpha}e^{-x} f(x)dx \approx
        \sum_{i=1}^n w_i f(x_i)

    This integration grid is defined as :
    .. math::
        \int_{0}^{\infty} f(x)dx \approx
        \sum_{i=1}^n \frac{w_i}{x_i^{\alpha} e^{-x_i}} f(x_i)
        = \sum_{i=1}^n  w_i' f(x_i)

    Parameters
    ----------
    npoints : int
        Number of points in the grid
    alpha : float, default to 0, required to be > -1
        parameter alpha value

    Returns
    -------
    OneDGrid
        A grid instance with points and weights, (0, inf)
    """
    if alpha <= -1:
        raise ValueError(f"Alpha need to be bigger than -1, given {alpha}")
    points, weights = roots_genlaguerre(npoints, alpha)
    weights = weights * np.exp(points) * np.power(points, -alpha)
    return OneDGrid(points, weights)
Exemplo n.º 19
0
 def test_total_atomic_grid(self):
     """Normal initialization test."""
     radial_pts = np.arange(0.1, 1.1, 0.1)
     radial_wts = np.ones(10) * 0.1
     rgrid = OneDGrid(radial_pts, radial_wts)
     rad = 0.5
     r_sectors = np.array([0.5, 1, 1.5])
     degs = np.array([6, 14, 14, 6])
     # generate a proper instance without failing.
     ag_ob = AtomGrid.from_pruned(rgrid,
                                  radius=rad,
                                  sectors_r=r_sectors,
                                  sectors_degree=degs)
     assert isinstance(ag_ob, AtomGrid)
     assert len(ag_ob.indices) == 11
     assert ag_ob.l_max == 15
     ag_ob = AtomGrid.from_pruned(rgrid,
                                  radius=rad,
                                  sectors_r=np.array([]),
                                  sectors_degree=np.array([6]))
     assert isinstance(ag_ob, AtomGrid)
     assert len(ag_ob.indices) == 11
     ag_ob = AtomGrid(rgrid, sizes=[110])
     assert ag_ob.l_max == 17
     assert_array_equal(ag_ob._degs, np.ones(10) * 17)
     assert ag_ob.size == 110 * 10
     # new init AtomGrid
     ag_ob2 = AtomGrid(rgrid, degrees=[17])
     assert ag_ob2.l_max == 17
     assert_array_equal(ag_ob2._degs, np.ones(10) * 17)
     assert ag_ob2.size == 110 * 10
     assert isinstance(ag_ob.rgrid, OneDGrid)
     assert_allclose(ag_ob.rgrid.points, rgrid.points)
     assert_allclose(ag_ob.rgrid.weights, rgrid.weights)
Exemplo n.º 20
0
def GaussChebyshevLobatto(npoints):
    r"""Generate 1D grid on [-1, 1] interval based on Gauss-Chebyshev-Lobatto.

    The definition of Gauss-Chebyshev-Lobato quadrature is:

    .. math::
        \int_{-1}^{1} \frac{f(x)}{\sqrt{1-x^2}} dx
        \approx \sum_{i=1}^n w_i f(x_i)

    However, to integrate function :math:`g(x)` over [-1, 1], this is re-written as:

    .. math::
        \int_{-1}^{1}g(x) dx \approx \sum_{i=1}^n w_i \sqrt{1-x_i^2} f(x_i)
        = \sum_{i=1}^n w_i' f(x_i)

    Where

    .. math::
        x_i = \cos\left( \frac{(i-1)\pi}{n-1} \right)

    And the weights

    .. math::
        w_{1} = w_{n} = \frac{\pi}{2(n-1)}

    And the internal weights

    .. math::
        w_{i\neq 1,n} = \frac{\pi}{n-1}


    Parameters
    ----------
    npoints : int
        Number of points in the grid

    Returns
    -------
    OneDGrid
        A 1D grid instance.

    """
    if npoints <= 1:
        raise ValueError("npoints must be greater that one, given {npoints}")
    idx = np.arange(npoints)
    weights = np.ones(npoints)

    idx = (idx * np.pi) / (npoints - 1)

    points = np.cos(idx)
    points = points[::-1]

    weights *= np.pi / (npoints - 1)
    weights *= np.sqrt(1 - np.power(points, 2))

    weights[0] /= 2
    weights[npoints - 1] = weights[0]

    return OneDGrid(points, weights, (-1, 1))
Exemplo n.º 21
0
def RectangleRuleSine(npoints):
    r"""Generate 1D grid on (0:1) interval based on rectangle rule.

    The fundamental definition of this quadrature is:

    .. math::
        \int_{0}^{1} f(x) dx \approx \sum_{i=1}^n w_i f(x_i)

    The range of integration can be modified by :math: `q = 2 x - 1`.

    .. math::
        2 \int_{0}^{1} f(x) dx = \int_{-1}^{1} f(q) dq

    Where

    .. math::
        x_i = \frac{2 i - 1}{2 n}

    And the weights

    .. math::
        w_i = \frac{2}{n^2 \pi} \sin(n\pi x_i) \sin^2(n\pi /2)
            + \frac{4}{n \pi}\sum_{m=1}^{n-1}
            \frac{\sin(m \pi x_i)\sin^2(m\pi /2)}
                {m}

    Parameters
    ----------
    npoints : int
        Number of points in the grid.

    Returns
    -------
    OneDGrid
        A 1D grid instance.

    """
    if npoints <= 1:
        raise ValueError("npoints must be greater that one, given {npoints}")
    idx = np.arange(npoints) + 1
    points = (2 * idx - 1) / (2 * npoints)

    weights = (
        (2 / (npoints * np.pi ** 2))
        * np.sin(npoints * np.pi * points)
        * np.sin(npoints * np.pi / 2) ** 2
    )

    m = np.arange(npoints - 1) + 1
    bm = np.sin(m * np.pi / 2) ** 2 / m
    sim = np.sin(np.outer(m * np.pi, points))
    wi = bm @ sim
    weights += (4 / (npoints * np.pi)) * wi

    points = 2 * points - 1
    weights *= 2

    return OneDGrid(points, weights, (-1, 1))
Exemplo n.º 22
0
 def test_find_l_for_rad_list(self):
     """Test private method find_l_for_rad_list."""
     radial_pts = np.arange(0.1, 1.1, 0.1)
     radial_wts = np.ones(10) * 0.1
     rgrid = OneDGrid(radial_pts, radial_wts)
     rad = 1
     r_sectors = np.array([0.2, 0.4, 0.8])
     degs = np.array([3, 5, 7, 3])
     atomic_grid_degree = AtomGrid._find_l_for_rad_list(
         rgrid.points, rad * r_sectors, degs)
     assert_equal(atomic_grid_degree, [3, 3, 5, 5, 7, 7, 7, 7, 3, 3])
Exemplo n.º 23
0
 def test_cubicspline_and_interp_mol(self):
     """Test cubicspline interpolation values."""
     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])
     values = self.helper_func_power(atgrid.points)
     result = spline_with_atomic_grid(atgrid, values)
     sph_coor = atgrid.convert_cart_to_sph()
     semi_sph_c = sph_coor[atgrid.indices[5] : atgrid.indices[6]]
     interp = interpolate(result, rad.points[5], semi_sph_c[:, 1], semi_sph_c[:, 2])
     # same result from points and interpolation
     assert_allclose(interp, values[atgrid.indices[5] : atgrid.indices[6]])
Exemplo n.º 24
0
def RectangleRuleSineEndPoints(npoints):
    r"""Generate 1D grid on [-1:1] interval based on rectangle rule.

    The fundamental definition of this quadrature is:

    .. math::
        \int_{-1}^{1} f(x) dx \approx \sum_{i=1}^n w_i f(x_i)

    The range of integration can be modified by :math: `q = 2 x - 1`.

    .. math::
        2 \int_{0}^{1} f(x) dx = \int_{-1}^{1} f(q) dq

    Where

    .. math::
        x_i = \frac{i}{n+1}

    And the weights

    .. math::
        w_i = \frac{2}{n+1} \sum_{m=1}^n
                \frac{\sin(m \pi x_i)(1-\cos(m \pi))}{m \pi}


    Parameters
    ----------
    npoints : int
        Number of points in the grid.

    Returns
    -------
    OneDGrid
        A 1D grid instance.

    """
    if npoints <= 1:
        raise ValueError("npoints must be greater that one, given {npoints}")
    idx = np.arange(npoints) + 1
    points = idx / (npoints + 1)

    weights = np.zeros(npoints)

    m = np.arange(npoints) + 1

    bm = (np.ones(npoints) - np.cos(m * np.pi)) / (m * np.pi)
    sim = np.sin(np.outer(m * np.pi, points))
    weights = bm @ sim

    points = 2 * points - 1
    weights *= 4 / (npoints + 1)

    return OneDGrid(points, weights, (-1, 1))
Exemplo n.º 25
0
def TanhSinh(npoints, delta=0.1):
    r"""Generate 1D grid on [-1,1] interval based on Tanh-Sinh rule.

    The fundamental definition is:

    .. math::
        \int_{-1}^{1} f(x) dx \approx
        \sum_{i=-\frac{1}{2}(n-1)}^{\frac{1}{2}(n-1)} w_i f(x_i)

    Where

    .. math::
        x_i = \tanh\left( \frac{\pi}{2} \sinh(i\delta) \right)

    And the weights

    .. math::
        w_i = \frac{\frac{\pi}{2}\delta \cosh(i\delta)}
        {\cosh^2(\frac{\pi}{2}\sinh(i\delta))}


    Parameters
    ----------
    npoints : int
        Number of points in the grid, this value must be odd.

    delta : float
        This values is a parameter :math:`\delta`, is related with the size.

    Returns
    -------
    OneDGrid
        A 1D grid instance.
    """
    if npoints <= 1:
        raise ValueError("npoints must be greater that one, given {npoints}")
    if npoints % 2 == 0:
        raise ValueError("npoints must be odd, given {npoints}")

    points = np.zeros(npoints)
    weights = np.zeros(npoints)

    j = int((1 - npoints) / 2) + np.arange(npoints)

    theta = j * delta

    points = np.tanh(np.pi * np.sinh(theta) / 2)
    weights = (
        np.pi * delta * np.cosh(theta) / (2 * np.cosh(np.pi * np.sinh(theta) / 2) ** 2)
    )

    return OneDGrid(points, weights, (-1, 1))
Exemplo n.º 26
0
 def test_cubicspline_and_interp_mol(self):
     """Test cubicspline interpolation values."""
     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])
     values = self.helper_func_power(atgrid.points)
     # spls = atgrid.fit_values(values)
     for i in range(10):
         interp = atgrid.interpolate(
             atgrid.points[atgrid.indices[i]:atgrid.indices[i + 1]], values)
         # same result from points and interpolation
         assert_allclose(interp,
                         values[atgrid.indices[i]:atgrid.indices[i + 1]])
Exemplo n.º 27
0
 def test_atomic_grid(self):
     """Test atomic grid center transilation."""
     rad_pts = np.array([0.1, 0.5, 1])
     rad_wts = np.array([0.3, 0.4, 0.3])
     rad_grid = OneDGrid(rad_pts, rad_wts)
     degs = np.array([3, 5, 7])
     # origin center
     # randome center
     pts, wts, ind = AtomGrid._generate_atomic_grid(rad_grid, degs)
     ref_pts, ref_wts, ref_ind = AtomGrid._generate_atomic_grid(rad_grid, degs)
     # diff grid points diff by center and same weights
     assert_allclose(pts, ref_pts)
     assert_allclose(wts, ref_wts)
Exemplo n.º 28
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.º 29
0
def GaussLegendre(npoints):
    """Generate Gauss-Legendre grid.

    Parameters
    ----------
    npoints : int
        Number of points in the grid

    Returns
    -------
    OneDGrid
        A grid instance with points and weights, [-1, 1]
    """
    points, weights = np.polynomial.legendre.leggauss(npoints)
    return OneDGrid(points, weights)
Exemplo n.º 30
0
def GaussChebyshev(npoints):
    """Generate Gauss-Legendre grid.

    Parameters
    ----------
    npoints : int
        Number of points in the grid

    Returns
    -------
    OneDGrid
        A grid instance with points and weights
    """
    points, weights = np.polynomial.chebyshev.chebgauss(npoints)
    return OneDGrid(points, weights)