def compute(self, function, data): """ Compute descriptor for one structure to the database. """ if function['type'] in ['BehlerParrinello', 'ACSF']: from pyxtal_ff.descriptors.ACSF import ACSF d = ACSF(function['parameters'], function['Rc'], function['force'], function['stress'], False).calculate(data['structure']) elif function['type'] in ['wACSF', 'wacsf']: from pyxtal_ff.descriptors.ACSF import ACSF d = ACSF(function['parameters'], function['Rc'], function['force'], function['stress'], True).calculate(data['structure']) elif function['type'] in ['SO4', 'Bispectrum', 'bispectrum']: from pyxtal_ff.descriptors.SO4 import SO4_Bispectrum d = SO4_Bispectrum( function['parameters']['lmax'], function['Rc'], derivative=function['force'], stress=function['stress'], normalize_U=function['parameters']['normalize_U']).calculate( data['structure']) elif function['type'] in ['SO3', 'SOAP', 'soap']: from pyxtal_ff.descriptors.SO3 import SO3 d = SO3(function['parameters']['nmax'], function['parameters']['lmax'], function['Rc'], derivative=function['force'], stress=function['stress']).calculate(data['structure']) elif function['type'] in ['EAMD', 'eamd']: from pyxtal_ff.descriptors.EAMD import EAMD d = EAMD(function['parameters'], function['Rc'], function['force'], function['stress']).calculate(data['structure']) else: msg = f"{function['type']} is not implemented" raise NotImplementedError(msg) if d['rdxdr'] is not None: N = d['x'].shape[0] L = d['x'].shape[1] rdxdr = np.zeros([N, L, 3, 3]) for _m in range(N): ids = np.where(d['seq'][:, 0] == _m)[0] rdxdr[_m, :, :, :] += np.einsum('ijkl->jkl', d['rdxdr'][ids, :, :, :]) d['rdxdr'] = rdxdr.reshape([N, L, 9])[:, :, [0, 4, 8, 1, 2, 5]] #d['rdxdr'] = np.einsum('ijklm->iklm', d['rdxdr'])\ #.reshape([shp[0], shp[2], shp[3]*shp[4]])[:, :, [0, 4, 8, 1, 2, 5]] #need to change d['energy'] = np.asarray(data['energy']) d['force'] = np.asarray(data['force']) if data['stress'] is not None: d['stress'] = np.asarray(data['stress']) else: d['stress'] = data['stress'] d['group'] = data['group'] return d
class TestwACSF(unittest.TestCase): struc = get_rotated_struc(nacl) wACSF0 = ACSF(symmetry_parameters=acsf_params, Rc=rc, derivative=True, atom_weighted=True).calculate(struc) struc = get_rotated_struc(nacl, 10, 'x') wACSF1 = ACSF(symmetry_parameters=acsf_params, Rc=rc, derivative=True, atom_weighted=True).calculate(struc) def test_wACSF_rotation_variance(self): array1 = self.wACSF0['x'] array2 = self.wACSF1['x'] self.assertTrue(np.allclose(array1, array2)) def test_dwACSFdR_rotation_variance(self): for i in range(len(self.wACSF0['x'])): array1 = np.linalg.norm(self.wACSF0['dxdr'][i, :, :], axis=1) array2 = np.linalg.norm(self.wACSF1['dxdr'][i, :, :], axis=1) self.assertTrue(np.allclose(array1, array2)) def test_dwACSFdR_vs_numerical(self): shp = self.wACSF0['x'].shape array1 = np.zeros([shp[0], shp[0], shp[1], 3]) for _m in range(shp[0]): ids = np.where(self.wACSF0['seq'][:, 1] == _m)[0] array1[self.wACSF0['seq'][ids, 0], _m, :, :] += self.wACSF0['dxdr'][ids, :, :] for j in range(shp[0]): for k in range(3): struc = get_perturbed_struc(nacl, j, k, eps) wACSF2 = ACSF(symmetry_parameters=acsf_params, Rc=rc, derivative=False, atom_weighted=True).calculate(struc) array2 = (wACSF2['x'] - self.wACSF0['x']) / eps self.assertTrue( np.allclose(array1[:, j, :, k], array2, atol=1e-6))
class TestACSF(unittest.TestCase): from pyxtal_ff.descriptors.ACSF import ACSF symmetry = {'G2': {'eta': [0.003214], 'Rs': [0]}, 'G4': {'lambda': [1], 'zeta':[1], 'eta': [0.000357]}, 'G5': {'lambda': [-1], 'zeta':[1], 'eta': [0.004]}, } struc = get_rotated_struc(cu) g0 = ACSF(symmetry, rcut, derivative=True).calculate(struc) struc = get_rotated_struc(cu, 10, 'x') g1 = ACSF(symmetry, rcut, derivative=True).calculate(struc) struc = get_perturbed_struc(cu, eps) g2 = ACSF(symmetry, rcut, derivative=False).calculate(struc) def test_G2_value(self): self.assertAlmostEqual(self.g0['x'][0,0], 0.36925589) def test_G4_value(self): self.assertAlmostEqual(self.g0['x'][0,1], 0.00232827) def test_G_rotation_variance(self): array1 = self.g0['x'].flatten() array2 = self.g1['x'].flatten() self.assertTrue(np.allclose(array1, array2)) def test_dGdR_rotation_variance(self): array1 = np.linalg.norm(self.g0['dxdr'][0,:,:], axis=1) array2 = np.linalg.norm(self.g1['dxdr'][0,:,:], axis=1) self.assertTrue(np.allclose(array1, array2)) def test_dGdR_vs_numerical(self): array1 = (self.g2['x'][0] - self.g0['x'][0]).flatten()/eps array2 = self.g0['dxdr'][0, :, 0].flatten() if not np.allclose(array1, array2): print('\n Numerical dGdR') print((self.g2['x'][0] - self.g0['x'][0])/eps) print('\n precompute') print(array2) self.assertTrue(np.allclose(array1, array2))
def test_dACSFdR_vs_numerical(self): shp = self.ACSF0['x'].shape array1 = np.zeros([shp[0], shp[0], shp[1], 3]) for _m in range(shp[0]): ids = np.where(self.ACSF0['seq'][:, 1] == _m)[0] array1[self.ACSF0['seq'][ids, 0], _m, :, :] += self.ACSF0['dxdr'][ids, :, :] for j in range(shp[0]): for k in range(3): struc = get_perturbed_struc(nacl, j, k, eps) ACSF2 = ACSF(symmetry_parameters=acsf_params, Rc=rc, derivative=False).calculate(struc) array2 = (ACSF2['x'] - self.ACSF0['x']) / eps self.assertTrue( np.allclose(array1[:, j, :, k], array2, atol=1e-6))
def compute_descriptor(function, structure): """ Compute descriptor for one structure. """ if function['type'] in ['BehlerParrinello', 'ACSF']: from pyxtal_ff.descriptors.ACSF import ACSF d = ACSF(function['parameters'], function['Rc'], function['force'], function['stress'], function['cutoff'], False).calculate(structure) elif function['type'] in ['wACSF', 'wacsf']: from pyxtal_ff.descriptors.ACSF import ACSF d = ACSF(function['parameters'], function['Rc'], function['force'], function['stress'], function['cutoff'], True).calculate(structure) elif function['type'] in ['SO4', 'Bispectrum', 'bispectrum']: from pyxtal_ff.descriptors.SO4 import SO4_Bispectrum d = SO4_Bispectrum( function['parameters']['lmax'], function['Rc'], derivative=True, stress=True, normalize_U=function['parameters']['normalize_U'], cutoff_function=function['cutoff']).calculate(structure) elif function['type'] in ['SO3', 'SOAP', 'soap']: from pyxtal_ff.descriptors.SO3 import SO3 d = SO3(function['parameters']['nmax'], function['parameters']['lmax'], function['Rc'], derivative=True, stress=True).calculate(structure) elif function['type'] in ['EAD', 'ead']: from pyxtal_ff.descriptors.EAD import EAD d = EAMD(function['parameters'], function['Rc'], True, True, function['cutoff']).calculate(structure) elif function['type'] in ['SNAP', 'snap']: from pyxtal_ff.descriptors.SNAP import SO4_Bispectrum d = SO4_Bispectrum( function['weights'], function['parameters']['lmax'], function['Rc'], derivative=True, stress=True, normalize_U=function['parameters']['normalize_U'], cutoff_function=function['cutoff']).calculate(structure) else: msg = f"{function['type']} is not implemented" raise NotImplementedError(msg) if d['rdxdr'] is not None: #shp = d['rdxdr'].shape #d['rdxdr'] = np.einsum('ijklm->iklm', d['rdxdr'])\ # .reshape([shp[0], shp[2], shp[3]*shp[4]])[:, :, [0,4,8,1,2,5]] N = d['x'].shape[0] L = d['x'].shape[1] rdxdr = np.zeros([N, L, 3, 3]) for _m in range(N): ids = np.where(d['seq'][:, 0] == _m)[0] rdxdr[_m, :, :, :] += np.einsum('ijkl->jkl', d['rdxdr'][ids, :, :, :]) d['rdxdr'] = rdxdr.reshape([N, L, 9])[:, :, [0, 4, 8, 1, 2, 5]] return d