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
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 = AtomicEnvironment(self.structure, n, self.gp.cutoffs) force, var = self.mgp.predict(chemenv) self.structure.forces[n][:] = force self.structure.stds[n][:] = np.sqrt(np.absolute(var)) self.structure.dft_forces = False
def update_gp(self, train_atoms, dft_frcs): output.write_to_output('\nAdding atom {} to the training set.\n' .format(train_atoms), self.output_name) output.write_to_output('Uncertainty: {}.\n' .format(self.structure.stds[train_atoms[0]]), self.output_name) # update gp model self.gp.update_db(self.structure, dft_frcs, custom_range=train_atoms) self.gp.set_L_alpha()
def write_mgp_header(self): output.write_to_output('bounds 2:' + str(self.mgp_model.bounds_2), self.output_name) output.write_to_output('bounds 3:' + str(self.mgp_model.bounds_2), self.output_name) output.write_to_output('grid num 2:' + str(self.mgp_model.grid_num_2), self.output_name) output.write_to_output('grid num 3:' + str(self.mgp_model.grid_num_3), self.output_name)
def predict_on_structure_mgp(structure, mgp, output=None, output_name=None, n_cpus=None, write_to_structure=True, selective_atoms: List[int] = None, skipped_atom_value=0): # changed """ Assign forces to structure based on an mgp """ if output and output_name: output.write_to_output('\npredict with mapping:\n', output_name) forces = np.zeros(shape=(structure.nat, 3)) vars = np.zeros(shape=(structure.nat, 3)) if selective_atoms: forces.fill(skipped_atom_value) vars.fill(skipped_atom_value) else: selective_atoms = [] for n in range(structure.nat): if n not in selective_atoms and selective_atoms: continue chemenv = AtomicEnvironment(structure, n, mgp.cutoffs) force, var, _, _ = mgp.predict(chemenv) if write_to_structure: structure.forces[n][:] = force structure.stds[n][:] = np.sqrt(np.absolute(var)) forces[n, :] = force vars[n, :] = var return forces, vars
def run_dft(self): output.write_to_output('\nCalling Quantum Espresso...\n', self.output_name) # calculate DFT forces forces = qe_util.run_espresso_par(self.qe_input, self.structure, self.pw_loc, self.no_cpus) self.structure.forces = forces # write wall time of DFT calculation self.dft_count += 1 output.write_to_output('QE run complete.\n', self.output_name) time_curr = time.time() - self.start_time output.write_to_output('number of DFT calls: %i \n' % self.dft_count, self.output_name) output.write_to_output('wall time from start: %.2f s \n' % time_curr, self.output_name)
def run(self): output.write_header(self.gp.cutoffs, self.gp.kernel_name, self.gp.hyps, self.gp.algo, self.dt, self.number_of_steps, self.structure, self.output_name, self.std_tolerance) counter = 0 self.start_time = time.time() while self.curr_step < self.number_of_steps: print('curr_step:', self.curr_step) # run DFT and train initial model if first step and DFT is on if self.curr_step == 0 and self.std_tolerance != 0: # call dft and update positions self.run_dft() dft_frcs = copy.deepcopy(self.structure.forces) new_pos = md.update_positions(self.dt, self.noa, self.structure) self.update_temperature(new_pos) self.record_state() # make initial gp model and predict forces self.update_gp(self.init_atoms, dft_frcs) if (self.dft_count-1) < self.freeze_hyps: self.train_gp() # after step 1, try predicting with GP model else: self.pred_func() self.dft_step = False new_pos = md.update_positions(self.dt, self.noa, self.structure) # get max uncertainty atoms std_in_bound, target_atoms = self.is_std_in_bound() if not std_in_bound: # record GP forces self.update_temperature(new_pos) self.record_state() gp_frcs = copy.deepcopy(self.structure.forces) # run DFT and record forces self.dft_step = True self.run_dft() dft_frcs = copy.deepcopy(self.structure.forces) new_pos = md.update_positions(self.dt, self.noa, self.structure) self.update_temperature(new_pos) self.record_state() # compute mae and write to output mae = np.mean(np.abs(gp_frcs - dft_frcs)) mac = np.mean(np.abs(dft_frcs)) output.write_to_output('\nmean absolute error:' ' %.4f eV/A \n' % mae, self.output_name) output.write_to_output('mean absolute dft component:' ' %.4f eV/A \n' % mac, self.output_name) # add max uncertainty atoms to training set self.update_gp(target_atoms, dft_frcs) if (self.dft_count-1) < self.freeze_hyps: self.train_gp() # write gp forces if counter >= self.skip and not self.dft_step: self.update_temperature(new_pos) self.record_state() counter = 0 counter += 1 self.update_positions(new_pos) self.curr_step += 1 output.conclude_run(self.output_name)