def test_becke_sum3_one(self): """Test becke weights add up to one with three centers.""" npoint = 100 points = np.random.uniform(-5, 5, (npoint, 3)) weights0 = np.ones(npoint, float) weights1 = np.ones(npoint, float) weights2 = np.ones(npoint, float) radii = np.array([0.5, 0.8, 5.0]) centers = np.array([[1.2, 2.3, 0.1], [-0.4, 0.0, -2.2], [2.2, -1.5, 0.0]]) weights0 = BeckeWeights.generate_becke_weights(points, radii, centers, select=[0], order=3) weights1 = BeckeWeights.generate_becke_weights(points, radii, centers, select=[1], order=3) weights2 = BeckeWeights.generate_becke_weights(points, radii, centers, select=[2], order=3) assert_allclose(weights0 + weights1 + weights2, np.ones(100))
def test_becke_sum2_one(self): """Test becke weights add up to one.""" npoint = 100 points = np.random.uniform(-5, 5, (npoint, 3)) nums = np.array([1, 2]) centers = np.array([[1.2, 2.3, 0.1], [-0.4, 0.0, -2.2]]) becke = BeckeWeights({1: 0.5, 2: 0.8}, order=3) weights0 = becke.generate_weights(points, centers, nums, select=[0]) weights1 = becke.generate_weights(points, centers, nums, select=[1]) assert_allclose(weights0 + weights1, np.ones(100))
def test_noble_gas_radius(self): """Test np.nan value to be handled properly.""" noble_list = [2, 10, 18, 36, 54, 85, 86] for i in noble_list: nums = np.array([i, i - 1]) if i != 86 else np.array([i, i - 2]) centers = np.array([[0.5, 0.0, 0.0], [-0.5, 0.0, 0.0]]) pts = np.zeros((10, 3), dtype=float) pts[:, 1:] += np.random.rand(10, 2) becke = BeckeWeights(order=3) wts = becke.generate_weights(pts, centers, nums, pt_ind=[0, 5, 10]) assert_allclose(wts, 0.5) wts = becke.compute_weights(pts, centers, nums, pt_ind=[0, 5, 10]) assert_allclose(wts, 0.5)
def test_becke_special_points(self): """Test becke weights for special cases.""" nums = np.array([1, 2, 3]) centers = np.array([[1.2, 2.3, 0.1], [-0.4, 0.0, -2.2], [2.2, -1.5, 0.0]]) becke = BeckeWeights({1: 0.5, 2: 0.8, 3: 5.0}, order=3) weights = becke.generate_weights(centers, centers, nums, select=0) assert_allclose(weights, [1, 0, 0]) weights = becke.generate_weights(centers, centers, nums, select=1) assert_allclose(weights, [0, 1, 0]) weights = becke.generate_weights(centers, centers, nums, select=2) assert_allclose(weights, [0, 0, 1]) # each point in seperate sectors. weights = becke.generate_weights(centers, centers, nums, pt_ind=[0, 1, 2, 3]) assert_allclose(weights, [1, 1, 1]) weights = becke.generate_weights( centers, centers, nums, select=[0, 1], pt_ind=[0, 1, 3] ) assert_allclose(weights, [1, 1, 0]) weights = becke.generate_weights( centers, centers, nums, select=[2, 0], pt_ind=[0, 2, 3] ) assert_allclose(weights, [0, 0, 0])
def test_from_size(self): """Test horton style grid.""" nums = np.array([1, 1]) coors = np.array([[0, 0, -0.5], [0, 0, 0.5]]) becke = BeckeWeights(order=3) mol_grid = MolGrid.from_size(nums, coors, self.rgrid, 110, becke, rotate=False) atg1 = AtomGrid.from_pruned( self.rgrid, 0.5, sectors_r=np.array([]), sectors_degree=np.array([17]), center=coors[0], ) atg2 = AtomGrid.from_pruned( self.rgrid, 0.5, sectors_r=np.array([]), sectors_degree=np.array([17]), center=coors[1], ) ref_grid = MolGrid(nums, [atg1, atg2], becke, store=True) assert_allclose(ref_grid.points, mol_grid.points) assert_allclose(ref_grid.weights, mol_grid.weights)
def test_integrate_hydrogen_trimer_1s(self): """Test molecular integral in H3.""" coordinates = np.array( [[0.0, 0.0, -0.5], [0.0, 0.0, 0.5], [0.0, 0.5, 0.0]], float) atg1 = AtomGrid.from_pruned( self.rgrid, 0.5, r_sectors=np.array([]), degs=np.array([17]), center=coordinates[0], ) atg2 = AtomGrid.from_pruned( self.rgrid, 0.5, r_sectors=np.array([]), degs=np.array([17]), center=coordinates[1], ) atg3 = AtomGrid.from_pruned( self.rgrid, 0.5, r_sectors=np.array([]), degs=np.array([17]), center=coordinates[2], ) becke = BeckeWeights(order=3) mg = MolGrid([atg1, atg2, atg3], becke, np.array([1, 1, 1])) dist0 = np.sqrt(((coordinates[0] - mg.points)**2).sum(axis=1)) dist1 = np.sqrt(((coordinates[1] - mg.points)**2).sum(axis=1)) dist2 = np.sqrt(((coordinates[2] - mg.points)**2).sum(axis=1)) fn = (np.exp(-2 * dist0) / np.pi + np.exp(-2 * dist1) / np.pi + np.exp(-2 * dist2) / np.pi) occupation = mg.integrate(fn) assert_almost_equal(occupation, 3.0, decimal=4)
def test_get_localgrid_1s1s(self): """Test local grid for a molecule with one atom.""" nums = np.array([1, 3]) coords = np.array([[0.0, 0.0, -0.5], [0.0, 0.0, 0.5]]) grid = MolGrid.horton_molgrid(coords, nums, self.rgrid, 110, BeckeWeights(), store=True) fn0 = np.exp(-4.0 * np.linalg.norm(grid.points - coords[0], axis=-1)) fn1 = np.exp(-8.0 * np.linalg.norm(grid.points - coords[1], axis=-1)) assert_allclose(grid.integrate(fn0), np.pi / 8, rtol=1e-5) assert_allclose(grid.integrate(fn1), np.pi / 64) # local grid centered on atom 0 to evaluate fn0 local0 = grid.get_localgrid(coords[0], 5.0) assert local0.size < grid.size localfn0 = np.exp(-4.0 * np.linalg.norm(local0.points - coords[0], axis=-1)) assert_allclose(fn0[local0.indices], localfn0) assert_allclose(local0.integrate(localfn0), np.pi / 8, rtol=1e-5) # local grid centered on atom 1 to evaluate fn1 local1 = grid.get_localgrid(coords[1], 2.5) assert local1.size < grid.size localfn1 = np.exp(-8.0 * np.linalg.norm(local1.points - coords[1], axis=-1)) assert_allclose(local1.integrate(localfn1), np.pi / 64, rtol=1e-6) assert_allclose(fn1[local1.indices], localfn1) # approximate the sum of fn0 and fn2 by combining results from local grids. fnsum = np.zeros(grid.size) fnsum[local0.indices] += localfn0 fnsum[local1.indices] += localfn1 assert_allclose(grid.integrate(fnsum), np.pi * (1 / 8 + 1 / 64), rtol=1e-5)
def test_get_localgrid_1s(self): """Test local grid for a molecule with one atom.""" nums = np.array([1]) coords = np.array([0.0, 0.0, 0.0]) # initialize MolGrid with atomic grid atg1 = AtomGrid.from_pruned( self.rgrid, 0.5, sectors_r=np.array([]), sectors_degree=np.array([17]), center=coords, ) grid = MolGrid(np.array([1]), [atg1], BeckeWeights(), store=False) fn = np.exp(-2 * np.linalg.norm(grid.points, axis=-1)) assert_allclose(grid.integrate(fn), np.pi) # conventional local grid localgrid = grid.get_localgrid(coords, 12.0) localfn = np.exp(-2 * np.linalg.norm(localgrid.points, axis=-1)) assert localgrid.size < grid.size assert localgrid.size == 10560 assert_allclose(localgrid.integrate(localfn), np.pi) assert_allclose(fn[localgrid.indices], localfn) # "whole" loal grid, useful for debugging code using local grids wholegrid = grid.get_localgrid(coords, np.inf) assert wholegrid.size == grid.size assert_allclose(wholegrid.points, grid.points) assert_allclose(wholegrid.weights, grid.weights) assert_allclose(wholegrid.indices, np.arange(grid.size)) # initialize MolGrid like horton grid = MolGrid.from_size(nums, coords[np.newaxis, :], self.rgrid, 110, BeckeWeights(), store=True) fn = np.exp(-4.0 * np.linalg.norm(grid.points, axis=-1)) assert_allclose(grid.integrate(fn), np.pi / 8) localgrid = grid.get_localgrid(coords, 5.0) localfn = np.exp(-4.0 * np.linalg.norm(localgrid.points, axis=-1)) assert localgrid.size < grid.size assert localgrid.size == 9900 assert_allclose(localgrid.integrate(localfn), np.pi / 8, rtol=1e-5) assert_allclose(fn[localgrid.indices], localfn)
def test_compute_weights(self): """Tes compute weights function.""" # generate random points npoint = 50 points = np.random.uniform(-5, 5, (npoint, 3)) nums = np.array([1, 2, 3]) centers = np.array([[1.2, 2.3, 0.1], [-0.4, 0.0, -2.2], [2.2, -1.5, 0.0]]) becke = BeckeWeights({1: 0.5, 2: 0.8, 3: 5.0}, order=3) indices = [0, 13, 29, 50] # compute with old generate_weights method weights_ref = becke.generate_weights(points, centers, nums, pt_ind=indices) # compute with compute_weights weights_compute = becke.compute_weights(points, centers, nums, pt_ind=indices) assert_allclose(weights_ref, weights_compute) # compute with one selected atom weights weights_ref2 = becke.generate_weights(points, centers, nums, select=1) weights_compute2 = becke.compute_weights(points, centers, nums, select=1) assert_allclose(weights_ref2, weights_compute2)
def __init__(self, atomic_grids, radii, aim_weights="becke", store=False): """Initialize molgrid class. Parameters ---------- atomic_grids : list[AtomicGrid] list of atomic grid radii : np.ndarray(N,) Radii for each atom in the molecular grid aim_weights : str or np.ndarray(K,), default to "becke" Atoms in molecule weights. If str, certain function will be called to compute aim_weights, if np.ndarray, it will be treated as the aim_weights """ # initialize these attributes self._coors = np.zeros((len(radii), 3)) self._indices = np.zeros(len(radii) + 1, dtype=int) self._size = np.sum([atomgrid.size for atomgrid in atomic_grids]) self._points = np.zeros((self._size, 3)) self._weights = np.zeros(self._size) self._atomic_grids = atomic_grids if store else None for i, atom_grid in enumerate(atomic_grids): self._coors[i] = atom_grid.center self._indices[i + 1] += self._indices[i] + atom_grid.size self._points[self._indices[i] : self._indices[i + 1]] = atom_grid.points self._weights[self._indices[i] : self._indices[i + 1]] = atom_grid.weights if isinstance(aim_weights, str): if aim_weights == "becke": self._aim_weights = BeckeWeights.generate_becke_weights( self._points, radii, self._coors, pt_ind=self._indices ) else: raise NotImplementedError( f"Given aim_weights is not supported, got {aim_weights}" ) elif isinstance(aim_weights, np.ndarray): if aim_weights.size != self.size: raise ValueError( "aim_weights is not the same size as grid.\n" f"aim_weights.size: {aim_weights.size}, grid.size: {self.size}." ) self._aim_weights = aim_weights else: raise TypeError(f"Not supported aim_weights type, got {type(aim_weights)}.")
def test_molgrid_attrs(self): """Test MolGrid attributes.""" # numbers = np.array([6, 8], int) coordinates = np.array([[0.0, 0.2, -0.5], [0.1, 0.0, 0.5]], float) atg1 = AtomGrid.from_pruned( self.rgrid, 1.228, r_sectors=np.array([]), degs=np.array([17]), center=coordinates[0], ) atg2 = AtomGrid.from_pruned( self.rgrid, 0.945, r_sectors=np.array([]), degs=np.array([17]), center=coordinates[1], ) becke = BeckeWeights(order=3) mg = MolGrid([atg1, atg2], becke, np.array([6, 8]), store=True) assert mg.size == 2 * 110 * 100 assert mg.points.shape == (mg.size, 3) assert mg.weights.shape == (mg.size, ) assert mg.aim_weights.shape == (mg.size, ) assert mg.get_atomic_grid(0) is atg1 assert mg.get_atomic_grid(1) is atg2 simple_ag1 = mg.get_atomic_grid(0) simple_ag2 = mg.get_atomic_grid(1) assert_allclose(simple_ag1.points, atg1.points) assert_allclose(simple_ag1.weights, atg1.weights) assert_allclose(simple_ag2.weights, atg2.weights) # test molgrid is not stored mg2 = MolGrid([atg1, atg2], becke, np.array([6, 8]), store=False) assert mg2._atomic_grids is None simple2_ag1 = mg2.get_atomic_grid(0) simple2_ag2 = mg2.get_atomic_grid(1) assert isinstance(simple2_ag1, LocalGrid) assert isinstance(simple2_ag2, LocalGrid) assert_allclose(simple2_ag1.points, atg1.points) assert_allclose(simple2_ag1.weights, atg1.weights) assert_allclose(simple2_ag2.weights, atg2.weights)
def test_molgrid_attrs_subgrid(self): """Test sub atomic grid attributes.""" # numbers = np.array([6, 8], int) coordinates = np.array([[0.0, 0.2, -0.5], [0.1, 0.0, 0.5]], float) atg1 = AtomGrid.from_pruned( self.rgrid, 1.228, r_sectors=np.array([]), degs=np.array([17]), center=coordinates[0], ) atg2 = AtomGrid.from_pruned( self.rgrid, 0.945, r_sectors=np.array([]), degs=np.array([17]), center=coordinates[1], ) becke = BeckeWeights(order=3) mg = MolGrid([atg1, atg2], becke, np.array([6, 8]), store=True) # mg = BeckeMolGrid(coordinates, numbers, None, (rgrid, 110), mode='keep') assert mg.size == 2 * 110 * 100 assert mg.points.shape == (mg.size, 3) assert mg.weights.shape == (mg.size, ) assert mg.aim_weights.shape == (mg.size, ) assert len(mg._indices) == 2 + 1 # assert mg.k == 3 # assert mg.random_rotate for i in range(2): atgrid = mg[i] assert isinstance(atgrid, AtomGrid) assert atgrid.size == 100 * 110 assert atgrid.points.shape == (100 * 110, 3) assert atgrid.weights.shape == (100 * 110, ) assert (atgrid.center == coordinates[i]).all() mg = MolGrid([atg1, atg2], becke, np.array([6, 8])) for i in range(2): atgrid = mg[i] assert isinstance(atgrid, LocalGrid) assert_allclose(atgrid.center, mg._coors[i])
def test_integrate_hydrogen_single_1s(self): """Test molecular integral in H atom.""" # numbers = np.array([1], int) coordinates = np.array([0.0, 0.0, -0.5], float) # rgrid = BeckeTF.transform_grid(oned, 0.001, 0.5)[0] # rtf = ExpRTransform(1e-3, 1e1, 100) # rgrid = RadialGrid(rtf) atg1 = AtomGrid.from_pruned( self.rgrid, 0.5, r_sectors=np.array([]), degs=np.array([17]), center=coordinates, ) becke = BeckeWeights(order=3) mg = MolGrid([atg1], becke, np.array([1])) # mg = BeckeMolGrid(coordinates, numbers, None, (rgrid, 110), random_rotate=False) dist0 = np.sqrt(((coordinates - mg.points)**2).sum(axis=1)) fn = np.exp(-2 * dist0) / np.pi occupation = mg.integrate(fn) assert_almost_equal(occupation, 1.0, decimal=6)
def test_becke_special_points(self): """Test becke weights for special cases.""" radii = np.array([0.5, 0.8, 5.0]) centers = np.array([[1.2, 2.3, 0.1], [-0.4, 0.0, -2.2], [2.2, -1.5, 0.0]]) weights = BeckeWeights.generate_becke_weights(centers, radii, centers, select=[0], order=3) assert_allclose(weights, [1, 0, 0]) weights = BeckeWeights.generate_becke_weights(centers, radii, centers, select=[1], order=3) assert_allclose(weights, [0, 1, 0]) weights = BeckeWeights.generate_becke_weights(centers, radii, centers, select=[2], order=3) assert_allclose(weights, [0, 0, 1]) # each point in seperate sectors. weights = BeckeWeights.generate_becke_weights(centers, radii, centers, pt_ind=[0, 1, 2, 3]) assert_allclose(weights, [1, 1, 1]) weights = BeckeWeights.generate_becke_weights(centers, radii, centers, select=[0, 1], pt_ind=[0, 1, 3]) assert_allclose(weights, [1, 1, 0]) weights = BeckeWeights.generate_becke_weights(centers, radii, centers, select=[2, 0], pt_ind=[0, 2, 3]) assert_allclose(weights, [0, 0, 0])
def test_integrate_hydrogen_8_1s(self): """Test molecular integral in H2.""" x, y, z = np.meshgrid(*(3 * [[-0.5, 0.5]])) centers = np.stack([x.ravel(), y.ravel(), z.ravel()], axis=1) atgs = [ AtomGrid.from_pruned( self.rgrid, 0.5, r_sectors=np.array([]), degs=np.array([17]), center=center, ) for center in centers ] becke = BeckeWeights(order=3) mg = MolGrid(atgs, becke, np.array([1] * len(centers))) fn = 0 for center in centers: dist = np.linalg.norm(center - mg.points, axis=1) fn += np.exp(-2 * dist) / np.pi occupation = mg.integrate(fn) assert_almost_equal(occupation, len(centers), decimal=2)
def test_horton_molgrid(self): """Test horton style grid.""" nums = np.array([1, 1]) coors = np.array([[0, 0, -0.5], [0, 0, 0.5]]) becke = BeckeWeights(order=3) mol_grid = MolGrid.horton_molgrid(coors, nums, self.rgrid, 110, becke) atg1 = AtomGrid.from_pruned( self.rgrid, 0.5, r_sectors=np.array([]), degs=np.array([17]), center=coors[0], ) atg2 = AtomGrid.from_pruned( self.rgrid, 0.5, r_sectors=np.array([]), degs=np.array([17]), center=coors[1], ) ref_grid = MolGrid([atg1, atg2], becke, nums, store=True) assert_allclose(ref_grid.points, mol_grid.points) assert_allclose(ref_grid.weights, mol_grid.weights)
def test_make_grid_integral(self): """Test molecular make_grid works as designed.""" pts = HortonLinear(70) tf = ExpRTransform(1e-5, 2e1) rgrid = tf.transform_1d_grid(pts) numbers = np.array([1, 1]) coordinates = np.array([[0.0, 0.0, -0.5], [0.0, 0.0, 0.5]], float) becke = BeckeWeights(order=3) # construct molgrid for grid_type, deci in ( ("coarse", 3), ("medium", 4), ("fine", 5), ("veryfine", 6), ("ultrafine", 6), ("insane", 6), ): mg = MolGrid.from_preset(numbers, coordinates, rgrid, grid_type, becke) dist0 = np.sqrt(((coordinates[0] - mg.points) ** 2).sum(axis=1)) dist1 = np.sqrt(((coordinates[1] - mg.points) ** 2).sum(axis=1)) fn = np.exp(-2 * dist0) / np.pi + np.exp(-2 * dist1) / np.pi occupation = mg.integrate(fn) assert_almost_equal(occupation, 2.0, decimal=deci)
def test_becke_compute_atom_weight(self): """Test becke compute pa function.""" npoint = 10 points = np.random.uniform(-5, 5, (npoint, 3)) nums = np.array([1, 2, 3]) centers = np.array([[1.2, 2.3, 0.1], [-0.4, 0.0, -2.2], [2.2, -1.5, 0.0]]) becke = BeckeWeights({1: 0.5, 2: 0.8, 3: 5.0}, order=3) weights0 = becke.generate_weights(points, centers, nums, select=[0]) weights1 = becke.generate_weights(points, centers, nums, select=[1]) weights2 = becke.generate_weights(points, centers, nums, select=[2]) aw_0 = becke.compute_atom_weight(points, centers, nums, 0) aw_1 = becke.compute_atom_weight(points, centers, nums, 1) aw_2 = becke.compute_atom_weight(points, centers, nums, 2) assert_allclose(weights0, aw_0) assert_allclose(weights1, aw_1) assert_allclose(weights2, aw_2)
def test_integrate_hydrogen_pair_1s(self): """Test molecular integral in H2.""" coordinates = np.array([[0.0, 0.0, -0.5], [0.0, 0.0, 0.5]], float) atg1 = AtomGrid.from_pruned( self.rgrid, 0.5, sectors_r=np.array([]), sectors_degree=np.array([17]), center=coordinates[0], ) atg2 = AtomGrid.from_pruned( self.rgrid, 0.5, sectors_r=np.array([]), sectors_degree=np.array([17]), center=coordinates[1], ) becke = BeckeWeights(order=3) mg = MolGrid(np.array([1, 1]), [atg1, atg2], becke) dist0 = np.sqrt(((coordinates[0] - mg.points) ** 2).sum(axis=1)) dist1 = np.sqrt(((coordinates[1] - mg.points) ** 2).sum(axis=1)) fn = np.exp(-2 * dist0) / np.pi + np.exp(-2 * dist1) / np.pi occupation = mg.integrate(fn) assert_almost_equal(occupation, 2.0, decimal=6)
def test_make_grid_different_grid_type(self): """Test different kind molgrid initizalize setting.""" # three different radial grid rad2 = GaussLaguerre(50) rad3 = GaussLaguerre(70) # construct grid numbers = np.array([1, 8, 1]) coordinates = np.array( [[0.0, 0.0, -0.5], [0.0, 0.0, 0.5], [0.0, 0.5, 0.0]], float) becke = BeckeWeights(order=3) # grid_type test with list mg = MolGrid.make_grid( numbers, coordinates, rad2, ["fine", "veryfine", "medium"], becke, store=True, ) dist0 = np.sqrt(((coordinates[0] - mg.points)**2).sum(axis=1)) dist1 = np.sqrt(((coordinates[1] - mg.points)**2).sum(axis=1)) dist2 = np.sqrt(((coordinates[2] - mg.points)**2).sum(axis=1)) fn = (np.exp(-2 * dist0) + np.exp(-2 * dist1) + np.exp(-2 * dist2)) / np.pi occupation = mg.integrate(fn) assert_almost_equal(occupation, 3, decimal=3) atgrid1 = AtomGrid.from_predefined(numbers[0], rad2, "fine", center=coordinates[0]) atgrid2 = AtomGrid.from_predefined(numbers[1], rad2, "veryfine", center=coordinates[1]) atgrid3 = AtomGrid.from_predefined(numbers[2], rad2, "medium", center=coordinates[2]) assert_allclose(mg._atomic_grids[0].points, atgrid1.points) assert_allclose(mg._atomic_grids[1].points, atgrid2.points) assert_allclose(mg._atomic_grids[2].points, atgrid3.points) # grid type test with dict mg = MolGrid.make_grid(numbers, coordinates, rad3, { 1: "fine", 8: "veryfine" }, becke, store=True) dist0 = np.sqrt(((coordinates[0] - mg.points)**2).sum(axis=1)) dist1 = np.sqrt(((coordinates[1] - mg.points)**2).sum(axis=1)) dist2 = np.sqrt(((coordinates[2] - mg.points)**2).sum(axis=1)) fn = (np.exp(-2 * dist0) + np.exp(-2 * dist1) + np.exp(-2 * dist2)) / np.pi occupation = mg.integrate(fn) assert_almost_equal(occupation, 3, decimal=3) atgrid1 = AtomGrid.from_predefined(numbers[0], rad3, "fine", center=coordinates[0]) atgrid2 = AtomGrid.from_predefined(numbers[1], rad3, "veryfine", center=coordinates[1]) atgrid3 = AtomGrid.from_predefined(numbers[2], rad3, "fine", center=coordinates[2]) assert_allclose(mg._atomic_grids[0].points, atgrid1.points) assert_allclose(mg._atomic_grids[1].points, atgrid2.points) assert_allclose(mg._atomic_grids[2].points, atgrid3.points)
def test_raise_errors(self): """Test molgrid errors raise.""" atg = AtomGrid.from_pruned( self.rgrid, 0.5, r_sectors=np.array([]), degs=np.array([17]), center=np.array([0.0, 0.0, 0.0]), ) # errors of aim_weight with self.assertRaises(TypeError): MolGrid([atg], aim_weights="test", atom_nums=np.array([1])) with self.assertRaises(ValueError): MolGrid([atg], aim_weights=np.array(3), atom_nums=np.array([1])) with self.assertRaises(TypeError): MolGrid([atg], aim_weights=[3, 5], atom_nums=np.array([1])) # integrate errors becke = BeckeWeights({1: 0.472_431_53}, order=3) molg = MolGrid([atg], becke, np.array([1])) with self.assertRaises(ValueError): molg.integrate() with self.assertRaises(TypeError): molg.integrate(1) with self.assertRaises(ValueError): molg.integrate(np.array([3, 5])) with self.assertRaises(ValueError): molg.get_atomic_grid(-3) molg = MolGrid([atg], becke, np.array([1]), store=True) with self.assertRaises(ValueError): molg.get_atomic_grid(-5) # test make_grid error pts = HortonLinear(70) tf = ExpRTransform(1e-5, 2e1) rgrid = tf.transform_1d_grid(pts) numbers = np.array([1, 1]) becke = BeckeWeights(order=3) # construct molgrid with self.assertRaises(ValueError): MolGrid.make_grid(numbers, np.array([0.0, 0.0, 0.0]), rgrid, "fine", becke) with self.assertRaises(ValueError): MolGrid.make_grid(np.array([1, 1]), np.array([[0.0, 0.0, 0.0]]), rgrid, "fine", becke) with self.assertRaises(ValueError): MolGrid.make_grid(np.array([1, 1]), np.array([[0.0, 0.0, 0.0]]), rgrid, "fine", becke) with self.assertRaises(TypeError): MolGrid.make_grid( np.array([1, 1]), np.array([[0.0, 0.0, -0.5], [0.0, 0.0, 0.5]]), {3, 5}, "fine", becke, ) with self.assertRaises(TypeError): MolGrid.make_grid( np.array([1, 1]), np.array([[0.0, 0.0, -0.5], [0.0, 0.0, 0.5]]), rgrid, np.array([3, 5]), becke, )
def __init__(self, atomic_grids, numbers, aim_weights="becke", store=False): """Initialize molgrid class. Parameters ---------- atomic_grids : list[AtomicGrid] list of atomic grid radii : np.ndarray(N,) Radii for each atom in the molecular grid aim_weights : str or np.ndarray(K,), default to "becke" Atoms in molecule weights. If str, certain function will be called to compute aim_weights, if np.ndarray, it will be treated as the aim_weights """ # initialize these attributes numbers = np.array(numbers) radii = get_cov_radii(numbers) self._coors = np.zeros((len(radii), 3)) self._indices = np.zeros(len(radii) + 1, dtype=int) self._size = np.sum([atomgrid.size for atomgrid in atomic_grids]) self._points = np.zeros((self._size, 3)) self._weights = np.zeros(self._size) self._atomic_grids = atomic_grids if store else None for i, atom_grid in enumerate(atomic_grids): self._coors[i] = atom_grid.center self._indices[i + 1] += self._indices[i] + atom_grid.size self._points[self._indices[i]:self._indices[i + 1]] = atom_grid.points self._weights[self._indices[i]:self. _indices[i + 1]] = atom_grid.weights if isinstance(aim_weights, str): if aim_weights == "becke": # Becke weights are computed for "chunks" of grid points # to counteract the scaling of the memory usage of the # vectorized implementation of the Becke partitioning. chunk_size = max(1, (10 * self._size) // self._coors.shape[0]**2) self._aim_weights = np.concatenate([ BeckeWeights.generate_becke_weights( self._points[ibegin:ibegin + chunk_size], radii, self._coors, pt_ind=(self._indices - ibegin).clip(min=0), ) for ibegin in range(0, self._size, chunk_size) ]) else: raise NotImplementedError( f"Given aim_weights is not supported, got {aim_weights}") elif isinstance(aim_weights, np.ndarray): if aim_weights.size != self.size: raise ValueError( "aim_weights is not the same size as grid.\n" f"aim_weights.size: {aim_weights.size}, grid.size: {self.size}." ) self._aim_weights = aim_weights else: raise TypeError( f"Not supported aim_weights type, got {type(aim_weights)}.")
def test_make_grid_different_rad_type(self): """Test different radial grid input for make molgrid.""" # radial grid test with list rad1 = GaussLaguerre(30) rad2 = GaussLaguerre(50) rad3 = GaussLaguerre(70) # construct grid numbers = np.array([1, 8, 1]) coordinates = np.array( [[0.0, 0.0, -0.5], [0.0, 0.0, 0.5], [0.0, 0.5, 0.0]], float ) becke = BeckeWeights(order=3) # construct molgrid mg = MolGrid.from_preset( numbers, coordinates, [rad1, rad2, rad3], {1: "fine", 8: "veryfine"}, becke, store=True, rotate=False, ) dist0 = np.sqrt(((coordinates[0] - mg.points) ** 2).sum(axis=1)) dist1 = np.sqrt(((coordinates[1] - mg.points) ** 2).sum(axis=1)) dist2 = np.sqrt(((coordinates[2] - mg.points) ** 2).sum(axis=1)) fn = (np.exp(-2 * dist0) + np.exp(-2 * dist1) + np.exp(-2 * dist2)) / np.pi occupation = mg.integrate(fn) assert_almost_equal(occupation, 3, decimal=3) atgrid1 = AtomGrid.from_preset( rad1, atnum=numbers[0], preset="fine", center=coordinates[0] ) atgrid2 = AtomGrid.from_preset( rad2, atnum=numbers[1], preset="veryfine", center=coordinates[1] ) atgrid3 = AtomGrid.from_preset( rad3, atnum=numbers[2], preset="fine", center=coordinates[2] ) assert_allclose(mg._atgrids[0].points, atgrid1.points) assert_allclose(mg._atgrids[1].points, atgrid2.points) assert_allclose(mg._atgrids[2].points, atgrid3.points) # radial grid test with dict mg = MolGrid.from_preset( numbers, coordinates, {1: rad1, 8: rad3}, {1: "fine", 8: "veryfine"}, becke, store=True, rotate=False, ) dist0 = np.sqrt(((coordinates[0] - mg.points) ** 2).sum(axis=1)) dist1 = np.sqrt(((coordinates[1] - mg.points) ** 2).sum(axis=1)) dist2 = np.sqrt(((coordinates[2] - mg.points) ** 2).sum(axis=1)) fn = (np.exp(-2 * dist0) + np.exp(-2 * dist1) + np.exp(-2 * dist2)) / np.pi occupation = mg.integrate(fn) assert_almost_equal(occupation, 3, decimal=3) atgrid1 = AtomGrid.from_preset( rad1, atnum=numbers[0], preset="fine", center=coordinates[0] ) atgrid2 = AtomGrid.from_preset( rad3, atnum=numbers[1], preset="veryfine", center=coordinates[1] ) atgrid3 = AtomGrid.from_preset( rad1, atnum=numbers[2], preset="fine", center=coordinates[2] ) assert_allclose(mg._atgrids[0].points, atgrid1.points) assert_allclose(mg._atgrids[1].points, atgrid2.points) assert_allclose(mg._atgrids[2].points, atgrid3.points)
def test_raise_errors(self): """Test errors raise.""" npoint = 100 points = np.random.uniform(-5, 5, (npoint, 3)) nums = np.array([1, 2]) centers = np.array([[1.2, 2.3, 0.1], [-0.4, 0.0, -2.2]]) # error of select and pt_ind becke = BeckeWeights({1: 0.5, 2: 0.8}) with self.assertRaises(ValueError): becke.generate_weights(points, centers, nums, select=[]) with self.assertRaises(ValueError): becke.generate_weights(points, centers, nums, pt_ind=[3]) with self.assertRaises(ValueError): becke.generate_weights(points, centers, nums, pt_ind=[3, 6]) with self.assertRaises(ValueError): becke.generate_weights(points, centers, nums, select=[], pt_ind=[]) with self.assertRaises(ValueError): becke.generate_weights(points, centers, nums, select=[0, 1], pt_ind=[0, 10, 50, 99]) with self.assertRaises(ValueError): becke.compute_weights(points, centers, nums, select=[]) with self.assertRaises(ValueError): becke.compute_weights(points, centers, nums, pt_ind=[3]) with self.assertRaises(ValueError): becke.compute_weights(points, centers, nums, pt_ind=[3, 6]) with self.assertRaises(ValueError): becke.compute_weights(points, centers, nums, select=[], pt_ind=[]) with self.assertRaises(ValueError): becke.compute_weights(points, centers, nums, select=[0, 1], pt_ind=[0, 10, 50, 99]) # error of order with self.assertRaises(ValueError): BeckeWeights({1: 0.5, 2: 0.8}, order=3.0) # error of radii with self.assertRaises(TypeError): BeckeWeights({1.0: 0.5, 2: 0.8}, order=3) with self.assertRaises(TypeError): BeckeWeights(np.array([0.5, 0.8]), order=3)
def test_raise_errors(self): """Test errors raise.""" npoint = 100 points = np.random.uniform(-5, 5, (npoint, 3)) radii = np.array([0.5, 0.8]) centers = np.array([[1.2, 2.3, 0.1], [-0.4, 0.0, -2.2]]) with self.assertRaises(ValueError): BeckeWeights.generate_becke_weights(points, radii, centers, select=[]) with self.assertRaises(ValueError): BeckeWeights.generate_becke_weights(points, radii, centers, pt_ind=[3]) with self.assertRaises(ValueError): BeckeWeights.generate_becke_weights(points, radii, centers, pt_ind=[3, 6]) with self.assertRaises(ValueError): BeckeWeights.generate_becke_weights(points, radii, centers, select=[], pt_ind=[]) with self.assertRaises(ValueError): BeckeWeights.generate_becke_weights(points, radii, centers, select=[0, 1], pt_ind=[0, 10, 50, 99]) with self.assertRaises(ValueError): BeckeWeights.generate_becke_weights(points, radii, centers[0], select=[0, 1], pt_ind=[0, 10, 50, 99])