def test_path(self): n_images = 8 images = [initial_structure] for i in range(1, n_images - 1): image = initial_structure.copy() image.set_calculator(copy.deepcopy(ase_calculator)) images.append(image) images.append(final_structure) neb = NEB(images, climb=True) neb.interpolate(method='linear') neb_catlearn = MLNEB(start=initial_structure, end=final_structure, interpolation=images, ase_calc=ase_calculator, restart=False) neb_catlearn.run(fmax=0.05, trajectory='ML-NEB.traj') atoms_catlearn = read('evaluated_structures.traj', ':') n_eval_catlearn = len(atoms_catlearn) - 2 self.assertEqual(n_eval_catlearn, 12) print('Checking number of function calls using 8 images...') np.testing.assert_array_equal(n_eval_catlearn, 12) max_unc = np.max(neb_catlearn.uncertainty_path) unc_test = 0.022412729039317382 print('Checking uncertainty on the path (8 images):') np.testing.assert_array_almost_equal(max_unc, unc_test, decimal=4)
def test_restart(self): """ Here we test the restart flag, the mic, and the internal interpolation.""" # Checking internal interpolation. neb_catlearn = MLNEB(start='initial_optimized.traj', end='final_optimized.traj', n_images=9, ase_calc=ase_calculator, interpolation='linear', restart=False) neb_catlearn.run(fmax=0.05, trajectory='ML-NEB.traj', max_step=0.2) print('Checking number of iterations using 9 images...') self.assertEqual(neb_catlearn.iter, 12) max_unc = np.max(neb_catlearn.uncertainty_path) unc_test = 0.0377 print('Checking uncertainty on the path (9 images):') np.testing.assert_array_almost_equal(max_unc, unc_test, decimal=4) # Reducing the uncertainty and fmax, varying num. images (restart): print("Checking restart flag...") print('Using tighter convergence criteria.') neb_catlearn = MLNEB(start='initial_optimized.traj', end='final_optimized.traj', n_images=11, ase_calc=ase_calculator, restart=True) neb_catlearn.run(fmax=0.01, max_step=0.20, unc_convergence=0.010, trajectory='ML-NEB.traj') print('Checking number of iterations restarting with 11 images...') self.assertEqual(neb_catlearn.iter, 5) print('Checking uncertainty on the path (11 images).') max_unc = np.max(neb_catlearn.uncertainty_path) unc_test = 0.0062 np.testing.assert_array_almost_equal(max_unc, unc_test, decimal=4)
image = initial_ase.copy() image.set_calculator(copy.deepcopy(ase_calculator)) images_ase.append(image) images_ase.append(final_ase) neb_ase = NEB(images_ase, climb=True, method='aseneb') neb_ase.interpolate(method='idpp') qn_ase = MDMin(neb_ase, trajectory='neb_ase.traj') qn_ase.run(fmax=0.05) # 2.B. NEB using CatLearn #################################################### neb_catlearn = MLNEB(start='initial_opt.traj', end='final_opt.traj', ase_calc=copy.deepcopy(ase_calculator), n_images=n_images, interpolation='idpp', restart=False) neb_catlearn.run(fmax=0.05, trajectory='ML-NEB.traj') # 3. Summary of the results ################################################# # NEB ASE: print('\nSummary of the results: \n') atoms_ase = read('neb_ase.traj', ':') n_eval_ase = int(len(atoms_ase) - 2 * (len(atoms_ase) / n_images)) print('Number of function evaluations CI-NEB implemented in ASE:', n_eval_ase)
images_ase.append(final_ase) neb_ase = NEB(images_ase, parallel=True, climb=True) neb_ase.interpolate(method='idpp') qn_ase = MDMin(neb_ase, logfile='neb_ase.log', trajectory='neb_ase.traj') itime = time.default_timer() qn_ase.run(fmax=0.05) logging.warning('ase = %s', time.default_timer() - itime) # 2.B. NEB using CatLearn neb_catlearn = MLNEB(start=slab_initial, end=slab_final, ase_calc=calc, n_images=n_images + 2, interpolation='idpp', restart=False) itime = time.default_timer() neb_catlearn.run(fmax=0.05, trajectory='ML-NEB.traj') logging.warning('mlneb = %s', time.default_timer() - itime) # 3. Summary of the results # NEB ASE: logging.warning('Summary of the results: ') atoms_ase = read('neb_ase.traj', ':') n_eval_ase = len(atoms_ase) - 2 * (len(atoms_ase) / n_images)
def test_acquisition(self): """ Here we test the acquisition functions""" print('Checking acquisition function 1 using 6 images...') neb_catlearn = MLNEB(start='initial_optimized.traj', end='final_optimized.traj', n_images=6, ase_calc=ase_calculator, restart=False) neb_catlearn.run(fmax=0.05, trajectory='ML-NEB.traj', acquisition='acq_1') self.assertEqual(neb_catlearn.iter, 12) max_unc = np.max(neb_catlearn.uncertainty_path) unc_test = 0.016837502479194518 np.testing.assert_array_almost_equal(max_unc, unc_test, decimal=4) print('Checking acquisition function 2 using 6 images...') neb_catlearn = MLNEB(start='initial_optimized.traj', end='final_optimized.traj', n_images=6, ase_calc=ase_calculator, restart=False) neb_catlearn.run(fmax=0.05, trajectory='ML-NEB.traj', acquisition='acq_2') self.assertEqual(neb_catlearn.iter, 10) max_unc = np.max(neb_catlearn.uncertainty_path) unc_test = 0.019377964708766612 np.testing.assert_array_almost_equal(max_unc, unc_test, decimal=4) print('Checking acquisition function 3 using 6 images...') neb_catlearn = MLNEB(start='initial_optimized.traj', end='final_optimized.traj', n_images=6, ase_calc=ase_calculator, restart=False) neb_catlearn.run(fmax=0.05, trajectory='ML-NEB.traj', acquisition='acq_3') self.assertEqual(neb_catlearn.iter, 10) max_unc = np.max(neb_catlearn.uncertainty_path) unc_test = 0.02956129325684482 np.testing.assert_array_almost_equal(max_unc, unc_test, decimal=4) print('Checking acquisition function 4 using 6 images...') neb_catlearn = MLNEB(start='initial_optimized.traj', end='final_optimized.traj', n_images=6, ase_calc=ase_calculator, restart=False) neb_catlearn.run(fmax=0.05, trajectory='ML-NEB.traj', acquisition='acq_4') self.assertEqual(neb_catlearn.iter, 12) max_unc = np.max(neb_catlearn.uncertainty_path) unc_test = 0.016837502479194518 np.testing.assert_array_almost_equal(max_unc, unc_test, decimal=4) print('Checking acquisition function 5 using 6 images...') neb_catlearn = MLNEB(start='initial_optimized.traj', end='final_optimized.traj', n_images=6, ase_calc=ase_calculator, restart=False) neb_catlearn.run(fmax=0.05, trajectory='ML-NEB.traj', acquisition='acq_5') self.assertEqual(neb_catlearn.iter, 10) max_unc = np.max(neb_catlearn.uncertainty_path) unc_test = 0.019377964708766612 np.testing.assert_array_almost_equal(max_unc, unc_test, decimal=4)
# Fix second and third layers: mask = [atom.tag > 1 for atom in slab] slab.set_constraint(FixAtoms(mask=mask)) # 1.2. Optimize initial and final end-points. # Initial end-point: qn = BFGS(slab, trajectory='initial.traj') qn.run(fmax=0.01) # Final end-point: slab[-1].x += slab.get_cell()[0, 0] / 2 qn = BFGS(slab, trajectory='final.traj') qn.run(fmax=0.01) # # Define number of images: n_images = 15 # 2.B. NEB using CatLearn neb_catlearn = MLNEB(start='initial.traj', end='final.traj', ase_calc=GPAW(**calc_args), n_images=n_images, interpolation='idpp', restart=False) neb_catlearn.run(fmax=0.05, trajectory='ML-NEB.traj', full_output=True) # 3. Summary of the results ################################################# # ML-NEB: atoms_catlearn = ase.io.read('evaluated_structures.traj', ':') n_eval_catlearn = len(atoms_catlearn) - 2 parprint('Number of function evaluations CatLearn:', n_eval_catlearn)
def my_calc(): return Aims(xc='pbesol', spin='none', relativistic=('atomic_zora', 'scalar'), vdw_correction_hirshfeld='true', k_grid=( 2, 2, 2, ), compute_forces=True, final_forces_cleaned=True) initial = read('initial.traj') final = read('final.traj') n = 7 calculator = my_calc() neb_catlearn = MLNEB(start=initial, end=final, ase_calc=calculator, n_images=n, interpolation='idpp', restart=False) neb_catlearn.run(fmax=0.01, trajectory='ML-NEB.traj', full_output=False)
ibrion=-1, ediffg=-0.01, # forces ediff=1e-5, #energy conv. prec='Accurate', # Slab nsw=0, # don't use the VASP internal relaxation, only use ASE ispin=1, nelm=300) # Optimize initial state: slab = read('./optimized_structures/initial.traj') slab.set_calculator(copy.deepcopy(ase_calculator)) qn = BFGS(slab, trajectory='initial.traj') qn.run(fmax=0.01) shutil.copy('./initial.traj', './optimized_structures/initial.traj') # Optimize final state: slab = read('./optimized_structures/final.traj') slab.set_calculator(copy.deepcopy(ase_calculator)) qn = BFGS(slab, trajectory='final.traj') qn.run(fmax=0.01) shutil.copy('./final.traj', './optimized_structures/final.traj') ####### CatLearn NEB: neb_catlearn = MLNEB(start='initial.traj', end='final.traj', ase_calc=copy.deepcopy(ase_calculator), n_images=11) neb_catlearn.run(fmax=0.05)
spinpol=False) # Optimize the initial and final states using a minimizer (MLMin, BFGS, FIRE ...) # Optimize the initial state using MLMin: slab = read('./structures/initial.traj') slab.set_calculator(copy.deepcopy(calc)) qn = MLMin(slab, trajectory='initial.traj') qn.run(fmax=0.03) shutil.copy('./initial.traj', './structures/initial.traj') # Optimize final state using MLMin: slab = read('./structures/final.traj') slab.set_calculator(copy.deepcopy(calc)) qn = MLMin(slab, trajectory='final.traj') qn.run(fmax=0.03) shutil.copy('./final.traj', './structures/final.traj') # Perform a Minimum Energy Path (MEP) search using ML-NEB: neb_catlearn = MLNEB( start='./structures/initial.traj', # Initial end-point. end='./structures/final.traj', # Final end-point. ase_calc=copy.deepcopy( calc ), # Calculator, it must be the same as the one used for the optimizations. n_images=15, # Number of images (interger or float, see above). interpolation= 'idpp', # Choose between linear or idpp interpolation (as implemented in ASE). You can also feed a list of Atoms with your own interpolation. restart=True) neb_catlearn.run(fmax=0.05, trajectory='ML-NEB.traj')
def test_acquisition(self): """ Here we test the acquisition functions""" print('Checking acquisition function 1 using 6 images...') neb_catlearn = MLNEB(start='initial_optimized.traj', end='final_optimized.traj', n_images=6, ase_calc=ase_calculator, restart=False) neb_catlearn.run(fmax=0.05, trajectory='ML-NEB.traj', max_step=0.2, acquisition='acq_1') self.assertEqual(neb_catlearn.iter, 16) max_unc = np.max(neb_catlearn.uncertainty_path) unc_test = 0.0028 np.testing.assert_array_almost_equal(max_unc, unc_test, decimal=4) print('Checking acquisition function 2 using 6 images...') neb_catlearn = MLNEB(start='initial_optimized.traj', end='final_optimized.traj', n_images=6, ase_calc=ase_calculator, restart=False) neb_catlearn.run(fmax=0.05, trajectory='ML-NEB.traj', max_step=0.2, acquisition='acq_2') self.assertEqual(neb_catlearn.iter, 13) max_unc = np.max(neb_catlearn.uncertainty_path) unc_test = 0.0128 np.testing.assert_array_almost_equal(max_unc, unc_test, decimal=4) print('Checking acquisition function 3 using 6 images...') neb_catlearn = MLNEB(start='initial_optimized.traj', end='final_optimized.traj', n_images=6, ase_calc=ase_calculator, restart=False) neb_catlearn.run(fmax=0.05, trajectory='ML-NEB.traj', max_step=0.2, acquisition='acq_3') self.assertEqual(neb_catlearn.iter, 14) max_unc = np.max(neb_catlearn.uncertainty_path) unc_test = 0.0036 np.testing.assert_array_almost_equal(max_unc, unc_test, decimal=4) print('Checking acquisition function 4 using 6 images...') neb_catlearn = MLNEB(start='initial_optimized.traj', end='final_optimized.traj', n_images=6, ase_calc=ase_calculator, restart=False) neb_catlearn.run(fmax=0.05, trajectory='ML-NEB.traj', max_step=0.2, acquisition='acq_4') self.assertEqual(neb_catlearn.iter, 16) max_unc = np.max(neb_catlearn.uncertainty_path) unc_test = 0.0028 np.testing.assert_array_almost_equal(max_unc, unc_test, decimal=4) print('Checking acquisition function 5 using 6 images...') neb_catlearn = MLNEB(start='initial_optimized.traj', end='final_optimized.traj', n_images=6, ase_calc=ase_calculator, restart=False) neb_catlearn.run(fmax=0.05, trajectory='ML-NEB.traj', max_step=0.2, acquisition='acq_5') self.assertEqual(neb_catlearn.iter, 13) max_unc = np.max(neb_catlearn.uncertainty_path) unc_test = 0.0128 np.testing.assert_array_almost_equal(max_unc, unc_test, decimal=4)
def pre_neb_aims(initial, final, hpc="hawk", basis_set ='light', filename="last_predicted_path.traj"): ''' This function performs a preliminary NEB calculation on user-provided structures using ML-NEB. If the calculation does not converge within 75 steps, it is terminated. Minimum Energy Path energy landscape is examined for occurence of multiple local maxima and if detected - geometry optimisations on local minima are performed. The optimised structures can be used as alternative start/end points for further calculations making the NEB calculation easier to converge. Parameters: hpc: string 'hawk', 'isambard', 'archer' see carmm.run.aims_path.set_aims_command basis_set: string 'light', 'tight' etc., see carmm.run.aims_path.set_aims_command filename: string Name of a file containing an unconverged NEB Minimum Energy Path. Default is 'last_predicted_path.traj' for CatLearn MLNEB. initial: Atoms object Starting geometry of a NEB calculation. final: Atoms object End geometry of a NEB calculation. ''' import os if not os.path.exists(filename): from ase.io import read from catlearn.optimize.mlneb import MLNEB # Set the environment parameters from carmm.run.aims_path import set_aims_command set_aims_command(hpc=hpc, basis_set=basis_set) # your settings go here def my_calc(): # New method that gives a default calculator from carmm.run.aims_calculator import get_aims_calculator return get_aims_calculator(dimensions=2) from carmm.build.neb.ilm import neb_identify_local_minima from carmm.build.neb.ilm import multiple_local_extrema # Desired number of images including start and end point # Enough to show energy landscape of Minimum Energy Path n = 15 calculator = my_calc() # Setup the Catlearn object for MLNEB neb_catlearn = MLNEB(start=initial, end=final, ase_calc=calculator, n_images=n, interpolation='idpp', restart=False) # Run the NEB optimisation. Adjust fmax to desired convergence criteria, # usually 0.01 ev/A. Max steps set to 75 for preliminary study. # MLNEB serial part is quick below 100 structures neb_catlearn.run(fmax=0.01, trajectory='ML-NEB.traj', full_output=False, steps=75) if multiple_local_extrema(filename=filename) is True: print("Multiple extrema detected in the predicted Minimum Energy Path.") print("Local minima will be identified and optimised") atoms_list, indices = neb_identify_local_minima(filename=filename) print(len(atoms_list), "minima detected. Performing geometry optimisations.") from ase.optimize import BFGS from carmm.run.aims_path import set_aims_command from carmm.run.aims_calculator import get_aims_calculator set_aims_command(hpc=hpc, basis_set=basis_set) x = 0 for atoms in atoms_list: id = indices[x] atoms.calc = get_aims_calculator(2, k_grid=(3, 3, 1)) opt = BFGS(atoms, restart="min_"+str(id)+".pckl", trajectory="min_"+str(id)+".traj") opt.run(fmax=0.01) x = x+1 print("Geometry optimisations completed.") print("Please consider the structures as alternative start/end points.") else: print("No multiple extrema detected in the predicted Minimum Energy Path.")
def search_ts(self, initial, final, fmax, unc, interpolation="idpp", n=0.25, restart=True, prev_calcs=None, input_check=0.01, verbose=True): ''' This function allows calculation of the transition state using the CatLearn software package in an ASE/sockets/FHI-aims setup. The resulting converged band will be located in the MLNEB.traj file. Args: initial: Atoms object Initial structure in the NEB band final: Atoms object Final structure in the NEB band fmax: float Convergence criterion of forces in eV/A unc: float Uncertainty in the fit of the NEB according to the Gaussian Progress Regression model, a secondary convergence criterion. n: int number of middle images, the following is recommended: n * npi = total_no_CPUs interpolation: str or [] The "idpp" or "linear" interpolation types are supported in ASE. alternatively user can provide a custom interpolation as a list of Atoms objects. n: int or flot Desired number of middle images excluding start and end point. If float the number of images is based on displacement of atoms. Dense sampling aids convergence but does not increase complexity as significantly as for classic NEB. restart: bool Use previous calculations contained in folders if True, start from scratch if False prev_calcs: list of Atoms objects Manually provide the training set input_check: float or None If float the calculators of the input structures will be checked if the structures are below the requested fmax and an optimisation will be performed if not. verbose: bool Flag for turning off printouts in the code Returns: Atoms object Transition state geometry structure ''' from catlearn.optimize.mlneb import MLNEB '''Retrieve common properties''' basis_set = self.basis_set hpc = self.hpc dimensions = sum(initial.pbc) params = self.params parent_dir = os.getcwd() '''Set the environment parameters''' set_aims_command(hpc=hpc, basis_set=basis_set, defaults=2020, nodes_per_instance=self.nodes_per_instance) if not interpolation: interpolation = "idpp" '''Read the geometry''' if self.filename: filename = self.filename else: filename = initial.get_chemical_formula() self.filename = filename counter, subdirectory_name = self._restart_setup("TS", filename, restart=restart, verbose=verbose) if os.path.exists( os.path.join(subdirectory_name[:-1] + str(counter - 1), "ML-NEB.traj")): previously_converged_ts_search = os.path.join( subdirectory_name[:-1] + str(counter - 1), "ML-NEB.traj") print("TS search already converged at", previously_converged_ts_search) neb = read(previously_converged_ts_search + "@:") self.ts = sorted(neb, key=lambda k: k.get_potential_energy(), reverse=True)[0] os.chdir(parent_dir) return self.ts elif input_check: '''Ensure input is converged''' if not is_converged(initial, input_check): self.filename += "_initial" initial = self.aims_optimise(initial, input_check, restart=True, verbose=False)[0] if not is_converged(final, input_check): self.filename = filename + "_final" final = self.aims_optimise(final, input_check, restart=True, verbose=False)[0] '''Set original name after input check is complete''' self.filename = filename out = str(counter) + "_" + str(filename) + ".out" '''Let the user restart from alternative file or Atoms object''' if prev_calcs: self.prev_calcs = prev_calcs os.makedirs(subdirectory_name, exist_ok=True) os.chdir(subdirectory_name) '''Create the sockets calculator - using a with statement means the object is closed at the end.''' with _calc_generator(params, out_fn=out, dimensions=dimensions)[0] as calculator: if self.dry_run: calculator = EMT() iterations = 0 while not os.path.exists('ML-NEB.traj'): if iterations > 0: self.prev_calcs = read("last_predicted_path.traj@:") interpolation = self.prev_calcs '''Setup the Catlearn object for MLNEB''' neb_catlearn = MLNEB(start=initial, end=final, ase_calc=calculator, n_images=n, interpolation=interpolation, neb_method="improvedtangent", prev_calculations=self.prev_calcs, mic=True, restart=restart) if not self.dry_run: '''Run the NEB optimisation. Adjust fmax to desired convergence criteria, usually 0.05 eV/A''' neb_catlearn.run(fmax=fmax, unc_convergence=unc, trajectory='ML-NEB.traj', ml_steps=75, sequential=False, steps=40) iterations += 1 else: os.chdir(parent_dir) return None '''Find maximum energy, i.e. transition state to return it''' neb = read("ML-NEB.traj@:") self.ts = sorted(neb, key=lambda k: k.get_potential_energy(), reverse=True)[0] os.chdir(parent_dir) return self.ts
image.set_constraint(constraint) images_ase.append(image) images_ase.append(final_ase) neb_ase = NEB(images_ase, climb=True) neb_ase.interpolate(method='idpp') qn_ase = BFGS(neb_ase, trajectory='neb_ase.traj') qn_ase.run(fmax=0.05) # 2.B. NEB using CatLearn neb_catlearn = MLNEB(start='initial.traj', end='final.traj', ase_calc=EMT(), n_images=n_images, interpolation='idpp', restart=False) neb_catlearn.run(fmax=0.05, trajectory='ML-NEB.traj') # 3. Summary of the results ################################################# # NEB ASE: print('\nSummary of the results: \n') atoms_ase = read('neb_ase.traj', ':') n_eval_ase = int(len(atoms_ase) - 2 * (len(atoms_ase) / n_images)) print('Number of function evaluations CI-NEB implemented in ASE:', n_eval_ase)