def characteriseTSinternal(self, mol): os.chdir((self.workingDir + '/Raw/' + self.procNum)) if (self.lowMeth == 'nwchem'): mol = tl.setCalc(mol, self.lowString, 'nwchem2', self.lowLev) self.Reac.get_forces() else: mol = tl.setCalc(mol, self.lowString, self.lowMeth, self.lowLev) vib = Vibrations(mol) vib.clean() vib.run() viblist = vib.get_frequencies() print("getting vibs") TSFreqs, zpe = tl.getVibString(viblist, False, True) print("vibs done " + str(zpe)) imaginaryFreq = tl.getImageFreq(viblist) vib.clean() os.chdir((self.workingDir)) # Finally get single point energy mol = tl.setCalc(mol, self.singleString, self.singleMeth, self.singleLev) print("Getting single point energy for TS = " + str(mol.get_potential_energy()) + "zpe = " + str(zpe) + "reactant energy = " + str(self.reactantEnergy)) energy = mol.get_potential_energy() + zpe return TSFreqs, imaginaryFreq, zpe, energy
def neural_hessian_ase(ase_atoms): print("Calculating Numerical Hessian using ASE") vib = Vibrations(ase_atoms, delta=0.05) vib.run() vib.summary() hessian = np.array(vib.H) * (kcal/mol) * Bohr**2 vib.clean() return hessian
def characteriseFreqInternal(self, mol): os.chdir((self.workingDir + '/' + '/Raw/' + self.procNum)) vib = Vibrations(mol) vib.clean() vib.run() viblist = vib.get_frequencies() freqs, zpe = tl.getVibString(viblist, False, False) vib.clean() os.chdir((self.workingDir)) return freqs, zpe
def get_thermo_correction( self, coords: simtk.unit.quantity.Quantity) -> unit.quantity.Quantity: """ Returns the thermochemistry correction. This calls: https://wiki.fysik.dtu.dk/ase/ase/thermochemistry/thermochemistry.html and uses the Ideal gas rigid rotor harmonic oscillator approximation to calculate the Gibbs free energy correction that needs to be added to the single point energy to obtain the Gibb's free energy coords: [K][3] Raises: verror: if imaginary frequencies are detected a ValueError is raised Returns: float -- temperature correct [kT] """ if not (len(coords.shape) == 3 and coords.shape[2] == 3 and coords.shape[0] == 1): raise RuntimeError( f"Something is wrong with the shape of the provided coordinates: {coords.shape}. Only x.shape[0] == 1 is possible." ) ase_mol = copy.deepcopy(self.ase_mol) for atom, c in zip(ase_mol, coords[0]): atom.x = c[0].value_in_unit(unit.angstrom) atom.y = c[1].value_in_unit(unit.angstrom) atom.z = c[2].value_in_unit(unit.angstrom) calculator = self.model.ase() ase_mol.set_calculator(calculator) vib = Vibrations(ase_mol, name=f"/tmp/vib{random.randint(1,10000000)}") vib.run() vib_energies = vib.get_energies() thermo = IdealGasThermo( vib_energies=vib_energies, atoms=ase_mol, geometry="nonlinear", symmetrynumber=1, spin=0, ) try: G = thermo.get_gibbs_energy( temperature=temperature.value_in_unit(unit.kelvin), pressure=pressure.value_in_unit(unit.pascal), ) except ValueError as verror: logger.critical(verror) vib.clean() raise verror # removes the vib tmp files vib.clean() return ( G * eV_to_kJ_mol ) * unit.kilojoule_per_mole # eV * conversion_factor(eV to kJ/mol)
def test_vib(): import os from ase import Atoms from ase.calculators.emt import EMT from ase.optimize import QuasiNewton from ase.vibrations import Vibrations from ase.thermochemistry import IdealGasThermo n2 = Atoms('N2', positions=[(0, 0, 0), (0, 0, 1.1)], calculator=EMT()) QuasiNewton(n2).run(fmax=0.01) vib = Vibrations(n2) vib.run() freqs = vib.get_frequencies() print(freqs) vib.summary() print(vib.get_mode(-1)) vib.write_mode(n=None, nimages=20) vib_energies = vib.get_energies() for image in vib.iterimages(): assert len(image) == 2 thermo = IdealGasThermo(vib_energies=vib_energies, geometry='linear', atoms=n2, symmetrynumber=2, spin=0) thermo.get_gibbs_energy(temperature=298.15, pressure=2 * 101325.) assert vib.clean(empty_files=True) == 0 assert vib.clean() == 13 assert len(list(vib.iterimages())) == 13 d = dict(vib.iterdisplace(inplace=False)) for name, atoms in vib.iterdisplace(inplace=True): assert d[name] == atoms vib = Vibrations(n2) vib.run() assert vib.combine() == 13 assert (freqs == vib.get_frequencies()).all() vib = Vibrations(n2) assert vib.split() == 1 assert (freqs == vib.get_frequencies()).all() assert vib.combine() == 13 # Read the data from other working directory dirname = os.path.basename(os.getcwd()) os.chdir('..') # Change working directory vib = Vibrations(n2, name=os.path.join(dirname, 'vib')) assert (freqs == vib.get_frequencies()).all() assert vib.clean() == 1
def get_modes(self,atm,freqname="vib."): for f in [f for f in os.listdir(".") if freqname in f and '.pckl' in f]: os.remove(f) new_target = open(os.devnull, "w") old_target, sys.stdout = sys.stdout, new_target atm.set_calculator(ANIENS(self.ens)) vib = Vibrations(atm, nfree=2, name=freqname) vib.run() freq = vib.get_frequencies() modes = np.stack(vib.get_mode(i) for i in range(freq.size)) vib.clean() sys.stdout = old_target return modes
def test_pickle_manipulation(self, n2_emt): atoms = n2_emt vib = Vibrations(atoms, name='interrupt') vib.run() disp_file = 'interrupt.1x-.pckl' comb_file = 'interrupt.all.pckl' assert os.path.isfile(disp_file) assert not os.path.isfile(comb_file) with pytest.raises(RuntimeError): vib.split() # Build a combined file assert vib.combine() == 13 # Individual displacements should be gone, combination should exist assert not os.path.isfile(disp_file) assert os.path.isfile(comb_file) # Not allowed to run after data has been combined with pytest.raises(RuntimeError): vib.run() # But reading is allowed vib.read() # Splitting should fail if any split file already exists with open(disp_file, 'w') as f: f.write("hello") with pytest.raises(RuntimeError): vib.split() os.remove(disp_file) # Now split() for real: replace .all.pckl file with displacements vib.split() assert os.path.isfile(disp_file) assert not os.path.isfile(comb_file) # Not allowed to clobber existing combined file with open(comb_file, 'w') as f: f.write("Hello") with pytest.raises(RuntimeError): vib.combine() os.remove(comb_file) # Combining data also fails if some data is missing os.remove('interrupt.1x-.pckl') with pytest.raises(RuntimeError): vib.combine() vib.clean()
def test_vibrations_methods(self, testdir, random_dimer): vib = Vibrations(random_dimer) vib.run() vib_energies = vib.get_energies() for image in vib.iterimages(): assert len(image) == 2 thermo = IdealGasThermo(vib_energies=vib_energies, geometry='linear', atoms=vib.atoms, symmetrynumber=2, spin=0) thermo.get_gibbs_energy(temperature=298.15, pressure=2 * 101325., verbose=False) with open(self.logfile, 'w') as fd: vib.summary(log=fd) with open(self.logfile, 'rt') as fd: log_txt = fd.read() assert log_txt == '\n'.join( VibrationsData._tabulate_from_energies(vib_energies)) + '\n' last_mode = vib.get_mode(-1) scale = 0.5 assert_array_almost_equal( vib.show_as_force(-1, scale=scale, show=False).get_forces(), last_mode * 3 * len(vib.atoms) * scale) vib.write_mode(n=3, nimages=5) for i in range(3): assert not Path('vib.{}.traj'.format(i)).is_file() mode_traj = ase.io.read('vib.3.traj', index=':') assert len(mode_traj) == 5 assert_array_almost_equal(mode_traj[0].get_all_distances(), random_dimer.get_all_distances()) with pytest.raises(AssertionError): assert_array_almost_equal(mode_traj[4].get_all_distances(), random_dimer.get_all_distances()) assert vib.clean(empty_files=True) == 0 assert vib.clean() == 13 assert len(list(vib.iterimages())) == 13 d = dict(vib.iterdisplace(inplace=False)) for name, image in vib.iterdisplace(inplace=True): assert d[name] == random_dimer
def test_vibrations_restart_dir(self, testdir, random_dimer): vib = Vibrations(random_dimer) vib.run() freqs = vib.get_frequencies() assert freqs is not None # write/read the data from another working directory atoms = random_dimer.copy() # This copy() removes the Calculator with ase.utils.workdir('run_from_here', mkdir=True): vib = Vibrations(atoms, name=str(Path.cwd().parent / 'vib')) assert_array_almost_equal(freqs, vib.get_frequencies()) assert vib.clean() == 13
def characteriseMinInternal(self, mol): os.chdir((self.workingDir + '/' + '/Raw/' + self.procNum)) if (self.lowMeth == 'nwchem'): mol = tl.setCalc(mol, self.lowString, 'nwchem2', self.lowLev) self.Reac.get_forces() else: mol = tl.setCalc(mol, self.lowString, self.lowMeth, self.lowLev) min = BFGS(mol) min.run(fmax=0.05, steps=50) vib = Vibrations(mol) vib.clean() vib.run() viblist = vib.get_frequencies() Freqs, zpe = tl.getVibString(viblist, False, False) vib.clean() os.chdir((self.workingDir)) # Finally get single point energy mol = tl.setCalc(mol, self.singleString, self.singleMeth, self.singleLev) print("Getting single point energy for TS = " + str(mol.get_potential_energy()) + "zpe = " + str(zpe) + "reactant energy = " + str(self.reactantEnergy)) energy = mol.get_potential_energy() + zpe return Freqs, energy, mol
slab = fcc111('Al', size=(2, 2, 2), vacuum=3.0) CH3 = molecule('CH3') add_adsorbate(slab, CH3, 2.5, 'ontop') constraint = FixAtoms(mask=[a.symbol == 'Al' for a in slab]) slab.set_constraint(constraint) slab.set_calculator(EMT()) dyn = QuasiNewton(slab, logfile='/dev/null') dyn.run(fmax=0.05) vib = Vibrations(slab, indices=[8, 9, 10, 11]) vib.run() vib.summary(log='/dev/null') vib.clean() AM = AnharmonicModes(vibrations_object=vib) rot_mode = AM.define_rotation( basepos=[0., 0., -1.], branch=[9, 10, 11], symnumber=3) AM.run() AM.summary(log='/dev/null') AM.clean() # print(AM.get_ZPE(), AM.get_entropic_energy()) assert abs(AM.get_ZPE() - 0.388) < 1e-3, AM.get_ZPE() assert abs(AM.get_entropic_energy() - (0.091)) < 1e-3, ( AM.get_entropic_energy())
slab = fcc111('Au', size=(2, 2, 2), vacuum=4.0) H = molecule('H') add_adsorbate(slab, H, 3.0, 'ontop') constraint = FixAtoms(mask=[a.symbol == 'Au' for a in slab]) slab.set_constraint(constraint) slab.set_calculator(EMT()) QuasiNewton(slab).run(fmax=0.001) vib = Vibrations(slab, indices=[8]) vib.run() vib.summary() vib.clean() AM = AnharmonicModes(vibrations_object=vib, settings={ 'plot_mode': True, }) for i in range(len(vib.hnu)): AM.define_vibration(mode_number=-1) AM.inspect_anmodes() AM.run() AM.summary() AM.clean() print(AM.get_ZPE(), AM.get_entropic_energy()) # assert abs(AM.get_ZPE() - 0.243) < 1e-3, AM.get_ZPE()
from ase.vibrations import Vibrations from ase.thermochemistry import IdealGasThermo n2 = Atoms('N2', positions=[(0, 0, 0), (0, 0, 1.1)], calculator=EMT()) QuasiNewton(n2).run(fmax=0.01) vib = Vibrations(n2) vib.run() print(vib.get_frequencies()) vib.summary() print(vib.get_mode(-1)) vib.write_mode(n=None, nimages=20) vib_energies = vib.get_energies() for image in vib.iterimages(): assert len(image) == 2 thermo = IdealGasThermo(vib_energies=vib_energies, geometry='linear', atoms=n2, symmetrynumber=2, spin=0) thermo.get_gibbs_energy(temperature=298.15, pressure=2 * 101325.) assert vib.clean(empty_files=True) == 0 assert vib.clean() == 13 assert len(list(vib.iterimages())) == 13 d = dict(vib.iterdisplace(inplace=False)) for name, atoms in vib.iterdisplace(inplace=True): assert d[name] == atoms
def test_vibrations(self, testdir, n2_emt, n2_optimized): atoms = n2_emt vib = Vibrations(atoms) vib.run() freqs = vib.get_frequencies() vib.write_mode(n=None, nimages=5) vib.write_jmol() vib_energies = vib.get_energies() for image in vib.iterimages(): assert len(image) == 2 thermo = IdealGasThermo(vib_energies=vib_energies, geometry='linear', atoms=atoms, symmetrynumber=2, spin=0) thermo.get_gibbs_energy(temperature=298.15, pressure=2 * 101325., verbose=False) vib.summary(log=self.logfile) with open(self.logfile, 'rt') as f: log_txt = f.read() assert log_txt == vibrations_n2_log mode1 = vib.get_mode(-1) assert_array_almost_equal(mode1, [[0., 0., -0.188935], [0., 0., 0.188935]]) assert_array_almost_equal( vib.show_as_force(-1, show=False).get_forces(), [[0., 0., -2.26722e-1], [0., 0., 2.26722e-1]]) for i in range(3): assert not os.path.isfile('vib.{}.traj'.format(i)) mode_traj = ase.io.read('vib.3.traj', index=':') assert len(mode_traj) == 5 assert_array_almost_equal(mode_traj[0].get_all_distances(), atoms.get_all_distances()) with pytest.raises(AssertionError): assert_array_almost_equal(mode_traj[4].get_all_distances(), atoms.get_all_distances()) with open('vib.xyz', 'rt') as f: jmol_txt = f.read() assert jmol_txt == jmol_txt_ref assert vib.clean(empty_files=True) == 0 assert vib.clean() == 13 assert len(list(vib.iterimages())) == 13 d = dict(vib.iterdisplace(inplace=False)) for name, image in vib.iterdisplace(inplace=True): assert d[name] == atoms atoms2 = n2_emt vib2 = Vibrations(atoms2) vib2.run() assert_array_almost_equal(freqs, vib.get_frequencies()) # write/read the data from another working directory atoms3 = n2_optimized.copy() # No calculator needed! workdir = os.path.abspath(os.path.curdir) try: os.mkdir('run_from_here') os.chdir('run_from_here') vib = Vibrations(atoms3, name=os.path.join(os.pardir, 'vib')) assert_array_almost_equal(freqs, vib.get_frequencies()) assert vib.clean() == 13 finally: os.chdir(workdir) if os.path.isdir('run_from_here'): os.rmdir('run_from_here')
def vibrate(self, atoms: Atoms, indices: list, read_only=False): ''' This method uses ase.vibrations module, see more for info. User provides the FHI-aims parameters, the Atoms object and list of indices of atoms to be vibrated. Variables related to FHI-aims are governed by the React object. Calculation folders are generated automatically and a sockets calculator is used for efficiency. Work in progress Args: atoms: Atoms object indices: list List of indices of atoms that require vibrations read_only: bool Flag for postprocessing - if True, the method only extracts information from existing files, no calculations are performed Returns: Zero-Point Energy: float ''' '''Retrieve common properties''' basis_set = self.basis_set hpc = self.hpc params = self.params parent_dir = os.getcwd() dimensions = sum(atoms.pbc) if not self.filename: '''develop a naming scheme based on chemical formula''' self.filename = atoms.get_chemical_formula() vib_dir = parent_dir + "/VibData_" + self.filename + "/Vibs" print(vib_dir) vib = Vibrations(atoms, indices=indices, name=vib_dir) '''If a calculation was terminated prematurely (e.g. time limit) empty .json files remain and the calculation of the corresponding stretch modes would be skipped on restart. The line below prevents this''' vib.clean(empty_files=True) '''Extract vibration data from existing files''' if read_only: vib.read() else: '''Calculate required vibration modes''' required_cache = [ os.path.join(vib_dir, "cache." + str(x) + y + ".json") for x in indices for y in ["x+", "x-", "y+", "y-", "y-", "z+", "z-"] ] check_required_modes_files = np.array( [os.path.exists(file) for file in required_cache]) if np.all(check_required_modes_files == True): vib.read() else: '''Set the environment variables for geometry optimisation''' set_aims_command(hpc=hpc, basis_set=basis_set, defaults=2020, nodes_per_instance=self.nodes_per_instance) '''Generate a unique folder for aims calculation''' counter, subdirectory_name = self._restart_setup( "Vib", filename=self.filename, restart=False, verbose=False) os.makedirs(subdirectory_name, exist_ok=True) os.chdir(subdirectory_name) '''Name the aims output file''' out = str(counter) + "_" + str(self.filename) + ".out" '''Calculate vibrations and write the in a separate directory''' with _calc_generator(params, out_fn=out, dimensions=dimensions)[0] as calculator: if not self.dry_run: atoms.calc = calculator else: atoms.calc = EMT() vib = Vibrations(atoms, indices=indices, name=vib_dir) vib.run() vib.summary() '''Generate a unique folder for aims calculation''' if not read_only: os.chdir(vib_dir) vib.write_mode() os.chdir(parent_dir) return vib.get_zero_point_energy()
from __future__ import print_function from ase import Atoms from ase.calculators.emt import EMT from ase.optimize import QuasiNewton from ase.vibrations import Vibrations from ase.thermochemistry import IdealGasThermo n2 = Atoms('N2', positions=[(0, 0, 0), (0, 0, 1.1)], calculator=EMT()) QuasiNewton(n2).run(fmax=0.01) vib = Vibrations(n2) vib.run() print(vib.get_frequencies()) vib.summary() print(vib.get_mode(-1)) vib.write_mode(n=None, nimages=20) vib_energies = vib.get_energies() thermo = IdealGasThermo(vib_energies=vib_energies, geometry='linear', atoms=n2, symmetrynumber=2, spin=0) thermo.get_gibbs_energy(temperature=298.15, pressure=2 * 101325.) assert vib.clean(empty_files=True) == 0 assert vib.clean() == 13