def main(): '''Main driver routine.''' initial = read('NH3_initial.traj') final = read('NH3_final.traj') images = [initial] images += [initial.copy() for ii in range(NIMAGES)] images += [final] neb = NEB(images) neb.interpolate() opt = BFGS(neb, trajectory='i2f.traj') calcs = [ Dftb(label='NH3_inversion', Hamiltonian_SCC='Yes', Hamiltonian_SCCTolerance='1.00E-06', Hamiltonian_MaxAngularMomentum_N='"p"', Hamiltonian_MaxAngularMomentum_H='"s"') for ii in range(NIMAGES) ] for ii, calc in enumerate(calcs): images[ii + 1].set_calculator(calc) opt.run(fmax=1.00E-02)
def nebmake(initial_atoms,final_atoms,n_images): """ Make interpolated images for NEB Args: initial_atoms (ASE Atoms object): initial MOF structure final_atoms (ASE Atoms object): final MOF structure n_images (int): number of NEB images """ pwd = os.getcwd() neb_path = os.path.join(pwd,'neb') if os.path.exists(neb_path): rmtree(neb_path) os.makedirs(neb_path) os.chdir(neb_path) images = [initial_atoms] for i in range(n_images): images.append(initial_atoms.copy()) images.append(final_atoms) neb = NEB(images) neb.interpolate('idpp',mic=True) for i, neb_image in enumerate(neb.images): if i < 10: ii = '0'+str(i) else: ii = str(i) os.mkdir(os.path.join(neb_path,ii)) write(os.path.join(neb_path,ii,'POSCAR'),neb_image,format='vasp') write_dummy_outcar(os.path.join(neb_path,'00','OUTCAR'),initial_atoms.get_potential_energy()) write_dummy_outcar(os.path.join(neb_path,ii,'OUTCAR'),final_atoms.get_potential_energy())
def create_lst_images(freactant, fproduct, nimages=11, mic=False): """create images with original LST algorithm without NEB force projection as in IDPP Parameters ---------- freactant : path to initial atoms fproduct : path to final atoms nimages : the number of images to be interpolated including two endpoints mic : apply mic or not (PBC) """ from ase.neb import IDPP from ase.optimize import BFGS from ase.build import minimize_rotation_and_translation # create linearly interpolated images images = _create_images(freactant, fproduct, nimages) neb = NEB(images, remove_rotation_and_translation=True) neb.interpolate() # refine images with LST algorithm d1 = images[0].get_all_distances(mic=mic) d2 = images[-1].get_all_distances(mic=mic) d = (d2 - d1) / (nimages - 1) for i, image in enumerate(images): image.set_calculator(IDPP(d1 + i * d, mic=mic)) qn = BFGS(image) qn.run(fmax=0.1) # apply optimal translation and rotation for i in range(nimages - 1): minimize_rotation_and_translation(images[i], images[i + 1]) return images
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 check_interpolation(initial, final, n_max, interpolation="linear", verbose=True, save=True): ''' Interpolates the provided geometries with n_max total images and checks whether any bond lengths are below sane defaults. Saves the interpolation in interpolation.traj Parameters: initial: Atoms object or string Starting geometry for interpolation. final: Atoms object or string End point geometry for interpolation n_max: integer Desired total number of images for the interpolation including start and end point. interpolation: string "linear" or "idpp". First better for error identification, latter for use in NEB calculation verbose: boolean If verbose output of information is required save: boolean Whether to save the trajectory for transfer on to an NEB calculation ''' from ase.neb import NEB from carmm.analyse.bonds import search_abnormal_bonds from ase.io.trajectory import Trajectory from ase.io import read # Pre-requirements if not isinstance(n_max, int): raise ValueError print("Max number of images must be an integer.") # Make a band consisting of 10 images: images = [initial] images += [initial.copy() for i in range(n_max-2)] images += [final] neb = NEB(images) # Interpolate linearly the potisions of the middle images: neb.interpolate(interpolation, apply_constraint=True) #TODO: Tidy up this horrible mix of if statements. if save: t = Trajectory('interpolation.traj', 'w') flag = True for i in range(0, n_max): if verbose: print("Assessing image", str(i+1) + '.') updated_flag = search_abnormal_bonds(images[i], verbose) if save: t.write(images[i]) if (not updated_flag): flag = updated_flag if save: t.close() return flag
def do_vasp(pos1, pos2, snimgs): nimgs = int(snimgs) ini = read(pos1) fin = read(pos2) ini.wrap() fin.wrap() traj = [ini] traj += [ini.copy() for i in range(nimgs)] traj += [fin] neb = NEB(traj) neb.interpolate('idpp') images = neb.images if not os.path.exists('00'): os.mkdir('00') if not os.path.exists(i2str(nimgs + 1)): os.mkdir(i2str(nimgs + 1)) images[0].write('00/POSCAR', vasp5=True, direct=True) images[-1].write(i2str(nimgs + 1) + '/POSCAR', vasp5=True, direct=True) for i in range(nimgs): if not os.path.exists(i2str(i + 1)): os.mkdir(i2str(i + 1)) images[i + 1].write(i2str(i + 1) + '/POSCAR', vasp5=True, direct=True) traj = Trajectory('images.tarj', 'w') for i in images: traj.write(i)
def write(self): method = self.method() images = self.getOriginalImages() new_images = [] for i in range(len(images)-1): initial, final = images[i:i+2] diff = final.positions - initial.positions diff = vectorLength(diff, 1) n_images = int(np.ceil(diff.max()/0.3)) - 1 print 'n_images=%d' % n_images t_images = [initial] for j in range(n_images): temp = t_images[0].copy() t_images.append(temp) t_images.append(final) neb = NEB(t_images) neb.interpolate() new_images.extend(neb.images[:-1]) new_images.append(images[-1]) neb = NEB(new_images) kpts = self.baseTask().parameters().kpts() self.method().writeNEB( runfile=self.runFile(), neb=neb, kpts=kpts, )
def test_single_precon_initialisation(setup_images): images, _, _ = setup_images precon = Exp() mep = NEB(images, method='spline', precon=precon) mep.get_forces() assert len(mep.precon) == len(mep.images) assert mep.precon[0].mu == mep.precon[1].mu
def test_Ag_Cu100(): from math import sqrt from ase import Atom, Atoms from ase.neb import NEB from ase.constraints import FixAtoms from ase.vibrations import Vibrations from ase.calculators.emt import EMT from ase.optimize import QuasiNewton, BFGS # Distance between Cu atoms on a (100) surface: d = 3.6 / sqrt(2) initial = Atoms('Cu', positions=[(0, 0, 0)], cell=(d, d, 1.0), pbc=(True, True, False)) initial *= (2, 2, 1) # 2x2 (100) surface-cell # Approximate height of Ag atom on Cu(100) surfece: h0 = 2.0 initial += Atom('Ag', (d / 2, d / 2, h0)) # Make band: images = [initial.copy() for i in range(6)] neb = NEB(images, climb=True) # Set constraints and calculator: constraint = FixAtoms(range(len(initial) - 1)) for image in images: image.calc = EMT() image.set_constraint(constraint) # Displace last image: images[-1].positions[-1] += (d, 0, 0) # Relax height of Ag atom for initial and final states: dyn1 = QuasiNewton(images[0]) dyn1.run(fmax=0.01) dyn2 = QuasiNewton(images[-1]) dyn2.run(fmax=0.01) # Interpolate positions between initial and final states: neb.interpolate() for image in images: print(image.positions[-1], image.get_potential_energy()) dyn = BFGS(neb, trajectory='mep.traj') dyn.run(fmax=0.05) for image in images: print(image.positions[-1], image.get_potential_energy()) a = images[0] vib = Vibrations(a, [4]) vib.run() print(vib.get_frequencies()) vib.summary() print(vib.get_mode(-1)) vib.write_mode(-1, nimages=20)
def test_turbomole_h3o2m(): # http://jcp.aip.org/resource/1/jcpsa6/v97/i10/p7507_s1 doo = 2.74 doht = 0.957 doh = 0.977 angle = radians(104.5) initial = Atoms('HOHOH', positions=[(-sin(angle) * doht, 0., cos(angle) * doht), (0., 0., 0.), (0., 0., doh), (0., 0., doo), (sin(angle) * doht, 0., doo - cos(angle) * doht) ]) if 0: view(initial) final = Atoms('HOHOH', positions=[(-sin(angle) * doht, 0., cos(angle) * doht), (0., 0., 0.), (0., 0., doo - doh), (0., 0., doo), (sin(angle) * doht, 0., doo - cos(angle) * doht)]) if 0: view(final) # Make band: images = [initial.copy()] for i in range(3): images.append(initial.copy()) images.append(final.copy()) neb = NEB(images, climb=True) # Write all commands for the define command in a string define_str = ('\n\na coord\n\n*\nno\nb all 3-21g ' 'hondo\n*\neht\n\n-1\nno\ns\n*\n\ndft\non\nfunc ' 'pwlda\n\n\nscf\niter\n300\n\n*') # Set constraints and calculator: constraint = FixAtoms(indices=[1, 3]) # fix OO BUG No.1: fixes atom 0 and 1 # constraint = FixAtoms(mask=[0,1,0,1,0]) # fix OO #Works without patch for image in images: image.calc = Turbomole(define_str=define_str) image.set_constraint(constraint) # Relax initial and final states: if 1: dyn1 = QuasiNewton(images[0]) dyn1.run(fmax=0.10) dyn2 = QuasiNewton(images[-1]) dyn2.run(fmax=0.10) # Interpolate positions between initial and final states: neb.interpolate() if 1: for image in images: print(image.get_distance(1, 2), image.get_potential_energy()) dyn = BFGS(neb, trajectory='turbomole_h3o2m.traj') dyn.run(fmax=0.10) for image in images: print(image.get_distance(1, 2), image.get_potential_energy())
def test_h3o2m(): # http://jcp.aip.org/resource/1/jcpsa6/v97/i10/p7507_s1 doo = 2.74 doht = 0.957 doh = 0.977 angle = radians(104.5) initial = Atoms('HOHOH', positions=[(-sin(angle) * doht, 0, cos(angle) * doht), (0., 0., 0.), (0., 0., doh), (0., 0., doo), (sin(angle) * doht, 0., doo - cos(angle) * doht) ]) if 0: view(initial) final = Atoms('HOHOH', positions=[(-sin(angle) * doht, 0., cos(angle) * doht), (0., 0., 0.), (0., 0., doo - doh), (0., 0., doo), (sin(angle) * doht, 0., doo - cos(angle) * doht)]) if 0: view(final) # Make band: images = [initial.copy()] for i in range(3): images.append(initial.copy()) images.append(final.copy()) neb = NEB(images, climb=True) def calculator(): return NWChem(task='gradient', theory='scf', charge=-1) # Set constraints and calculator: constraint = FixAtoms(indices=[1, 3]) # fix OO for image in images: image.calc = calculator() image.set_constraint(constraint) # Relax initial and final states: if 1: dyn1 = QuasiNewton(images[0]) dyn1.run(fmax=0.10) dyn2 = QuasiNewton(images[-1]) dyn2.run(fmax=0.10) # Interpolate positions between initial and final states: neb.interpolate() if 1: for image in images: print(image.get_distance(1, 2), image.get_potential_energy()) dyn = BFGS(neb, trajectory='nwchem_h3o2m.traj') dyn.run( fmax=0.10) # use better basis (e.g. aug-cc-pvdz) for NEB to converge for image in images: print(image.get_distance(1, 2), image.get_potential_energy())
def check_interpolation(initial, final, n_max): ''' Interpolates the provided geometries with n_max total images and checks whether any bond lengths below 0.74 Angstrom exist saves the interpolation in interpolation.traj # TODO: incorporate ase.neighborlist.natural_cutoff # for abnormal bond lengths based on typical A-B bonds Parameters: initial: Atoms object or string If a string, e.g. 'initial.traj', a file of this name will be read. Starting geometry for interpolation. final: Atoms object or string If a string, e.g. 'final.traj', a file of this name will be read. End point geometry for interpolation n_max: integer Desired total number of images for the interpolation including start and end point. ''' from ase.neb import NEB from software.analyse.Interatomic_distances.analyse_bonds import search_abnormal_bonds from ase.io.trajectory import Trajectory from ase.io import read # Pre-requirements if isinstance(initial, str) is True: initial = read(initial) if isinstance(final, str) is True: final = read(final) if not isinstance(n_max, int): raise ValueError print("Max number of images must be an integer.") # Make a band consisting of 10 images: images = [initial] images += [initial.copy() for i in range(n_max - 2)] images += [final] neb = NEB(images, climb=True) # Interpolate linearly the potisions of the middle images: neb.interpolate() t = Trajectory('interpolation.traj', 'w') for i in range(0, n_max): print("Assessing image", str(i + 1) + '.') search_abnormal_bonds(images[i]) t.write(images[i]) t.close()
def test_precon_assembly(setup_images): images, _, _ = setup_images neb = NEB(images, method='spline', precon='Exp') neb.get_forces() # trigger precon assembly # check precon for each image is symmetric positive definite for image, precon in zip(neb.images, neb.precon): assert isinstance(precon, Exp) P = precon.asarray() N = 3 * len(image) assert P.shape == (N, N) assert np.abs(P - P.T).max() < 1e-6 assert np.all(np.linalg.eigvalsh(P)) > 0
def _setup_images_global(): N_intermediate = 3 N_cell = 2 initial = bulk('Cu', cubic=True) initial *= N_cell # place vacancy near centre of cell D, D_len = get_distances(np.diag(initial.cell) / 2, initial.positions, initial.cell, initial.pbc) vac_index = D_len.argmin() vac_pos = initial.positions[vac_index] del initial[vac_index] # identify two opposing nearest neighbours of the vacancy D, D_len = get_distances(vac_pos, initial.positions, initial.cell, initial.pbc) D = D[0, :] D_len = D_len[0, :] nn_mask = np.abs(D_len - D_len.min()) < 1e-8 i1 = nn_mask.nonzero()[0][0] i2 = ((D + D[i1])**2).sum(axis=1).argmin() print(f'vac_index={vac_index} i1={i1} i2={i2} ' f'distance={initial.get_distance(i1, i2, mic=True)}') final = initial.copy() final.positions[i1] = vac_pos initial.calc = calc() final.calc = calc() qn = ODE12r(initial) qn.run(fmax=1e-3) qn = ODE12r(final) qn.run(fmax=1e-3) images = [initial] for image in range(N_intermediate): image = initial.copy() image.calc = calc() images.append(image) images.append(final) neb = NEB(images) neb.interpolate() return neb.images, i1, i2
def test_spline_fit(setup_images): images, _, _ = setup_images neb = NEB(images) fit = neb.spline_fit() # check spline points are equally spaced assert np.allclose(fit.s, np.linspace(0, 1, len(images))) # check spline matches target at fit points assert np.allclose(fit.x(fit.s), fit.x_data) # ensure derivative is smooth across central fit point eps = 1e-4 assert np.allclose(fit.dx_ds(fit.s[2] + eps), fit.dx_ds(fit.s[2] + eps))
def get_atoms(): # 2x2-Al(001) surface with 3 layers and an # Au atom adsorbed in a hollow site: slab = fcc100('Al', size=(2, 2, 3)) add_adsorbate(slab, 'Au', 1.7, 'hollow') slab.center(axis=2, vacuum=4.0) # Fix second and third layers: mask = [atom.tag > 1 for atom in slab] slab.set_constraint(FixAtoms(mask=mask)) # Use EMT potential: slab.set_calculator(EMT()) # Initial state: qn = QuasiNewton(slab, logfile=None) qn.run(fmax=0.05) initial = slab.copy() # Final state: slab[-1].x += slab.get_cell()[0, 0] / 2 qn = QuasiNewton(slab, logfile=None) qn.run(fmax=0.05) final = slab.copy() # Setup a NEB calculation constraint = FixAtoms(mask=[atom.tag > 1 for atom in initial]) images = [initial] for i in range(3): image = initial.copy() image.set_constraint(constraint) images.append(image) images.append(final) neb = NEB(images, parallel=mpi.parallel) neb.interpolate() def set_calculator(calc): i = 0 for image in neb.images[1:-1]: if not mpi.parallel or mpi.rank // (mpi.size // 3) == i: image.set_calculator(calc) i += 1 neb.set_calculator = set_calculator return neb
def run_neb_calculation(cpu): images = [PickleTrajectory('H.traj')[-1]] for i in range(nimages): images.append(images[0].copy()) images[-1].positions[6, 1] = 2 - images[0].positions[6, 1] neb = NEB(images, parallel=True, world=cpu) neb.interpolate() images[cpu.rank + 1].set_calculator(Calculator()) dyn = BFGS(neb) dyn.run(fmax=fmax) if cpu.rank == 1: results.append(images[2].get_potential_energy())
def create_idpp_images(freactant, fproduct, nimages=11): """ create images interpolated using IDPP algorithm Parameters ---------- freactant : path to initial atoms fproduct : path to final atoms nimages : the number of images to be interpolated including two endpoints """ images = _create_images(freactant, fproduct, nimages) # Interpolate intermediate images neb = NEB(images, remove_rotation_and_translation=True) neb.interpolate("idpp") return images
def run_neb_calculation(cpu): images = [PickleTrajectory('H.traj')[-1]] for i in range(nimages): images.append(images[0].copy()) images[-1].positions[6, 1] = 2 - images[0].positions[6, 1] neb = NEB(images, parallel=True, world=cpu) neb.interpolate() images[cpu.rank + 1].set_calculator(MorsePotential()) dyn = BFGS(neb) dyn.run(fmax=fmax) if cpu.rank == 1: results.append(images[2].get_potential_energy())
def nudged_elastic_band(images, fmax=0.01, algo='BFGS', trajectory='path-neb.traj', final='neb.traj'): calc = cline.gen_active_calc() load1 = calc.size[0] master = calc.rank == 0 for image in images: image.calc = calc # calculate for the first and last images # (for more efficient ML) images[0].get_potential_energy() images[-1].get_potential_energy() # define and run NEB neb = NEB(images, allow_shared_calculator=True) Min = getattr(optimize, algo) dyn = Min(neb, trajectory=trajectory, master=master) dyn.run(fmax) load2 = calc.size[0] if master: print(f'\tTotal number of Ab initio calculations: {load2-load1}\n') # output if master: out = Trajectory(final, 'w') for image in images: image.get_potential_energy() if master: out.write(image)
def test_integrate_forces(setup_images): images, _, _ = setup_images forcefit = fit_images(images) neb = NEB(images) spline_points = 1000 # it is the default value s, E, F = neb.integrate_forces(spline_points=spline_points) # check the difference between initial and final images np.testing.assert_allclose(E[0] - E[-1], forcefit.energies[0] - forcefit.energies[-1], atol=1.0e-10) # assert the maximum Energy value is in the middle assert np.argmax(E) == spline_points // 2 - 1 # check the maximum values (barrier value) # tolerance value is rather high since the images are not relaxed np.testing.assert_allclose(E.max(), forcefit.energies.max(), rtol=2.5e-2)
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 get_neb(in_file='input.traj'): """Performs a ASE NEB optimization with the ase-espresso calculator with the keywords defined inside the atoms object information. Parameters ---------- in_file : str Name of the input file to load from the local directory. """ images = read(in_file, ':') for atoms in images[1:-1]: calc = espresso(**atoms.info) atoms.set_calculator(calc) neb = NEB(images) opt = BFGS(neb, trajectory='output.traj', logfile=None) opt.run(fmax=atoms.info.get('fmax')) out_images = read('output.traj', ':') # Save the calculator to the local disk for later use. try: calc.save_flev_output() except (RuntimeError): calc.save_output() return atoms_to_encode(out_images)
def interp_by_neb(initial, final, n_images, interp='idpp', calculator=None, constraint=None, fmax=0.5, steps=10, **kwargs): """Interpolate between the initial and final points by NEB method. :param initial: The initial image. :param final: The final image. :param int n_images: The number of image between the initial and final images. :param string interp: The interpolation method. :param Callable calculator: The callable to generate calculators for the images. It can be set to None if no real optimization is intended. :param constraint: The constraint for the images. :param fmax: The maximal force to stop the optimization. :param steps: The number of optimization steps allowed. :param kwargs: All other keyword arguments are forwarded to the initializer of the ASE NEB class. :return: The list of images between the points. """ # To circumvent the error from interpolation when we have no middle images. if n_images == 0: return [initial, final] images = [initial] for _ in range(n_images): image = initial.copy() images.append(image) if calculator is not None: image.set_calculator(calculator()) if constraint is not None: image.set_constraint(constraint) continue images.append(final) neb = NEB(images, **kwargs) neb.interpolate(method=interp) if calculator is not None: dyn = MDMin(neb) dyn.run(fmax=fmax, steps=steps) return neb.images
def getPath(Reac,Prod,gl): xyzfile3 = open(("IRC3.xyz"), "w") Path = [] Path.append(Reac.copy()) for i in range(0,30): image = Reac.copy() image = tl.setCalc(image,"DOS/", gl.lowerMethod, gl.lowerLevel) Path.append(image) image = Prod.copy() image = tl.setCalc(image,"DOS/", gl.lowerMethod, gl.lowerLevel) Path.append(image) neb1 = NEB(Path,k=1.0,remove_rotation_and_translation = True) try: neb1.interpolate('idpp',optimizer="MDMin",k=1.0) except: neb1.interpolate() optimizer = FIRE(neb1) optimizer.run(fmax=0.07, steps = 500) neb2 = NEB(Path,k=1.0, climb=True, remove_rotation_and_translation = True ) optimizer = FIRE(neb2) optimizer.run(fmax=0.07, steps = 1500) for i in range(0,len(Path)): tl.printTraj(xyzfile3, Path[i]) xyzfile3.close() return Path
def test_idpp(): initial = molecule('C2H6') final = initial.copy() final.positions[2:5] = initial.positions[[3, 4, 2]] images = [initial] for i in range(5): images.append(initial.copy()) images.append(final) neb = NEB(images) d0 = images[3].get_distance(2, 3) neb.interpolate() d1 = images[3].get_distance(2, 3) idpp_interpolate(neb, fmax=0.005) d2 = images[3].get_distance(2, 3) print(d0, d1, d2) assert abs(d2 - 1.74) < 0.01
def test_vacancy(): from ase import Atoms from ase.optimize import QuasiNewton from ase.neb import NEB from ase.optimize.mdmin import MDMin try: from asap3 import EMT except ImportError: pass else: a = 3.6 b = a / 2 initial = Atoms('Cu4', positions=[(0, 0, 0), (0, b, b), (b, 0, b), (b, b, 0)], cell=(a, a, a), pbc=True) initial *= (4, 4, 4) del initial[0] images = [initial] + [initial.copy() for i in range(6)] images[-1].positions[0] = (0, 0, 0) for image in images: image.calc = EMT() #image.calc = ASAP() for image in [images[0], images[-1]]: QuasiNewton(image).run(fmax=0.01) neb = NEB(images) neb.interpolate() for a in images: print(a.positions[0], a.get_potential_energy()) dyn = MDMin(neb, dt=0.1, trajectory='mep1.traj') #dyn = QuasiNewton(neb) print(dyn.run(fmax=0.01, steps=25)) for a in images: print(a.positions[0], a.get_potential_energy())
def main(): '''Main driver routine.''' system = read(GEO_PATH, format='gen') write('dummy.gen', system, format='gen') initial = read('NH3_initial.traj') final = read('NH3_final.traj') images = [initial] images += [initial.copy() for ii in range(NIMAGES)] images += [final] neb = NEB(images) neb.interpolate() opt = BFGS(neb, trajectory='i2f.traj') socketids = range(1, NIMAGES + 1) wdirs = ['_calc/image_{:d}'.format(socket) for socket in socketids] unixsockets = ['dftbplus_{:d}'.format(socket) for socket in socketids] write_modhsd(socketids) calcs = [ SocketIOCalculator(log='socket.log', unixsocket=unixsocket) for unixsocket in unixsockets ] for ii, calc in enumerate(calcs): images[ii + 1].set_calculator(calc) for cwd in wdirs: Popen(DFTBP_PATH, cwd=cwd) opt.run(fmax=1.00E-02) for calc in calcs: calc.close()
def test_emt_h3o2m(initial, final, testdir): # Make band: images = [initial.copy()] for i in range(3): images.append(initial.copy()) images.append(final.copy()) neb = NEB(images, climb=True) # Set constraints and calculator: constraint = FixAtoms(indices=[1, 3]) # fix OO for image in images: image.calc = EMT() image.set_constraint(constraint) for image in images: # O-H(shared) distance print(image.get_distance(1, 2), image.get_potential_energy()) # Relax initial and final states: # One would have to optimize more tightly in order to get # symmetric anion from both images[0] and [1], but # if one optimizes tightly one gets rotated(H2O) ... OH- instead dyn1 = QuasiNewton(images[0]) dyn1.run(fmax=0.01) dyn2 = QuasiNewton(images[-1]) dyn2.run(fmax=0.01) # Interpolate positions between initial and final states: neb.interpolate() for image in images: print(image.get_distance(1, 2), image.get_potential_energy()) with BFGS(neb, trajectory='emt_h3o2m.traj') as dyn: dyn.run(fmax=0.05) for image in images: print(image.get_distance(1, 2), image.get_potential_energy())
def test_neb_optimizers(setup_images, method): images, _, _ = setup_images mep = NEB(images, method='spline', precon='Exp') mep.get_forces() # needed so residuals are available R0 = mep.get_residual() opt = NEBOptimizer(mep, method=method) opt.run(steps=2) # take two steps R1 = mep.get_residual() # check residual has got smaller assert R1 < R0
def method_ASE(RIGID_ROTATION, FPTR="../xyz/CNH_HCN.xyz"): from ase.io import read, write from ase.neb import NEB from ase.calculators.orca import orca from ase.optimize import SD from os import mkdir, chdir from os.path import isdir # Read in frames if not isdir("ASE"): mkdir("ASE") chdir("ASE") start, images = [], [] FPTR = "../" + FPTR if not FPTR.endswith(".xyz"): FPTR += ".xyz" for a in read(FPTR, ':'): start += [a] images += [a.copy()] # Setup neb neb = NEB(images, parallel=False, remove_rotation_and_translation=RIGID_ROTATION, method="improvedtangent") # Set the calculator for image in images: image.set_calculator(orca(label="CNH_HCN", RunTyp="Gradient")) # Run neb dyn = SD(neb, trajectory='CNH_HCN.traj') dyn.run(fmax=FMAX) # Save? traj = read("CNH_HCN.traj", ':-1') write("../CNH_HCN_opt_ASE.xyz", traj) chdir("..") print("\nDONE WITH ASE SIMULATION...\n")
def saddlepoint(min1, min2, name): images=[LM[min1]] images += [LM[min1].copy() for i in range(5)] images += [LM[min2]] for image in images: image.set_calculator(TIP4P()) add_tip4p_const(image) neb = NEB(images, climb=True, parallel=True) try: neb.interpolate() except: try: print("try idpp interpolate") neb.interpolate(method="idpp") except: return optimize(neb, name)
images = [slab] for i in range(6): image = slab.copy() # Set constraints and calculator: image.set_constraint(constraint) image.calc = EMT() images.append(image) # Displace last image: image[-2].position = image[-1].position image[-1].x = d image[-1].y = d / sqrt(3) dyn = QuasiNewton(images[-1]) dyn.run(fmax=0.05) neb = NEB(images, climb=not True) # Interpolate positions between initial and final states: neb.interpolate(method='idpp') for image in images: print(image.positions[-1], image.get_potential_energy()) dyn = BFGS(neb, maxstep=0.04, trajectory='mep.traj') dyn.run(fmax=0.05) for image in images: print(image.positions[-1], image.get_potential_energy()) if locals().get('display'): import os
from ase.build import molecule from ase.neb import NEB initial = molecule('C2H6') final = initial.copy() final.positions[2:5] = initial.positions[[3, 4, 2]] images = [initial] for i in range(5): images.append(initial.copy()) images.append(final) neb = NEB(images) d0 = images[3].get_distance(2, 3) neb.interpolate() d1 = images[3].get_distance(2, 3) neb.idpp_interpolate(fmax=0.005) d2 = images[3].get_distance(2, 3) print(d0, d1, d2) assert abs(d2 - 1.74) < 0.01
def nebmake(directory, start, final, images, tolerance=0, ci=False, poscar_override=[], linear=False, write=True): if type(start) == str: start_POSCAR = os.path.join(start, 'CONTCAR') if os.path.exists(os.path.join(start, 'CONTCAR')) and os.path.getsize(os.path.join(start, 'CONTCAR')) > 0 else os.path.join(start, 'POSCAR') final_POSCAR = os.path.join(final, 'CONTCAR') if os.path.exists(os.path.join(final, 'CONTCAR')) and os.path.getsize(os.path.join(final, 'CONTCAR')) > 0 else os.path.join(final, 'POSCAR') p1 = Poscar.from_file(start_POSCAR) p2 = Poscar.from_file(final_POSCAR) s1 = p1.structure s2 = p2.structure else: s1 = start s2 = final # s1.sort() # s2.sort() atoms = [] if poscar_override: for i in range(int(len(poscar_override)/2)): atoms.append( (poscar_override[i*2], poscar_override[i*2+1]) ) (s1, s2) = reorganize_structures(s1, s2, atoms=atoms, autosort_tol=tolerance) tolerance=0 try: structures = s1.interpolate(s2, images, autosort_tol=tolerance) except Exception as e: a=input('Failed. Type y to sort --> ') if a=='y': s1.sort() s2.sort() else: raise e structures = s1.interpolate(s2, images, autosort_tol=tolerance) if not linear: from pymatgen.io.ase import AseAtomsAdaptor from ase.neb import NEB structures_ase = [ AseAtomsAdaptor.get_atoms(struc) for struc in structures ] neb = NEB(structures_ase) neb.interpolate('idpp') # type: NEB structures = [ AseAtomsAdaptor.get_structure(atoms) for atoms in neb.images ] if write: start_OUTCAR = os.path.join(start, 'OUTCAR') final_OUTCAR = os.path.join(final, 'OUTCAR') incar = Incar.from_file(os.path.join(start, 'INCAR')) kpoints = Kpoints.from_file(os.path.join(start, 'KPOINTS')) potcar = Potcar.from_file(os.path.join(start, 'POTCAR')) incar['ICHAIN'] = 0 incar['IMAGES'] = images-1 incar['LCLIMB'] = ci for i, s in enumerate(structures): folder = os.path.join(directory, str(i).zfill(2)) os.mkdir(folder) Poscar(s, selective_dynamics=p1.selective_dynamics).write_file(os.path.join(folder, 'POSCAR')) if i == 0: shutil.copy(start_OUTCAR, os.path.join(folder, 'OUTCAR')) if i == images: shutil.copy(final_OUTCAR, os.path.join(folder, 'OUTCAR')) i += 1 incar.write_file(os.path.join(directory, 'INCAR')) kpoints.write_file(os.path.join(directory, 'KPOINTS')) potcar.write_file(os.path.join(directory, 'POTCAR')) return structures
# Approximate height of Ag atom on Cu(100) surfece: h0 = 2.2373 initial += Atom('Pt', (10.96, 11.074, h0)) initial += Atom('Pt', (13.7, 11.074, h0)) initial += Atom('Pt', (9.59, 8.701, h0)) initial += Atom('Pt', (12.33, 8.701, h0)) initial += Atom('Pt', (15.07, 8.701, h0)) initial += Atom('Pt', (10.96, 6.328, h0)) initial += Atom('Pt', (13.7, 6.328, h0)) if 0: view(initial) # Make band: images = [initial.copy() for i in range(7)] neb = NEB(images) # Set constraints and calculator: indices = np.compress(initial.positions[:, 2] < -5.0, range(len(initial))) constraint = FixAtoms(indices) for image in images: image.set_calculator(ASAP()) image.constraints.append(constraint) # Displace last image: for i in xrange(1,8,1): images[-1].positions[-i] += (d/2, -h1/3, 0) write('initial.traj', images[0]) # Relax height of Ag atom for initial and final states: for image in [images[0], images[-1]]:
from ase.structure import molecule from ase.neb import NEB initial = molecule('C2H6') final = initial.copy() final.positions[2:5] = initial.positions[[3, 4, 2]] images = [initial] for i in range(5): images.append(initial.copy()) images.append(final) neb = NEB(images) d0 = images[3].get_distance(2, 3) neb.interpolate() d1 = images[3].get_distance(2, 3) neb.idpp_interpolate() d2 = images[3].get_distance(2, 3) print(d0, d1, d2) assert abs(d2 - 1.74) < 0.01
def execute_one_neb(self, n_cur, to_run, climb=False, many_steps=False): '''Internal method which executes one NEB optimization.''' self.iteration += 1 # First we copy around all the images we are not using in this # neb (for reproducability purposes) if self.world.rank == 0: for i in range(n_cur): if i not in to_run[1: -1]: filename = '%s%03d.traj' % (self.prefix, i) self.all_images[i].write(filename) filename_ref = self.iter_folder + \ '/%s%03diter%03d.traj' % (self.prefix, i, self.iteration) if os.path.isfile(filename): shutil.copy2(filename, filename_ref) if self.world.rank == 0: print('Now starting iteration %d on ' % self.iteration, to_run) # Attach calculators to all the images we will include in the NEB self.attach_calculators([self.all_images[i] for i in to_run[1: -1]]) neb = NEB([self.all_images[i] for i in to_run], k=[self.k[i] for i in to_run[0:-1]], method=self.method, parallel=self.parallel, remove_rotation_and_translation=self .remove_rotation_and_translation, climb=climb) # Do the actual NEB calculation qn = self.optimizer(neb, logfile=self.iter_folder + '/%s_log_iter%03d.log' % (self.prefix, self.iteration)) # Find the ranks which are masters for each their calculation if self.parallel: nneb = to_run[0] nim = len(to_run) - 2 n = self.world.size // nim # number of cpu's per image j = 1 + self.world.rank // n # my image number assert nim * n == self.world.size traj = Trajectory('%s%03d.traj' % (self.prefix, j + nneb), 'w', self.all_images[j + nneb], master=(self.world.rank % n == 0)) filename_ref = self.iter_folder + \ '/%s%03diter%03d.traj' % (self.prefix, j + nneb, self.iteration) trajhist = Trajectory(filename_ref, 'w', self.all_images[j + nneb], master=(self.world.rank % n == 0)) qn.attach(traj) qn.attach(trajhist) else: num = 1 for i, j in enumerate(to_run[1: -1]): filename_ref = self.iter_folder + \ '/%s%03diter%03d.traj' % (self.prefix, j, self.iteration) trajhist = Trajectory(filename_ref, 'w', self.all_images[j]) qn.attach(seriel_writer(trajhist, i, num).write) traj = Trajectory('%s%03d.traj' % (self.prefix, j), 'w', self.all_images[j]) qn.attach(seriel_writer(traj, i, num).write) num += 1 if isinstance(self.maxsteps, (list, tuple)) and many_steps: steps = self.maxsteps[1] elif isinstance(self.maxsteps, (list, tuple)) and not many_steps: steps = self.maxsteps[0] else: steps = self.maxsteps if isinstance(self.fmax, (list, tuple)) and many_steps: fmax = self.fmax[1] elif isinstance(self.fmax, (list, tuple)) and not many_steps: fmax = self.fmax[0] else: fmax = self.fmax qn.run(fmax=fmax, steps=steps) # Remove the calculators and replace them with single # point calculators and update all the nodes for # preperration for next iteration neb.distribute = types.MethodType(store_E_and_F_in_spc, neb) neb.distribute()
initial.set_calculator(LennardJones()) images = [initial] # Set calculator for i in range(nimages): image = initial.copy() image.set_calculator(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 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)
import os from ase.io import read from ase.neb import NEB from ase.calculators.turbomole import Turbomole from ase.optimize import BFGS initial = read('initial.coord') final = read('final.coord') os.system('rm -f coord; cp initial.coord coord') # Make a band consisting of 5 configs: configs = [initial] configs += [initial.copy() for i in range(3)] configs += [final] band = NEB(configs, climb=True) # Interpolate linearly the positions of the not-endpoint-configs: band.interpolate() #Set calculators for config in configs: config.set_calculator(Turbomole()) # Optimize the Path: relax = BFGS(band, trajectory='neb.traj') relax.run(fmax=0.05)
def __init__(self, images, control, k=1.0, climb=False, parallel=False, minmodes=None, decouple_modes=False): self.control = control NEB.__init__(self, images, k, climb, parallel) self.spring_force = 'full' # Set up MinModeAtoms objects for each image and make individual logfiles for each # NB: Shouldn't there be a ERM_Control class that takes care of this crap? self.images = [] for i in range(self.nimages): min_control = control.copy() i_num = ('%0' + str(len(str(self.nimages))) + 'i') % i d_logfile_old = self.control.get_logfile() m_logfile_old = self.control.get_eigenmode_logfile() if d_logfile_old not in ['-', None]: if type(d_logfile_old) == str: d_logfile_old = d_logfile_old.split('.') else: d_logfile_old = d_logfile_old.name.split('.') d_logfile_old.insert(-1, i_num) d_logfile_new = '-'.join(['.'.join(d_logfile_old[:-2]), '.'.join(d_logfile_old[-2:])]) else: d_logfile_new = d_logfile_old if m_logfile_old not in ['-', None]: if type(m_logfile_old) == str: m_logfile_old = m_logfile_old.split('.') else: m_logfile_old = m_logfile_old.name.split('.') m_logfile_old.insert(-1, i_num) m_logfile_new = '-'.join(['.'.join(m_logfile_old[:-2]), '.'.join(m_logfile_old[-2:])]) else: m_logfile_new = m_logfile_old if i in [0, self.nimages - 1]: write_rank = 0 else: write_rank = (i - 1) * size // (self.nimages - 2) min_control.set_write_rank(write_rank) min_control.initialize_logfiles(logfile = d_logfile_new, eigenmode_logfile = m_logfile_new) if minmodes is None: minmode = None else: minmodes = np.array(minmodes) if minmodes.shape == (self.nimages, self.natoms, 3): # Assume one minmode for each image raise NotImplementedError() elif minmodes.shape == (2, self.natoms, 3): # Assume end images minmodes and interpolate raise NotImplementedError() elif minmodes.shape == (self.natoms, 3): minmode = [minmodes.copy()] else: raise ValueError('ERM did not understand the minmodes given to it.') image = MinModeAtoms(images[i], min_control, eigenmodes = minmode) self.images.append(image) self.forces['dimer'] = np.zeros((self.nimages, self.natoms, 3)) # Populate the tangents for i in range(1, self.nimages - 1): p_m = self.images[i - 1].get_positions() p_p = self.images[i + 1].get_positions() t = (p_p - p_m) / 2.0 if 0.0 in t: # Assume a linear interpolation # HACK/BUG: Currently the last or first "free" image will yield p[-1] - p[0] t = self.images[-1].get_positions() - self.images[0].get_positions() t /= (self.nimages - 1.0) self.tangents[i] = t self.tangents[0] = t self.tangents[-1] = -t # Save user variables self.decouple_modes = decouple_modes # Release the orthogonality constraint of the minmode and tanget. # Development stuff self.plot_devplot = False self.plot_subplot = False self.plot_animate = 0 self.plot_x = None self.plot_y = None self.plot_e = None self.xrange = None self.yrange = None
del atoms[5] print(atoms) assert len(atoms.constraints[0].index) == 5 fmax = 0.05 nimages = 3 print([a.get_potential_energy() for a in Trajectory('H.traj')]) images = [Trajectory('H.traj')[-1]] 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())
def run(self): '''Run the AutoNEB optimization algorithm.''' n_cur = self.__initialize__() while len(self.all_images) < self.n_simul + 2: if isinstance(self.k, (float, int)): self.k = [self.k] * (len(self.all_images) - 1) if self.world.rank == 0: print('Now adding images for initial run') # Insert a new image where the distance between two images is # the largest spring_lengths = [] for j in range(n_cur - 1): spring_vec = self.all_images[j + 1].get_positions() - \ self.all_images[j].get_positions() spring_lengths.append(np.linalg.norm(spring_vec)) jmax = np.argmax(spring_lengths) if self.world.rank == 0: print('Max length between images is at ', jmax) # The interpolation used to make initial guesses # If only start and end images supplied make all img at ones if len(self.all_images) == 2: n_between = self.n_simul else: n_between = 1 toInterpolate = [self.all_images[jmax]] for i in range(n_between): toInterpolate += [toInterpolate[0].copy()] toInterpolate += [self.all_images[jmax + 1]] neb = NEB(toInterpolate) neb.interpolate(method=self.interpolate_method) tmp = self.all_images[:jmax + 1] tmp += toInterpolate[1:-1] tmp.extend(self.all_images[jmax + 1:]) self.all_images = tmp # Expect springs to be in equilibrium k_tmp = self.k[:jmax] k_tmp += [self.k[jmax] * (n_between + 1)] * (n_between + 1) k_tmp.extend(self.k[jmax + 1:]) self.k = k_tmp # Run the NEB calculation with the new image included n_cur += n_between # Determine if any images do not have a valid energy yet energies = self.get_energies() n_non_valid_energies = len([e for e in energies if e != e]) if self.world.rank == 0: print('Start of evaluation of the initial images') while n_non_valid_energies != 0: if isinstance(self.k, (float, int)): self.k = [self.k] * (len(self.all_images) - 1) # First do one run since some energie are non-determined to_run, climb_safe = self.which_images_to_run_on() self.execute_one_neb(n_cur, to_run, climb=False) energies = self.get_energies() n_non_valid_energies = len([e for e in energies if e != e]) if self.world.rank == 0: print('Finished initialisation phase.') # Then add one image at a time until we have n_max images while n_cur < self.n_max: if isinstance(self.k, (float, int)): self.k = [self.k] * (len(self.all_images) - 1) # Insert a new image where the distance between two images # is the largest OR where a higher energy reselution is needed if self.world.rank == 0: print('****Now adding another image until n_max is reached', '({0}/{1})****'.format(n_cur, self.n_max)) spring_lengths = [] for j in range(n_cur - 1): spring_vec = self.all_images[j + 1].get_positions() - \ self.all_images[j].get_positions() spring_lengths.append(np.linalg.norm(spring_vec)) total_vec = self.all_images[0].get_positions() - \ self.all_images[-1].get_positions() tl = np.linalg.norm(total_vec) fR = max(spring_lengths) / tl e = self.get_energies() ed = [] emin = min(e) enorm = max(e) - emin for j in range(n_cur - 1): delta_E = (e[j + 1] - e[j]) * (e[j + 1] + e[j] - 2 * emin) / 2 / enorm ed.append(abs(delta_E)) gR = max(ed) / enorm if fR / gR > self.space_energy_ratio: jmax = np.argmax(spring_lengths) t = 'spring length!' else: jmax = np.argmax(ed) t = 'energy difference between neighbours!' if self.world.rank == 0: print('Adding image between {0} and'.format(jmax), '{0}. New image point is selected'.format(jmax + 1), 'on the basis of the biggest ' + t) toInterpolate = [self.all_images[jmax]] toInterpolate += [toInterpolate[0].copy()] toInterpolate += [self.all_images[jmax + 1]] neb = NEB(toInterpolate) neb.interpolate(method=self.interpolate_method) tmp = self.all_images[:jmax + 1] tmp += toInterpolate[1:-1] tmp.extend(self.all_images[jmax + 1:]) self.all_images = tmp # Expect springs to be in equilibrium k_tmp = self.k[:jmax] k_tmp += [self.k[jmax] * 2] * 2 k_tmp.extend(self.k[jmax + 1:]) self.k = k_tmp # Run the NEB calculation with the new image included n_cur += 1 to_run, climb_safe = self.which_images_to_run_on() self.execute_one_neb(n_cur, to_run, climb=False) if self.world.rank == 0: print('n_max images has been reached') # Do a single climb around the top-point if requested if self.climb: if isinstance(self.k, (float, int)): self.k = [self.k] * (len(self.all_images) - 1) if self.world.rank == 0: print('****Now doing the CI-NEB calculation****') to_run, climb_safe = self.which_images_to_run_on() assert climb_safe, 'climb_safe should be true at this point!' self.execute_one_neb(n_cur, to_run, climb=True, many_steps=True) if not self.smooth_curve: return self.all_images # If a smooth_curve is requsted ajust the springs to follow two # gaussian distributions e = self.get_energies() peak = self.get_highest_energy_index() k_max = 10 d1 = np.linalg.norm(self.all_images[peak].get_positions() - self.all_images[0].get_positions()) d2 = np.linalg.norm(self.all_images[peak].get_positions() - self.all_images[-1].get_positions()) l1 = -d1 ** 2 / log(0.2) l2 = -d2 ** 2 / log(0.2) x1 = [] x2 = [] for i in range(peak): v = (self.all_images[i].get_positions() + self.all_images[i + 1].get_positions()) / 2 - \ self.all_images[0].get_positions() x1.append(np.linalg.norm(v)) for i in range(peak, len(self.all_images) - 1): v = (self.all_images[i].get_positions() + self.all_images[i + 1].get_positions()) / 2 - \ self.all_images[0].get_positions() x2.append(np.linalg.norm(v)) k_tmp = [] for x in x1: k_tmp.append(k_max * exp(-((x - d1) ** 2) / l1)) for x in x2: k_tmp.append(k_max * exp(-((x - d1) ** 2) / l2)) self.k = k_tmp # Roll back to start from the top-point if self.world.rank == 0: print('Now moving from top to start') highest_energy_index = self.get_highest_energy_index() nneb = highest_energy_index - self.n_simul - 1 while nneb >= 0: self.execute_one_neb(n_cur, range(nneb, nneb + self.n_simul + 2), climb=False) nneb -= 1 # Roll forward from the top-point until the end nneb = self.get_highest_energy_index() if self.world.rank == 0: print('Now moving from top to end') while nneb <= self.n_max - self.n_simul - 2: self.execute_one_neb(n_cur, range(nneb, nneb + self.n_simul + 2), climb=False) nneb += 1 return self.all_images
final = Atoms('HOHOH', positions=[(-sin(angle) * doht, 0., cos(angle) * doht), (0., 0., 0.), (0., 0., doo - doh), (0., 0., doo), (sin(angle) * doht, 0., doo - cos(angle) * doht)]) if 0: view(final) # Make band: images = [initial.copy()] for i in range(3): images.append(initial.copy()) images.append(final.copy()) neb = NEB(images, climb=True) # Set constraints and calculator: constraint = FixAtoms(indices=[1, 3]) # fix OO for image in images: image.set_calculator(EMT()) image.set_constraint(constraint) for image in images: # O-H(shared) distance print(image.get_distance(1, 2), image.get_potential_energy()) # Relax initial and final states: if 1: # XXX: Warning: # One would have to optimize more tightly in order to get # symmetric anion from both images[0] and [1], but
#optimise the initial state # Atom above step slab[-1].position = (x3,y2+1,z2+3.5) final = slab.copy() final.set_calculator(EMT()) relax = QuasiNewton(final) relax.run(fmax=0.05) view(final) #create a list of images for interpolation images = [initial] for i in range(nimages): images.append(initial.copy()) for image in images: image.set_calculator(EMT()) images.append(final) view(images) #carry out idpp interpolation neb = NEB(images) neb.interpolate('idpp') #Run NEB calculation qn = QuasiNewton(neb, trajectory='N_diffusion.traj', logfile='N_diffusion.log') qn.run(fmax=0.05)