def GibbsAds(energy, frequencies, T): #Expecting T in Kelvin #note that frequencies should have a lower bound, e.g. 56 cm-1, in order to bound entropic contributions. cm_to_eV = 1.23981e-4 vib_energies = list(frequencies) for i in range(len(vib_energies)): vib_energies[i] = vib_energies[i] * cm_to_eV thermo_ads = HarmonicThermo(vib_energies=vib_energies, electronicenergy=energy) val = thermo_ads.get_gibbs_energy(temperature=T, verbose=False) return val
def _calculate_Gcorr(self, adsorbate, verbose=False): """Re-calculates the G_correction for the specified adsorbate. Note since only harmonic degrees of freedom are considered and the clean slab is considered to be static (i.e., its vibrations are unaffected by the presence of the adsorbate), then its G correction is 0. Args: adsorbate (string) verbose (bool, optional) """ if adsorbate == '': self.data[adsorbate]['EtoG'] = 0. if adsorbate == '': self.data[adsorbate]['EtoG'] = 0. else: vibs = self.data[adsorbate]['vibs'] thermo = HarmonicThermo(vib_energies=vibs, electronicenergy=None) self.data[adsorbate]['EtoG'] = thermo.get_gibbs_energy( temperature=self.temperature, verbose=verbose)
# name of output file for free energies output_name = 'out.energy' ### At 300K and 101325 Pa ### change for your operating conditions T = 300 # K P = 101325 # Pa ######################################################################################################### ##### END ##### ######################################################################################################### energy = atoms.get_potential_energy() # caclulate the energy, to be used to determine G vibrateatoms = [atom.index for atom in atoms if atom.symbol in ['H','N']] # calculate the vibrational modes for all N and H atoms # Calculate vibrations vib = Vibrations(atoms,indices=vibrateatoms,delta=0.03) # define a vibration calculation vib.run() # run the vibration calculation vib.summary(method='standard') # summarize the calculated results for mode in range(len(vibrateatoms)*3): # Make trajectory files to visualize the modes. vib.write_mode(mode) vibenergies=vib.get_energies() vibenergies=[vib for vib in vibenergies if not isinstance(vib,complex)] # only take the real modes gibbs = HarmonicThermo(vib_energies = vibenergies, electronicenergy = energy) freeenergy = gibbs.get_gibbs_energy(T,P) f=open(output_name,'w') f.write('Potential energy: '+str(energy)+'\n'+'Free energy: '+str(freeenergy)+'\n') f.close
isif=2, prec="Normal", ediff=1E-4, ediffg=-0.02, xc="pbe", ispin=2, lcharg=True, encut=470, lorbit=11, nelmin=6, nelm=60, ivdw=11, isym=0, lreal="Auto", gamma=True, potim=0.015, nfree=2) freq_cluster.calc = freq_calc vib = Vibrations(freq_cluster) vib.run() vib_energies = vib.get_energies() thermo = HarmonicThermo( vib_energies=vib_energies, potentialenergy=potentialenergy, atoms=freq_cluster ) #harmonic approximation for the adsorbate species vibration G = thermo.get_gibbs_energy(temperature=298.15, pressure=101325.) S = thermo.get_entropy(temperature=298.15) H = thermo.get_helmholtz_energy(temperature=298.15)
P = 101325 # Pa ######################################################################################################### ##### END ##### ######################################################################################################### energy = atoms.get_potential_energy( ) # caclulate the energy, to be used to determine G vibrateatoms = [atom.index for atom in atoms if atom.symbol in ['H', 'N'] ] # calculate the vibrational modes for all N and H atoms # Calculate vibrations vib = Vibrations(atoms, indices=vibrateatoms, delta=0.03) # define a vibration calculation vib.run() # run the vibration calculation vib.summary(method='standard') # summarize the calculated results for mode in range(len(vibrateatoms) * 3): # Make trajectory files to visualize the modes. vib.write_mode(mode) vibenergies = vib.get_energies() vibenergies = [vib for vib in vibenergies if not isinstance(vib, complex)] # only take the real modes gibbs = HarmonicThermo(vib_energies=vibenergies, electronicenergy=energy) freeenergy = gibbs.get_gibbs_energy(T, P) f = open(output_name, 'w') f.write('Potential energy: ' + str(energy) + '\n' + 'Free energy: ' + str(freeenergy) + '\n') f.close
## more information here: https://wiki.fysik.dtu.dk/ase/ase/thermochemistry/thermochemistry.html name = 'example_ads' #electronic energy in eV energy = -21861.531796 #vibrational energies in meV vibenergies = [60.5, 77.1, 314.2] #convert from meV to eV for each mode vibenergies[:] = [ve / 1000. for ve in vibenergies] #list of temperatures temperatures = [300] #operating pressure pressures = [101325] f = open(name + '_free.energy', 'w') for temperature in temperatures: for pressure in pressures: gibbs = HarmonicThermo(vib_energies=vibenergies, electronicenergy=energy) freeenergy = gibbs.get_gibbs_energy(temperature, pressure) f.write('Temperature: ' + str(temperature) + '\t' + 'Pressure: ' + str(pressure) + '\t' + 'Free energy: ' + str(freeenergy) + '\n') f.close
class Reactant: """ """ def __init__( self, surf_name=None, surf_class=None, #type species_name=None, species_type=None, traj_loc=None, vib_loc=None, symmetrynumber=None, geometry=None, spin=None, calc_params=None, tag='', ): self.surf_name = surf_name self.surf_class = surf_class self.species_name = species_name self.species_type = species_type self.traj_loc = traj_loc self.symmetrynumber = symmetrynumber self.geometry = geometry self.spin = spin self.tag = tag if calc_params != None: self.calc_params = calc_params if traj_loc != None: self.atoms = read(traj_loc) self.calc_params = self.get_calc_params() if self.calc_params['xc'] == 'BEEF': self.beef = self.beef_reader() else: self.atoms = [] self.calc_params = {} if vib_loc != None: self.vibs = self.vibs_reader(vib_loc) if self.species_type == 'slab': self.gibbs = None elif self.species_type == 'gas': self.gibbs = IdealGasThermo( vib_energies=self.vibs, potentialenergy=0, atoms=self.atoms, geometry=self.geometry, symmetrynumber=self.symmetrynumber, spin=self.spin, ) elif self.species_type == 'adsorbate': self.gibbs = HarmonicThermo(vib_energies=self.vibs, potentialenergy=0) else: print "Warning: unrecognized species_type: ", self.species_type self.gibbs = None def get_calc_params(self): directory = '/'.join(self.traj_loc.split('/')[0:-1]) if len(directory) < 1: directory = '.' #Look for all log/input files in all folders in main directory, choose first for calc params calcdirs = glob(directory + '/*/log') if len(calcdirs) == 0: print "WARNING: No log file found for: %s" % (self.species_name) calc_params = {'pw': None, 'xc': None, 'kpts': None, 'psp': None} return calc_params #Get parameters from longest log file #size = 0 #for i, cd in enumerate(calcdirs): # if os.stat(cd).st_size > size: # j = i # size = os.stat(cd).st_size j = 0 log_file = open(calcdirs[j], 'r').readlines() inpdirs = glob(directory + '/*/pw.inp') inp_file = open(inpdirs[j], 'r') calc_params = {} calc_params['psp'] = {} for i, line in enumerate(log_file): line = line.strip() #XC if line.startswith('Exchange-correlation'): if 'BEEF' in line: xc = 'BEEF' elif 'RPBE' in line: xc = 'RPBE' elif 'PBE' in line: xc = 'PBE' #PSP if line.startswith('PseudoPot.'): elem = line.split()[4] md5 = log_file[i + 2].split()[-1] calc_params['psp'][elem] = md5 #PW if line.startswith('kinetic-energy cutoff'): pw = float(re.findall("\d+\.\d+", line)[0]) pw *= 13.61 #ryd to ev pw = str(int(pw)) #round pw and turn to str calc_params['xc'] = xc calc_params['pw'] = pw #K-PTS inplines = inp_file.readlines() kpts = inplines[-1].split() calc_params['kpts'] = ''.join(kpts[0:3]) if len(calc_params) < 3: print "ERROR: Unable to extract calculator parameters automatically, user can supply manually." exit() inp_file.close() return calc_params def beef_reader(self): directory = '/'.join(self.traj_loc.split('/')[0:-1]) if os.path.exists(directory + '/ensemble.pkl') == False or os.stat( directory + '/ensemble.pkl').st_size == 0: print "Warning: No beef ensemble for %s" % (directory) return beef_array = pickle.load(open(directory + '/ensemble.pkl', 'r')) #Check if BEEF normalized around zero or not #Correct???? if abs(np.mean(beef_array)) < 100: beef_array += read(self.traj_loc).get_potential_energy() return beef_array def vibs_reader(self, vib_loc): f = open(vib_loc + '/myjob.out', 'r') vibenergies = [] for line in f: try: temp = line.replace('.', '') temp = temp.replace(' ', '') temp = temp.replace('i', '') float(temp) except ValueError: continue num, meV, inv_cm, = line.split() if 'i' in meV: meV = 7 vibenergies.append(float(meV)) #convert from meV to eV for each mode vibenergies[:] = [round(ve / 1000., 4) for ve in vibenergies] if vibenergies == []: print "Warning: No vibrational energies for %s" % (self.traj_loc) return vibenergies def get_Gcorr(self, T, P=101325, verbose=False): if self.species_type == 'slab' or self.species_type == 'bulk': Gcorr = 0 elif self.species_type == 'gas': if len(self.vibs) == 0: print "ERROR: No vibrations for %s" % (self.traj_loc) exit() Gcorr = self.gibbs.get_gibbs_energy(T, P, verbose=verbose) elif self.species_type == 'adsorbate': if len(self.vibs) == 0: print "ERROR: No vibrations for %s" % (self.traj_loc) exit() Gcorr = self.gibbs.get_helmholtz_energy(T, verbose=verbose) else: print "Error: ambiguous species type for function get_dGcorr. Should be 'gas' or 'adsorbate'." exit() return Gcorr def get_Hcorr(self, T, verbose=False): if self.species_type == 'slab' or self.species_type == 'bulk': Hcorr = 0 elif self.species_type == 'gas': Hcorr = self.gibbs.get_enthalpy(T, verbose=verbose) elif self.species_type == 'adsorbate': Hcorr = self.gibbs.get_internal_energy(T, verbose=verbose) return Hcorr
###################################################### ## more information here: https://wiki.fysik.dtu.dk/ase/ase/thermochemistry/thermochemistry.html name = 'example_ads' #electronic energy in eV energy = -21861.531796 #vibrational energies in meV vibenergies = [60.5, 77.1, 314.2] #convert from meV to eV for each mode vibenergies[:] = [ve/1000. for ve in vibenergies] #list of temperatures temperatures = [300] #operating pressure pressures = [101325] f=open(name+'_free.energy','w') for temperature in temperatures: for pressure in pressures: gibbs = HarmonicThermo(vib_energies = vibenergies, electronicenergy = energy) freeenergy = gibbs.get_gibbs_energy(temperature,pressure) f.write('Temperature: '+str(temperature)+'\t'+'Pressure: '+str(pressure)+'\t'+'Free energy: '+str(freeenergy)+'\n') f.close