def GenGrid(self, GP, bond_struc, processes=mp.cpu_count()): ''' generate grid data of mean prediction and L^{-1}k* for each triplet default implemented in a parallelized style ''' processes = mp.cpu_count() nop = self.grid_num bond_lengths = np.linspace(self.l_bound, self.u_bound, nop) bond_means = np.zeros([nop]) bond_vars = np.zeros([nop, nop]) env1 = env.AtomicEnvironment(bond_struc, 0, self.cutoffs) env2 = env.AtomicEnvironment(bond_struc, 0, self.cutoffs) pool_list = [(i, bond_lengths[i], bond_lengths, GP, env1, env2) for i in range(nop)] pool = mp.Pool(processes=processes) A_list = pool.starmap(self._GenGrid_inner, pool_list) pool.close() pool.join() A_list.sort(key=lambda x: x[0]) for b1 in range(nop): bond_means[b1] = A_list[b1][1] bond_vars[b1, :] = A_list[b1][2] return bond_means, bond_vars
def generate_mb_envs_pos(positions0, species_1, cutoffs, cell, delt, d1, mask=None): positions = [positions0] noa = len(positions0) positions_2 = deepcopy(positions0) positions_2[0][d1 - 1] = delt positions += [positions_2] positions_3 = deepcopy(positions[0]) positions_3[0][d1 - 1] = -delt positions += [positions_3] test_struc = [] for i in range(3): test_struc += [struc.Structure(cell, species_1, positions[i])] env_0 = [] env_p = [] env_m = [] for i in range(noa): env_0 += [env.AtomicEnvironment(test_struc[0], i, cutoffs)] env_p += [env.AtomicEnvironment(test_struc[1], i, cutoffs)] env_m += [env.AtomicEnvironment(test_struc[2], i, cutoffs)] return [env_0, env_p, env_m]
def test_three_body_force_en(): """Check that the analytical force/en kernel matches finite difference of energy kernel.""" # create env 1 delt = 1e-8 cell = np.eye(3) cutoffs = np.array([1, 1]) positions_1 = [ np.array([0., 0., 0.]), np.array([random(), random(), random()]), np.array([random(), random(), random()]) ] positions_2 = deepcopy(positions_1) positions_2[0][0] = delt species_1 = [1, 2, 1] atom_1 = 0 test_structure_1 = struc.Structure(cell, species_1, positions_1) test_structure_2 = struc.Structure(cell, species_1, positions_2) env1_1 = env.AtomicEnvironment(test_structure_1, atom_1, cutoffs) env1_2 = env.AtomicEnvironment(test_structure_2, atom_1, cutoffs) # create env 2 positions_1 = [ np.array([0., 0., 0.]), np.array([random(), random(), random()]), np.array([random(), random(), random()]) ] species_2 = [1, 1, 2] atom_2 = 0 test_structure_1 = struc.Structure(cell, species_2, positions_1) env2 = env.AtomicEnvironment(test_structure_1, atom_2, cutoffs) sig = random() ls = random() d1 = 1 hyps = np.array([sig, ls]) # check force kernel calc1 = en.three_body_en(env1_2, env2, hyps, cutoffs) calc2 = en.three_body_en(env1_1, env2, hyps, cutoffs) kern_finite_diff = (calc1 - calc2) / delt kern_analytical = en.three_body_force_en(env1_1, env2, d1, hyps, cutoffs) tol = 1e-4 assert (np.isclose(-kern_finite_diff / 3, kern_analytical, atol=tol))
def test_three_body_grad(): # create env 1 cell = np.eye(3) cutoffs = np.array([1, 1]) positions_1 = [np.array([0., 0., 0.]), np.array([random(), random(), random()]), np.array([random(), random(), random()])] species_1 = [1, 2, 1] atom_1 = 0 test_structure_1 = struc.Structure(cell, species_1, positions_1) env1 = env.AtomicEnvironment(test_structure_1, atom_1, cutoffs) # create env 2 positions_1 = [np.array([0., 0., 0.]), np.array([random(), random(), random()]), np.array([random(), random(), random()])] species_2 = [1, 1, 2] atom_2 = 0 test_structure_1 = struc.Structure(cell, species_2, positions_1) env2 = env.AtomicEnvironment(test_structure_1, atom_2, cutoffs) sig = random() ls = random() d1 = randint(1, 3) d2 = randint(1, 3) hyps = np.array([sig, ls]) grad_test = en.three_body_grad(env1, env2, d1, d2, hyps, cutoffs) delta = 1e-8 new_sig = sig + delta new_ls = ls + delta sig_derv_brute = (en.three_body(env1, env2, d1, d2, np.array([new_sig, ls]), cutoffs) - en.three_body(env1, env2, d1, d2, hyps, cutoffs)) / delta l_derv_brute = (en.three_body(env1, env2, d1, d2, np.array([sig, new_ls]), cutoffs) - en.three_body(env1, env2, d1, d2, hyps, cutoffs)) / delta tol = 1e-4 assert(np.isclose(grad_test[1][0], sig_derv_brute, atol=tol)) assert(np.isclose(grad_test[1][1], l_derv_brute, atol=tol))
def GenGrid(self, GP, bond_struc, processes=mp.cpu_count()): ''' generate grid data of mean prediction and L^{-1}k* for each triplet implemented in a parallelized style ''' # ------ change GP kernel to 3 body ------ original_kernel = GP.kernel original_hyps = np.copy(GP.hyps) GP.kernel = three_body_mc GP.hyps = GP.hyps[-3:] # ------ construct grids ------ nop = self.grid_num[0] noa = self.grid_num[2] bond_lengths = np.linspace(self.l_bound[0], self.u_bound[0], nop) angles = np.linspace(self.l_bound[2], self.u_bound[2], noa) bond_means = np.zeros([nop, nop, noa]) bond_vars = np.zeros([nop, nop, noa, len(GP.alpha)]) env12 = env.AtomicEnvironment(bond_struc, 0, self.cutoffs) pool_list = [(i, angles[i], bond_lengths, GP, env12) for i in range(noa)] pool = mp.Pool(processes=processes) A_list = pool.map(self._GenGrid_inner, pool_list) for a12 in range(noa): bond_means[:, :, a12] = A_list[a12][0] bond_vars[:, :, a12, :] = A_list[a12][1] pool.close() pool.join() # ------ change back to original GP ------ GP.hyps = original_hyps GP.kernel = original_kernel return bond_means, bond_vars
def force_envs(strucs): """Perturb atom 0 in both structures up and down and in all directions.""" signs = [1, -1] dims = [0, 1, 2] force_envs = [] for structure in strucs: sign_envs_curr = [] for sign in signs: dim_envs_curr = [] for dim in dims: positions_pert = np.copy(structure.positions) positions_pert[0, dim] += delta * sign struc_pert = struc.Structure(structure.cell, structure.coded_species, positions_pert) atom_envs = [] for n in range(structure.nat): env_curr = env.AtomicEnvironment(struc_pert, n, cutoffs) atom_envs.append(env_curr) dim_envs_curr.append(atom_envs) sign_envs_curr.append(dim_envs_curr) force_envs.append(sign_envs_curr) yield force_envs
def predict_atom_diag_var_2b(atom_env, gp_model, force_kernel): bond_array = atom_env.bond_array_2 ctype = atom_env.ctype var = 0 for m in range(bond_array.shape[0]): ri1 = bond_array[m, 0] ci1 = bond_array[m, 1:] etype1 = atom_env.etypes[m] # build up a struc of triplet for prediction cell = np.eye(3) * 100 positions = np.array([np.zeros(3), ri1 * ci1]) species = np.array([ctype, etype1]) spc_struc = struc.Structure(cell, species, positions) spc_struc.coded_species = np.array(species) env12 = env.AtomicEnvironment(spc_struc, 0, gp_model.cutoffs) coord = np.copy(env12.bond_array_2[0, 1:]) # env12.bond_array_2[0, 1:] = np.array([1., 0., 0.]) if force_kernel: v12 = np.zeros(3) for d in range(3): _, v12[d] = gp_model.predict(env12, d + 1) print("v12", np.sqrt(v12), coord) else: _, v12 = gp_model.predict_local_energy_and_var(env12) var += np.sqrt(v12) var = var**2 return var
def test_predict(all_gp, all_mgp, bodies): """ test the predict for mc_simple kernel """ gp_model = all_gp[f'{bodies}'] mgp_model = all_mgp[f'{bodies}'] atom_id = 1 nenv = 10 cell = np.eye(3) cutoffs = gp_model.cutoffs unique_species = gp_model.training_data[0].species struc_test, f = get_random_structure(cell, unique_species, nenv) test_envi = env.AtomicEnvironment(struc_test, atom_id, cutoffs) mgp_pred = mgp_model.predict(test_envi, mean_only=True) # check mgp is within 1 meV/A of the gp for s in range(3): gp_pred_x = gp_model.predict(test_envi, s + 1) print(mgp_pred, gp_pred_x) assert(np.abs(mgp_pred[0][s] - gp_pred_x[0]) < 1e-3), \ f"{bodies} body mapping is wrong" clean()
def test_predict(all_gp, all_mgp, bodies, multihyps): """ test the predict for mc_simple kernel """ # multihyps = False gp_model = all_gp[f'{bodies}{multihyps}'] mgp_model = all_mgp[f'{bodies}{multihyps}'] nenv = 10 cell = np.eye(3) cutoffs = gp_model.cutoffs unique_species = gp_model.training_data[0].species struc_test, f = get_random_structure(cell, unique_species, nenv) test_envi = env.AtomicEnvironment(struc_test, 1, cutoffs) gp_pred_en = gp_model.predict_local_energy(test_envi) gp_pred_x = gp_model.predict(test_envi, 1) mgp_pred = mgp_model.predict(test_envi, mean_only=True) # check mgp is within 1 meV/A of the gp assert(np.abs(mgp_pred[3] - gp_pred_en) < 1e-3), \ f"{bodies} body energy mapping is wrong" assert(np.abs(mgp_pred[0][0] - gp_pred_x[0]) < 1e-3), \ f"{bodies} body mapping is wrong" clean()
def predict_on_structure(self): for n in range(self.structure.nat): chemenv = env.AtomicEnvironment(self.structure, n, self.gp.cutoffs) for i in range(3): force, var = self.gp.predict(chemenv, i + 1) self.structure.forces[n][i] = float(force) self.structure.stds[n][i] = np.sqrt(np.abs(var))
def test_2_plus_3_body(otf_object, structure, params): # reconstruct gp model kernel = mc_simple.two_plus_three_body_mc kernel_grad = mc_simple.two_plus_three_body_mc_grad gp_model = otf_object.make_gp(kernel=kernel, kernel_grad=kernel_grad, hyp_no=2) gp_model.par = True gp_model.hyp_labels = ['sig2', 'ls2', 'sig3', 'ls3', 'noise'] # create MGP grid_params = params['grid'] grid_params['bodies'] = [2, 3] struc_params = params['struc'] mgp_model = MappedGaussianProcess(gp_model.hyps, gp_model.cutoffs, grid_params, struc_params, mean_only=True, container_only=False, GP=gp_model, lmp_file_name='AgI_Molten_15.txt') # test if MGP prediction matches GP atom = 0 environ = env.AtomicEnvironment(structure, atom, gp_model.cutoffs) gp_pred_x = gp_model.predict(environ, 1) mgp_pred = mgp_model.predict(environ, mean_only=True) # check mgp is within 1 meV/A of the gp assert (np.abs(mgp_pred[0][0] - gp_pred_x[0]) < 1e-3)
def predict_struc_diag_var(struc, gp_model): variance = np.zeros((struc.nat, 3)) for atom in range(struc.nat): atom_env = env.AtomicEnvironment(struc, atom, gp_model.cutoffs) var = predict_atom_diag_var(atom_env, gp_model) variance[atom, :] = var return variance
def another_env(cutoffs, delt): cell = 10.0 * np.eye(3) # atomic structure 1 pos_1 = np.vstack([[0, 0, 0], 0.1 * random([3, 3])]) pos_1[1, 1] += 1 pos_1[2, 0] += 1 pos_1[3, :2] += 1 pos_2 = deepcopy(pos_1) pos_2[0][0] = delt pos_3 = deepcopy(pos_1) pos_3[0][0] = -delt species_1 = [1, 1, 1, 1] test_structure_1 = struc.Structure(cell, species_1, pos_1) test_structure_2 = struc.Structure(cell, species_1, pos_2) test_structure_3 = struc.Structure(cell, species_1, pos_3) # atom 0, original position env1_1_0 = env.AtomicEnvironment(test_structure_1, 0, cutoffs) # atom 0, 0 perturbe along x env1_2_0 = env.AtomicEnvironment(test_structure_2, 0, cutoffs) # atom 1, 0 perturbe along x env1_2_1 = env.AtomicEnvironment(test_structure_2, 1, cutoffs) # atom 2, 0 perturbe along x env1_2_2 = env.AtomicEnvironment(test_structure_2, 2, cutoffs) # atom 0, 0 perturbe along -x env1_3_0 = env.AtomicEnvironment(test_structure_3, 0, cutoffs) # atom 1, 0 perturbe along -x env1_3_1 = env.AtomicEnvironment(test_structure_3, 1, cutoffs) # atom 2, 0 perturbe along -x env1_3_2 = env.AtomicEnvironment(test_structure_3, 2, cutoffs) # create env 2 pos_1 = np.vstack([[0, 0, 0], 0.1 * random([3, 3])]) pos_1[1, 1] += 1 pos_1[2, 0] += 1 pos_1[3, :2] += 1 pos_2 = deepcopy(pos_1) pos_2[0][0] = delt pos_3 = deepcopy(pos_1) pos_3[0][0] = -delt species_2 = [1, 2, 2, 1] test_structure_1 = struc.Structure(cell, species_2, pos_1) env2_1_0 = env.AtomicEnvironment(test_structure_1, 0, cutoffs) return env1_1_0, env1_2_0, env1_3_0, \ env1_2_1, env1_3_1, env1_2_2, env1_3_2, env2_1_0
def predict_on_atom(self, atom): chemenv = env.AtomicEnvironment(self.structure, atom, self.gp.cutoffs) comps = [] stds = [] # predict force components and standard deviations for i in range(3): force, var = self.gp.predict(chemenv, i + 1) comps.append(float(force)) stds.append(np.sqrt(np.abs(var))) return comps, stds
def struc_envs(strucs): """Store the environments of the random structures.""" struc_envs = [] for structure in strucs: envs_curr = [] for n in range(structure.nat): env_curr = env.AtomicEnvironment(structure, n, cutoffs) envs_curr.append(env_curr) struc_envs.append(envs_curr) yield struc_envs
def predict_on_structure_mgp(self): # changed """ Assign forces to self.structure based on self.gp """ output.write_to_output('\npredict with mapping:\n', self.output_name) for n in range(self.structure.nat): chemenv = env.AtomicEnvironment(self.structure, n, self.gp.cutoffs) force, var = self.mgp_model.predict(chemenv) self.structure.forces[n][:] = force self.structure.stds[n][:] = np.sqrt(np.absolute(var)) self.structure.dft_forces = False
def get_grid_env(GP, species, bodies): if isinstance(GP.cutoffs, dict): max_cut = np.max(list(GP.cutoffs.values())) else: max_cut = np.max(GP.cutoffs) big_cell = np.eye(3) * 100 positions = [[(i + 1) / (bodies + 1) * 0.1, 0, 0] for i in range(bodies)] grid_struc = struc.Structure(big_cell, species, positions) grid_env = env.AtomicEnvironment(grid_struc, 0, GP.cutoffs, cutoffs_mask=GP.hyps_mask) return grid_env
def predict_atom_diag_var_3b(atom_env, gp_model, force_kernel): bond_array = atom_env.bond_array_3 triplets = atom_env.triplet_counts cross_bond_inds = atom_env.cross_bond_inds cross_bond_dists = atom_env.cross_bond_dists ctype = atom_env.ctype var = 0 pred_dict = {} for m in range(bond_array.shape[0]): ri1 = bond_array[m, 0] ci1 = bond_array[m, 1:] etype1 = atom_env.etypes[m] for n in range(triplets[m]): ind1 = cross_bond_inds[m, m + n + 1] ri2 = bond_array[ind1, 0] ci2 = bond_array[ind1, 1:] etype2 = atom_env.etypes[ind1] ri3 = cross_bond_dists[m, m + n + 1] # build up a struc of triplet for prediction cell = np.eye(3) * 100 positions = np.array([np.zeros(3), ri1 * ci1, ri2 * ci2]) species = np.array([ctype, etype1, etype2]) spc_struc = struc.Structure(cell, species, positions) spc_struc.coded_species = np.array(species) env12 = env.AtomicEnvironment(spc_struc, 0, gp_model.cutoffs) # env12.bond_array_3[0, 1:] = np.array([1., 0., 0.]) # env12.bond_array_3[1, 1:] = np.array([0., 0., 0.]) if force_kernel: v12 = np.zeros(3) for d in range(3): _, v12[d] = gp_model.predict(env12, d + 1) print("v12", np.sqrt(v12), env12.ctype, env12.etypes) else: _, v12 = gp_model.predict_local_energy_and_var(env12) spc = f"{env12.ctype}_{env12.etypes[0]}_{env12.etypes[1]}" if spc in pred_dict: pred_dict[spc] += np.sqrt(v12) else: pred_dict[spc] = np.sqrt(v12) var += np.sqrt(v12) var = var**2 print(pred_dict) return var
def stress_envs(strucs): """Strain both structures up and down and in all directions.""" stress_envs = [] signs = [1, -1] for structure in strucs: sign_envs_curr = [] for sign in signs: strain_envs_curr = [] for m in range(3): for n in range(m, 3): cell_pert = np.copy(structure.cell) positions_pert = np.copy(structure.positions) # Strain the cell. for p in range(3): cell_pert[p, m] += structure.cell[p, n] * delta * sign # Strain the positions. for k in range(structure.nat): positions_pert[ k, m] += structure.positions[k, n] * delta * sign struc_pert = struc.Structure(cell_pert, structure.coded_species, positions_pert) atom_envs = [] for q in range(structure.nat): env_curr = env.AtomicEnvironment( struc_pert, q, cutoffs) atom_envs.append(env_curr) strain_envs_curr.append(atom_envs) sign_envs_curr.append(strain_envs_curr) stress_envs.append(sign_envs_curr) yield stress_envs
def GenGrid_svd(self, GP, bond_struc, processes=mp.cpu_count()): ''' generate grid data of mean prediction and L^{-1}k* for each triplet implemented in a parallelized style ''' # ------ change GP kernel to 2 body ------ GP.kernel = two_body original_cutoffs = np.copy(GP.cutoffs) GP.cutoffs = [GP.cutoffs[0]] original_hyps = np.copy(GP.hyps) GP.hyps = [GP.hyps[0], GP.hyps[1], GP.hyps[-1]] # ------ construct grids ------ nop = self.grid_num bond_lengths = np.linspace(self.l_bound[0], self.u_bound[0], nop) bond_means = np.zeros([nop]) bond_vars = np.zeros([nop, len(GP.alpha)]) env12 = env.AtomicEnvironment(bond_struc, 0, self.cutoffs) pool_list = [(i, bond_lengths, GP, env12)\ for i in range(nop)] pool = mp.Pool(processes=processes) A_list = pool.map(self._GenGrid_svd_inner, pool_list) for p in range(nop): bond_means[p] = A_list[p][0] bond_vars[p, :] = A_list[p][1] pool.close() pool.join() # ------ change back original GP ------ GP.cutoffs = original_cutoffs GP.hyps = original_hyps GP.kernel = two_plus_three_body return bond_means, bond_vars
def generate_envs(cutoffs, delta): """ create environment with perturbation on direction i """ # create env 1 # perturb the x direction of atom 0 for +- delta cell = np.eye(3) * np.max(cutoffs + 0.1) atom_1 = 0 pos_1 = np.vstack([[0, 0, 0], random([3, 3])]) pos_2 = deepcopy(pos_1) pos_2[0][0] = delta pos_3 = deepcopy(pos_1) pos_3[0][0] = -delta species_1 = [1, 2, 1, 1] # , 1, 1, 2, 1, 2] test_structure_1 = struc.Structure(cell, species_1, pos_1) test_structure_2 = struc.Structure(cell, species_1, pos_2) test_structure_3 = struc.Structure(cell, species_1, pos_3) env1_1 = env.AtomicEnvironment(test_structure_1, atom_1, cutoffs) env1_2 = env.AtomicEnvironment(test_structure_2, atom_1, cutoffs) env1_3 = env.AtomicEnvironment(test_structure_3, atom_1, cutoffs) # create env 2 # perturb the y direction pos_1 = np.vstack([[0, 0, 0], random([3, 3])]) pos_2 = deepcopy(pos_1) pos_2[0][1] = delta pos_3 = deepcopy(pos_1) pos_3[0][1] = -delta atom_2 = 0 species_2 = [1, 1, 2, 1] #, 2, 1, 2, 2, 2] test_structure_1 = struc.Structure(cell, species_2, pos_1) test_structure_2 = struc.Structure(cell, species_2, pos_2) test_structure_3 = struc.Structure(cell, species_2, pos_3) env2_1 = env.AtomicEnvironment(test_structure_1, atom_2, cutoffs) env2_2 = env.AtomicEnvironment(test_structure_2, atom_2, cutoffs) env2_3 = env.AtomicEnvironment(test_structure_3, atom_2, cutoffs) return env1_1, env1_2, env1_3, env2_1, env2_2, env2_3
def generate_envs(cutoffs, delta): # create env 1 cell = np.eye(3) positions_1 = np.vstack([[0, 0, 0], random([3, 3])]) positions_2 = np.copy(positions_1) positions_2[0][0] = delta positions_3 = np.copy(positions_1) positions_3[0][0] = -delta species_1 = [1, 2, 1, 1, 1, 1, 2, 1, 2] atom_1 = 0 test_structure_1 = struc.Structure(cell, species_1, positions_1) test_structure_2 = struc.Structure(cell, species_1, positions_2) test_structure_3 = struc.Structure(cell, species_1, positions_3) env1_1 = env.AtomicEnvironment(test_structure_1, atom_1, cutoffs) env1_2 = env.AtomicEnvironment(test_structure_2, atom_1, cutoffs) env1_3 = env.AtomicEnvironment(test_structure_3, atom_1, cutoffs) # create env 2 positions_1 = np.vstack([[0, 0, 0], random([3, 3])]) positions_2 = np.copy(positions_1) positions_2[0][1] = delta positions_3 = np.copy(positions_1) positions_3[0][1] = -delta atom_2 = 0 species_2 = [1, 1, 2, 1, 2, 1, 2, 2, 2] test_structure_1 = struc.Structure(cell, species_2, positions_1) test_structure_2 = struc.Structure(cell, species_2, positions_2) test_structure_3 = struc.Structure(cell, species_2, positions_3) env2_1 = env.AtomicEnvironment(test_structure_1, atom_2, cutoffs) env2_2 = env.AtomicEnvironment(test_structure_2, atom_2, cutoffs) env2_3 = env.AtomicEnvironment(test_structure_3, atom_2, cutoffs) return env1_1, env1_2, env1_3, env2_1, env2_2, env2_3
# mff_pred[atom, :] = mff_f # mff_var[atom, :] = mff_v # var_err += np.mean(np.absolute(mff_v-variances[atom, :])) ## print(env_curr.ctype, mff_v, variances[atom]) store_predictions.append(predictions) store_mffpred.append(mff_pred) store_forces.append(forces) # test a toy case for testing lammps positions = np.array([[0, 0, 0], [0, 0, 1.76339], [0, 1.41071, 0]]) species_list = ['H', 'C', 'H'] new_cell = np.eye(3) * 20 toy_struc = struc.Structure(new_cell, species_list, positions) for atom in range(3): atom_env = env.AtomicEnvironment(toy_struc, atom, cutoffs) pred_f, pred_v = mff_model.predict(atom_env, mean_only=True) print(pred_f) # ----------------- save coeffs --------------------- if 2 in grid_params['bodies']: for ind, spc in enumerate(mff_model.spcs[0]): save_name = '{}{}_{}'.format(spc[0], spc[1], 2) np.save(save_name, mff_model.maps_2[ind].mean.model.__coeffs__) if 3 in grid_params['bodies']: for ind, spc in enumerate(mff_model.spcs[1]): save_name = '{}{}{}_{}'.format(spc[0], spc[1], spc[2], 3) np.save(save_name, mff_model.maps_3[ind].mean.model.__coeffs__) # ----------------- save predictions and ground truth
energies = np.zeros(len(lammps_files)) """Print forces and GP standard deviations to make sure the values look reasonable.""" out_f = open('gp_f.txt', 'w') # loop over NEB structures for count, lammps_file in enumerate(tqdm(lammps_files)): """The lammps_parser function, defined in dump_parser.py in this directory, extracts the coordinates from a dump file and converts the BOX_BOUNDS output into an array of Bravais lattice vectors.""" positions, cell = lammps_parser(lammps_file) structure = struc.Structure(cell, species, positions) # loop over atoms in the structure local_energies = np.zeros(nat) for n in range(structure.nat): """Construct an atomic environment object, which stores all the interatomic distances within 2- and 3-body cutoff spheres that are needed to compute the local energy assigned to the atom.""" chemenv = env.AtomicEnvironment(structure, n, gp_model.cutoffs) for i in range(3): force, var = gp_model.predict(chemenv, i + 1) structure.forces[n][i] = float(force) structure.stds[n][i] = np.sqrt(np.abs(var)) local_energies[n] = gp_model.predict_local_energy(chemenv) out_f.write('Image = ' + str(count) + '\n') out_f.write('forces:') out_f.write(str(structure.forces)) out_f.write('\n') out_f.write('stds:') out_f.write(str(structure.stds)) out_f.write('\n') """Sum up the local energies to get the total energy of the structure.""" total_energy = np.sum(local_energies)
def test_lmp_predict(all_gp, all_mgp, bodies, multihyps): """ test the lammps implementation """ for f in os.listdir("./"): if f in [ f'tmp{bodies}{multihyps}in', f'tmp{bodies}{multihyps}out', f'tmp{bodies}{multihyps}dump', f'tmp{bodies}{multihyps}data', 'log.lammps' ]: os.remove(f) clean() mgp_model = all_mgp[f'{bodies}{multihyps}'] gp_model = all_gp[f'{bodies}{multihyps}'] lammps_location = mgp_model.lmp_file_name # lmp file is automatically written now every time MGP is constructed mgp_model.write_lmp_file(lammps_location) # create test structure cell = np.eye(3) nenv = 10 unique_species = gp_model.training_data[0].species cutoffs = gp_model.cutoffs struc_test, f = get_random_structure(cell, unique_species, nenv) atom_num = 1 test_envi = env.AtomicEnvironment(struc_test, atom_num, cutoffs) atom_types = [1, 2] atom_masses = [108, 127] atom_species = struc_test.coded_species # create data file data_file_name = f'tmp{bodies}{multihyps}.data' data_text = lammps_calculator.lammps_dat(struc_test, atom_types, atom_masses, atom_species) lammps_calculator.write_text(data_file_name, data_text) # create lammps input by = 'no' ty = 'no' if '2' in bodies: by = 'yes' if '3' in bodies: ty = 'yes' style_string = 'mgp' coeff_string = f'* * {lammps_location} H He {by} {ty}' lammps_executable = os.environ.get('lmp') dump_file_name = f'tmp{bodies}{multihyps}.dump' input_file_name = f'tmp{bodies}{multihyps}.in' output_file_name = f'tmp{bodies}{multihyps}.out' input_text = \ lammps_calculator.generic_lammps_input(data_file_name, style_string, coeff_string, dump_file_name, newton=True) lammps_calculator.write_text(input_file_name, input_text) lammps_calculator.run_lammps(lammps_executable, input_file_name, output_file_name) lammps_forces = lammps_calculator.lammps_parser(dump_file_name) mgp_forces = mgp_model.predict(test_envi, mean_only=True) # check that lammps agrees with gp to within 1 meV/A for i in range(3): assert (np.abs(lammps_forces[atom_num, i] - mgp_forces[0][i]) < 1e-3) for f in os.listdir("./"): if f in [ f'tmp{bodies}{multihyps}in', f'tmp{bodies}{multihyps}out', f'tmp{bodies}{multihyps}dump', f'tmp{bodies}{multihyps}data', 'log.lammps', lammps_location ]: os.remove(f) clean()
def test_two_plus_three_body_force(): """Check that the analytical force kernel matches finite difference of energy kernel.""" # create env 1 delt = 1e-5 cell = np.eye(3) cutoffs = np.array([1, 0.9]) positions_1 = [np.array([0., 0., 0.]), np.array([random(), random(), random()]), np.array([random(), random(), random()])] positions_2 = deepcopy(positions_1) positions_2[0][0] = delt positions_3 = deepcopy(positions_1) positions_3[0][0] = -delt species_1 = [1, 2, 1] atom_1 = 0 test_structure_1 = struc.Structure(cell, species_1, positions_1) test_structure_2 = struc.Structure(cell, species_1, positions_2) test_structure_3 = struc.Structure(cell, species_1, positions_3) env1_1 = env.AtomicEnvironment(test_structure_1, atom_1, cutoffs) env1_2 = env.AtomicEnvironment(test_structure_2, atom_1, cutoffs) env1_3 = env.AtomicEnvironment(test_structure_3, atom_1, cutoffs) # create env 2 positions_1 = [np.array([0., 0., 0.]), np.array([random(), random(), random()]), np.array([random(), random(), random()])] positions_2 = deepcopy(positions_1) positions_2[0][1] = delt positions_3 = deepcopy(positions_1) positions_3[0][1] = -delt species_2 = [1, 1, 2] atom_2 = 0 test_structure_1 = struc.Structure(cell, species_2, positions_1) test_structure_2 = struc.Structure(cell, species_2, positions_2) test_structure_3 = struc.Structure(cell, species_2, positions_3) env2_1 = env.AtomicEnvironment(test_structure_1, atom_2, cutoffs) env2_2 = env.AtomicEnvironment(test_structure_2, atom_2, cutoffs) env2_3 = env.AtomicEnvironment(test_structure_3, atom_2, cutoffs) # set hyperparameters sig1 = random() ls1 = random() sig2 = random() ls2 = random() d1 = 1 d2 = 2 hyps = np.array([sig1, ls1, sig2, ls2]) # check force kernel calc1 = en.two_plus_three_en(env1_2, env2_2, hyps, cutoffs) calc2 = en.two_plus_three_en(env1_3, env2_3, hyps, cutoffs) calc3 = en.two_plus_three_en(env1_2, env2_3, hyps, cutoffs) calc4 = en.two_plus_three_en(env1_3, env2_2, hyps, cutoffs) kern_finite_diff = (calc1 + calc2 - calc3 - calc4) / (4*delt**2) kern_analytical = en.two_plus_three_body(env1_1, env2_1, d1, d2, hyps, cutoffs) tol = 1e-4 assert(np.isclose(kern_finite_diff, kern_analytical, atol=tol))
def test_parse_header(): # ------------------------------------------------------------------------- # reconstruct gp model from otf snippet # ------------------------------------------------------------------------- file_name = 'test_files/AgI_snippet.out' hyp_no = 2 # parse otf output otf_object = otf_parser.OtfAnalysis(file_name) otf_cell = otf_object.header['cell'] # reconstruct gp model kernel = mc_simple.two_plus_three_body_mc kernel_grad = mc_simple.two_plus_three_body_mc_grad gp_model = otf_object.make_gp(kernel=kernel, kernel_grad=kernel_grad, hyp_no=hyp_no) gp_model.par = True gp_model.hyp_labels = ['sig2', 'ls2', 'sig3', 'ls3', 'noise'] # ------------------------------------------------------------------------- # check gp reconstruction # ------------------------------------------------------------------------- # create test structure species = np.array([47, 53] * 27) positions = otf_object.position_list[-1] forces = otf_object.force_list[-1] structure = struc.Structure(otf_cell, species, positions) atom = 0 environ = env.AtomicEnvironment(structure, atom, gp_model.cutoffs) force_comp = 2 pred, _ = gp_model.predict(environ, force_comp) assert (np.isclose(pred, forces[0][1])) # ------------------------------------------------------------------------- # map the potential # ------------------------------------------------------------------------- file_name = 'AgI.gp' grid_num_2 = 64 grid_num_3 = 15 lower_cut = 2. two_cut = 7. three_cut = 5. lammps_location = 'AgI_Molten_15.txt' # set struc params. cell and masses arbitrary? mapped_cell = np.eye(3) * 100 struc_params = { 'species': [47, 53], 'cube_lat': mapped_cell, 'mass_dict': { '0': 27, '1': 16 } } # grid parameters grid_params = { 'bounds_2': [[lower_cut], [two_cut]], 'bounds_3': [[lower_cut, lower_cut, 0], [three_cut, three_cut, np.pi]], 'grid_num_2': grid_num_2, 'grid_num_3': [grid_num_3, grid_num_3, grid_num_3], 'svd_rank_2': 64, 'svd_rank_3': 90, 'bodies': [2, 3], 'load_grid': None, 'update': True } mgp_model = MappedGaussianProcess(gp_model, grid_params, struc_params, mean_only=True, lmp_file_name=lammps_location) # ------------------------------------------------------------------------- # test the mapped potential # ------------------------------------------------------------------------- gp_pred_x = gp_model.predict(environ, 1) mgp_pred = mgp_model.predict(environ, mean_only=True) # check mgp is within 1 meV/A of the gp assert (np.abs(mgp_pred[0][0] - gp_pred_x[0]) < 1e-3) # ------------------------------------------------------------------------- # check lammps potential # ------------------------------------------------------------------------- # mgp_model.write_lmp_file(lammps_location) # lmp file is automatically written now every time MGP is constructed # create test structure species = otf_object.gp_species_list[-1] positions = otf_object.position_list[-1] forces = otf_object.force_list[-1] structure = struc.Structure(otf_cell, species, positions) atom_types = [1, 2] atom_masses = [108, 127] atom_species = [1, 2] * 27 # create data file data_file_name = 'tmp.data' data_text = lammps_calculator.lammps_dat(structure, atom_types, atom_masses, atom_species) lammps_calculator.write_text(data_file_name, data_text) # create lammps input style_string = 'mgp' #TODO: change the name of lammps coeff_string = '* * {} 47 53 yes yes'.format(lammps_location) lammps_executable = '$lmp' dump_file_name = 'tmp.dump' input_file_name = 'tmp.in' output_file_name = 'tmp.out' input_text = \ lammps_calculator.generic_lammps_input(data_file_name, style_string, coeff_string, dump_file_name) lammps_calculator.write_text(input_file_name, input_text) lammps_calculator.run_lammps(lammps_executable, input_file_name, output_file_name) lammps_forces = lammps_calculator.lammps_parser(dump_file_name) # check that lammps agrees with gp to within 1 meV/A assert (np.abs(lammps_forces[0, 1] - forces[0, 1]) < 1e-3) os.system('rm tmp.in tmp.out tmp.dump tmp.data AgI_Molten_15.txt' ' log.lammps') os.system('rm grid3*.npy') os.system('rm -r kv3')
def test_two_plus_three_body_grad(): # create env 1 cell = np.eye(3) cutoffs = np.array([1, 1]) positions_1 = [np.array([0., 0., 0.]), np.array([random(), random(), random()]), np.array([random(), random(), random()])] species_1 = [1, 2, 1] atom_1 = 0 test_structure_1 = struc.Structure(cell, species_1, positions_1) env1 = env.AtomicEnvironment(test_structure_1, atom_1, cutoffs) # create env 2 positions_1 = [np.array([0., 0., 0.]), np.array([random(), random(), random()]), np.array([random(), random(), random()])] species_2 = [1, 1, 2] atom_2 = 0 test_structure_1 = struc.Structure(cell, species_2, positions_1) env2 = env.AtomicEnvironment(test_structure_1, atom_2, cutoffs) # set hyperparameters sig1 = random() ls1 = random() sig2 = random() ls2 = random() d1 = randint(1, 3) d2 = randint(1, 3) delta = 1e-8 hyps = np.array([sig1, ls1, sig2, ls2]) hyps1 = np.array([sig1+delta, ls1, sig2, ls2]) hyps2 = np.array([sig1, ls1+delta, sig2, ls2]) hyps3 = np.array([sig1, ls1, sig2+delta, ls2]) hyps4 = np.array([sig1, ls1, sig2, ls2+delta]) grad_test = en.two_plus_three_body_grad(env1, env2, d1, d2, hyps, cutoffs) sig1_derv_brute = (en.two_plus_three_body(env1, env2, d1, d2, hyps1, cutoffs) - en.two_plus_three_body(env1, env2, d1, d2, hyps, cutoffs)) / delta l1_derv_brute = \ (en.two_plus_three_body(env1, env2, d1, d2, hyps2, cutoffs) - en.two_plus_three_body(env1, env2, d1, d2, hyps, cutoffs)) / delta sig2_derv_brute = \ (en.two_plus_three_body(env1, env2, d1, d2, hyps3, cutoffs) - en.two_plus_three_body(env1, env2, d1, d2, hyps, cutoffs)) / delta l2_derv_brute = \ (en.two_plus_three_body(env1, env2, d1, d2, hyps4, cutoffs) - en.two_plus_three_body(env1, env2, d1, d2, hyps, cutoffs)) / delta tol = 1e-4 assert(np.isclose(grad_test[1][0], sig1_derv_brute, atol=tol)) assert(np.isclose(grad_test[1][1], l1_derv_brute, atol=tol)) assert(np.isclose(grad_test[1][2], sig2_derv_brute, atol=tol)) assert(np.isclose(grad_test[1][3], l2_derv_brute, atol=tol))
def test_two_plus_three_body_force_en(): """Check that the analytical force/en kernel matches finite difference of energy kernel.""" # create env 1 delt = 1e-8 cell = np.eye(3) cutoffs = np.array([1, 1]) positions_1 = [np.array([0., 0., 0.]), np.array([random(), random(), random()]), np.array([random(), random(), random()]), np.array([random(), random(), random()]), np.array([random(), random(), random()]), np.array([random(), random(), random()]), np.array([random(), random(), random()]), np.array([random(), random(), random()]), np.array([random(), random(), random()])] positions_2 = deepcopy(positions_1) positions_2[0][0] = delt species_1 = [1, 2, 1] atom_1 = 0 test_structure_1 = struc.Structure(cell, species_1, positions_1) test_structure_2 = struc.Structure(cell, species_1, positions_2) env1_1 = env.AtomicEnvironment(test_structure_1, atom_1, cutoffs) env1_2 = env.AtomicEnvironment(test_structure_2, atom_1, cutoffs) # create env 2 positions_1 = [np.array([0., 0., 0.]), np.array([random(), random(), random()]), np.array([random(), random(), random()]), np.array([random(), random(), random()]), np.array([random(), random(), random()]), np.array([random(), random(), random()]), np.array([random(), random(), random()]), np.array([random(), random(), random()]), np.array([random(), random(), random()])] species_2 = [1, 1, 2] atom_2 = 0 test_structure_1 = struc.Structure(cell, species_2, positions_1) env2 = env.AtomicEnvironment(test_structure_1, atom_2, cutoffs) # set hyperparameters sig1 = random() ls1 = random() sig2 = random() ls2 = random() d1 = 1 hyps = np.array([sig1, ls1, sig2, ls2]) # check force kernel calc1 = en.two_body_en(env1_2, env2, hyps[0:2], cutoffs) calc2 = en.two_body_en(env1_1, env2, hyps[0:2], cutoffs) calc3 = en.three_body_en(env1_2, env2, hyps[2:4], cutoffs) calc4 = en.three_body_en(env1_1, env2, hyps[2:4], cutoffs) kern_finite_diff = (calc1 - calc2) / (2 * delt) + \ (calc3 - calc4) / (3 * delt) kern_analytical = \ en.two_plus_three_force_en(env1_1, env2, d1, hyps, cutoffs) tol = 1e-4 assert(np.isclose(-kern_finite_diff, kern_analytical, atol=tol))
store_predictions = [] store_mffpred = [] store_forces = [] var_err = 0 for n, snap in enumerate(test_snaps): structure = test_strucs[n] forces = test_forces[n] noa = len(structure.positions) predictions = np.zeros([noa, 3]) variances = np.zeros([noa, 3]) mff_pred = np.zeros([noa, 3]) mff_var = np.zeros([noa, 3]) for atom in range(noa): env_curr = env.AtomicEnvironment(structure, atom, cutoffs) for m in range(3): d = m + 1 comp_pred, comp_var = gp_model.predict(env_curr, d) predictions[atom, m] = comp_pred variances[atom, m] = comp_var # make prediction with mff mff_f, mff_v = mff_model.predict(env_curr, mean_only=False) mff_pred[atom, :] = mff_f mff_var[atom, :] = mff_v var_err += np.mean(np.absolute(mff_v - variances[atom, :])) # print(env_curr.ctype, mff_v, variances[atom]) store_predictions.append(predictions)