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 build_mgp(self, skip=True): """ Construct :class:`MappedGaussianProcess` based on the current GP :param skip: if `True`, then it will not construct MGP :type skip: Bool """ # l_bound not implemented if skip: return 1 # set svd rank based on the training set, grid number and threshold 1000 grid_params = self.mgp_model.grid_params struc_params = self.mgp_model.struc_params lmp_file_name = self.mgp_model.lmp_file_name mean_only = self.mgp_model.mean_only container_only = False train_size = len(self.gp_model.training_data) rank_2 = np.min([1000, grid_params['grid_num_2'], train_size * 3]) rank_3 = np.min( [1000, grid_params['grid_num_3'][0]**3, train_size * 3]) grid_params['svd_rank_2'] = rank_2 grid_params['svd_rank_3'] = rank_3 hyps = self.gp_model.hyps cutoffs = self.gp_model.cutoffs self.mgp_model = MappedGaussianProcess(hyps, cutoffs, grid_params, struc_params, mean_only, container_only, self.gp_model, lmp_file_name)
def train_mgp(self, skip=True): t0 = time.time() if self.l_bound < self.grid_params['bounds_2'][0, 0]: self.grid_params['bounds_2'][0, 0] = self.l_bound - 0.01 self.grid_params['bounds_3'][ 0, :2] = np.ones(2) * self.l_bound - 0.01 if skip and (self.curr_step in self.non_mapping_steps): return 1 # set svd rank based on the training set, grid number and threshold 1000 train_size = len(self.gp.training_data) rank_2 = np.min([1000, self.grid_params['grid_num_2'], train_size * 3]) rank_3 = np.min( [1000, self.grid_params['grid_num_3'][0]**3, train_size * 3]) self.grid_params['svd_rank_2'] = rank_2 self.grid_params['svd_rank_3'] = rank_3 output.write_to_output('\ntraining set size: {}\n'.format(train_size), self.output_name) output.write_to_output('lower bound: {}\n'.format(self.l_bound)) output.write_to_output('mgp l_bound: {}\n'.format( self.grid_params['bounds_2'][0, 0])) output.write_to_output('Constructing mapped force field...\n', self.output_name) self.mgp = MappedGaussianProcess(self.gp, self.grid_params, self.struc_params) output.write_to_output( 'building mapping time: {}'.format(time.time() - t0), self.output_name) self.is_mgp_built = True
} } # grid parameters lower_cut = 2.5 grid_num_2 = 8 grid_num_3 = 8 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': 0, 'svd_rank_3': 0, 'bodies': [2, 3], 'load_grid': None, 'update': True } mgp_model = MappedGaussianProcess(gp_model.hyps, gp_model.cutoffs, grid_params, struc_params, mean_only=False, container_only=False, GP=gp_model, lmp_file_name='agi.mgp') # ------------ create ASE's flare calculator ----------------------- flare_calc = FLARE_Calculator(gp_model, mgp_model, par=True, use_mapping=True)
def test_stress_with_lammps(): """ Based on gp_test_al.out, ensures that given hyperparameters and DFT calls a GP model can be reproduced and correctly re-predict forces and uncertainties :return: """ # build up GP from a previous trajectory parsed = OtfAnalysis('test_files/VelocityVerlet.log') positions = parsed.position_list forces = parsed.force_list gp_model = parsed.make_gp(kernel=two_plus_three_body_mc, kernel_grad=two_plus_three_body_mc_grad) # build up MGP from GP struc_params = { 'species': [47, 53], 'cube_lat': np.eye(3) * 100, 'mass_dict': { '0': 27, '1': 16 } } # grid parameters lower_cut = 2.5 grid_num_2 = 64 grid_num_3 = 32 two_cut = 5.0 three_cut = 5.0 grid_params = { 'bounds_2': [[lower_cut], [two_cut]], 'bounds_3': [[lower_cut, lower_cut, -1], [three_cut, three_cut, 1]], 'grid_num_2': grid_num_2, 'grid_num_3': [grid_num_3, grid_num_3, grid_num_3], 'svd_rank_2': 0, 'svd_rank_3': 0, 'bodies': [2, 3], 'load_grid': None, 'update': True } 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='lmp.mgp') # ------------ create ASE's flare calculator ----------------------- flare_calc = FLARE_Calculator(gp_model, mgp_model, par=True, use_mapping=True) a = 3.855 alpha = 90 super_cell = crystal( ['Ag', 'I'], # Ag, I basis=[(0, 0, 0), (0.5, 0.5, 0.5)], size=(2, 1, 1), cellpar=[a, a, a, alpha, alpha, alpha]) super_cell.positions = positions[-1] super_cell.set_calculator(flare_calc) super_cell.get_forces() stresses = super_cell.calc.results['stresses'] # parse lammps stress lmp_file = open('test_files/stress.lammps') lines = lmp_file.readlines()[9:] for ind, line in enumerate(lines): line = line.split() strs = np.array([float(l) for l in line[1:]]) / 1.60217662e6 assert np.isclose(stresses[ind], strs, rtol=1e-3).all() os.system('rm -r __pycache__') os.system('rm grid3*') os.system('rm -r kv3') os.system('rm lmp.mgp')
grid_params = { 'bounds_2': [[lower_cut], [two_cut]], 'bounds_3': [[lower_cut, lower_cut, -1], [three_cut, three_cut, 1]], '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.hyps, gp_model.cutoffs, grid_params, struc_params, mean_only=True, container_only=False, GP=gp_model, 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 # -------------------------------------------------------------------------
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 flare_calc(): flare_calc_dict = {} for md_engine in md_list: # ---------- create gaussian process model ------------------- gp_model = GaussianProcess( kernel_name='2+3_mc', hyps=[0.1, 1., 0.001, 1, 0.06], cutoffs=(5.0, 5.0), hyp_labels=['sig2', 'ls2', 'sig3', 'ls3', 'noise'], opt_algorithm='BFGS', par=False) # ----------- create mapped gaussian process ------------------ struc_params = { 'species': [1, 2], 'cube_lat': np.eye(3) * 100, 'mass_dict': { '0': 2, '1': 4 } } # grid parameters lower_cut = 2.5 two_cut, three_cut = gp_model.cutoffs grid_num_2 = 8 grid_num_3 = 8 grid_params = { 'bounds_2': [[lower_cut], [two_cut]], 'bounds_3': [[lower_cut, lower_cut, -1], [three_cut, three_cut, 1]], 'grid_num_2': grid_num_2, 'grid_num_3': [grid_num_3, grid_num_3, grid_num_3], 'svd_rank_2': 0, 'svd_rank_3': 0, 'bodies': [2, 3], 'load_grid': None, 'update': True } mgp_model = MappedGaussianProcess(gp_model.hyps, gp_model.cutoffs, grid_params, struc_params, mean_only=False, container_only=False, GP=gp_model, lmp_file_name='lmp.mgp', n_cpus=1) # ------------ create ASE's flare calculator ----------------------- flare_calculator = FLARE_Calculator(gp_model, mgp_model, par=True, use_mapping=True) flare_calc_dict[md_engine] = flare_calculator print(md_engine) yield flare_calc_dict del flare_calc_dict
def test_init(bodies, all_gp, all_mgp): """ test the init function """ gp_model = all_gp[f'{bodies}'] grid_num_2 = 64 grid_num_3 = 20 lower_cut = 0.01 two_cut = gp_model.cutoffs[0] three_cut = gp_model.cutoffs[1] lammps_location = f'{bodies}_mgp_ff.txt' # set struc params. cell and masses arbitrary? mapped_cell = np.eye(3) * 2 struc_params = { 'species': [1, 2], 'cube_lat': mapped_cell, 'mass_dict': { '0': 27, '1': 16 } } # grid parameters # grid parameters blist = [] if ('2' in bodies): blist += [2] if ('3' in bodies): blist += [3] grid_params = { 'bounds_2': [[lower_cut], [two_cut]], 'bounds_3': [[lower_cut, lower_cut, -1], [three_cut, three_cut, 1]], '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': blist, 'cutoffs': [two_cut, three_cut], 'load_grid': None, 'update': False } struc_params = { 'species': [1, 2], 'cube_lat': mapped_cell, 'mass_dict': { '0': 27, '1': 16 } } mgp_model = MappedGaussianProcess(gp_model.hyps, gp_model.cutoffs, grid_params, struc_params, mean_only=True, container_only=True, GP=gp_model, lmp_file_name=lammps_location) all_mgp[f'{bodies}'] = mgp_model