def test_equidistant_trimer(self): with DescriptorSet(['Ag'], cutoff=8.0) as ds: types = ['Ag', 'Ag', 'Ag'] N = 30 r_vec = np.linspace(1., 5., N) theta_vec = np.linspace(0.0 * np.pi, 2. * np.pi, N, endpoint=True) for ri in r_vec: for ti in theta_vec: xyzs = np.array([[0.0, 0.0, 0.0], [ri, 0.0, 0.0], [ri * np.cos(ti), ri * np.sin(ti), 0.0]]) Gs = ds.eval(types, xyzs) Gs_atomwise = ds.eval_atomwise(types, xyzs) np.testing.assert_allclose(Gs, Gs_atomwise, equal_nan=False) dGs = ds.eval_derivatives(types, xyzs) dGs_atomwise = ds.eval_derivatives_atomwise(types, xyzs) np.testing.assert_allclose(dGs, dGs_atomwise, equal_nan=False) Gs, dGs = ds.eval_with_derivatives(types, xyzs) Gs_atomwise, dGs_atomwise = ( ds.eval_with_derivatives_atomwise(types, xyzs)) np.testing.assert_allclose(Gs, Gs_atomwise, equal_nan=False) np.testing.assert_allclose(dGs, dGs_atomwise, equal_nan=False, atol=1e-15)
def test_derivaties(self): with DescriptorSet(['Ni', 'Au'], cutoff=10.) as ds: pos = np.array([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [-1.0, 0.0, 0.0], [0.0, -1.0, 0.0]]) types = ['Ni', 'Ni', 'Au', 'Ni', 'Au'] rss = [0.0, 0.0, 0.0] etas = [1.0, 0.01, 0.0001] ds.add_G2_functions(rss, etas) ds.add_G5_functions(etas, [1.0], [1.0]) out_cpp = ds.eval(types, pos) analytical_derivatives = ds.eval_derivatives(types, pos) numerical_derivatives = np.zeros( (len(out_cpp), out_cpp[0].size, pos.size)) dx = np.sqrt(np.finfo(float).eps) for i in range(pos.size): dpos = np.zeros(pos.shape) dpos[np.unravel_index(i, dpos.shape)] += dx numerical_derivatives[:, :, i] = ( np.array(ds.eval(types, pos + dpos)) - np.array(ds.eval(types, pos - dpos))) / (2 * dx) np.testing.assert_array_almost_equal( numerical_derivatives.flatten(), np.array(analytical_derivatives).flatten())
def test_eval_with_derivatives(self): xyzs = np.array([ [1.19856, 0.00000, 0.71051], # C [2.39807, 0.00000, 0.00000], # C [2.35589, 0.00000, -1.39475], # C [1.19865, 0.00000, -2.09564], # N [0.04130, 0.00000, -1.39453], # C [0.00000, 0.00000, 0.00000], # C [-0.95363, 0.00000, 0.52249], # H [3.35376, 0.00000, 0.51820], # H [3.26989, 0.00000, -1.98534], # H [-0.87337, 0.00000, -1.98400], # H [1.19077, 0.00000, 2.07481], # O [2.10344, 0.00000, 2.41504] ]) # H types = ['C', 'C', 'C', 'N', 'C', 'C', 'H', 'H', 'H', 'H', 'O', 'H'] with DescriptorSet(['C', 'N', 'H', 'O'], cutoff=7.0) as ds: # Parameters from Artrith and Kolpak Nano Lett. 2014, 14, 2670 ds.add_Artrith_Kolpak_set() Gs_ref = ds.eval(types, xyzs) dGs_ref = ds.eval_derivatives(types, xyzs) Gs, dGs = ds.eval_with_derivatives(types, xyzs) np.testing.assert_allclose(Gs, Gs_ref) np.testing.assert_allclose(dGs, dGs_ref)
def test_exceptions(self): with DescriptorSet(['H', 'O']) as ds: try: ds.add_two_body_descriptor('H', 'O', 'FOO', []) except TypeError: pass try: ds.add_three_body_descriptor('H', 'O', 'H', 'FOO', []) except TypeError: pass try: ds.add_two_body_descriptor('H', 'O', 'BehlerG1', [], cuttype='FOO') except TypeError: pass try: ds.add_three_body_descriptor('H', 'O', 'O', 'BehlerG4', [1.0, 1.0, 1.0], cuttype='FOO') except TypeError: pass
def test_dimer_polynomial(self): with DescriptorSet(['Au'], cutoff=7.) as ds: types = ['Au', 'Au'] rss = [0.0, 0.0, 0.0] bohr2ang = 0.529177249 etas = np.array([0.01, 0.1, 1.0]) / bohr2ang**2 ds.add_G2_functions(rss, etas, cuttype='polynomial') def cutfun(r): return (1 - 10.0 * (r / ds.cutoff)**3 + 15.0 * (r / ds.cutoff)**4 - 6.0 * (r / ds.cutoff)**5) * (r < ds.cutoff) dr = np.sqrt(np.finfo(float).eps) for ri in np.linspace(2, 8, 10): Gi = ds.eval(types, np.array([[0.0, 0.0, 0.0], [0.0, 0.0, ri]])) # Assert Symmmetry np.testing.assert_array_equal(Gi[0], Gi[1]) # Assert Values np.testing.assert_allclose( Gi[0], np.exp(-etas * (ri - rss)**2) * cutfun(ri)) # Derivatives dGa = ds.eval_derivatives( types, np.array([[0.0, 0.0, 0.0], [0.0, 0.0, ri]])) # Assert Symmmetry np.testing.assert_array_equal(dGa[0], dGa[1]) # Assert Values np.testing.assert_allclose( dGa[0][:, 1, -1], np.exp(-etas * (ri - rss)**2) * (cutfun(ri) * 2.0 * (-etas) * (ri - rss) + (-30.0 * (ri**2 / ds.cutoff**3) + 60.0 * (ri**3 / ds.cutoff**4) - 30.0 * (ri**4 / ds.cutoff**5)) * (ri < ds.cutoff))) Gi_drp = ds.eval( types, np.array([[0.0, 0.0, 0.0], [0.0, 0.0, ri + dr]])) Gi_drm = ds.eval( types, np.array([[0.0, 0.0, 0.0], [0.0, 0.0, ri - dr]])) dGn = [(Gi_drp[i] - Gi_drm[i]) / (2 * dr) for i in [0, 1]] # Assert Symmetry np.testing.assert_array_equal(dGn[0], dGn[1]) # Assert Values np.testing.assert_allclose(dGa[0][:, 1, -1], dGn[0], rtol=1E-7, atol=1E-7)
def test_dimer_cos(self): with DescriptorSet(['Au'], cutoff=7.) as ds: types = ['Au', 'Au'] rss = [0.0, 0.0, 0.0] etas = np.array([0.01, 0.1, 1.0]) ds.add_G2_functions(rss, etas) def cutfun(r): return 0.5 * (1.0 + np.cos(np.pi * r / ds.cutoff)) * (r < ds.cutoff) dr = np.sqrt(np.finfo(float).eps) for ri in np.linspace(0.1, 8, 101): Gi = ds.eval(types, np.array([[0.0, 0.0, 0.0], [0.0, 0.0, ri]])) # Assert Symmmetry np.testing.assert_array_equal(Gi[0], Gi[1]) # Assert Values np.testing.assert_allclose( Gi[0], np.exp(-etas * (ri - rss)**2) * cutfun(ri)) # Derivatives dGa = ds.eval_derivatives( types, np.array([[0.0, 0.0, 0.0], [0.0, 0.0, ri]])) # Assert Symmetry np.testing.assert_array_equal(dGa[0], dGa[1]) # Assert Values np.testing.assert_allclose( dGa[0][:, 1, -1], np.exp(-etas * (ri - rss)**2) * (cutfun(ri) * 2.0 * (-etas) * (ri - rss) + 0.5 * (-np.sin(np.pi * ri / ds.cutoff) * np.pi / ds.cutoff) * (ri < ds.cutoff))) Gi_drp = ds.eval( types, np.array([[0.0, 0.0, 0.0], [0.0, 0.0, ri + dr]])) Gi_drm = ds.eval( types, np.array([[0.0, 0.0, 0.0], [0.0, 0.0, ri - dr]])) dGn = [(Gi_drp[i] - Gi_drm[i]) / (2 * dr) for i in [0, 1]] # Assert Symmetry np.testing.assert_array_equal(dGn[0], dGn[1]) # Assert Values np.testing.assert_allclose(dGa[0][:, 1, -1], dGn[0], rtol=1E-7, atol=1E-7)
def test_derivatives_numerically(self): with DescriptorSet(['Au', 'Ag'], cutoff=self.cutoff) as ds: self.add_descriptor(ds) types = ['Au', 'Ag', 'Ag', 'Ag', 'Ag', 'Ag'] xyzs = np.array([[0.0, 0.0, 0.0], [1.2, 0.0, 0.0], [-1.1, 0.0, 0.0], [0.0, 1.2, 0.0], [1., 2., 3.], [3, 2., 1.]]) dG = ds.eval_derivatives_atomwise(types, xyzs)[0][0] dG_num = np.zeros_like(dG) delta = 1e-6 for i in range(len(xyzs)): for j in range(3): dx = np.zeros_like(xyzs) dx[i, j] = delta G_plus = ds.eval_atomwise(types, xyzs + dx)[0] G_minus = ds.eval_atomwise(types, xyzs - dx)[0] dG_num[i, j] = (G_plus - G_minus) / (2 * delta) np.testing.assert_allclose(dG_num, dG, atol=1e-9)
def test_cutoff_function(self): r_vec = np.linspace(0.1, 8, 80) geos = [[('F', np.array([0.0, 0.0, 0.0])), ('H', np.array([0.0, 0.0, ri]))] for ri in r_vec] with DescriptorSet(['H', 'F'], cutoff=6.5) as ds: for (t1, t2) in product(ds.atomtypes, repeat=2): ds.add_two_body_descriptor( t1, t2, 'BehlerG1', [], cuttype=self.cuttype) Gs = [] dGs = [] for geo in geos: Gs.append(ds.eval_geometry(geo)) dGs.append(ds.eval_geometry_derivatives(geo)) np.testing.assert_allclose( np.array(Gs)[:, 0, 0], self.function(r_vec, ds.cutoff), equal_nan=False) np.testing.assert_allclose( np.array(dGs)[:, 0, 0, 1, -1], self.function_derivative(r_vec, ds.cutoff), atol=1e-12, equal_nan=False)
def test_derivative_numerically(self): with DescriptorSet(['H', 'F'], cutoff=6.5) as ds: for (t1, t2) in product(ds.atomtypes, repeat=2): ds.add_two_body_descriptor( t1, t2, 'BehlerG1', [], cuttype=self.cuttype) dr = 1e-5 # deliberately chosen as to not include 6.5 r_vec = np.linspace(0.1, 8, 81) dG = np.zeros_like(r_vec) dG_num = np.zeros_like(r_vec) for i, ri in enumerate(r_vec): geo = [('F', np.array([0.0, 0.0, 0.0])), ('H', np.array([0.0, 0.0, ri]))] dG[i] = ds.eval_geometry_derivatives(geo)[0][0, 1, -1] geo_p = [('F', np.array([0.0, 0.0, 0.0])), ('H', np.array([0.0, 0.0, ri+dr]))] geo_m = [('F', np.array([0.0, 0.0, 0.0])), ('H', np.array([0.0, 0.0, ri-dr]))] G_p = ds.eval_geometry(geo_p)[0][0] G_m = ds.eval_geometry(geo_m)[0][0] dG_num[i] = (G_p - G_m)/(2*dr) np.testing.assert_allclose(dG, dG_num, atol=1e-10)
def test_invariances(self): with DescriptorSet(['C', 'H'], cutoff=6.5) as ds: ds.add_Artrith_Kolpak_set() types = ['H', 'H', 'H', 'C', 'C', 'H', 'H', 'H'] xyzs = np.array([[1.0217062478, 0.0000000000, 1.1651331805], [-0.5108531239, 0.8848235658, 1.1651331805], [-0.5108531239, -0.8848235658, 1.1651331805], [0.0000000000, 0.0000000000, 0.7662728375], [0.0000000000, 0.0000000000, -0.7662728375], [0.5108531239, -0.8848235658, -1.1651331805], [-1.0217062478, 0.0000000000, -1.1651331805], [0.5108531239, 0.8848235658, -1.1651331805]]) Gs, dGs = ds.eval_with_derivatives_atomwise(types, xyzs) Gs = np.asarray(Gs) dGs = np.asarray(dGs) # Test for translational invariance Gs_test, dGs_test = ds.eval_with_derivatives_atomwise( types, xyzs + 10.) Gs_test = np.asarray(Gs_test) dGs_test = np.asarray(dGs_test) np.testing.assert_allclose(Gs, Gs_test, atol=1E-7) np.testing.assert_allclose(dGs, dGs_test, atol=1E-7) # Test for rotational invariance def rotation_matrix(axis, theta): """ Stolen from https://stackoverflow.com/questions/6802577/rotation-of-3d-vector Return the rotation matrix associated with counterclockwise rotation about the given axis by theta radians. """ axis = np.asarray(axis) axis = axis / np.linalg.norm(axis) a = np.cos(theta / 2.0) b, c, d = -axis * np.sin(theta / 2.0) aa, bb, cc, dd = a * a, b * b, c * c, d * d bc, ad, ac, ab, bd, cd = (b * c, a * d, a * c, a * b, b * d, c * d) return np.array( [[aa + bb - cc - dd, 2 * (bc + ad), 2 * (bd - ac)], [2 * (bc - ad), aa + cc - bb - dd, 2 * (cd + ab)], [2 * (bd + ac), 2 * (cd - ab), aa + dd - bb - cc]]) R = rotation_matrix([2, 1, 3], np.pi / 3.) Gs_test, dGs_test = ds.eval_with_derivatives_atomwise( types, xyzs.dot(R)) Gs_test = np.asarray(Gs_test) # dGs_test has to be rotated back to the original orientation dGs_test = np.asarray(dGs_test).dot(np.linalg.inv(R)) np.testing.assert_allclose(Gs, Gs_test, atol=1E-7) np.testing.assert_allclose(dGs, dGs_test, atol=1E-7) # Test for rotational invariance xyzs = xyzs[[1, 0, 2, 4, 3, 6, 5, 7]] Gs_test, dGs_test = ds.eval_with_derivatives_atomwise( types, xyzs + 10.) Gs_test = np.asarray(Gs_test) dGs_test = np.asarray(dGs_test) np.testing.assert_allclose(Gs, Gs_test, atol=1E-7)
import numpy as np from mlpot.descriptors import DescriptorSet import json ds = DescriptorSet(['Ni', 'Pt']) ds.add_Artrith_Kolpak_set() types = ['Ni'] * 5 + ['Pt'] * 8 xyzs = np.array([ -0.014480168, 0.034207338, 3.241557994, 2.898730059, -1.086507438, -0.962365452, 0.628479665, -3.011745934, 1.021810156, -1.106421727, -0.938238334, 0.966816473, 0.014835984, -0.034293064, -3.241593337, -2.898807639, 1.086543157, 0.962013396, 2.255579722, 1.959448215, 1.257961041, 1.106258420, 0.938154989, -0.966654169, -2.255797799, -1.959412496, -1.257693960, -0.628657260, 3.011781654, -1.021547837, 0.767345025, 2.434319406, 3.240815029, 2.475190116, 0.450660540, 3.269695405 ]).reshape((-1, 3)) Gs, dGs = ds.eval_with_derivatives(types, xyzs) Gs = [Gi.tolist() for Gi in Gs] dGs = [dGi.tolist() for dGi in dGs] with open('NiPt13.json', 'w') as fout: json.dump({'types': types, 'Gs': Gs, 'dGs': dGs}, fout)
def test_trimer(self): with DescriptorSet(['Ag'], cutoff=8.0) as ds: types = ['Ag', 'Ag', 'Ag'] def fcut(r): return 0.5 * (1.0 + np.cos(np.pi * r / ds.cutoff)) * (r < ds.cutoff) # Parameters from Artrith and Kolpak Nano Lett. 2014, 14, 2670 etas = np.array([0.0009, 0.01, 0.02, 0.035, 0.06, 0.1, 0.2]) for eta in etas: ds.add_two_body_descriptor('Ag', 'Ag', 'BehlerG2', [eta, 0.0], cuttype='cos') ang_etas = np.array([0.0001, 0.003, 0.008]) zetas = np.array([1.0, 4.0]) for ang_eta in ang_etas: for lamb in [-1.0, 1.0]: for zeta in zetas: ds.add_three_body_descriptor('Ag', 'Ag', 'Ag', 'BehlerG4', [lamb, zeta, ang_eta], cuttype='cos') # Also test BehlerG5 for ang_eta in ang_etas: for lamb in [-1.0, 1.0]: for zeta in zetas: ds.add_three_body_descriptor('Ag', 'Ag', 'Ag', 'BehlerG5', [lamb, zeta, ang_eta], cuttype='cos') N = 30 r_vec = np.linspace(1., 5., N) theta_vec = np.linspace(0.0 * np.pi, 2. * np.pi, N, endpoint=True) for ri in r_vec: for ti in theta_vec: xyzs = np.array([[0.0, 0.0, 0.0], [0.5 * ri, 0.0, 0.0], [ri * np.cos(ti), ri * np.sin(ti), 0.0]]) rij = np.linalg.norm(xyzs[0, :] - xyzs[1, :]) rik = np.linalg.norm(xyzs[0, :] - xyzs[2, :]) rjk = np.linalg.norm(xyzs[1, :] - xyzs[2, :]) np.testing.assert_allclose( rjk, np.sqrt(rij**2 + rik**2 - 2. * rij * rik * np.cos(ti)), atol=1E-12) Gs = ds.eval(types, xyzs) Gs_atomwise = ds.eval_atomwise(types, xyzs) Gs_ref = np.concatenate([ np.exp(-etas * rij**2) * fcut(rij) + np.exp(-etas * rik**2) * fcut(rik) ] + [ 2**(1. - zetas) * np.exp(-eta * (rij**2 + rik**2 + rjk**2)) * (1. + lamb * np.cos(ti))**zetas * fcut(rij) * fcut(rik) * fcut(rjk) for eta in ang_etas for lamb in [-1.0, 1.0] ] + [ 2**(1. - zetas) * np.exp(-eta * (rij**2 + rik**2)) * (1. + lamb * np.cos(ti))**zetas * fcut(rij) * fcut(rik) for eta in ang_etas for lamb in [-1.0, 1.0] ]) np.testing.assert_allclose(Gs, Gs_atomwise, equal_nan=False) np.testing.assert_allclose(Gs[0], Gs_ref, equal_nan=False) np.testing.assert_allclose(Gs_atomwise[0], Gs_ref, equal_nan=False) dGs = ds.eval_derivatives(types, xyzs) dGs_atomwise = ds.eval_derivatives_atomwise(types, xyzs) # Adding the equal_nan=False option shows a bug for # descriptors using rik as input np.testing.assert_allclose(dGs, dGs_atomwise, equal_nan=False) Gs, dGs = ds.eval_with_derivatives(types, xyzs) Gs_atomwise, dGs_atomwise = ( ds.eval_with_derivatives_atomwise(types, xyzs)) np.testing.assert_allclose(Gs, Gs_atomwise, equal_nan=False) np.testing.assert_allclose(dGs, dGs_atomwise, equal_nan=False, atol=1e-15)
def test_print_functions(self): with DescriptorSet(['C', 'H', 'O']) as ds: ds.available_descriptors() ds.add_Artrith_Kolpak_set() ds.print_descriptors()
def test_acetone(self): from scipy.optimize import approx_fprime # TODO: switch to custom implementation! x0 = np.array([ 0.00000, 0.00000, 0.00000, # C 1.40704, 0.00902, -0.67203, # C 1.67062, -0.92069, -1.22124, # H 2.20762, 0.06960, 0.11291, # H 1.61784, 0.88539, -1.32030, # H -1.40732, -0.00378, -0.67926, # C -1.65709, 0.91221, -1.25741, # H -2.20522, -0.03081, 0.10912, # H -1.64457, -0.88332, -1.31507, # H 0.00000, -0.00000, 1.20367 ]) # O types = ['C', 'C', 'H', 'H', 'H', 'C', 'H', 'H', 'H', 'O'] with DescriptorSet(['C', 'H', 'O'], cutoff=7.0) as ds: radial_etas = [0.01, 0.05, 0.1, 0.5, 1.0, 2.0, 5.0] rss = [0.0] * len(radial_etas) angular_etas = [0.0001, 0.003, 0.008] lambs = [1.0, -1.0] zetas = [1.0, 4.0] ds.add_G2_functions(rss, radial_etas) ds.add_G5_functions(angular_etas, zetas, lambs) f0 = ds.eval(types, x0.reshape((-1, 3))) df = ds.eval_derivatives(types, x0.reshape((-1, 3))) eps = np.sqrt(np.finfo(float).eps) for i in range(len(f0)): for j in range(len(f0[i])): def f(x): return np.array(ds.eval(types, x.reshape( (-1, 3))))[i][j] np.testing.assert_array_almost_equal( df[i][j], approx_fprime(x0, f, epsilon=eps).reshape((-1, 3)))