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_cartesian_to_spherical(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_cartesian_to_spherical(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)
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)
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)
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
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)
def test_fitting_spherical_harmonics(self): r"""Test fitting the radial components of spherical harmonics is just a one, rest zeros.""" max_degree = 10 # 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() # Evaluate all spherical harmonics on the atomic grid points (r_i, theta_j, phi_j). spherical_harmonics = generate_real_spherical_harmonics( max_degree, spherical[:, 1], spherical[:, 2] # theta, phi points ) i = 0 # Go through each spherical harmonic up to max_degree // 2 and check if projection # for its radial component is one and the rest are all zeros. 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)]): spherical_harm = spherical_harmonics[i, :] radial_components = atom_grid.radial_component_splines( spherical_harm) assert len(radial_components) == (atom_grid.l_max // 2 + 1)**2.0 radial_pts = np.arange(0.0, 1.0, 0.01) # Go Through each (l, m) for j, radial_comp in enumerate(radial_components): # If the current index is j, then projection of spherical harmonic # onto itself should be all ones, else they are all zero. if i == j: assert_almost_equal(radial_comp(radial_pts), 1.0) else: assert_almost_equal(radial_comp(radial_pts), 0.0, decimal=8) i += 1