def efs_force(bond_array_1, c1, etypes1, bond_array_2, c2, etypes2, sig, ls, r_cut, cutoff_func): energy_kernels = np.zeros(3) force_kernels = np.zeros((3, 3)) stress_kernels = np.zeros((6, 3)) ls1 = 1 / (2 * ls * ls) ls2 = 1 / (ls * ls) ls3 = ls2 * ls2 sig2 = sig * sig for m in range(bond_array_1.shape[0]): ri = bond_array_1[m, 0] fi, _ = cutoff_func(r_cut, ri, 0) e1 = etypes1[m] for n in range(bond_array_2.shape[0]): e2 = etypes2[n] # check if bonds agree if (c1 == c2 and e1 == e2) or (c1 == e2 and c2 == e1): rj = bond_array_2[n, 0] fj, _ = cutoff_func(r_cut, rj, 0) r11 = ri - rj D = r11 * r11 for d1 in range(3): cj = bond_array_2[n, d1 + 1] _, fdj = cutoff_func(r_cut, rj, cj) C = r11 * cj energy_kernels[d1] += \ force_energy_helper(-C, D, fj, fi, fdj, ls1, ls2, sig2) / 2 stress_count = 0 for d3 in range(3): ci = bond_array_1[m, d3 + 1] _, fdi = cutoff_func(r_cut, ri, ci) A = ci * cj B = r11 * ci force_kern = \ force_helper(A, B, C, D, fi, fj, fdi, fdj, ls1, ls2, ls3, sig2) force_kernels[d3, d1] += force_kern for d2 in range(d3, 3): coordinate = bond_array_1[m, d2 + 1] * ri stress_kernels[stress_count, d1] -= \ force_kern * coordinate / 2 stress_count += 1 return energy_kernels, force_kernels, stress_kernels
def force_energy(bond_array_1, c1, etypes1, bond_array_2, c2, etypes2, sig, ls, r_cut, cutoff_func): """2-body multi-element kernel between a force component and a local energy accelerated with Numba. Args: bond_array_1 (np.ndarray): 2-body bond array of the first local environment. c1 (int): Species of the central atom of the first local environment. etypes1 (np.ndarray): Species of atoms in the first local environment. bond_array_2 (np.ndarray): 2-body bond array of the second local environment. c2 (int): Species of the central atom of the second local environment. etypes2 (np.ndarray): Species of atoms in the second local environment. d1 (int): Force component of the first environment (1=x, 2=y, 3=z). sig (float): 2-body signal variance hyperparameter. ls (float): 2-body length scale hyperparameter. r_cut (float): 2-body cutoff radius. cutoff_func (Callable): Cutoff function. Returns: float: Value of the 2-body force/energy kernel. """ kern = np.zeros(3) ls1 = 1 / (2 * ls * ls) ls2 = 1 / (ls * ls) sig2 = sig * sig for m in range(bond_array_1.shape[0]): ri = bond_array_1[m, 0] e1 = etypes1[m] for n in range(bond_array_2.shape[0]): e2 = etypes2[n] # Check if species agree. if (c1 == c2 and e1 == e2) or (c1 == e2 and c2 == e1): rj = bond_array_2[n, 0] fj, _ = cutoff_func(r_cut, rj, 0) r11 = ri - rj D = r11 * r11 for d1 in range(3): ci = bond_array_1[m, d1 + 1] fi, fdi = cutoff_func(r_cut, ri, ci) B = r11 * ci kern[d1] += \ force_energy_helper(B, D, fi, fj, fdi, ls1, ls2, sig2) return kern / 2
def efs_energy(bond_array_1, c1, etypes1, bond_array_2, c2, etypes2, sig, ls, r_cut, cutoff_func): energy_kernel = 0 # TODO: add dtype to other zeros force_kernels = np.zeros(3) stress_kernels = np.zeros(6) ls1 = 1 / (2 * ls * ls) ls2 = 1 / (ls * ls) sig2 = sig * sig for m in range(bond_array_1.shape[0]): ri = bond_array_1[m, 0] fi, _ = cutoff_func(r_cut, ri, 0) e1 = etypes1[m] for n in range(bond_array_2.shape[0]): e2 = etypes2[n] # Check if the species agree. if (c1 == c2 and e1 == e2) or (c1 == e2 and c2 == e1): rj = bond_array_2[n, 0] fj, _ = cutoff_func(r_cut, rj, 0) r11 = ri - rj D = r11 * r11 energy_kernel += fi * fj * sig2 * exp(-D * ls1) / 4 # Compute the force kernel. stress_count = 0 for d1 in range(3): ci = bond_array_1[m, d1 + 1] B = r11 * ci _, fdi = cutoff_func(r_cut, ri, ci) force_kern = \ force_energy_helper(B, D, fi, fj, fdi, ls1, ls2, sig2) force_kernels[d1] += force_kern / 2 # Compute the stress kernel from the force kernel. for d2 in range(d1, 3): coordinate = bond_array_1[m, d2 + 1] * ri stress_kernels[stress_count] -= \ force_kern * coordinate / 4 stress_count += 1 return energy_kernel, force_kernels, stress_kernels
def stress_energy(bond_array_1, c1, etypes1, bond_array_2, c2, etypes2, sig, ls, r_cut, cutoff_func): """2-body multi-element kernel between a partial stress component and a local energy accelerated with Numba. Args: bond_array_1 (np.ndarray): 2-body bond array of the first local environment. c1 (int): Species of the central atom of the first local environment. etypes1 (np.ndarray): Species of atoms in the first local environment. bond_array_2 (np.ndarray): 2-body bond array of the second local environment. c2 (int): Species of the central atom of the second local environment. etypes2 (np.ndarray): Species of atoms in the second local environment. sig (float): 2-body signal variance hyperparameter. ls (float): 2-body length scale hyperparameter. r_cut (float): 2-body cutoff radius. cutoff_func (Callable): Cutoff function. Returns: float: Value of the 2-body partial-stress/energy kernel. """ kern = np.zeros(6) ls1 = 1 / (2 * ls * ls) ls2 = 1 / (ls * ls) sig2 = sig * sig for m in range(bond_array_1.shape[0]): ri = bond_array_1[m, 0] e1 = etypes1[m] for n in range(bond_array_2.shape[0]): e2 = etypes2[n] # Check if the species agree. if (c1 == c2 and e1 == e2) or (c1 == e2 and c2 == e1): rj = bond_array_2[n, 0] fj, _ = cutoff_func(r_cut, rj, 0) r11 = ri - rj D = r11 * r11 # Compute the force kernel. stress_count = 0 for d1 in range(3): ci = bond_array_1[m, d1 + 1] B = r11 * ci fi, fdi = cutoff_func(r_cut, ri, ci) force_kern = \ force_energy_helper(B, D, fi, fj, fdi, ls1, ls2, sig2) # Compute the stress kernel from the force kernel. for d2 in range(d1, 3): coordinate = bond_array_1[m, d2 + 1] * ri kern[stress_count] -= force_kern * coordinate stress_count += 1 return kern / 4