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 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 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 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 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 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 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 _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 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 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)
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 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 run_NEB(): if method == 'dyn': neb = NEB(images, fmax=fmax, dynamic_relaxation=True) neb.interpolate() elif method == 'dyn_scale': neb = NEB(images, fmax=fmax, dynamic_relaxation=True, scale_fmax=6.) neb.interpolate() else: # Default NEB neb = NEB(images) neb.interpolate() # Optimize and check number of calculations. # We use a hack with a global counter to count the force evaluations: force_evaluations[0] = 0 opt = BFGS(neb) opt.run(fmax=fmax) force_calls.append(force_evaluations[0]) # Get potential energy of transition state. Emax.append( np.sort([image.get_potential_energy() for image in images[1:-1]])[-1])
def interpolate(images, n=10): ''' Interpolate linearly the potisions of the middle temp: ''' from ase.neb import NEB if len(images) == 2: new_images = [images[0]] for i in range(n): new_images.append(images[0].copy()) new_images.append(images[1]) neb = NEB(new_images) neb.interpolate() return new_images elif len(images) == 3: new_images1 = [images[0]] for i in range(n): new_images.append(images[0].copy()) new_images.append(images[1]) neb = NEB(new_images1) neb.interpolate() new_images = neb.images.copy() # new_images2 = [images[1]] for i in range(n): new_images.append(images[1].copy()) new_images.append(images[2]) neb = NEB(new_images2) neb.interpolate() new_images.extend(neb.images) return new_images
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())
from ase.io import read from ase.constraints import FixAtoms from ase.neb import NEB from JDFTx import JDFTx from ase.optimize import BFGS from ase.parallel import rank, size initial = read('initial.traj') final = read('final.traj') constraint = FixAtoms(mask=[atom.tag > 1 for atom in initial]) images = [initial] for i in range(3): image = initial.copy() image.set_calculator(JDFTx(executable='mpirun -n 1 -N 1 -c 12 --exclude=node[1001-1032] /home/jfm343/JDFTXDIR/build/jdftx', pseudoDir='/home/jfm343/JDFTXDIR/build/pseudopotentials',pseudoSet='GBRV-pbe',commands={'elec-cutoff' : '20 100','kpoint-folding' : '2 2 1'})) image.set_constraint(constraint) images.append(image) images.append(final) neb = NEB(images, parallel=True) neb.interpolate() qn = BFGS(neb, trajectory='neb.traj') qn.run(fmax=0.05)
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
# 2.A. NEB using ASE ######################################################### initial_ase = read('initial_opt.traj') final_ase = read('final_opt.traj') constraint = FixAtoms(mask=[atom.tag > 1 for atom in initial_ase]) images_ase = [initial_ase] for i in range(1, n_images - 1): 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')
# 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 error = os.system('ase-gui mep.traj@-7:') assert error == 0
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)
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 # 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()) dyn = BFGS(neb, trajectory='emt_h3o2m.traj') dyn.run(fmax=0.05) for image in images: print(image.get_distance(1, 2), image.get_potential_energy())
#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)
class Exchange(SiestaBarriersBase): """ """ def __init__( self, host_structure, number_of_images, trace_atom_initial_position, trace_atom_final_position, exchange_direction='xyz', tolerance_radius=[0.5, 0.5, 0.5], ghost=False, interpolation_method='idpp', ): super().__init__( neb_scheme='exchange', relaxed=False, host_structure=host_structure, initial_relaxed_path=None, initial_relaxed_fdf_name=None, final_relaxed_path=None, final_relaxed_fdf_name=None, trace_atom_initial_position=trace_atom_initial_position, trace_atom_final_position=trace_atom_final_position, atol=1e-2, rtol=1e-2) self.host_structure = host_structure self.number_of_images = number_of_images self.tolerance_radius = tolerance_radius self.trace_atom_initial_position = trace_atom_initial_position self.trace_atom_final_position = trace_atom_final_position self.exchange_direction = exchange_direction self.tolerance_radius = tolerance_radius self.ghost = ghost self.interpolation_method = interpolation_method #--------------------------------------------------------- # Main Methods #--------------------------------------------------------- def Generate_Exchange_Images(self): """ """ from .Utils.utils_siesta import read_siesta_fdf, read_siesta_XV from .Utils.utils_exchange import pre_prepare_sisl, is_frac_or_cart_or_index, pre_prepare_ase_after_relax_AA, pre_prepare_ase_after_relax_AB, pre_prepare_ase_after_relax_A, pre_prepare_ase_after_relax_B import os import glob, shutil import numpy as np import sys from .BarriersIO import SiestaBarriersIO import sisl from ase.neb import NEB if self.relaxed == True: print("=================================================") print(" The Relaxed Exchange Image Generation ... ") print("=================================================") #self.host_structure = read_siesta_fdf(self.host_path,self.host_fdf_name) self.initial_structure = read_siesta_XV( self.initial_relaxed_path, self.initial_relaxed_fdf_name) self.final_structure = read_siesta_XV(self.final_relaxed_path, self.final_relaxed_fdf_name) if self.check_AA_or_AB() == True: self.test_A = pre_prepare_ase_after_relax_A( self.initial_structure['XV'], self.final_structure['XV']) self.test_B = pre_prepare_ase_after_relax_B( self.initial_structure['XV'], self.final_structure['XV']) else: #print ("Not Implemented Yet!") self.test_A = pre_prepare_ase_after_relax_A( self.initial_structure['XV'], self.final_structure['XV']) self.test_B = pre_prepare_ase_after_relax_B( self.initial_structure['XV'], self.final_structure['XV']) initial_A = sisl.Geometry.toASE(self.test_A['initial']) final_A = sisl.Geometry.toASE(self.test_A['final']) initial_B = sisl.Geometry.toASE(self.test_B['initial']) final_B = sisl.Geometry.toASE(self.test_B['final']) else: print("=================================================") print(" The Initial Exchange Image Generation ... ") print("=================================================") frac_or_cart_or_index = is_frac_or_cart_or_index( self.trace_atom_initial_position) self.test = pre_prepare_sisl( frac_or_cart_or_index, self.host_structure, self.trace_atom_initial_position, self.trace_atom_final_position, self.rtol, self.atol, ) initial = sisl.Geometry.toASE(self.test['initial']) final = sisl.Geometry.toASE(self.test['final']) self.initial_structure = {} self.final_structure = {} self.initial_structure['XV'] = self.test['initial'] self.final_structure['XV'] = self.test['final'] self.check_AA_or_AB() #%%***************************************************************** #%% Do the Image Creation with ASE Here #%%***************************************************************** if self.relaxed == True: print("NEB Interpolation for : Relaxed Structures") print("Copying ASE For NEB Image 0 : initial image ") self.images_A = [initial_A] self.images_B = [initial_B] for i in range(self.number_of_images): print("Copying ASE For NEB Image {} : images ".format(i + 1)) self.images_A.append(initial_A.copy()) self.images_B.append(initial_B.copy()) self.images_A.append(final_A) self.images_B.append(final_B) print("Copying ASE For NEB Image {} : final image".format(i + 2)) #%% self.neb_A = NEB(self.images_A) self.neb_B = NEB(self.images_B) self.neb_A.interpolate(self.interpolation_method) self.neb_B.interpolate(self.interpolation_method) self.sisl_images_A = [] self.sisl_images_B = [] for i in range(self.number_of_images + 2): self.sisl_images_A.append( sisl.Geometry.fromASE(self.images_A[i])) self.sisl_images_B.append( sisl.Geometry.fromASE(self.images_B[i])) #------------------------------------------------------------------- # For Exchange #------------------------------------------------------------------- moving_specie_A = {} moving_specie_B = {} for i in range(len(self.sisl_images_A)): moving_specie_A[i] = sisl.Geometry( self.sisl_images_A[i].xyz[-1], atoms=self.sisl_images_A[i].atoms.Z[-1]) moving_specie_B[i] = sisl.Geometry( self.sisl_images_B[i].xyz[-1], atoms=self.sisl_images_B[i].atoms.Z[-1]) ni_list = [] for i in range(self.number_of_images + 2): ni_list.append(int(i)) ni_list.sort(reverse=True) j = 0 #for i in ni_list: # #moving_specie_B[j] = sisl.Geometry(moving_specie_A[i].xyz,atoms=self.test['trace_atom_B_initial'].atoms.Z) # moving_specie_B[j] = sisl.Geometry(moving_specie_A[i].xyz,atoms=self.test_B['trace_atom_B_initial'].atoms.Z) # j = j+1 #moving_specie_B[0].xyz = self.test_B['trace_atom_B_initial'].xyz #moving_specie_B[self.number_of_images+2] = self.test['trace_atom_B_final'].xyz d = moving_specie_B[0].xyz - moving_specie_A[0].xyz d = d.reshape(3, ) dsq = d**2 dsum = np.sum(dsq) dsum = np.sqrt(dsum) ToleranceRadius = self.tolerance_radius #ToleranceRadius= np.array([-1.5,1.5,0.0]) #Ang print("d", d) print("dsum", dsum) print("Tolernace Radius :{}".format(self.tolerance_radius)) Migration_Direction = self.exchange_direction NumberOfImages = self.number_of_images if Migration_Direction.lower() == "x": d[0] = d[0] + dsum + ToleranceRadius[0] Steps = d / NumberOfImages print("Migration Direction Axis: x") if Migration_Direction.lower() == "y": d[1] = d[1] + dsum + ToleranceRadius[1] Steps = d / NumberOfImages print("Migration Direction Axis: y") if Migration_Direction.lower() == "z": d[2] = d[2] + dsum + ToleranceRadius[2] Steps = d / NumberOfImages print("Migration Direction Axis: z") if Migration_Direction.lower() == "xy": d[0] = d[0] + dsum + ToleranceRadius[0] d[1] = d[1] + dsum + ToleranceRadius[1] Steps = d / NumberOfImages print("Migration Direction Plane: xy") if Migration_Direction.lower() == "xz": d[0] = d[0] + dsum + ToleranceRadius[0] d[2] = d[2] + dsum + ToleranceRadius[2] Steps = d / NumberOfImages print("Migration Direction Plane: xz") if Migration_Direction.lower() == "yz": d[1] = d[1] + dsum + ToleranceRadius[1] d[2] = d[2] + dsum + ToleranceRadius[2] Steps = d / NumberOfImages print("Migration Direction Plane: yz") if Migration_Direction.lower() == "xyz": d[0] = d[0] + dsum + ToleranceRadius[0] d[1] = d[1] + dsum + ToleranceRadius[1] d[2] = d[2] + dsum + ToleranceRadius[2] Steps = d / NumberOfImages print("Migration Direction Volume: xyz") for l in range(1, NumberOfImages + 1): print("Atom A ", l, moving_specie_A[l].xyz + Steps) moving_specie_A[l].xyz = moving_specie_A[l].xyz + Steps for l in range(1, NumberOfImages + 1): print("Atom B ", l, moving_specie_B[l].xyz - Steps) moving_specie_B[l].xyz = moving_specie_B[l].xyz - Steps #print("DEBUG: {}".format(moving_specie_B[self.number_of_images+2])) #moving_specie_B[self.number_of_images+2] = self.test['trace_atom_B_final'].xyz #print("DEBUG: {}".format(moving_specie_B[self.number_of_images+2])) for k in range(self.number_of_images + 2): self.sisl_images_A[k] = self.sisl_images_A[k].remove([-1]) print(" Putting Specie A & B in Sisl Geometry Object ") for i in range(self.number_of_images + 2): self.sisl_images_A[i] = self.sisl_images_A[i].add( moving_specie_A[i]) self.sisl_images_A[i] = self.sisl_images_A[i].add( moving_specie_B[i]) self.sisl_images = self.sisl_images_A else: print("NEB Interpolation for : UnRelaxed Structures") print("Copying ASE For NEB Image 0 : initial image ") self.images = [initial] for i in range(self.number_of_images): print("Copying ASE For NEB Image {} : images ".format(i + 1)) self.images.append(initial.copy()) self.images.append(final) print("Copying ASE For NEB Image {} : final image".format(i + 2)) #%% self.neb = NEB(self.images) self.neb.interpolate(self.interpolation_method) self.sisl_images = [] for i in range(self.number_of_images + 2): self.sisl_images.append(sisl.Geometry.fromASE(self.images[i])) #------------------------------------------------------------------- # For Exchange #------------------------------------------------------------------- moving_specie_A = {} moving_specie_B = {} for i in range(len(self.sisl_images)): moving_specie_A[i] = sisl.Geometry( self.sisl_images[i].xyz[-1], atoms=self.sisl_images[i].atoms.Z[-1]) ni_list = [] for i in range(self.number_of_images + 2): ni_list.append(int(i)) ni_list.sort(reverse=True) j = 0 for i in ni_list: moving_specie_B[j] = sisl.Geometry( moving_specie_A[i].xyz, atoms=self.test['trace_atom_B_initial'].atoms.Z) #moving_specie_B[j] = sisl.Geometry(moving_specie_A[i].xyz,atoms=self.test['trace_atom_B_initial'].atoms.Z) j = j + 1 #moving_specie_B[0].xyz = self.test['trace_atom_B_initial'].xyz #moving_specie_B[self.number_of_images+2] = self.test['trace_atom_B_final'].xyz d = moving_specie_B[0].xyz - moving_specie_A[0].xyz d = d.reshape(3, ) dsq = d**2 dsum = np.sum(dsq) dsum = np.sqrt(dsum) ToleranceRadius = self.tolerance_radius #ToleranceRadius= np.array([-1.5,1.5,0.0]) #Ang print("d", d) print("dsum", dsum) print("Tolernace Radius :{}".format(self.tolerance_radius)) Migration_Direction = self.exchange_direction NumberOfImages = self.number_of_images if Migration_Direction.lower() == "x": d[0] = d[0] + dsum + ToleranceRadius[0] Steps = d / NumberOfImages print("Migration Direction Axis: x") if Migration_Direction.lower() == "y": d[1] = d[1] + dsum + ToleranceRadius[1] Steps = d / NumberOfImages print("Migration Direction Axis: y") if Migration_Direction.lower() == "z": d[2] = d[2] + dsum + ToleranceRadius[2] Steps = d / NumberOfImages print("Migration Direction Axis: z") if Migration_Direction.lower() == "xy": d[0] = d[0] + dsum + ToleranceRadius[0] d[1] = d[1] + dsum + ToleranceRadius[1] Steps = d / NumberOfImages print("Migration Direction Plane: xy") if Migration_Direction.lower() == "xz": d[0] = d[0] + dsum + ToleranceRadius[0] d[2] = d[2] + dsum + ToleranceRadius[2] Steps = d / NumberOfImages print("Migration Direction Plane: xz") if Migration_Direction.lower() == "yz": d[1] = d[1] + dsum + ToleranceRadius[1] d[2] = d[2] + dsum + ToleranceRadius[2] Steps = d / NumberOfImages print("Migration Direction Plane: yz") if Migration_Direction.lower() == "xyz": d[0] = d[0] + dsum + ToleranceRadius[0] d[1] = d[1] + dsum + ToleranceRadius[1] d[2] = d[2] + dsum + ToleranceRadius[2] Steps = d / NumberOfImages print("Migration Direction Volume: xyz") for l in range(1, NumberOfImages + 1): print("Atom A ", l, moving_specie_A[l].xyz + Steps) moving_specie_A[l].xyz = moving_specie_A[l].xyz + Steps for l in range(1, NumberOfImages + 1): print("Atom B ", l, moving_specie_B[l].xyz - Steps) moving_specie_B[l].xyz = moving_specie_B[l].xyz - Steps #print("DEBUG: {}".format(moving_specie_B[self.number_of_images+2])) #moving_specie_B[self.number_of_images+2] = self.test['trace_atom_B_final'].xyz #print("DEBUG: {}".format(moving_specie_B[self.number_of_images+2])) for k in range(self.number_of_images + 2): self.sisl_images[k] = self.sisl_images[k].remove([-1]) print(" Putting Specie A & B in Sisl Geometry Object ") for i in range(self.number_of_images + 2): self.sisl_images[i] = self.sisl_images[i].add( moving_specie_A[i]) self.sisl_images[i] = self.sisl_images[i].add( moving_specie_B[i]) self.IO = SiestaBarriersIO( neb_type='exchange', sisl_images=self.sisl_images, flos_path=self.flos_path, flos_file_name_relax=self.flos_file_name_relax, flos_file_name_neb=self.flos_file_name_neb, number_of_images=self.number_of_images, initial_relaxed_path=self.initial_relaxed_path, initial_relaxed_fdf_name=self.initial_relaxed_fdf_name, final_relaxed_path=self.final_relaxed_path, final_relaxed_fdf_name=self.final_relaxed_fdf_name, relax_engine=self.relax_engine, relaxed=self.relaxed, ghost=self.ghost, ) def NEB_Results(self): """ """ self.IO = SiestaBarriersIO( self.sisl_images, self.flos_path, self.flos_file_name_relax, self.flos_file_name_neb, self.number_of_images, self.initial_relaxed_path, self.final_relaxed_path, self.relax_engine, self.relaxed, self.ghost, self.initial_relaxed_fdf_name, self.final_relaxed_fdf_name, self.neb_results_path) #========================================================================= # Checking Methods #========================================================================= def check_ghost(self): """ """ for i in self.initial_structure['XV'].atoms.Z: if i < 0: self.ghost = True print("There are ghost Species in 'XV'!") def check_AA_or_AB(self): """ """ from .Utils.utils_siestabarrier import is_frac_or_cart_or_index if self.relaxed: if self.initial_structure['XV'].atoms.Z[ -1] == self.initial_structure['XV'].atoms.Z[-2]: print("!----------------------------------!") print("The Exchange Species Are Same Atoms!") print("!----------------------------------!") return True else: print("!----------------------------------!") print("The Exchange Species Are Different Atoms!") print("!----------------------------------!") return False else: print("DEBUG:") if self.test['trace_atom_A_initial'].atoms.Z[0] == self.test[ 'trace_atom_B_initial'].atoms.Z[0]: print("!----------------------------------!") print("The Exchange Species Are Same Atoms!") print("!----------------------------------!") else: print("!----------------------------------!") print("The Exchange Species Are Different Atoms!") print("!----------------------------------!")
from ase.optimize.fire import FIRE as QuasiNewton # Optimise molecule. initial = molecule('C2H6') initial.calc = EMT() relax = QuasiNewton(initial) relax.run(fmax=0.05) # Create final state. final = initial.copy() 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) # Run IDPP interpolation. neb = NEB(images) neb.interpolate('idpp') # Run NEB calculation. qn = QuasiNewton(neb, trajectory='ethane_idpp.traj', logfile='ethane_idpp.log') qn.run(fmax=0.05)
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
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
import numpy as np from ase.io import read from ase.constraints import FixAtoms from ase.calculators.emt import EMT from ase.neb import NEB from ase.optimize.fire import FIRE as QuasiNewton initial = read('N2.traj') final = read('2N.traj') configs = [initial.copy() for i in range(8)] + [final] constraint = FixAtoms(mask=[atom.symbol != 'N' for atom in initial]) for config in configs: config.set_calculator(EMT()) config.set_constraint(constraint) band = NEB(configs) band.interpolate() # Create a quickmin object: relax = QuasiNewton(band) relax.run(steps=20) e0 = initial.get_potential_energy() for config in configs: d = config[-2].position - config[-1].position print np.linalg.norm(d), config.get_potential_energy() - e0
def optNEB(self, trans, path, changePoints, mols): # Open files for saving IRCdata xyzfile3 = open((path + "/IRC3.xyz"), "w") MEP = open((path + "/MEP.txt"), "w") imagesTemp1 = [] index = changePoints[0] - 100 molTemp = mols[index].copy() imagesTemp1.append(molTemp.copy()) for i in range(0, 100): imagesTemp1.append(mols[changePoints[0] - 100].copy()) try: imagesTemp1.append(mols[changePoints[-1] + 300]) except: imagesTemp1.append(self.CombProd.copy()) neb1 = NEB(imagesTemp1, k=1.0, remove_rotation_and_translation=True) try: neb1.interpolate('idpp') except: neb1.interpolate() for i in range(0, len(imagesTemp1)): try: imagesTemp1[i] = tl.setCalc(imagesTemp1[i], self.lowString, self.lowMeth, self.lowLev) for i in range(0, len(trans)): c = FixAtoms(trans) imagesTemp1[i].set_constraint(c) min = BFGS(imagesTemp1[i]) min.run(fmax=0.005, steps=40) del imagesTemp1[i].constraints except: pass optimizer = FIRE(neb1) try: optimizer.run(fmax=0.07, steps=300) except: pass print("passed seccond neb") neb1_2 = NEB(imagesTemp1, k=0.01, remove_rotation_and_translation=True) try: optimizer.run(fmax=0.07, steps=200) except: pass neb2 = NEB(imagesTemp1, climb=True, remove_rotation_and_translation=True) try: optimizer.run(fmax=0.07, steps=200) except: pass for i in range(0, len(imagesTemp1)): tl.printTraj(xyzfile3, imagesTemp1[i]) print("NEB printed") xyzfile3.close() point = 0 maxEne = -50000000 try: for i in range(0, len(imagesTemp1)): MEP.write( str(i) + ' ' + str(imagesTemp1[i].get_potential_energy()) + '\n') if imagesTemp1[i].get_potential_energy() > maxEne and i > 5: point = i maxEne = imagesTemp1[i].get_potential_energy() self.TS2 = imagesTemp1[point] except: point = 0 print("TS Climb part") write(path + '/TSClimbGuess.xyz', self.TS2) try: self.TS2Freqs, self.imaginaryFreq2, zpe, energy, self.TS2, rmol, pmol = self.characteriseTSExt( self.TS2, False, path, self.QTS3) except: self.TS2Freqs, self.imaginaryFreq2, zpe, energy, self.TS2, rmol, pmol = self.characteriseTSExt( self.TS2, True, path, self.QTS3) self.TScorrect = self.compareRandP(rmol, pmol) self.forwardBarrier2 = energy + zpe