def test_eos(): import numpy as np import scipy # skip test early if no scipy from ase.build import bulk from ase.calculators.emt import EMT from ase.eos import EquationOfState as EOS, eos_names scipy # silence pyflakes b = bulk('Al', 'fcc', a=4.0, orthorhombic=True) b.set_calculator(EMT()) cell = b.get_cell() volumes = [] energies = [] for x in np.linspace(0.98, 1.01, 5): b.set_cell(cell * x, scale_atoms=True) volumes.append(b.get_volume()) energies.append(b.get_potential_energy()) results = [] for name in eos_names: if name == 'antonschmidt': # Someone should fix this! continue eos = EOS(volumes, energies, name) v, e, b = eos.fit() print('{0:20} {1:.8f} {2:.8f} {3:.8f} '.format(name, v, e, b)) assert abs(v - 3.18658700e+01) < 4e-4 assert abs(e - -9.76187802e-03) < 5e-7 assert abs(b - 2.46812688e-01) < 2e-4 results.append((v, e, b)) print(np.ptp(results, 0)) print(np.mean(results, 0))
def calc_lattice_parameter_al(atom_set, A, lmbd, D, mu2): global n_sets, cells q = 0.2 n_points = 10 lattice_param_set = np.zeros(n_sets) calc = get_calc((A, lmbd, D, mu2)) for index, atoms in enumerate(atom_set): # # # Find lattice constant with lowest energy # # # cell_0 = atoms.cells[index] # Unit cell object of the Al bulk atoms.set_calculator(calc) energies = [] volumes = [] inval = np.linspace(-q, q, n_points) for eps in inval: atoms.cell = (1 + eps) * cell_0 # Adjust lattice constant of unit cell # Calculate the potential energy for the Al bulk energies.append(atoms.get_potential_energy()) volumes.append(atoms.get_volume()) # Plot energies as a function of unit cell volume (directly related to latt. const.) eos = EquationOfState(volumes, energies) v0, E, B = eos.fit() # Latt. const. acc. to ASE doc., but why is this correct? a_calc = v0**(1 / 3.0) n_min = np.argmin(energies) atoms.cell = (1 + inval[n_min]) * cell_0 lattice_param_set[index] = a_calc return lattice_param_set
def eos(self, atoms, name): args = self.args traj = Trajectory(self.get_filename(name, 'traj'), 'w', atoms) N, eps = args.equation_of_state.split(',') N = int(N) eps = float(eps) / 100 strains = np.linspace(1 - eps, 1 + eps, N) v1 = atoms.get_volume() volumes = strains**3 * v1 energies = [] cell1 = atoms.cell for s in strains: atoms.set_cell(cell1 * s, scale_atoms=True) energies.append(atoms.get_potential_energy()) traj.write(atoms) traj.close() eos = EquationOfState(volumes, energies, args.eos_type) v0, e0, B = eos.fit() atoms.set_cell(cell1 * (v0 / v1)**(1 / 3), scale_atoms=True) data = {'volumes': volumes, 'energies': energies, 'fitted_energy': e0, 'fitted_volume': v0, 'bulk_modulus': B, 'eos_type': args.eos_type} return data
def fit(filename): configs = read(filename + "@:") volumes = [a.get_volume() for a in configs] energies = [a.get_potential_energy() for a in configs] eos = EquationOfState(volumes, energies) v0, e0, B = eos.fit() return (4 * v0)**(1 / 3.0)
def eos(self, atoms, name): args = self.args traj = Trajectory(self.get_filename(name, 'traj'), 'w', atoms) N, eps = args.equation_of_state.split(',') N = int(N) eps = float(eps) / 100 strains = np.linspace(1 - eps, 1 + eps, N) v1 = atoms.get_volume() volumes = strains**3 * v1 energies = [] cell1 = atoms.cell for s in strains: atoms.set_cell(cell1 * s, scale_atoms=True) energies.append(atoms.get_potential_energy()) traj.write(atoms) traj.close() eos = EquationOfState(volumes, energies, args.eos_type) v0, e0, B = eos.fit() atoms.set_cell(cell1 * (v0 / v1)**(1 / 3), scale_atoms=True) data = { 'volumes': volumes, 'energies': energies, 'fitted_energy': e0, 'fitted_volume': v0, 'bulk_modulus': B, 'eos_type': args.eos_type } return data
def eos(self, atoms, name): args = self.args traj = Trajectory(self.get_filename(name, 'traj'), 'w', atoms) N, eps = args.equation_of_state.split(',') N = int(N) eps = float(eps) / 100 strains = np.linspace(1 - eps, 1 + eps, N) v1 = atoms.get_volume() volumes = strains**3 * v1 energies = [] cell1 = atoms.cell for s in strains: atoms.set_cell(cell1 * s, scale_atoms=True) energies.append(atoms.get_potential_energy()) traj.write(atoms) traj.close() eos = EquationOfState(volumes, energies, args.eos_type) v0, e0, B = eos.fit() atoms.set_cell(cell1 * (v0 / v1)**(1 / 3), scale_atoms=True) from ase.parallel import parprint as p p('volumes:', volumes) p('energies:', energies) p('fitted energy:', e0) p('fitted volume:', v0) p('bulk modulus:', B) p('eos type:', args.eos_type)
def calc_lattice_parameter(al_bulk_ASE, A, lmbd, D, mu2): q = 0.2 n_points = 15 calc = get_calc((A, lmbd, D, mu2)) # # # Find lattice constant with lowest energy # # # cell_0 = al_bulk_ASE.get_cell() # Unit cell object of the Al bulk al_bulk_ASE.set_calculator(calc) energies = [] volumes = [] for eps in np.linspace(-q, q, n_points): al_bulk_ASE.set_cell( (1 + eps) * cell_0) # Adjust lattice constant of unit cell # Calculate the potential energy for the Al bulk energies.append(al_bulk_ASE.get_potential_energy()) volumes.append(al_bulk_ASE.get_volume()) #plt.plot(np.asarray(volumes)**(1 / 3), energies) # plt.show() # Plot energies as a function of unit cell volume (directly related to latt. const.) eos = EquationOfState(volumes, energies) v0, E, B = eos.fit() # Latt. const. acc. to ASE doc., but why is this correct? a_calc = v0**(1 / 3.0) print('a=' + str(a_calc)) al_bulk_ASE.set_cell(cell_0) return a_calc
def eosfit_spec(atoms, calc, rg, method="birchmurnaghan"): from ase.eos import EquationOfState from numpy import linspace rootdir = os.getcwd() if not os.path.exists('eosfit'): os.mkdir('eosfit') os.chdir('eosfit') cell = atoms.get_cell() atoms.set_calculator(calc) traj = Trajectory('eosfit.traj', 'w') for x in rg: print(str(x)) atoms.set_cell(cell * x, scale_atoms=True) atoms.get_potential_energy() traj.write(atoms) configs = Trajectory('eosfit.traj', 'r') volumes = [at.get_volume() for at in configs] energies = [at.get_potential_energy() for at in configs] eos = EquationOfState(volumes, energies, eos=method) v0, e0, B = eos.fit() eos.plot('eosfit.svg') fp = open('eosdata.dat', 'w') fp.write('Volume\t\tEnergy') for i in range(len(configs)): fp.write(str(volumes[i]) + '\t' + str(energies[i]) + '\n') os.chdir(rootdir)
def calc_lattice_parameter_al(al_bulk, A, lmbd, D, mu2): q = 0.03 n_points = 14 calc = get_calc((A, lmbd, D, mu2)) # # # Find lattice constant with lowest energy # # # cell_0 = al_bulk.cell # Unit cell object of the Al bulk al_bulk.set_calculator(calc) energies = [] volumes = [] for eps in np.linspace(-q, q, n_points): al_bulk.cell = (1 + eps) * cell_0 # Adjust lattice constant of unit cell # Calculate the potential energy for the Al bulk energies.append(al_bulk.get_potential_energy()) volumes.append(al_bulk.get_volume()) # Plot energies as a function of unit cell volume (directly related to latt. const.) eos = EquationOfState(volumes, energies) v0, E, B = eos.fit() # Latt. const. acc. to ASE doc., but why is this correct? a_calc = (4 * v0)**(1 / 3.0) al_bulk.cell = cell_0 print('Lattice_parameter:', a_calc) return a_calc
def do_autotune_volume(self,start_scan=0.90,end_scan=1.10,num_scan=25,exclude_type=None,only_type=None): # Load system and calculator system = self.system.copy() calc = self.system.calc system.set_calculator(calc) # Scale volumes and collect energy & volume measurements ens = [] vols = [] start_cell = system.get_cell() print("Performing volume scan.") for i,x in enumerate(np.linspace(start_scan,end_scan,num_scan)): #print(i) scale = x**(1./3.) system.set_cell(scale*start_cell,scale_atoms=True) vols.append(system.get_volume()) ens.append(system.get_potential_energy()) self.volume_vs_energy = [vols,ens] # Fit to Equations of States print("Fitting data to equations of state.") eos_types = "sjeos taylor murnaghan birch birchmurnaghan pouriertarantola p3 antonschmidt".split() if exclude_type != None: _ = [eos_types.remove(i) for i in exclude_type] elif only_type != None: eos_types = only_type eos_fits = {} errors = [] for typ in eos_types: try: eos = EquationOfState(vols,ens,eos=typ) v, e, B = eos.fit() eos_fits[typ] = {'volume':v,'energy':e,'buld_modulus':B} except: errors.append(typ) self.eos_fits = eos_fits self.eos_errors = errors if len(errors)>0 else None if len(errors) > 0: print("WARNING: Was not able to fit equation of state for the following: {}".format(errors)) # Rescale initial cell to optimized volume print("Rescaling with optimized volume.") vol_avg = np.average([eos_fits[key]['volume'] for key in eos_fits.keys()]) system.set_cell(start_cell,scale_atoms=True) scale = (vol_avg/system.get_volume())**(1./3.) print("Optimized volume: {}".format(vol_avg)) del self.system self.system = system self.system.set_cell(scale*start_cell,scale_atoms=True) print("Performing second relaxation.") self.system.get_potential_energy()
def fit(symbol: str) -> Tuple[float, float, float, float]: V = [] E = [] for atoms in read('{}.traj@:'.format(symbol)): V.append(atoms.get_volume() / len(atoms)) E.append(atoms.get_potential_energy() / len(atoms)) eos = EOS(V, E, 'birchmurnaghan') eos.fit() e0, B, Bp, v0 = eos.eos_parameters return e0, v0, B, Bp
def relax(input_atoms, ref_db): atoms_string = input_atoms.get_chemical_symbols() # Open connection to the database with reference data db = connect(ref_db) # Load our model structure which is just FCC atoms = FaceCenteredCubic('X', latticeconstant=1.) atoms.set_chemical_symbols(atoms_string) # Compute the average lattice constant of the metals in this individual # and the sum of energies of the constituent metals in the fcc lattice # we will need this for calculating the heat of formation a = 0 ei = 0 for m in set(atoms_string): dct = db.get(metal=m) count = atoms_string.count(m) a += count * dct.latticeconstant ei += count * dct.energy_per_atom a /= len(atoms_string) atoms.set_cell([a, a, a], scale_atoms=True) # Since calculations are extremely fast with EMT we can also do a volume # relaxation atoms.set_calculator(EMT()) eps = 0.05 volumes = (a * np.linspace(1 - eps, 1 + eps, 9))**3 energies = [] for v in volumes: atoms.set_cell([v**(1. / 3)] * 3, scale_atoms=True) energies.append(atoms.get_potential_energy()) eos = EquationOfState(volumes, energies) v1, ef, B = eos.fit() latticeconstant = v1**(1. / 3) # Calculate the heat of formation by subtracting ef with ei hof = (ef - ei) / len(atoms) # Place the calculated parameters in the info dictionary of the # input_atoms object input_atoms.info['key_value_pairs']['hof'] = hof # Raw score must always be set # Use one of the following two; they are equivalent input_atoms.info['key_value_pairs']['raw_score'] = -hof # set_raw_score(input_atoms, -hof) input_atoms.info['key_value_pairs']['latticeconstant'] = latticeconstant # Setting the atoms_string directly for easier analysis atoms_string = ''.join(input_atoms.get_chemical_symbols()) input_atoms.info['key_value_pairs']['atoms_string'] = atoms_string
def bulk_modulus(self): try: v = [abs(np.linalg.det(atoms.cell)) for atoms in self.images] e = [self.images.get_energy(a) for a in self.images] from ase.eos import EquationOfState eos = EquationOfState(v, e) plotdata = eos.getplotdata() except Exception as err: self.bad_plot(err, _('Images must have energies ' 'and varying cell.')) else: self.pipe('eos', plotdata)
def run_task(self,fw_spec): jobID,latticeParams = fw_spec['jobID'],fw_spec['latticeParams'] # WHY IS LATTICEPARAMS [[FLOAT]] INSTEAD OF [FLOAT]? job = db2object(jobID) existsPrecalc = job.precalc != 'None' optAtoms = job.fromParams(latticeParams[0]) optCell = optAtoms.get_cell() strains = np.linspace(1-job.strain,1+job.strain,9) calc = job.calc(restart=True) if existsPrecalc else job.calc() vol,eng = [],[] for i, strain in enumerate(strains): atoms = optAtoms.copy() atoms.set_cell(optCell*strain,scale_atoms=True) if existsPrecalc: preCalc = job.calc(precalc=True) job.optimizePos(atoms,preCalc,saveWF = True) if job.dftcode =='gpaw': atoms,calc = job.gpawRestart() job.optimizePos(atoms,calc) energy = atoms.get_potential_energy() volume = atoms.get_volume() vol.append(deepcopy(volume)) eng.append(deepcopy(energy)) parprint('%f %f'%(strain,energy)) with paropen('bulkmod.log','a') as logfile: logfile.write('%s\t%s\n' %(strain,energy)) parprint('%f %f'%(strain,energy)) aHat,quadR2 = quadFit(np.array(deepcopy(vol)),np.array(deepcopy(eng))) try: eos = EquationOfState(vol,eng) v0, e0, b = eos.fit() eos.plot(filename='bulk-eos.png',show=False) b0= b/kJ*1e24 #GPa use this value if EOS doesn't fail except ValueError: # too bad of a fit for ASE to handle b0 = aHat*2*vol[4]*160.2 # units: eV/A^6 * A^3 * 1, where 1 === 160.2 GPa*A^3/eV return FWAction( stored_data= {'b0':b0,'quadR2':quadR2} ,mod_spec=[{'_push': {'b0':b0,'quadR2':quadR2}}])
def Free_energy( x, T, E0, V0, B0, Bp ): #T in K, M is molar mass, E0 in eV, V0 in A^3, B0 in eV/A^3, x is concentration in atomic fraction try: i = 0 M = 0 for el in elements: M = M + mass_dict[el] * x[i] i = i + 1 M = abs(M) r0 = (3 * V0 / 4 / np.pi)**(1.0 / 3.0) T_D0 = C * np.sqrt(r0 * B0 * 160.21766208 / M) g = 1 - (np.tanh(4 * (T - T_D0) / T_D0) / 2.0 + 0.5) / 3.0 #2/3 for high T, 1 for low T gamma = -g + 0.5 * (1 + Bp) x = np.array(x) V = np.linspace(V0 - 0.1 * V0, V0 + 0.1 * V0, NUM_VOL_POINTS) F_temp = [] for Vi in V: E = E0 + 9 * V0 * B0 / 16 * (((V0 / Vi)**(2.0 / 3.0) - 1)**3 * Bp + ((V0 / Vi)**(2.0 / 3.0) - 1)**2 * (6 - 4 * (V0 / Vi)**(2.0 / 3.0))) T_D = T_D0 * (V0 / Vi)**gamma x = T_D / T #t = np.linspace(0.000001,x,10000) #Deb_func = 3.0 / x**3 * np.trapz(t**3 / (np.exp(t) - 1), t) F_vib = 9.0 / 8.0 * kB * T_D - kB * T * Debye( x) + 3 * kB * T * np.log(1 - np.exp(-(T_D / T))) F = E + F_vib F_temp.append(F) eos = EquationOfState(V, F_temp) vol_eq, F_eq, B_eq = eos.fit() return F_eq except KeyboardInterrupt: raise except Exception as e: print(x) raise
def ev_bulk(volumes, energies, plot_name): """Plot volume energy curve and calculates bulk modulus Args: volumes (list of float): The volumes correlated to the energies calculated. energies (list of float): The energies the cell calculated by gfn0 xtb. plot_name (str): The file name the plot is saved to. Returns: v0 (float): The volume of minimum energy. e0 (float): The fitted minimum energy of the V/E curve. B (float): The calculated bulk modulus. """ volumes = np.array(volumes) energies = np.array(energies) * Hartree / eV eos = EquationOfState(volumes, energies, eos="murnaghan") v0, e0, B = eos.fit() print(B / kJ * 1.0e24, "GPa") # Converts into GPa ax = eos.plot() fig = plt.gcf() fig.set_size_inches(8, 5) fig.savefig(plot_name) return v0, e0, B
# compute MM and QM equations of state def strain(at, e, calc): at = at.copy() at.set_cell((1.0 + e) * at.cell, scale_atoms=True) at.set_calculator(calc) v = at.get_volume() e = at.get_potential_energy() return v, e eps = np.linspace(-0.01, 0.01, 13) v_qm, E_qm = zip(*[strain(bulk_at, e, qm) for e in eps]) v_mm, E_mm = zip(*[strain(bulk_at, e, mm) for e in eps]) eos_qm = EquationOfState(v_qm, E_qm) v0_qm, E0_qm, B_qm = eos_qm.fit() a0_qm = v0_qm**(1.0 / 3.0) eos_mm = EquationOfState(v_mm, E_mm) v0_mm, E0_mm, B_mm = eos_mm.fit() a0_mm = v0_mm**(1.0 / 3.0) mm_r = RescaledCalculator(mm, a0_qm, B_qm, a0_mm, B_mm) v_mm_r, E_mm_r = zip(*[strain(bulk_at, e, mm_r) for e in eps]) eos_mm_r = EquationOfState(v_mm_r, E_mm_r) v0_mm_r, E0_mm_r, B_mm_r = eos_mm_r.fit() a0_mm_r = v0_mm_r**(1.0 / 3) # check match of a0 and B after rescaling is adequete
from ase.calculators.emt import EMT from ase.eos import EquationOfState from ase.db import connect db = connect('refs.db') metals = ['Al', 'Au', 'Cu', 'Ag', 'Pd', 'Pt', 'Ni'] for m in metals: atoms = FaceCenteredCubic(m) atoms.calc = EMT() e0 = atoms.get_potential_energy() a = atoms.cell[0][0] eps = 0.05 volumes = (a * np.linspace(1 - eps, 1 + eps, 9))**3 energies = [] for v in volumes: atoms.set_cell([v**(1. / 3)] * 3, scale_atoms=True) energies.append(atoms.get_potential_energy()) eos = EquationOfState(volumes, energies) v1, e1, B = eos.fit() atoms.set_cell([v1**(1. / 3)] * 3, scale_atoms=True) ef = atoms.get_potential_energy() db.write(atoms, metal=m, latticeconstant=v1**(1. / 3), energy_per_atom=ef / len(atoms))
""" cell = bulk.get_cell() traj = Trajectory('bulk.traj', 'w') for x in np.linspace(0.90, 1.10, 5): bulk.set_cell(cell * x, scale_atoms=True) bulk.get_potential_energy() traj.write(bulk) ########## EOS ############# from ase.io import read from ase.units import kJ from ase.eos import EquationOfState configs = read('bulk.traj@0:5') # read 10 configurations # Extract volumes and energies: volumes = [bulk.get_volume() for bulk in configs] energies = [bulk.get_potential_energy() for bulk in configs] eos = EquationOfState(volumes, energies, eos='birchmurnaghan') v0, e0, B = eos.fit() # Return info on optimised system print("Volume: ", v0 + " Angstrom^3") print("Total energy at a0: " + e0 + " eV") print("FCC Lattice parameter a0: ", (4*v0)**(1/3), "Angstrom") #print("FCC Lattice parameter a0: ", (4*v0/NUMBER_OF_ATOMS_IN_UNIT_CELL)**(1/3), "Angstrom") print("Bulk modulus: ", B / kJ * 1.0e24, 'GPa') eos.plot('bulk-eos.png') #view('bulk.traj')
from ase.calculators.emt import EMT from ase.eos import EquationOfState as EOS, eos_names scipy # silence pyflakes b = bulk('Al', 'fcc', a=4.0, orthorhombic=True) b.set_calculator(EMT()) cell = b.get_cell() volumes = [] energies = [] for x in np.linspace(0.98, 1.01, 5): b.set_cell(cell * x, scale_atoms=True) volumes.append(b.get_volume()) energies.append(b.get_potential_energy()) results = [] for name in eos_names: if name == 'antonschmidt': # Someone should fix this! continue eos = EOS(volumes, energies, name) v, e, b = eos.fit() print('{0:20} {1:.8f} {2:.8f} {3:.8f} '.format(name, v, e, b)) assert abs(v - 3.18658700e+01) < 4e-4 assert abs(e - -9.76187802e-03) < 5e-7 assert abs(b - 2.46812688e-01) < 2e-4 results.append((v, e, b)) print(np.ptp(results, 0)) print(np.mean(results, 0))
def fit_a(conv, n, description_for_archive, analysis_type, show, push2archive): """Fit equation of state for bulk systems. The following equation is used:: sjeos (default) A third order inverse polynomial fit 10.1103/PhysRevB.67.026103 2 3 -1/3 E(V) = c + c t + c t + c t , t = V 0 1 2 3 taylor A third order Taylor series expansion about the minimum volume murnaghan PRB 28, 5480 (1983) birch Intermetallic compounds: Principles and Practice, Vol I: Principles. pages 195-210 birchmurnaghan PRB 70, 224107 pouriertarantola PRB 70, 224107 vinet PRB 70, 224107 antonschmidt Intermetallics 11, 23-32 (2003) p3 A third order polynomial fit Use:: eos = EquationOfState(volumes, energies, eos='sjeos') v0, e0, B = eos.fit() eos.plot() """ # e, v, emin, vmin = plot_conv( conv[n], calc, "fit_gb_volume2") alist = [] vlist = [] etotlist = [] magn1 = [] magn2 = [] alphas = [] for id in conv[n]: cl = db[id] st = cl.end alist.append(cl.end.rprimd[0][0]) etotlist.append(cl.energy_sigma0) vlist.append(cl.end.vol) magn1.append(cl.magn1) magn2.append(cl.magn2) alpha, beta, gamma = st.get_angles() alphas.append(alpha) print('alpha, energy: {:4.2f}, {:6.3f}'.format(alpha, cl.energy_sigma0)) fit_and_plot(U1=(alphas, etotlist, 'o-r'), image_name='figs/angle', ylabel='Total energy, eV', xlabel='Angle, deg', xlim=(89, 92.6)) if ase_flag: if 'angle' in analysis_type: eos = EquationOfState(alphas, etotlist, eos='sjeos') else: eos = EquationOfState(vlist, etotlist, eos='sjeos') # import inspect # print (inspect.getfile(EquationOfState)) v0, e0, B = eos.fit() #print "c = ", clist[2] printlog(''' v0 = {0} A^3 a0 = {1} A E0 = {2} eV B = {3} eV/A^3'''.format(v0, v0**(1. / 3), e0, B), imp='Y') savedpath = 'figs/' + cl.name + '.png' makedir(savedpath) cl.B = B * 160.218 # plt.close() # plt.clf() # plt.close('all') if 'fit' in show: mpl.rcParams.update({'font.size': 14}) eos.plot(savedpath, show=True) printlog('fit results are saved in ', savedpath, imp='y') else: printlog('To use fitting install ase: pip install ase') # plt.clf() if push2archive: push_figure_to_archive(local_figure_path=savedpath, caption=description_for_archive) return
cell_0 = al.cell # Unit cell object of the Al bulk for eps in np.linspace(-0.02, 0.02, N_lattice_spacings): al.cell = ( 1 + eps) * cell_0 # Adjust lattice constant of unit cell # Calculate the potential energy for the Al bulk energies.append(al.get_potential_energy()) volumes.append(al.get_volume()) # # confs = read('out.txt@0:' + str(N_lattice_spacings)) # Read the configurations # # Extract volumes and energies: # volumes = [atoms.get_volume() for atoms in confs] # energies = [atoms.get_potential_energy() for atoms in confs] # # if rank == 0: # # print energies, shape(energies) # if rank == 0: print 'Energies: ' + str(energies) print 'Volumes: ' + str(volumes) # Plot energies as a function of unit cell volume (directly related to latt. const.) eos = EquationOfState(volumes, energies) v0, E_bulk, B = eos.fit() eos.plot('Al_eos.png') # Latt. const. acc. to ASE doc., but why is this correct? a_calc = (4 * v0)**(1 / 3.0) print 'a_calc: ' + str(a_calc) else: al.get_potential_energy()
def calc_lattice_parameter(al_bulk_ASE, A, lmbd, D, mu2): calc = get_calc((A, lmbd, D, mu2)) eps = 0.001 energies = [] volumes = [] al_bulk_ASE.set_calculator(calc) # # # Find lattice constant with lowest energy # # # cell_0 = al_bulk_ASE.get_cell() # Unit cell object of the Al bulk # DIRECTION cell_orig = cell_0 E1 = al_bulk_ASE.get_potential_energy() al_bulk_ASE.set_cell((1 + eps) * cell_0) E2 = al_bulk_ASE.get_potential_energy() direction = (E2 - E1) / abs((E2 - E1)) print('Direction', direction) # Go one step in the right al_bulk_ASE.set_cell(cell_orig) energies.append(al_bulk_ASE.get_potential_energy()) volumes.append(al_bulk_ASE.get_volume()) cell_0 = al_bulk_ASE.get_cell() al_bulk_ASE.set_cell( (1 - direction * eps) * cell_0) # Adjust lattice constant of unit cell energies.append(al_bulk_ASE.get_potential_energy()) volumes.append(al_bulk_ASE.get_volume()) # Go two steps back while (energies[-1] - energies[-2]) < 0: cell_0 = al_bulk_ASE.get_cell() # Adjust lattice constant of unit cell al_bulk_ASE.set_cell((1 - direction * eps) * cell_0) # Calculate the potential energy for the Al bulk energies.append(al_bulk_ASE.get_potential_energy()) volumes.append(al_bulk_ASE.get_volume()) cell_0 = al_bulk_ASE.get_cell() al_bulk_ASE.set_cell( (1 - direction * eps) * cell_0) # Adjust lattice constant of unit cell # Calculate the potential energy for the Al bulk energies.append(al_bulk_ASE.get_potential_energy()) volumes.append(al_bulk_ASE.get_volume()) # plt.plot((4 * np.asarray(volumes))**(1 / 3), energies) # plt.show() # Plot energies as a function of unit cell volume (directly related to latt. const.) eos = EquationOfState(volumes, energies) v0, E, B = eos.fit() # Latt. const. acc. to ASE doc., but why is this correct? print('asdasdasdasdasd: ', E) a_calc = (4 * v0)**(1 / 3.0) # a_calc = v0**(1 / 3.0) print('a=' + str(a_calc)) al_bulk_ASE.set_cell(cell_0) return a_calc
INP_FILELIST.append(pwinput.filename) pwinput.write() # run commands OUT_FILELIST = [] for i, f in enumerate(INP_FILELIST): fileout = "OUT_PW_" + str(i) OUT_FILELIST.append(fileout) # Uncomment this if the run is already done os.system("pw.x < " + f + " > " + fileout) print("Running " + str(i) + " is done") ene = np.zeros(len(OUT_FILELIST)) for i, f in enumerate(OUT_FILELIST): ene[i] = read_pwscf_energy(f) print("ene[i] = ", ene[i]) from ase.units import Bohr, kJ from ase.eos import EquationOfState volumes = A_LIST[:]**3 / 4.0 # fcc volumes (in Angstrom^3) ene[:] = ene[:] * Ry # convert to eV eos = EquationOfState(volumes, ene) v0, e0, B = eos.fit() print("B = %18.10f GPa" % (B / kJ * 1.0e24)) eos.plot("IMG_fit_EOS.pdf") a_calc = (4 * v0)**(1 / 3) print("a_exp = ", a_exp) print("a_calc = ", a_calc)
from ase.io import read from ase.units import kJ from ase.eos import EquationOfState configs = read('Ag.traj@0:5') # read 5 configurations # Extract volumes and energies: volumes = [ag.get_volume() for ag in configs] energies = [ag.get_potential_energy() for ag in configs] eos = EquationOfState(volumes, energies) v0, e0, B = eos.fit() print(B / kJ * 1.0e24, 'GPa') eos.plot('Ag-eos.png')
energies = [] volumes = [] LC = [3.5, 3.55, 3.6, 3.65, 3.7, 3.75] for a in LC: cu_bulk = bulk("Cu", "fcc", a=a) calc = EMT() cu_bulk.set_calculator(calc) e = cu_bulk.get_potential_energy() energies.append(e) volumes.append(cu_bulk.get_volume()) eos = EquationOfState(volumes, energies) v0, e0, B = eos.fit() aref = 3.6 vref = bulk("Cu", "fcc", a=aref).get_volume() copper_lattice_constant = (v0 / vref)**(1 / 3) * aref slab = fcc100("Cu", a=copper_lattice_constant, size=(2, 2, 3)) ads = molecule("C") add_adsorbate(slab, ads, 3, offset=(1, 1)) cons = FixAtoms(indices=[atom.index for atom in slab if (atom.tag == 3)]) slab.set_constraint(cons) slab.center(vacuum=13.0, axis=2) slab.set_pbc(True) slab.wrap(pbc=[True] * 3) slab.set_calculator(copy.copy(parent_calc))
def genstr(scale): atoms = read('str.cif') # Scale the cell cell = atoms.get_cell() cell[2][2] = scale * cell[2][2] atoms.set_cell(cell, scale_atoms=False) # Translate Li, F atoms vertically for j in range(len(atoms)): if atoms[j].symbol != 'C': atoms[j].position[2] += (scale - 1) * 11.08 / 2 return atoms # Main for i, scale in enumerate(np.linspace(0.85, 1.0, num=5)): atoms = genstr(scale) atoms.calc = GPAW(xc=xc, kpts=kpoints, gpts=gpoints, txt=str(i) + '.txt') e.append(atoms.get_potential_energy()) v.append(atoms.get_volume()) eos = EquationOfState(v, e, eos='birchmurnaghan') v0, e0, B = eos.fit() eos.plot('eos.png', show=False) opt_scale = v0 / read('str.cif').get_volume() write('opt_str.cif', genstr(opt_scale))
def getBulkModulus(jobID, latticeParams): """ Use optimized lattice parameters from fmin(getEnergy). Calculate energies around the minimum. Returns optimized atomic positions, energy of minimum, calculated bulk modulus, and writes wavefunctions to file inp.gpw """ ### INITIALIZE vol, eng = [], [] jobObject, bulkObject, calcObject, dft, preCalcObject, preCalcObject, existsPrecalc, optAtoms, magmoms = initialize( jobID, latticeParams) with open('lattice_opt.log', 'r') as f: nIter = len(f.readlines()) + 9 #count number of ionic steps taken optCell = optAtoms.get_cell() strains = np.linspace(0.99, 1.01, 9) ### GENERATE dE/dV plot for i, strain in enumerate(strains): atoms = deepcopy(optAtoms) atoms.set_cell(optCell * strain, scale_atoms=True) ### PRECALCULATE if existsPrecalc: optimizePos(atoms, dft, preCalcObject, magmoms, restart=False, saveWF=True) ### CALCULATE optimizePos(atoms, dft, calcObject, magmoms, restart=existsPrecalc, saveWF=False) ### COLLECT RESULTS energy = atoms.get_potential_energy() volume = atoms.get_volume() vol.append(deepcopy(volume)) eng.append(deepcopy(energy)) parprint('%f %f' % (strain, energy)) ### COLLECT DETAILED DATA ABOUT MINIMUM ENERGY STATE if i == 4: pos = atoms.get_scaled_positions() vMin = deepcopy(volume) io.write('optimized.traj', atoms) magmom = atoms.get_magnetic_moments( ) if calcObject.magmom > 0 else np.zeros(len(atoms)) if dft == 'gpaw': atoms.calc.write('inp.gpw', mode='all') #for use in getXCContribs aHat, quadR2 = quadFit(np.array(deepcopy(vol)), np.array(deepcopy(eng))) b0 = aHat * 2 * vMin * 160.2 # units: eV/A^6 * A^3 * 1, where 1 === 160.2 GPa*A^3/eV parprint('quadR2 = ' + str(quadR2)) try: eos = EquationOfState(vol, eng) v0, e0, b = eos.fit() eos.plot(filename='bulk-eos.png', show=False) b0 = b / kJ * 1e24 #GPa use this value if EOS doesn't fail except ValueError: e0 = eng[4] return (optCell, nIter, pos, magmom, e0, b0, quadR2) #GPa
def lattice_constant(volumes, energies): eos = EquationOfState(volumes, energies) v, e, B = eos.fit() a = (v * 4)**(1 / 3) return a
def do_volume_autotune(self, encut=None, start_scan=0.925, end_scan=1.075, num_scans=20, exclude_type=None, only_type=None): if not os.path.isfile(self.poscar_vol): encut = encut if encut != None else self.do_encut_autotune() logging.info("Commencing volume scan...") print("Determining optimal volume...") start_scan, end_scan, num_scans, exclude_type, only_type, vols, ens = self.set_volume_autotune_params( start_scan=start_scan, end_scan=end_scan, num_scans=num_scans, exclude_type=exclude_type, only_type=only_type) # Load POSCAR try: sys = read(self.poscar_init) calc = self.calc_dict['volume'] calc.set(encut=encut) start_cell = sys.get_cell() except: logging.error( "Initial POSCAR file could not be found at {}".format( poscar_init)) print("Error: See error log for details.") return None logging.info("Loaded initial POSCAR file.") # Do volume scan logging.info("Performing volume scan.") for x in np.linspace(start_scan, end_scan, num_scans): sys.set_cell(x * start_cell, scale_atoms=True) sys.set_calculator(calc) ens.append(sys.get_potential_energy()) vols.append(sys.get_volume()) logging.info("Volume scan complete.") # Fit EoS logging.info("Fitting equations of state.") eos_types = "sjeos taylor murnaghan birch birchmurnaghan pouriertarantola p3 antonschmidt".split( ) if exclude_type != None: _ = [eos_types.remove(i) for i in exclude] elif only_type != None: eos_types = only_type eos_fits = {} for typ in eos_types: eos = EquationOfState(vols, ens, eos=typ) try: v, e, B = eos.fit() eos_fits[typ] = { 'volume': v, 'energy': e, 'buld_modulus': B } except: print("Unable to fit type {}.".format(typ)) # Rescale initial cell to optimized volume logging.info("Optimal volume found. Rescaling original cell.") vol_avg = np.average( [eos_fits[key]['volume'] for key in eos_fits.keys()]) sys.set_cell(start_cell, scale_atoms=True) scale = sys.get_volume() / vol_avg sys.set_cell(scale * start_cell, scale_atoms=True) # Perform sc-step logging.info("Performing self-consistent step.") print("Second relaxation") #calc.set(isif=3) # Everything can relax sys.set_calculator(calc) en = sys.get_potential_energy() # Set relaxed structure as active structure print("Setting relaxed structure to active structure.") self.system = sys # Save structure logging.info("Saving self-consistent calculator.") write(self.poscar_vol, sys) print("Done.") logging.info("Volume scan complete.") self.clean_up() else: sys = read(self.poscar_vol) print("Volume optimized system ready.")
from ase.units import kJ, Bohr, Hartree from ase.eos import EquationOfState import numpy as np filename = "TEMP_EOS_data.dat" dat = np.loadtxt(filename) # dont forget to convert to Angstrom and eV volumes = dat[:,0]**3/2.0 * Bohr**3 # only for bcc energies = dat[:,1]*Hartree energies_abinit = dat[:,2]*Hartree energies_pwscf = dat[:,3]*Hartree eos = EquationOfState(volumes, energies) v0, e0, B = eos.fit() print("PWDFT.jl: B = %18.10f GPa" % (B/kJ * 1.0e24)) eos.plot("pwdft-eos-ase.pdf") eos = EquationOfState(volumes, energies_abinit) v0, e0, B = eos.fit() print("ABINIT : B = %18.10f GPa" % (B/kJ * 1.0e24)) eos.plot("abinit-eos-ase.pdf") eos = EquationOfState(volumes, energies_pwscf) v0, e0, B = eos.fit() print("PWSCF : B = %18.10f GPa" % (B/kJ * 1.0e24)) eos.plot("pwscf-eos-ase.pdf")
import numpy as np from ase.lattice.cubic import FaceCenteredCubic from ase.calculators.emt import EMT from ase.eos import EquationOfState from ase.db import connect db = connect("refs.db") metals = ["Al", "Au", "Cu", "Ag", "Pd", "Pt", "Ni"] for m in metals: atoms = FaceCenteredCubic(m) atoms.set_calculator(EMT()) e0 = atoms.get_potential_energy() a = atoms.cell[0][0] eps = 0.05 volumes = (a * np.linspace(1 - eps, 1 + eps, 9)) ** 3 energies = [] for v in volumes: atoms.set_cell([v ** (1.0 / 3)] * 3, scale_atoms=True) energies.append(atoms.get_potential_energy()) eos = EquationOfState(volumes, energies) v1, e1, B = eos.fit() atoms.set_cell([v1 ** (1.0 / 3)] * 3, scale_atoms=True) ef = atoms.get_potential_energy() db.write(atoms, metal=m, latticeconstant=v1 ** (1.0 / 3), energy_per_atom=ef / len(atoms))
def __init__(self, volumes, energies, eos='sj'): EquationOfState.__init__(self, volumes, energies, eos='sj')