def strucs(): """Create two random structures.""" np.random.seed(0) positions_1 = np.random.rand(n_atoms, 3) positions_2 = np.random.rand(n_atoms, 3) structure_1 = struc.Structure(cell, species, positions_1) structure_2 = struc.Structure(cell, species, positions_2) strucs = [structure_1, structure_2] yield strucs
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 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 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 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 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 get_structure_from_input(self, prev_pos_init): positions, species, cell, masses = \ self.dft_module.parse_dft_input(self.dft_input) self.structure = struc.Structure( cell=cell, species=species, positions=positions, mass_dict=masses, prev_positions=prev_pos_init, species_labels=species)
def output_md_structures(self): """ Returns structure objects corresponding to the MD frames of an OTF run. :return: """ structures = [] cell = self.header["cell"] species = self.header["species"] for i in range(len(self.position_list)): if not self.calculate_energy: energy = 0 else: energy = self.energies[i] cur_struc = struc.Structure( cell=cell, species=species, positions=self.position_list[i], forces=self.force_list[i], stds=self.uncertainty_list[i], ) cur_struc.energy = energy # cur_struc.stress = self.stress_list[i] structures.append(cur_struc) return structures
def make_gp(self, cell=None, kernel=None, kernel_grad=None, algo=None, call_no=None, cutoffs=None, hyps=None, init_gp=None, energy_force_kernel=None, hyp_no=None, par=True): if init_gp is None: # Use run's values as extracted from header # TODO Allow for kernel gradient in header if cell is None: cell = self.header['cell'] if kernel is None: kernel = self.header['kernel'] if kernel_grad is None: raise Exception('Kernel gradient not supplied') if algo is None: algo = self.header['algo'] if cutoffs is None: cutoffs = self.header['cutoffs'] if call_no is None: call_no = len(self.gp_position_list) if hyp_no is None: hyp_no = call_no if hyps is None: gp_hyps = self.gp_hyp_list[hyp_no - 1][-1] else: gp_hyps = hyps gp_model = \ gp.GaussianProcess(kernel, kernel_grad, gp_hyps, cutoffs, opt_algorithm=algo, energy_force_kernel=energy_force_kernel, par=par) else: gp_model = init_gp call_no = len(self.gp_position_list) gp_hyps = self.gp_hyp_list[hyp_no - 1][-1] gp_model.hyps = gp_hyps for (positions, forces, atoms, _, species) in \ zip(self.gp_position_list[:call_no], self.gp_force_list[:call_no], self.gp_atom_list[:call_no], self.gp_hyp_list[:call_no], self.gp_species_list[:call_no]): struc_curr = struc.Structure(cell, species, positions) gp_model.update_db(struc_curr, forces, custom_range=atoms) gp_model.set_L_alpha() return gp_model
def structure(otf_object): # create test structure otf_cell = otf_object.header['cell'] species = np.array([47, 53] * 27) positions = otf_object.position_list[-1] test_struc = struc.Structure(otf_cell, species, positions) yield test_struc del test_struc
def dft_input_to_structure(qe_input: str): """ Parses a qe input and returns the atoms in the file as a Structure object :param qe_input: QE Input file to parse :return: """ positions, species, cell, masses = parse_dft_input(qe_input) _, coded_species = struc.get_unique_species(species) return struc.Structure(positions=positions, species=coded_species, cell=cell, mass_dict=masses, species_labels=species)
def make_gp( self, cell=None, call_no=None, hyps=None, init_gp=None, hyp_no=None, **kwargs, ): if "restart" in self.header and self.header["restart"] > 0: assert ( init_gp is not None ), "Please input the init_gp as the gp model dumppedbefore restarting otf." if call_no is None: call_no = len(self.gp_position_list) if hyp_no is None: hyp_no = len(self.gp_hyp_list) # use the last hyps by default if hyps is None: # check out the last non-empty element from the list hyps = self.gp_hyp_list[hyp_no - 1] if cell is None: cell = self.header["cell"] if init_gp is None: # Use run's values as extracted from header # TODO Allow for kernel gradient in header dictionary = deepcopy(self.header) dictionary["hyps"] = hyps for k in kwargs: if kwargs[k] is not None: dictionary[k] = kwargs[k] gp_model = GaussianProcess.from_dict(dictionary) else: gp_model = init_gp gp_model.hyps = hyps for (positions, forces, atoms, species) in zip( self.gp_position_list[:call_no], self.gp_force_list[:call_no], self.gp_atom_list[:call_no], self.gp_species_list[:call_no], ): struc_curr = struc.Structure(cell, species, positions) gp_model.update_db(struc_curr, forces, custom_range=atoms) gp_model.set_L_alpha() return gp_model
def make_gp(self, cell=None, kernel_name=None, algo=None, call_no=None, cutoffs=None, hyps=None, init_gp=None, hyp_no=None, par=True, kernel=None): if init_gp is None: # Use run's values as extracted from header # TODO Allow for kernel gradient in header if cell is None: cell = self.header['cell'] if kernel_name is None: kernel_name = self.header['kernel_name'] if algo is None: algo = self.header['algo'] if cutoffs is None: cutoffs = self.header['cutoffs'] if call_no is None: call_no = len(self.gp_position_list) if hyp_no is None: hyp_no = call_no if hyps is None: gp_hyps = self.gp_hyp_list[hyp_no-1][-1] else: gp_hyps = hyps if (kernel is not None) and (kernel_name is None): DeprecationWarning("kernel replaced with kernel_name") kernel_name = kernel.__name__ gp_model = \ gp.GaussianProcess(kernel_name=kernel_name, hyps=gp_hyps, cutoffs=cutoffs, opt_algorithm=algo, par=par) else: gp_model = init_gp call_no = len(self.gp_position_list) gp_hyps = self.gp_hyp_list[hyp_no-1][-1] gp_model.hyps = gp_hyps for (positions, forces, atoms, _, species) in \ zip(self.gp_position_list[:call_no], self.gp_force_list[:call_no], self.gp_atom_list[:call_no], self.gp_hyp_list[:call_no], self.gp_species_list[:call_no]): struc_curr = struc.Structure(cell, species, positions) gp_model.update_db(struc_curr, forces, custom_range=atoms) gp_model.set_L_alpha() return gp_model
def make_gp( self, cell=None, call_no=None, hyps=None, init_gp=None, hyp_no=None, **kwargs, ): if call_no is None: call_no = len(self.gp_position_list) if hyp_no is None: hyp_no = call_no if hyps is None: # check out the last non-empty element from the list for icall in reversed(range(hyp_no)): if len(self.gp_hyp_list[icall]) > 0: hyps = self.gp_hyp_list[icall][-1] break if cell is None: cell = self.header['cell'] if init_gp is None: # Use run's values as extracted from header # TODO Allow for kernel gradient in header dictionary = deepcopy(self.header) dictionary['hyps'] = hyps for k in kwargs: if kwargs[k] is not None: dictionary[k] = kwargs[k] gp_model = \ GaussianProcess.from_dict(dictionary) else: gp_model = init_gp gp_model.hyps = hyps for (positions, forces, atoms, _, species) in \ zip(self.gp_position_list[:call_no], self.gp_force_list[:call_no], self.gp_atom_list[:call_no], self.gp_hyp_list[:call_no], self.gp_species_list[:call_no]): struc_curr = struc.Structure(cell, species, positions) gp_model.update_db(struc_curr, forces, custom_range=atoms) gp_model.set_L_alpha() return gp_model
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 fit(self, parent_data): for image in parent_data: train_structure = struc.Structure(image.get_cell(), image.get_atomic_numbers(), image.get_positions()) forces = image.get_forces(apply_constraint=False) energy = image.get_potential_energy(apply_constraint=False) self.gp_model.update_db(train_structure, forces, [], energy, mode="all", update_qr=True)
def partial_fit(self, new_dataset): for image in new_dataset: train_structure = struc.Structure(image.get_cell(), image.get_atomic_numbers(), image.get_positions()) forces = image.get_forces(apply_constraint=False) energy = image.get_potential_energy(apply_constraint=False) self.gp_model.update_db( train_structure, forces, self.update_gp_range, energy, mode=self.update_gp_mode, update_qr=True, )
def output_md_structures(self): """ Returns structure objects corresponding to the MD frames of an OTF run. :return: """ positions = self.position_list structures = [] cell = self.header['cell'] species = self.header['species'] forces = self.force_list stds = self.uncertainty_list for i in range(len(positions)): cur_struc = struc.Structure(cell=cell, species=species, positions=positions[i]) cur_struc.forces = forces[i] cur_struc.stds = stds[i] structures.append(cur_struc) return structures
def build_bond_struc(self, struc_params): ''' build a bond structure, used in grid generating ''' cutoff = np.min(self.GP.cutoffs) cell = struc_params['cube_lat'] mass_dict = struc_params['mass_dict'] bond_struc = [] for bodies in [2, 3]: species = [struc_params['species'] for i in range(bodies)] positions = [[(i+1)/(bodies+1)*cutoff, 0, 0] \ for i in range(bodies)] bond_struc.append( struc.Structure(cell, species, positions, mass_dict)) if self.bodies == '2': return bond_struc[0] elif self.bodies == '3': return bond_struc[1] elif self.bodies == '2+3': return bond_struc
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 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
N_Ag += 1 else: N_Pd += 1 species = ['Ag'] * N_Ag + ['Pd'] * N_Pd nat = len(species) dump.close() 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))
def __init__(self, dft_input: str, dt: float, number_of_steps: int, gp: gp.GaussianProcess, dft_loc: str, std_tolerance_factor: float = 1, prev_pos_init: np.ndarray = None, par: bool = False, skip: int = 0, init_atoms: List[int] = None, calculate_energy=False, output_name='otf_run', max_atoms_added=1, freeze_hyps=10, rescale_steps=[], rescale_temps=[], dft_softwarename="qe", no_cpus=1, npool=None, mpi="srun"): self.dft_input = dft_input self.dt = dt self.number_of_steps = number_of_steps self.gp = gp self.dft_loc = dft_loc self.std_tolerance = std_tolerance_factor self.skip = skip self.dft_step = True self.freeze_hyps = freeze_hyps self.dft_module = dft_software[dft_softwarename] # parse input file positions, species, cell, masses = \ self.dft_module.parse_dft_input(self.dft_input) _, coded_species = struc.get_unique_species(species) self.structure = struc.Structure(cell=cell, species=coded_species, positions=positions, mass_dict=masses, prev_positions=prev_pos_init, species_labels=species) self.noa = self.structure.positions.shape[0] self.atom_list = list(range(self.noa)) self.curr_step = 0 self.max_atoms_added = max_atoms_added # initialize local energies if calculate_energy: self.local_energies = np.zeros(self.noa) else: self.local_energies = None # set atom list for initial dft run if init_atoms is None: self.init_atoms = [int(n) for n in range(self.noa)] else: self.init_atoms = init_atoms self.dft_count = 0 # set pred function if not par and not calculate_energy: self.pred_func = predict.predict_on_structure elif par and not calculate_energy: self.pred_func = predict.predict_on_structure_par elif not par and calculate_energy: self.pred_func = predict.predict_on_structure_en elif par and calculate_energy: self.pred_func = predict.predict_on_structure_par_en self.par = par # set rescale attributes self.rescale_steps = rescale_steps self.rescale_temps = rescale_temps self.output = Output(output_name, always_flush=True) # set number of cpus and npool for qe runs self.no_cpus = no_cpus self.npool = npool self.mpi = mpi
def build_bond_struc(self, struc_params): ''' build a bond structure, used in grid generating ''' cutoff = np.min(self.cutoffs) cell = struc_params['cube_lat'] species_list = struc_params['species'] N_spc = len(species_list) # ------------------- 2 body (2 atoms (1 bond) config) --------------- bond_struc_2 = [] spc_2 = [] if 2 in self.bodies: bodies = 2 for spc1_ind, spc1 in enumerate(species_list): for spc2 in species_list[spc1_ind:]: species = [spc1, spc2] spc_2.append(species) positions = [[(i+1)/(bodies+1)*cutoff, 0, 0] for i in range(bodies)] spc_struc = \ struc.Structure(cell, species, positions) spc_struc.coded_species = np.array(species) bond_struc_2.append(spc_struc) # ------------------- 3 body (3 atoms (1 triplet) config) ------------- bond_struc_3 = [] spc_3 = [] if 3 in self.bodies: bodies = 3 for spc1_ind in range(N_spc): spc1 = species_list[spc1_ind] for spc2_ind in range(N_spc): # (spc1_ind, N_spc): spc2 = species_list[spc2_ind] for spc3_ind in range(N_spc): # (spc2_ind, N_spc): spc3 = species_list[spc3_ind] species = [spc1, spc2, spc3] spc_3.append(species) positions = [[(i+1)/(bodies+1)*cutoff, 0, 0] for i in range(bodies)] spc_struc = struc.Structure(cell, species, positions) spc_struc.coded_species = np.array(species) bond_struc_3.append(spc_struc) # if spc1 != spc2: # species = [spc2, spc3, spc1] # spc_3.append(species) # positions = [[(i+1)/(bodies+1)*cutoff, 0, 0] \ # for i in range(bodies)] # spc_struc = struc.Structure(cell, species, positions) # spc_struc.coded_species = np.array(species) # bond_struc_3.append(spc_struc) # if spc2 != spc3: # species = [spc3, spc1, spc2] # spc_3.append(species) # positions = [[(i+1)/(bodies+1)*cutoff, 0, 0] \ # for i in range(bodies)] # spc_struc = struc.Structure(cell, species, positions) # spc_struc.coded_species = np.array(species) # bond_struc_3.append(spc_struc) self.bond_struc = [bond_struc_2, bond_struc_3] self.spcs = [spc_2, spc_3]
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_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))