def analyse(self): for name, data in self.data.items(): if 'strains' in data: atoms = self.create_system(name) # use relaxed volume if present if 'relaxed volume' in data: volume = data['relaxed volume'] else: volume = atoms.get_volume() volumes = data['strains']**3 * volume energies = data['energies'] # allow selection of eos type independent of data if self.eos is not None: eos = EquationOfState(volumes, energies, self.eos) else: eos = EquationOfState(volumes, energies) try: v, e, B = eos.fit() except (RuntimeError, ValueError): pass else: data['fitted energy'] = e data['volume'] = v data['B'] = B if abs(v) < min(volumes) or abs(v) > max(volumes): raise ValueError(name + ': fit outside of range! ' + \ str(abs(v)) + ' not in ' + \ str(volumes))
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 bulk_summary(self, plot, a0): natoms = len(self.atoms) eos = EquationOfState(self.volumes, self.energies) v, e, B = eos.fit() x = (v / self.atoms.get_volume())**(1.0 / 3) self.log('Fit using %d points:' % len(self.energies)) self.log('Volume per atom: %.3f Ang^3' % (v / natoms)) if a0: a = a0 * x self.log('Lattice constant: %.3f Ang' % a) else: a = None self.log('Bulk modulus: %.1f GPa' % (B * 1e24 / units.kJ)) self.log('Total energy: %.3f eV (%d atom%s)' % (e, natoms, ' s'[1:natoms])) if plot: import pylab as plt plt.plot(self.volumes, self.energies, 'o') x = np.linspace(self.volumes[0], self.volumes[-1], 50) plt.plot(x, eos.fit0(x**-(1.0 / 3)), '-r') plt.show() bulk = self.atoms.copy() bulk.set_cell(x * bulk.cell, scale_atoms=True) self.write_optimized(bulk, e) return e, v, B, a
def eos(self, atoms, name): opts = self.opts traj = PickleTrajectory(self.get_filename(name, 'traj'), 'w', atoms) eps = 0.01 strains = np.linspace(1 - eps, 1 + eps, 5) 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, opts.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': opts.eos_type} return data
def f(width, k, g): filename = 'Fe-FD-%.2f-%02d-%2d.traj' % (width, k, g) configs = read(filename + '@::2') # Extract volumes and energies: 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 v0, e0, B
def fitEos(volumes, energies): # fit EOS # from ase.utils.eos import EquationOfState from ase.units import kJ, _e eos = EquationOfState(volumes, energies) vpaf, epaf, B1 = eos.fit() print("vpaf: %f, epaf: %f, B1: %f") % (vpaf, epaf, 1.0e24 * B1 / kJ)
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 input_atoms.info['key_value_pairs']['raw_score'] = -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 EMTO_EOS(work_dir, atoms, calc, OPTIONS = np.linspace(0.98, 1.02, 9)): os.system('mkdir -p {0}/calc'.format(work_dir)) result = '{0}/result.txt'.format(work_dir) os.system('rm {0}'.format(result)) save(result, 'Bulk modululs calculation') volumes = [] energies = [] for o in OPTIONS: a = atoms.copy() scale = [[o, 0, 0], [0, o, 0], [0, 0, o]] a.set_cell(np.dot(atoms.get_cell(), scale), scale_atoms=True) calc.set(dir='{0}/calc/opt-{1:0.3f}'.format(work_dir, o)) a.set_calculator(calc) n = a.get_number_of_atoms() e = a.get_potential_energy() / n v = a.get_volume() / n if e < -0.001: volumes.append(v) energies.append(e) save(result, '{0},{1},{2}'.format(o, v, e) ) eos = EquationOfState(volumes, energies) v0, e0, B = eos.fit() eos.plot('{0}/B.png'.format(work_dir)) save(result, 'calculation finshised') save(result, OPTIONS) save(result, volumes) save(result, energies) save(result, '------------------------') save(result, '{0},{1},{2}'.format(v0, e0, B/kJ*1.0e24)) save(result, '------------------------') return v0, e0, B/kJ*1.0e24
def analyse(self): OptimizeTask.analyse(self) for name, data in self.data.items(): if 'strains' in data: atoms = self.create_system(name) volumes = data['strains']**3 * atoms.get_volume() energies = data['energies'] eos = EquationOfState(volumes, energies) try: v, e, B = eos.fit() except ValueError: self.results[name].extend([None, None]) else: self.results[name][1:] = [ energies[2] - e, v, B * 1e24 / units.kJ ] else: self.results[name].extend([None, None])
def analyse(self): for name, data in self.data.items(): if 'strains' in data: atoms = self.create_system(name) volumes = data['strains']**3 * atoms.get_volume() energies = data['energies'] eos = EquationOfState(volumes, energies) try: v, e, B = eos.fit() except ValueError: pass else: data['fitted energy'] = e data['volume'] = v data['B'] = B if abs(v) < min(volumes) or abs(v) > max(volumes): raise ValueError(name + ': fit outside of range! ' + \ str(abs(v)) + ' not in ' + \ str(volumes))
def L12_BM_LC_Calculator(self, EMT, PARAMETERS): # Return 0 is used when the method is not desired to be used # return 0 """ The method L12_BM_LC_Calculator uses the EMT calculator to find the lattice constant which gives the lowest possible energy for an alloy of two elements and from a polynomial fit of the energy as a function of the lattice constant it calculates and returns the Bulk modulus, the volume of the system at the lowest possible energy and this energy """ # Three values for the lattice constant, a0, are chosen. The highest and lowest value is chosen so that it # is certain that these are to high/low respectively compared to the "correct" value. This is done by using the # experimental value of the lattice constant, a0_exp, as the middle value and to high/low values are then: # a0_exp +- a0_mod, a0_mod = a0_exp/10 a0_exp = ((PARAMETERS[self.Element[0]][1] + 3 * PARAMETERS[self.Element[1]][1]) * numpy.sqrt(2) * beta * Bohr / 4) a0_mod = a0_exp * 0.20 a0_guesses = numpy.array([a0_exp - a0_mod, a0_exp, a0_exp + a0_mod]) # An atoms object consisting of atoms of the chosen element is initialized atoms = L1_2(size=(self.Size, self.Size, self.Size), symbol=self.Element, latticeconstant=a0_exp) atoms.set_calculator(EMT) # An identity matrix for the system is saved to a variable IdentityMatrix = numpy.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) # An array for the energy for the chosen guesses for a0 is initialized: E_guesses = numpy.zeros(5) # The energies are calculated for i in range(3): # Changes the lattice constant for the atoms object atoms.set_cell(a0_guesses[i] * self.Size * IdentityMatrix, scale_atoms=True) # Calculates the energy of the system for the new lattice constant E_guesses[i] = atoms.get_potential_energy() # Bisection is used in order to find a small interval of the lattice constant for the minimum of the energy (an # abitrary interval length is chosen), This is possible because we are certian from theory that there is only # one minimum of the energy function in the interval of interest and thus we wont "fall" into a local minimum # and stay there by accident. while (a0_guesses[2] - a0_guesses[0]) >= self.Tol: if min([E_guesses[0], E_guesses[2]]) == E_guesses[0]: # A new guess for the lattice constant is introduced a0_new_guess = 0.67 * a0_guesses[1] + 0.33 * a0_guesses[2] # The energy for this new guess is calculated atoms.set_cell(a0_new_guess * self.Size * IdentityMatrix, scale_atoms=True) E_new_guess = atoms.get_potential_energy() # A check for changes in the energy minimum is made and the guesses for a0 and their corrosponding # energies are ajusted. if min(E_new_guess, min(E_guesses[0:3])) != E_new_guess: a0_guesses[2] = a0_new_guess E_guesses[2] = E_new_guess else: a0_guesses[0] = a0_guesses[1] a0_guesses[1] = a0_new_guess E_guesses[0] = E_guesses[1] E_guesses[1] = E_new_guess elif min([E_guesses[0], E_guesses[2]]) == E_guesses[2]: # A new guess for the lattice constant is introduced a0_new_guess = 0.33 * a0_guesses[0] + 0.67 * a0_guesses[1] # The energy for this new guess is calculated atoms.set_cell(a0_new_guess * self.Size * IdentityMatrix, scale_atoms=True) E_new_guess = atoms.get_potential_energy() # A check for changes in the energy minimum is made and the guesses for a0 and their corrosponding # energies are ajusted. if min(E_new_guess, min(E_guesses[0:3])) != E_new_guess: a0_guesses[0] = a0_new_guess E_guesses[0] = E_new_guess else: a0_guesses[2] = a0_guesses[1] a0_guesses[1] = a0_new_guess E_guesses[2] = E_guesses[1] E_guesses[1] = E_new_guess # An estimate of the minimum energy can now be found from a second degree polynomial fit through the three # current guesses for a0 and the corresponding values of the energy. Poly = numpyfit.polyfit(a0_guesses, E_guesses[0:3], 2) # The lattice constant corresponding to the lowest energy from the Polynomiel fit is found a0 = -Poly[1] / (2 * Poly[0]) # Now five guesses for a0 and the corresponding energy are evaluated from and around the current a0. a0_guesses = a0 * numpy.array([ 1 - 2 * self.Tol / 5, 1 - self.Tol / 5, 1, 1 + self.Tol / 5, 1 + 2 * self.Tol / 5 ]) for i in range(5): # Changes the lattice constant for the atoms object atoms.set_cell(a0_guesses[i] * self.Size * IdentityMatrix, scale_atoms=True) # Calculates the energy of the system for the new lattice constant E_guesses[i] = atoms.get_potential_energy() # The method EquationOfState is now used to find the Bulk modulus and the minimum energy for the system. # The volume of the sample for the given a0_guesses Vol = (self.Size * a0_guesses)**3 # The equilibrium volume, energy and bulk modulus are calculated (Vol0, E0, B) = EquationOfState(Vol.tolist(), E_guesses.tolist()).fit() return (Vol0, E0, B, Vol0**(1. / 3) / self.Size)
from ase.constraints import UnitCellFilter from ase.lattice.cubic import FaceCenteredCubic from ase.optimize import FIRE from ase.utils.eos import EquationOfState from atomistica import TabulatedAlloyEAM ### n = 2 a = FaceCenteredCubic('Au', size=[n, n, n]) x0 = a.cell[0, 0]/n c = TabulatedAlloyEAM(fn='Au-Grochola-JCP05.eam.alloy') a.set_calculator(c) # Vary volume and fit minimum def en(a, x): a.set_cell([x, x, x], scale_atoms=True) return a.get_potential_energy() x = np.linspace(0.9*x0, 1.1*x0, 101) e = [ en(a, n*_x)/(n**3) for _x in x ] eos = EquationOfState(x**3, e) v0, e0, B = eos.fit() print 'lattice constant (from equation of state) =', v0**(1./3) # Keep cell rectangular during optimization FIRE(UnitCellFilter(a, mask=[1,1,1,0,0,0]), logfile=None).run(fmax=0.0001) print 'lattice constant (from stress equilibration) =', a.cell[0, 0]/n
def BulkModulus(images): v = np.array([abs(np.linalg.det(A)) for A in images.A]) #import matplotlib.pyplot as plt import pylab as plt plt.ion() EquationOfState(v, images.E).plot()
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") from picture_functions import fit_and_plot 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
def get_eos(self, static=False): '''calculate the equation of state for the attached atoms. Returns a dictionary of data for each step. You do not need to specify any relaxation parameters, only the base parameters for the calculations. Writes to eos.org with a report of output. if static is True, then run a final static calculation at high precision, with ismear=-5. ''' # this returns if the data exists. if os.path.exists('eos.json'): with open('eos.json') as f: return json.loads(f.read()) # we need an initial calculation to get us going. self.calculate() cwd = os.getcwd() data = {'cwd': os.getcwd()} # dictionary to store results in org = [] # list of strings to make the org-file report org += ['#+STARTUP: showeverything'] org += ['* Initial guess'] org += [str(self)] org += ['', '[[shell:jaspsum -p {0}][view initial guess]]'.format(cwd)] with open('eos.org', 'w') as f: f.write('\n'.join(org)) atoms = self.get_atoms() original_atoms = atoms.copy() # save for comparison later. v_init = atoms.get_volume() # ############################################################ # ## Step 1 # ############################################################ org += ['* step 1 - relax ions and shape'] volumes1, energies1 = [], [] ready = True factors = [-0.15, -0.07, 0.0, 0.07, 0.15] for i, f in enumerate(factors): wd = cwd + '/step-1/f-{0}'.format(i) self.clone(wd) with jasp(wd, isif=4, ibrion=2, ediffg=-0.05, ediff=1e-6, nsw=50, atoms=atoms) as calc: try: # add org-link to calculation org += ['[[shell:jaspsum {0}][{0}]]'.format(wd)] atoms.set_volume(v_init * (1 + f)) volumes1.append(atoms.get_volume()) energies1.append(atoms.get_potential_energy()) calc.strip() except (VaspSubmitted, VaspQueued): ready = False if not ready: log.info('Step 1 is still running') raise VaspRunning data['step1'] = {} data['step1']['volumes'] = volumes1 data['step1']['energies'] = energies1 with open('eos.json', 'w') as f: f.write(json.dumps(data)) # create an org-table of the data. org += ['', '#+tblname: step1', '| volume (A^3) | Energy (eV) |', '|-'] for v, e in zip(volumes1, energies1): org += ['|{0}|{1}|'.format(v, e)] org += [''] with open('eos.org', 'w') as f: f.write('\n'.join(org)) eos1 = EquationOfState(volumes1, energies1) try: v1, e1, B1 = eos1.fit() except: with open('error', 'w') as f: f.write('Error fitting the equation of state') data['step1']['eos'] = (v1, e1, B1) with open('eos.json', 'w') as f: f.write(json.dumps(data)) # create a plot f = eos1.plot(show=False) f.subplots_adjust(left=0.18, right=0.9, top=0.9, bottom=0.15) plt.xlabel(u'volume ($\AA^3$)') plt.ylabel(u'energy (eV)') plt.title(u'E: %.3f eV, V: %.3f $\AA^3$, B: %.3f GPa' % (e1, v1, B1 / GPa)) plt.text(eos1.v0, max(eos1.e), 'EOS: %s' % eos1.eos_string) f.savefig('eos-step1.png') org += ['[[./eos-step1.png]]', ''] min_energy_index = np.argmin(energies1) if min_energy_index in [0, -1]: log.warn('Your minimum energy is at an endpoint.' 'This indicates something is wrong.') with open('eos.org', 'w') as f: f.write('\n'.join(org)) # ######################################################## # # STEP 2 # ######################################################## # step 2 - isif=4, ibrion=1. now we allow the shape of each cell to # change, and we use the best guess from step 1 for minimum volume. ready = True volumes2, energies2 = [], [] factors = [-0.09, -0.06, -0.03, 0.0, 0.03, 0.06, 0.09] org += ['* step 2 - relax ions and shape with improved minimum estimate'] for i, f in enumerate(factors): wd = cwd + '/step-2/f-{0}'.format(i) # clone closest result from above. with jasp('step-1/f-{0}'.format(min_energy_index)) as calc: calc.clone(wd) with jasp(wd, isif=4, ibrion=1, nsw=50) as calc: try: atoms = calc.get_atoms() atoms.set_volume(v1 * (1 + f)) volumes2 += [atoms.get_volume()] energies2 += [atoms.get_potential_energy()] calc.strip() except (VaspSubmitted, VaspQueued): ready = False if not ready: log.info('Step 2 is still running') raise VaspRunning # update org and json files. data['step2'] = {} data['step2']['volumes'] = volumes2 data['step2']['energies'] = energies2 with open('eos.json', 'w') as f: f.write(json.dumps(data)) # create an org-table of the data. org += ['', '#+tblname: step2', '| volume (A^3) | Energy (eV) |', '|-'] for v, e in zip(volumes2, energies2): org += ['|{0}|{1}|'.format(v, e)] org += [''] with open('eos.org', 'w') as f: f.write('\n'.join(org)) eos2 = EquationOfState(volumes2, energies2) try: v2, e2, B2 = eos2.fit() except: with open('error', 'w') as f: f.write('Error fitting the equation of state') data['step2']['eos'] = (v2, e2, B2) with open('eos.json', 'w') as f: f.write(json.dumps(data)) f = eos2.plot(show=False) f.subplots_adjust(left=0.18, right=0.9, top=0.9, bottom=0.15) plt.xlabel(u'volume ($\AA^3$)') plt.ylabel(u'energy (eV)') plt.title(u'E: %.3f eV, V: %.3f $\AA^3$, B: %.3f GPa' % (e2, v2, B2 / GPa)) plt.text(eos2.v0, max(eos2.e), 'EOS: %s' % eos2.eos_string) f.savefig('eos-step2.png') org += [ '[[./eos-step2.png]]', ''] with open('eos.org', 'w') as f: f.write('\n'.join(org)) # statistical analysis of the equation of state EOS = ['sjeos', 'taylor', 'murnaghan', 'birch', 'birchmurnaghan', 'pouriertarantola', 'vinet'] from ase.units import kJ Vs, Es, Bs = [], [], [] for label in EOS: eos = EquationOfState(volumes2, energies2, eos=label) try: v, e, B = eos.fit() Vs += [v] Es += [e] Bs += [B / kJ * 1.0e24] # GPa except: with open('error', 'w') as f: f.write('Error fitting the ' 'equation of state {0}'.format(label)) avgV = np.mean(Vs) stdV = np.std(Vs) avgE = np.mean(Es) stdE = np.std(Es) avgB = np.mean(Bs) stdB = np.std(Bs) from scipy.stats.distributions import t n = len(Vs) dof = n - 1 alpha = 0.05 Vconf = t.ppf(1 - alpha/2., dof) * stdV * np.sqrt(1 + 1./n) Bconf = t.ppf(1 - alpha/2., dof) * stdB * np.sqrt(1 + 1./n) data['step2']['avgV'] = avgV data['step2']['Vconf95'] = Vconf data['step2']['avgB'] = avgB data['step2']['Bconf95'] = Bconf org += ['** Statistical analysis', ''' Volume = {avgV:1.3f} \pm {Vconf:1.3f} \AA^3 at the 95% confidence level B = {avgB:1.0f} \pm {Bconf:1.0f} GPa at the 95% confidence level '''.format(**locals())] with open('eos.org', 'w') as f: f.write('\n'.join(org)) with open('eos.json', 'w') as f: f.write(json.dumps(data)) # step 3 should be isif = 3 where we let the volume change too # start from the minimum in step2 org += ['* step 3 - relax volume'] emin_ind = np.argmin(energies2) log.info('Minimum energy found in factor={0}.'.format(factors[emin_ind])) with jasp('step-2/f-{0}'.format(emin_ind)) as calc: calc.clone('step-3') with jasp('step-3', isif=3, # vol, shape and internal degrees of freedom ibrion=1, prec='high', nsw=50) as calc: atoms = calc.get_atoms() atoms.set_volume(avgV) calc.calculate() calc.strip() org += [str(calc)] atoms = calc.get_atoms() data['step3'] = {} data['step3']['potential_energy'] = atoms.get_potential_energy() data['step3']['volume'] = atoms.get_volume() with open('eos.org', 'w') as f: f.write('\n'.join(org)) with open('eos.json', 'w') as f: f.write(json.dumps(data)) # now the final step with ismear=-5 for the accurate energy. This # is recommended by the VASP manual. We only do this if you # specify static=True as an argument if static: with jasp('step-3') as calc: calc.clone('step-4') with jasp('step-4', isif=None, ibrion=None, nsw=None, icharg=2, # do not reuse charge istart=1, prec='high', ismear=-5) as calc: calc.calculate() atoms = calc.get_atoms() data['step4'] = {} data['step4']['potential_energy'] = atoms.get_potential_energy() org += ['* step-4 - static calculation', str(calc)] # final write out with open('eos.org', 'w') as f: f.write('\n'.join(org)) # dump data to a json file with open('eos.json', 'w') as f: f.write(json.dumps(data)) return data
print("-------------------------------------------") print("Calculation output for Nickel (fccNi) at 0K") print("-------------------------------------------") print(" Volumes Energies") for e, v in zip(v_Ni, e_Ni): print "{:<15} {:>10}".format(e, v) SAVE_PLOT = os.path.exists('./images') and os.path.isdir('./images') # Fit EOS print("----------------------------") print("Equation of state parameters") if not SAVE_PLOT: print("(to save a plot, mkdir 'images')") print("----------------------------") print(" E0 V0 B fit") files = [] for tag in ['vinet', 'birchmurnaghan']: eos = EquationOfState(v_Ni, e_Ni, eos=tag) v0, e0, B = eos.fit() print("{:2.6f} {:2.3f} {:2.1f} {:<16} ".format(e0, v0, B / GPa, tag)) if SAVE_PLOT: fname = 'images/fccNi-0K-eos-{0}.png'.format(tag) eos.plot(fname) files.append(fname) if SAVE_PLOT: print("Plots saved as {0}".format(", ".join([f for f in files])))
def get_e_v(fname): data = np.loadtxt(fname, usecols=(1, 3, 5, 6, 7)) volumes = data[:, 1] energies = data[:, 4] return volumes, energies def custom_plot(volumes, energies, eos): plot.plot(volumes, energies, 'ro') x = np.linspace(min(eos.v), max(eos.v), 100) y = eval(eos.eos_string)(x, eos.eos_parameters[0], eos.eos_parameters[1], eos.eos_parameters[2], eos.eos_parameters[3]) plot.plot(x, y, label='fit') plot.xlabel('Volume ($\AA^3$)') plot.ylabel('Energy (eV)') plot.legend(loc='best') plot.savefig('eos.png') plot.show() if __name__ == '__main__': volumes, energies = get_e_v('test_bulk.txt') # eos = 'sjeos', 'murnaghan', 'birch', 'taylor', 'vinet' etc. eos = EquationOfState(volumes, energies, eos='murnaghan') v0, e0, B = eos.fit() # the ASE units for the bulk modulus is eV/Angstrom^3 print('optimum volume, energy and bulk moduls', v0, e0, B) # plot # eos.plot(filename= "eos_fit") custom_plot(volumes, energies, eos)
from __future__ import print_function import pickle import numpy as np import matplotlib.pyplot as plt from ase.utils.eos import EquationOfState import ase.units as units results = [] K = range(3, 13) for k in K: A, data = pickle.load(open('eos-%d.pckl' % k)) for energies, xcname in zip(data, ['PBE', 'LDA', 'PBE0']): eos = EquationOfState(A**3 / 4, energies) v0, e0, B = eos.fit() a = (v0 * 4)**(1 / 3.0) B *= 1.0e24 / units.kJ print(('%-4s %2d %.3f %.3f %.2f' % (xcname, k, a, e0, B))) results.append((a, B)) results = np.array(results).reshape((-1, 3, 2)) LDA = dict(a=5.4037, B=95.1, eGX=0.52) PBE = dict( a=5.469, B=87.8, eGG=2.56, eGX=0.71, eGL=1.54, eI=0.47, # indirect ea=4.556) PBE0 = dict(a=5.433, B=99.0, eGG=3.96, eGX=1.93, eGL=2.87, eI=1.74, ea=4.555)
def analyse(self, atomsfile=None): try: BulkTask.analyse(self) except ValueError: # allow fit outside of range pass for name, data in self.data.items(): if 'strains' in data: atoms = self.create_system(name) # use relaxed volume if present if 'relaxed volume' in data: volume = data['relaxed volume'] else: volume = atoms.get_volume() volumes = data['strains']**3 * volume energies = data['energies'] # allow selection of eos type independent of data if self.eos is not None: eos = EquationOfState(volumes, energies, self.eos) else: eos = EquationOfState(volumes, energies) try: v, e, B = eos.fit() except ValueError: pass else: data['fitted energy'] = e data['volume'] = v data['B'] = B # with respect tot the reference volume data['volume error [%]'] = ( data['volume'] / atoms.get_volume() - 1) * 100 if self.collection.B: i = self.collection.labels.index(self.collection.xc) - 1 B = self.collection.B[name][i] * units.kJ * 1e-24 data['B error [%]'] = (data['B'] / B - 1) * 100 else: data['B error [%]'] = None data['strukturbericht'] = self.collection.data[name][0] data['crystal structure'] = strukturbericht[ data['strukturbericht']] # calculate lattice constant from volume cs = data['crystal structure'] if cs == 'bcc': a0 = (volume * 2)**(1 / 3.) a = (data['volume'] * 2)**(1 / 3.) elif cs == 'cesiumchloride': a0 = (volume)**(1 / 3.) a = (data['volume'])**(1 / 3.) elif cs in [ 'fcc', 'diamond', 'zincblende', 'rocksalt', 'fluorite' ]: a0 = (volume * 4)**(1 / 3.) a = (data['volume'] * 4)**(1 / 3.) i = self.collection.labels.index(self.collection.xc) - 1 a0_ref = self.collection.data[name][i] if 'relaxed volume' not in data: # no volume relaxation performed - volume equals the reference one assert abs(a0 - a0_ref) < 1.e-4 data['lattice constant'] = a data['lattice constant error [%]'] = (a - a0_ref) / a0_ref * 100 if atomsfile: # MDTMP: TODO atomdata = read_json(atomsfile) for name, data in self.data.items(): atoms = self.create_system(name) e = -data['energy'] for atom in atoms: e += atomdata[atom.symbol]['energy'] e /= len(atoms) data['cohesive energy'] = e if self.collection.xc == 'PBE': eref = self.collection.data[name][7] else: eref = self.collection.data[name][9] data['cohesive energy error [%]'] = (e / eref - 1) * 100 self.summary_keys += [ 'cohesive energy', 'cohesive energy error [%]' ]
kpts=(6, 6, 6), isym=2, debug=logging.DEBUG, atoms=newatoms) calculators.append(calc) # now we set up the Pool of processes pool = multiprocessing.Pool( processes=3) # ask for 6 cores but run MPI on 2 cores # get the output from running each calculation out = pool.map(do_calculation, calculators) pool.close() pool.join() # this makes the script wait here until all jobs are done # now proceed with analysis V = [x[0] for x in out] E = [x[1] for x in out] eos = EquationOfState(V, E) v1, e1, B = eos.fit() print 'step1: v1 = {v1}'.format(**locals()) ### ################################################################ ## STEP 2, eos around the minimum ## ################################################################# factors = [-0.06, -0.04, -0.02, 0.0, 0.02, 0.04, 0.06] calculators = [] # reset list for f in factors: newatoms = atoms.copy() newatoms.set_volume(v1 * (1 + f)) label = 'bulk/cu-mp2/step2-{0}'.format(COUNTER) COUNTER += 1 calc = jasp(label, xc='PBE', encut=350,
atoms.set_calculator(calc) nm_e = 0 nm_e = atoms.get_potential_energy() / atoms.get_number_of_atoms() nm_v = atoms.get_volume() / atoms.get_number_of_atoms() if nm_e < -0.001: volumes.append(nm_v) energies.append(nm_e) save(result, '{3} result : {0} {1} {2}'.format(opt, nm_v, nm_e, name)) print volumes, energies eos = EquationOfState(volumes, energies) v0, e0, B = eos.fit() eos.plot('{0}/graph/{1}.png'.format(temp_dir, name)) save( result, '{0} {1} {2} {3}'.format(v0, e0, B / kJ * 1.0e24, (4.0 * v0)**(1.0 / 3.0))) save(result, OPTIONS) save(result, volumes) save(result, energies) save(result, '------------------------') save(result_sum, '{0}, {1}, {2}, {3}, {4}, {5}'.format(name, e0, v0, B, volumes, energies))
print("-----------------------------------------") print("Calculation output for Iron (fccFe) at 0K") print("-----------------------------------------") print(" Volumes Energies") for e, v in zip(v_Fe, e_Fe): print "{:<15} {:>10}".format(e, v) SAVE_PLOT = os.path.exists('./images') and os.path.isdir('./images') # Fit EOS print("----------------------------") print("Equation of state parameters") if not SAVE_PLOT: print("(to save a plot, mkdir 'images')") print("----------------------------") print(" E0 V0 B fit") files = [] for tag in ['vinet', 'birchmurnaghan']: eos = EquationOfState(v_Fe, e_Fe, eos=tag) v0, e0, B = eos.fit() print("{:2.6f} {:2.3f} {:2.1f} {:<16} ".format(e0, v0, B/GPa, tag)) if SAVE_PLOT: fname = 'images/fccFe-0K-eos-{0}.png'.format(tag) eos.plot(fname) files.append(fname) if SAVE_PLOT: print("Plots saved as {0}".format(", ".join([f for f in files])))