def test_neb_methods(method, optimizer, precon, optmethod, ref_vacancy, setup_images): # unpack the reference result Ef_ref, dE_ref, saddle_ref = ref_vacancy # now relax the MEP for comparison images, _, _ = setup_images fmax_history = [] def save_fmax_history(mep): fmax_history.append(mep.get_residual()) k = 0.1 if precon == 'Exp': k = 0.01 mep = NEB(images, k=k, method=method, precon=precon) if optmethod is not None: opt = optimizer(mep, method=optmethod) else: opt = optimizer(mep) opt.attach(save_fmax_history, 1, mep) opt.run(fmax=1e-2) nebtools = NEBTools(images) Ef, dE = nebtools.get_barrier(fit=False) print(f'{method},{optimizer.__name__},{precon} ' f'=> Ef = {Ef:.3f}, dE = {dE:.3f}') forcefit = fit_images(images) output_dir = os.path.dirname(__file__) with open( f'{output_dir}/MEP_{method}_{optimizer.__name__}_{optmethod}' f'_{precon}.json', 'w') as f: json.dump( { 'fmax_history': fmax_history, 'method': method, 'optmethod': optmethod, 'precon': precon, 'optimizer': optimizer.__name__, 'path': forcefit.path, 'energies': forcefit.energies.tolist(), 'fit_path': forcefit.fit_path.tolist(), 'fit_energies': forcefit.fit_energies.tolist(), 'lines': np.array(forcefit.lines).tolist(), 'Ef': Ef, 'dE': dE }, f) centre = 2 # we have 5 images total, so central image has index 2 vdiff, _ = find_mic(images[centre].positions - saddle_ref.positions, images[centre].cell) print(f'Ef error {Ef - Ef_ref} dE error {dE - dE_ref} ' f'position error at saddle {abs(vdiff).max()}') assert abs(Ef - Ef_ref) < 1e-2 assert abs(dE - dE_ref) < 1e-2 assert abs(vdiff).max() < 1e-2
def run(self, calc, filename): """ Runs NEB calculations. Parameters ---------- calc: object. Calculator to be used to run method. filename: str. Label to save generated trajectory files.""" initial = self.starting_images[0].copy() final = self.starting_images[-1].copy() if self.ml2relax: # Relax initial and final images ml_initial = initial ml_initial.set_calculator(calc) ml_final = final ml_final.set_calculator(calc) print("BUILDING INITIAL") qn = BFGS(ml_initial, trajectory="initial.traj", logfile="initial_relax_log.txt") qn.run(fmax=0.01, steps=100) print("BUILDING FINAL") qn = BFGS(ml_final, trajectory="final.traj", logfile="final_relax_log.txt") qn.run(fmax=0.01, steps=100) initial = ml_initial.copy() final = ml_final.copy() initial.set_calculator(calc) final.set_calculator(calc) images = [initial] for i in range(self.intermediate_samples): image = initial.copy() image.set_calculator(calc) images.append(image) images.append(final) print("NEB BEING BUILT") neb = SingleCalculatorNEB(images) neb.interpolate() print("NEB BEING OPTIMISED") opti = BFGS(neb, trajectory=filename + ".traj", logfile="al_neb_log.txt") opti.run(fmax=0.01, steps=100) print("NEB DONE") """ The following code is used to visualise the NEB at every iteration """ built_neb = NEBTools(images) barrier, dE = built_neb.get_barrier() # max_force = built_neb.get_fmax() # fig = built_neb.plot_band() plt.show()
def get_data(name): assert name in ("Co", "Zn") traj = Trajectory(traj_name(name)) nb = NEBTools(traj) s, E, *_ = nb.get_fit() E[-1] = E[0] # force energy to be same ss = numpy.linspace(min(s), max(s)) ee = interp1d(s, E, kind="cubic")(ss) print(max(ee)) return s, E, ss, ee
def prepare_graph(transition_states, lmdf, trandir, log='@-7:'): Ed = [] for ts in transition_states: outputs = read(trandir + ts + log) for output in outputs: add_tip4p_const(output) nebtools = NEBTools(outputs) Ef, dE = nebtools.get_barrier() Ed.append([ts[:-5], Ef, Ed]) Ed = pd.DataFrame(Ed, columns=['images', 'Ed', 'deltaE']) mins = Ed['images'].apply(lambda x: x.split("_")) min1 = [] min2 = [] revers = [] for line in mins: min1.append(line[0]) min2.append(line[1]) revers.append(line[1] + "_" + line[0]) db = pd.DataFrame(columns=["m1", "m2", "Ed", "images"]) db['m1'] = min1 db['m2'] = min2 db['Ed'] = Ed['Ed'] db['images'] = Ed['images'] db = db.merge(lmdf[['m2', 'E2']], how='left', on='m2') db = db.merge(lmdf[['m1', 'E1']], how='left', on='m1') db['ET'] = db['Ed'] + db['E1'] db2 = pd.DataFrame(columns=["m1", "m2", "Ed", "images", "E2", "E1", "ET"]) db2['m1'] = db["m2"] db2['m2'] = db["m1"] db2['ET'] = db['ET'] db2['Ed'] = db['Ed'] db2['E1'] = db["E2"] db2['E2'] = db["E1"] db2['images'] = revers new = pd.concat([db, db2]) new = new[new["ET"] <= 0] new = new[new["E1"] <= new["ET"]] new = new[new["E2"] <= new["ET"]] dbnp = new.values g = nx.Graph() g.add_nodes_from(new['m1']) g.add_nodes_from(new['m2']) for line in dbnp: line[3] = line[0][4:] + '_' + line[1][4:] if line[2] != np.nan: g.add_edge(line[0], line[1], ts=[line[0], line[1], line[6]]) return g, new
def run(args, parser): # Nothing will ever be stored in args.output; need to manually find # if its supplied by checking extensions. if args.filenames[-1].endswith('.pdf'): args.output = args.filenames.pop(-1) else: args.output = 'nebplots.pdf' images = Images() images.read(args.filenames) nebtools = NEBTools(images=images) nebtools.plot_bands(constant_x=args.constant_x, constant_y=args.constant_y, nimages=args.n_images, label=args.output[:-4])
def _ref_vacancy_global(_setup_images_global): # use distance from moving atom to one of its neighbours as reaction coord # relax intermediate image to the saddle point using a bondlength constraint images, i1, i2 = _setup_images_global initial, saddle, final = (images[0].copy(), images[2].copy(), images[4].copy()) initial.calc = calc() saddle.calc = calc() final.calc = calc() saddle.set_constraint(FixBondLength(i1, i2)) opt = ODE12r(saddle) opt.run(fmax=1e-2) nebtools = NEBTools([initial, saddle, final]) Ef_ref, dE_ref = nebtools.get_barrier(fit=False) print('REF:', Ef_ref, dE_ref) return Ef_ref, dE_ref, saddle
def test_autoneb(asap3): EMT = asap3.EMT fmax = 0.02 # Pt atom adsorbed in a hollow site: slab = fcc211('Pt', size=(3, 2, 2), vacuum=4.0) add_adsorbate(slab, 'Pt', 0.5, (-0.1, 2.7)) # Fix second and third layers: slab.set_constraint(FixAtoms(range(6, 12))) # Use EMT potential: slab.calc = EMT() # Initial state: qn = QuasiNewton(slab, trajectory='neb000.traj') qn.run(fmax=fmax) # Final state: slab[-1].x += slab.get_cell()[0, 0] slab[-1].y += 2.8 qn = QuasiNewton(slab, trajectory='neb001.traj') qn.run(fmax=fmax) # Stops PermissionError on Win32 for access to # the traj file that remains open. del qn def attach_calculators(images): for i in range(len(images)): images[i].calc = EMT() autoneb = AutoNEB(attach_calculators, prefix='neb', optimizer='BFGS', n_simul=3, n_max=7, fmax=fmax, k=0.5, parallel=False, maxsteps=[50, 1000]) autoneb.run() nebtools = NEBTools(autoneb.all_images) assert abs(nebtools.get_barrier()[0] - 0.937) < 1e-3
def test_ethene_rotation(tmpdir): tmpdir.chdir() # Optimise molecule initial = molecule('C2H6') smart_cell(initial, vac=4.0, h=0.01) initial.set_calculator(iEspresso(pw=300, dw=4000, kpts='gamma')) qn = QuasiNewton(initial, 'initial.traj') qn.run(fmax=0.01) # Create final state final = initial.copy() final.positions[2:5] = initial.positions[[3, 4, 2]] final.set_calculator(iEspresso(pw=300, dw=4000, kpts='gamma')) final.get_potential_energy() # Generate blank images images = [initial] nimage = 7 for i in range(nimage): image = initial.copy() image.set_calculator(iEspresso(pw=300, dw=4000, kpts='gamma')) images.append(image) images.append(final) # Run IDPP interpolation neb = NEBEspresso(images) neb.interpolate('idpp') # Run NEB calculation qn = QuasiNewton(neb, logfile='ethane_linear.log', trajectory='neb.traj') qn.run(fmax=0.05) nt = NEBTools(neb.images) print('fmax: ', nt.get_fmax()) print('Ef, dE: ', nt.get_barrier())
def test_neb(plt): from ase import Atoms from ase.constraints import FixAtoms import ase.io from ase.neb import NEB, NEBTools from ase.calculators.morse import MorsePotential from ase.optimize import BFGS, QuasiNewton def calc(): # Common calculator for all images. return MorsePotential() # Create and relax initial and final states. initial = Atoms('H7', positions=[(0, 0, 0), (1, 0, 0), (0, 1, 0), (1, 1, 0), (0, 2, 0), (1, 2, 0), (0.5, 0.5, 1)], constraint=[FixAtoms(range(6))], calculator=calc()) dyn = QuasiNewton(initial) dyn.run(fmax=0.01) final = initial.copy() final.calc = calc() final.positions[6, 1] = 2 - initial.positions[6, 1] dyn = QuasiNewton(final) dyn.run(fmax=0.01) # Run NEB without climbing image. fmax = 0.05 nimages = 4 images = [initial] for index in range(nimages - 2): images += [initial.copy()] images[-1].calc = calc() images += [final] neb = NEB(images) neb.interpolate() with BFGS(neb, trajectory='mep.traj') as dyn: dyn.run(fmax=fmax) # Check climbing image. neb.climb = True dyn.run(fmax=fmax) # Check NEB tools. nt_images = ase.io.read('mep.traj', index='-{:d}:'.format(nimages)) nebtools = NEBTools(nt_images) nt_fmax = nebtools.get_fmax(climb=True) Ef, dE = nebtools.get_barrier() print(Ef, dE, fmax, nt_fmax) assert nt_fmax < fmax assert abs(Ef - 1.389) < 0.001 # Plot one band. nebtools.plot_band() # Plot many (ok, 2) bands. nt_images = ase.io.read('mep.traj', index='-{:d}:'.format(2 * nimages)) nebtools = NEBTools(nt_images) nebtools.plot_bands()
# and rotational degrees of freedom neb = NEB(images, remove_rotation_and_translation=remove_rotation_and_translation) neb.interpolate() # Test used these old defaults which are not optimial, but work # in this particular system neb.idpp_interpolate(fmax=0.1, optimizer=BFGS) qn = FIRE(neb, dt=0.005, maxmove=0.05, dtmax=0.1) qn.run(steps=20) # Switch to CI-NEB, still removing the external degrees of freedom # Also spesify the linearly varying spring constants neb = NEB(images, climb=True, remove_rotation_and_translation=remove_rotation_and_translation) qn = FIRE(neb, dt=0.005, maxmove=0.05, dtmax=0.1) qn.run(fmax=fmax) images = neb.images nebtools = NEBTools(images) Ef_neb, dE_neb = nebtools.get_barrier(fit=False) nsteps_neb = qn.nsteps if remove_rotation_and_translation: Ef_neb_0 = Ef_neb nsteps_neb_0 = nsteps_neb assert abs(Ef_neb - Ef_neb_0) < 1e-2 assert nsteps_neb_0 < nsteps_neb * 0.7
for i in range(nimages): images.append(images[0].copy()) images[-1].positions[6, 1] = 2 - images[0].positions[6, 1] neb = NEB(images) neb.interpolate() if 0: # verify that initial images make sense from ase.visualize import view view(neb.images) for image in images: image.set_calculator(MorsePotential()) dyn = BFGS(neb, trajectory='mep.traj') # , logfile='mep.log') dyn.run(fmax=fmax) for a in neb.images: print(a.positions[-1], a.get_potential_energy()) neb.climb = True dyn.run(fmax=fmax) # Check NEB tools. nt_images = read('mep.traj@-4:') nebtools = NEBTools(nt_images) nt_fmax = nebtools.get_fmax(climb=True) Ef, dE = nebtools.get_barrier() print(Ef, dE, fmax, nt_fmax) assert nt_fmax < fmax assert abs(Ef - 1.389) < 0.001
final.positions[2:5] = initial.positions[[3, 4, 2]] # Generate blank images. images = [initial] for i in range(9): images.append(initial.copy()) for image in images: image.calc = EMT() images.append(final) neb = NEB(images, climb=True) neb.interpolate(method='idpp') #idpp插值,设置初猜 # set calculator for atoms in images: atoms.calc = EMT() atoms.get_potential_energy() # Optimize: py_fname = os.path.splitext(sys.argv[0])[0] traj_fname = "{}.traj".format(py_fname) log_fname = "{}.log".format(py_fname) optimizer = FIRE(neb, trajectory=traj_fname, logfile=log_fname) optimizer.run(fmax=0.04) neb_result = list(iread(traj_fname)) for i in neb_result: #print(i.get_potential_energy()) pass neb_result = NEBTools(neb_result) neb_result.plot_bands(True, True, label=py_fname) print(neb_result.get_barrier(), neb_result.get_fmax())
qn.run(fmax=0.05) # Final state: slab[-1].x += slab.get_cell()[0, 0] slab[-1].y += 2.8 qn = QuasiNewton(slab, trajectory='neb001.traj') qn.run(fmax=0.05) # Stops PermissionError on Win32 for access to # the traj file that remains open. del qn def attach_calculators(images): for i in range(len(images)): images[i].set_calculator(EMT()) autoneb = AutoNEB(attach_calculators, prefix='neb', n_simul=3, n_max=7, fmax=0.05, k=0.5, parallel=False, maxsteps=[50, 1000]) autoneb.run() nebtools = NEBTools(autoneb.all_images) assert abs(nebtools.get_barrier()[0] - 0.938) < 1e-3
def plotneb(trajectory='ML_NEB_catlearn.traj', view_path=True): """ Plot NEB path from a trajectory file containing the optimized images. This is meant to be used with ML-NEB. The error bars show the uncertainty for each image along the path. """ images = read(trajectory, ':') # Get fit from NEBTools. nebtools = NEBTools(images) nebfit = nebtools.get_fit() x_pred = nebfit[0] e_pred = nebfit[1] x_fit = nebfit[2] e_fit = nebfit[3] e_barrier = np.max(e_pred) print('Energy barrier:', e_barrier, 'eV') u_pred = [] for i in images: u_pred.append(i.info['uncertainty']) fig, ax = plt.subplots(figsize=(8, 5)) prop_plots = dict(arrowstyle="<|-|>, head_width=0.5, head_length=1.", connectionstyle="arc3", color='teal', ls='-', lw=0.0) ax.annotate("", xy=(x_pred[np.argmax(e_pred)], np.max(e_pred)), xycoords='data', xytext=(x_pred[np.argmax(e_pred)], 0.0), textcoords='data', arrowprops=prop_plots) prop_plots = dict(arrowstyle="|-|", connectionstyle="arc3", ls='-', lw=2., color='teal') ax.annotate("", xy=(x_pred[np.argmax(e_pred)], np.max(e_pred)), xycoords='data', xytext=(x_pred[np.argmax(e_pred)], 0.0), textcoords='data', arrowprops=prop_plots) ax.annotate(s=str(np.round(e_barrier, 3)) + ' eV', xy=(x_pred[np.argmax(e_pred)], np.max(e_pred) / 1.65), xycoords='data', fontsize=15.0, textcoords='data', ha='right', rotation=90, color='teal') ax.plot(x_fit, e_fit, color='black', linestyle='--', linewidth=1.5) ax.errorbar(x_pred, e_pred, yerr=u_pred, alpha=0.8, markersize=0.0, ecolor='midnightblue', ls='', elinewidth=3.0, capsize=1.0) ax.plot(x_pred, e_pred, color='firebrick', alpha=0.7, marker='o', markersize=13.0, markeredgecolor='black', ls='') ax.set_xlabel('Path distance ($\AA$)') ax.set_ylabel('Energy (eV)') plt.tight_layout(h_pad=1) print('Saving pdf file with the NEB profile in file: ' + 'MLNEB.pdf') plt.savefig('./' 'MLNEB.pdf', format='pdf') plt.show() if view_path is True: print('Visualizing NEB images in ASE...') view(images)
def test_neb_tr(): nimages = 3 fmax = 0.01 for remove_rotation_and_translation in [True, False]: # Define coordinates for initial and final states initial = Atoms('O4', [(1.94366484, 2.24788196, 2.32204726), (3.05353823, 2.08091038, 2.30712548), (2.63770601, 3.05694348, 2.67368242), (2.50579418, 2.12540646, 3.28585811)]) final = Atoms('O4', [(1.95501370, 2.22270649, 2.33191017), (3.07439495, 2.13662682, 2.31948449), (2.44730550, 1.26930465, 2.65964947), (2.52788189, 2.18990240, 3.29728667)]) final.set_cell((5, 5, 5)) initial.set_cell((5, 5, 5)) final.calc = LennardJones() initial.calc = LennardJones() images = [initial] # Set calculator for i in range(nimages): image = initial.copy() image.calc = LennardJones() images.append(image) images.append(final) # Define the NEB and make a linear interpolation # with removing translational # and rotational degrees of freedom neb = NEB( images, remove_rotation_and_translation=remove_rotation_and_translation) neb.interpolate() # Test used these old defaults which are not optimial, but work # in this particular system idpp_interpolate(neb, fmax=0.1, optimizer=BFGS) qn = FIRE(neb, dt=0.005, maxstep=0.05, dtmax=0.1) qn.run(steps=20) # Switch to CI-NEB, still removing the external degrees of freedom # Also spesify the linearly varying spring constants neb = NEB( images, climb=True, remove_rotation_and_translation=remove_rotation_and_translation) qn = FIRE(neb, dt=0.005, maxstep=0.05, dtmax=0.1) qn.run(fmax=fmax) images = neb.images nebtools = NEBTools(images) Ef_neb, dE_neb = nebtools.get_barrier(fit=False) nsteps_neb = qn.nsteps if remove_rotation_and_translation: Ef_neb_0 = Ef_neb nsteps_neb_0 = nsteps_neb assert abs(Ef_neb - Ef_neb_0) < 1e-2 assert nsteps_neb_0 < nsteps_neb * 0.7
# write output geometries of GO io.write("initial.xyz", initial) io.write("final.xyz", final) # Make a band consisting of N images: images = [initial] images += [initial.copy() for i in range(17)] images += [final] print(" -> set calculator") for image in images: image.set_calculator( PySCF_simple(atoms=image, method='MP2', basis='6-31g*')) neb = NEB(images, climb=True, k=0.6) nebTools = NEBTools(images) neb.interpolate('idpp') print(" -> start neb run") opt = FIRE(neb) opt.run(fmax=0.05) print(nebTools.get_barrier()) # get IRC data Ef, dE = nebTools.get_barrier() max_force = nebTools.get_fmax() x, y, x_fit, y_fit, forces = nebTools.get_fit() # save IRC data
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) # ML-NEB: atoms_catlearn = read('evaluated_structures.traj', ':') n_eval_catlearn = len(atoms_catlearn) - 2 print('Number of function evaluations CatLearn:', n_eval_catlearn) # Comparison: print( '\nThe ML-NEB algorithm required ', (n_eval_ase / n_eval_catlearn), 'times less number of function evaluations than ' 'the standard NEB algorithm.') # Plot ASE NEB: nebtools_ase = NEBTools(images_ase) Sf_ase = nebtools_ase.get_fit()[2] Ef_ase = nebtools_ase.get_fit()[3] Ef_neb_ase, dE_neb_ase = nebtools_ase.get_barrier(fit=False) nebtools_ase.plot_band() plt.show() # Plot ML-NEB predicted path and show images along the path: plotneb(trajectory='ML-NEB.traj', view_path=False)
# with removing translational # and rotational degrees of freedom neb = NEB(images, remove_rotation_and_translation=remove_rotation_and_translation) neb.interpolate() # Test used these old defaults which are not optimial, but work # in this particular system neb.idpp_interpolate(fmax=0.1, optimizer=BFGS) qn = FIRE(neb, dt=0.005, maxmove=0.05, dtmax=0.1) qn.run(steps=20) # Switch to CI-NEB, still removing the external degrees of freedom # Also spesify the linearly varying spring constants neb = NEB(images, climb=True, remove_rotation_and_translation=remove_rotation_and_translation) qn = FIRE(neb, dt=0.005, maxmove=0.05, dtmax=0.1) qn.run(fmax=fmax) images = neb.images nebtools = NEBTools(images) Ef_neb, dE_neb = nebtools.get_barrier(fit=False) nsteps_neb = qn.nsteps if remove_rotation_and_translation: Ef_neb_0 = Ef_neb nsteps_neb_0 = nsteps_neb assert abs(Ef_neb - Ef_neb_0) < 1e-2 assert nsteps_neb_0 < nsteps_neb * 0.7
# creates: diffusion-I.png, diffusion-T.png, diffusion-F.png # creates: diffusion-barrier.png import runpy from ase.io import read, write from ase.neb import NEBTools runpy.run_path('diffusion1.py') runpy.run_path('diffusion2.py') runpy.run_path('diffusion4.py') runpy.run_path('diffusion5.py') images = read('neb.traj@-5:') for name, a in zip('ITF', images[::2]): cell = a.get_cell() del a.constraints a = a * (2, 2, 1) a.set_cell(cell) renderer = write('diffusion-%s.pov' % name, a, povray_settings=dict(transparent=False, display=False)) renderer.render() nebtools = NEBTools(images) assert abs(nebtools.get_barrier()[0] - 0.374) < 1e-3
import matplotlib.pyplot as plt from ase.neb import NEBTools from ase.io import read images = read('neb.traj@-5:') nebtools = NEBTools(images) # Get the calculated barrier and the energy change of the reaction. Ef, dE = nebtools.get_barrier() # Get the barrier without any interpolation between highest images. Ef, dE = nebtools.get_barrier(fit=False) # Get the actual maximum force at this point in the simulation. max_force = nebtools.get_fmax() # Create a figure like that coming from ASE-GUI. fig = nebtools.plot_band() fig.savefig('diffusion-barrier.png') # Create a figure with custom parameters. fig = plt.figure(figsize=(5.5, 4.0)) ax = fig.add_axes((0.15, 0.15, 0.8, 0.75)) nebtools.plot_band(ax) fig.savefig('diffusion-barrier.png')
# Final state: slab[-1].x += slab.get_cell()[0, 0] slab[-1].y += 2.8 qn = QuasiNewton(slab, trajectory='neb001.traj') qn.run(fmax=0.05) # Stops PermissionError on Win32 for access to # the traj file that remains open. del qn def attach_calculators(images): for i in range(len(images)): images[i].set_calculator(EMT()) autoneb = AutoNEB(attach_calculators, prefix='neb', optimizer='BFGS', n_simul=3, n_max=7, fmax=0.05, k=0.5, parallel=False, maxsteps=[50, 1000]) autoneb.run() nebtools = NEBTools(autoneb.all_images) assert abs(nebtools.get_barrier()[0] - 0.938) < 1e-3
import matplotlib.pyplot as plt from ase import Atoms, Atom from ase.neb import NEBTools from ase import Atoms from ase.io import read, write from ase.visualize import view images = read('neb.traj@-7:') write('neb.xyz',images) nebtools = NEBTools(images) for i in range(7): image = images[i] print(image.get_cell()) #get barrier Ef,dE = nebtools.get_barrier() #get force max_force = nebtools.get_fmax() #Create a figure fig = nebtools.plot_band() fig.savefig('phase_transition.png')