示例#1
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
示例#2
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
示例#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)
        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)
示例#4
0
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
示例#5
0
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)
示例#6
0
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 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)
示例#8
0
    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()
示例#9
0
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
示例#10
0
文件: gui.py 项目: ssrokyz/ase-3.20.1
 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)
示例#11
0
	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}}])
示例#12
0
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
示例#13
0
文件: xtb_ev.py 项目: egh17/TightEV
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
示例#14
0
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 pandas as pd
from glob import glob
from ase.eos import EquationOfState

eos_name = 'birch'

for f in glob('AutoCrossfilts_VASP/*.csv'):
    dat = pd.read_csv(f)
    dat.dropna(inplace=True)
    #if dat:
    print(f)
    try:
        if max(dat['kpts']) > 100000:
            Eos = EquationOfState(dat['volume'], dat['energy'], eos=eos_name)
            E0, E0_err, V0, V0_err, B, B_err, BP, BP_err, y_pred = Eos.fit()
            pd.DataFrame({
                'E0': [E0],
                'V0': [V0],
                'B': [B],
                'BP': [BP]
            }).to_csv('Init_files/{}_Rdata_init.csv'.format(
                f.replace('.csv', '').replace('AutoCrossfilts_VASP/', '')),
                      index=False)
    except:
        print('Issue with {}'.format(f))
示例#16
0

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))
示例#17
0
    g_min, g_max = min_max['min'], min_max['max']
    min_max_norm(G_, g_min, g_max)

    e_nn, _ = predict_energy_2(
        np.asarray(G_), nn_Ti,
        nn_O)  #prediciton of energy using the neural network
    #print(e_nn)
    enn_array.append(e_nn[0])

E_val = enn_array
V_val = [
    58.75108702399997, 60.30618319748107, 61.88848153184836, 63.49821788398833,
    65.13562811078714, 66.8009480691312, 68.49441361590668, 70.21626060799997
]

eos = EquationOfState(V_val, E_val)
v0, e0, B = eos.fit()

f = open('results/result_eos.txt', 'w')  #writes results to txt file

print(
    '\n\n-----------------Birch-Murnaghan Equation of states of rutile TiO2-------------------------',
    file=f)
print('Equilibrium volume = ', '{0: <4.4f}'.format(v0), 'eV', file=f)
print('Equilibrium energy = ', '{0: <4.4f}'.format(e0), 'ij', file=f)
print('Bulk modulus predicted by NN model  = ',
      '{0: <4.4f}'.format(B / kJ * 1e24),
      'GPa',
      file=f)
print('Bulk modulus found  using DFT       =  211 GPa', file=f)
print(
示例#18
0
def test_rescaled_calculator():
    """
    Test rescaled RescaledCalculator() by computing lattice constant
    and bulk modulus using fit to equation of state
    and comparing it to the desired values
    """

    from ase.calculators.eam import EAM
    from ase.units import GPa

    # A simple empirical N-body potential for
    # transition metals by M. W. Finnis & J.E. Sinclair
    # https://www.tandfonline.com/doi/abs/10.1080/01418618408244210
    # using analytical formulation in order to avoid extra file dependence
    # All the constants are taken from the paper.
    # Please refer to the paper for more details

    def pair_potential(r):
        """
        returns the pair potential as a equation 27 in pair_potential
        r - numpy array with the values of distance to compute the pair function
        """
        # parameters for W
        c = 3.25
        c0 = 47.1346499
        c1 = -33.7665655
        c2 = 6.2541999

        energy = (c0 + c1 * r + c2 * r**2.0) * (r - c)**2.0
        energy[r > c] = 0.0

        return energy

    def cohesive_potential(r):
        """
        returns the cohesive potential as a equation 28 in pair_potential
        r - numpy array with the values of distance to compute the pair function
        """
        # parameters for W
        d = 4.400224

        rho = (r - d)**2.0
        rho[r > d] = 0.0

        return rho

    def embedding_function(rho):
        """
        returns energy as a function of electronic density from eq 3
        """

        A = 1.896373
        energy = -A * np.sqrt(rho)

        return energy

    cutoff = 4.400224
    W_FS = EAM(elements=['W'],
               embedded_energy=np.array([embedding_function]),
               electron_density=np.array([[cohesive_potential]]),
               phi=np.array([[pair_potential]]),
               cutoff=cutoff,
               form='fs')

    # 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.calc = calc
        v = at.get_volume()
        e = at.get_potential_energy()
        return v, e

    # desired DFT values
    a0_qm = 3.18556
    C11_qm = 522  # pm 15 GPa
    C12_qm = 193  # pm 5 GPa
    B_qm = (C11_qm + 2.0 * C12_qm) / 3.0

    bulk_at = bulk("W", cubic=True)

    mm_calc = W_FS
    eps = np.linspace(-0.01, 0.01, 13)
    v_mm, E_mm = zip(*[strain(bulk_at, e, mm_calc) for e in eps])

    eos_mm = EquationOfState(v_mm, E_mm)
    v0_mm, E0_mm, B_mm = eos_mm.fit()
    B_mm /= GPa
    a0_mm = v0_mm**(1.0 / 3.0)

    mm_r = RescaledCalculator(mm_calc, a0_qm, B_qm, a0_mm, B_mm)
    bulk_at = bulk("W", cubic=True, a=a0_qm)
    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()
    B_mm_r /= GPa
    a0_mm_r = v0_mm_r**(1.0 / 3)

    # check match of a0 and B after rescaling is adequate
    # 0.1% error in lattice constant and bulk modulus
    assert abs((a0_mm_r - a0_qm) / a0_qm) < 1e-3
    assert abs((B_mm_r - B_qm) / B_qm) < 1e-3
示例#19
0
def main():

    latoms = vf.get_list_of_atoms()
    latoms2 = vf.get_list_of_outcar()

    natoms = latoms[0].get_positions().shape[0]

    V = np.array([]) 
    ca = np.array([])
    magtot = np.array([])

    for i in np.arange(len(latoms)):
        temp = latoms[i].get_volume()/natoms
        V = np.append(V, temp) 
        
        temp = latoms[i].get_cell()[:]
        temp = np.linalg.norm( temp[2,:] ) / np.linalg.norm( temp[0,:] ) 
        ca = np.append(ca, temp) 


        try:
            temp = latoms2[i].get_magnetic_moment()/natoms
        except:
            temp = 0
        magtot = np.append(magtot, temp)
        
    magtot = np.abs(magtot)


    jobn, Etot, Eent, pres = vf.vasp_read_post_data()

    a_pos = np.array([])  # scale in POSCAR
    for i in jobn:
        filename = './y_dir/%s/CONTCAR' %(i)
        with open(filename,'r') as f:
            a_pos = np.append( a_pos, float( f.readlines()[1] ) )

 
    Etot = Etot / natoms
    fitres = myfitting(V, Etot)


    V1 = np.array([])
    a1_pos = np.array([])
    p_dft = np.array([])

    for i in np.arange(len(jobn)):
        p_dft = np.append( p_dft, pres[i,0:2].mean()*(0.1) )  # pressure [GPa]
        
        if jobn[i][0] == '0' or jobn[i][0] == '1' :   
            V1 = np.append( V1, V[i] / float(jobn[i]))
            a1_pos = np.append( a1_pos, a_pos[i] / (float(jobn[i]))**(1/3) )
     
    
    if (V1.std() > 1e-8) or (a1_pos.std() > 1e-8) :
        print('V1, V1.std(), a1_pos.std():')
        print( V1, V1.std(), a1_pos.std()  )
        sys.exit('V1 or a1_pos is wrong. Abort!')
    else:
        V1 = V1.mean()
        a1_pos = a1_pos.mean()

    write_output(V, Etot, fitres, V1, a1_pos, p_dft)
    plot_eos(V, Etot, fitres, p_dft, V1, ca, magtot)


    ASE_eos = EquationOfState(V, Etot, eos='birchmurnaghan')
    temp = np.array([ 
    ASE_eos.fit()[1] - fitres[0], 
    ASE_eos.fit()[0] - fitres[1],
    ASE_eos.fit()[2] - fitres[2] ])
    print('==> check with ASE fitting, diff: {0} \n'.format(temp) )
示例#20
0
from ase.io.trajectory import Trajectory
from ase.io import read
from ase.units import kJ
from ase.eos import EquationOfState, vinet

numberline = 0
f3 = open('e-v.dat')
for line in f3:
    numberline = numberline + 1

energies = np.zeros(numberline)
volumes = np.zeros(numberline)
i = 0
with open("e-v.dat") as f3:
    for line in f3:
        line = line.rstrip('\n')
        volumes[i], energies[i] = line.split(" ")
        i = i + 1

eos = EquationOfState(volumes, energies, eos='vinet')
eos.fit()
e0, B, Bp, v0 = eos.eos_parameters
fp = open("helmholtz-volume.dat")
for i, line in enumerate(fp):
    if i == 1:
        a, b, Fmin, d, e, V = line.split()
fp.close()
print(float(Fmin) - vinet(float(V), e0, B, Bp, v0)),
#print eos
#v0, e0, B= eos.fit()
示例#21
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
示例#22
0
def test_forceqmmm():
    # parameters
    N_cell = 2
    R_QMs = np.array([3, 7])

    # setup bulk and MM region
    bulk_at = bulk("Cu", cubic=True)
    sigma = (bulk_at * 2).get_distance(0, 1) * (2.**(-1. / 6))
    mm = LennardJones(sigma=sigma, epsilon=0.05)
    qm = EMT()

    # 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.calc = 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
    assert abs(
        (a0_mm_r - a0_qm) / a0_qm) < 1e-3  # 0.1% error in lattice constant
    assert abs((B_mm_r - B_qm) / B_qm) < 0.05  # 5% error in bulk modulus

    # plt.plot(v_mm, E_mm - np.min(E_mm), 'o-', label='MM')
    # plt.plot(v_qm, E_qm - np.min(E_qm), 'o-', label='QM')
    # plt.plot(v_mm_r, E_mm_r - np.min(E_mm_r), 'o-', label='MM rescaled')
    # plt.legend()

    at0 = bulk_at * N_cell
    r = at0.get_distances(0, np.arange(1, len(at0)), mic=True)
    print(len(r))
    del at0[0]  # introduce a vacancy
    print("N_cell", N_cell, 'N_MM', len(at0))

    ref_at = at0.copy()
    ref_at.calc = qm
    opt = FIRE(ref_at)
    opt.run(fmax=1e-3)
    u_ref = ref_at.positions - at0.positions

    us = []
    for R_QM in R_QMs:
        at = at0.copy()
        mask = r < R_QM
        print('R_QM', R_QM, 'N_QM', mask.sum(), 'N_total', len(at))
        qmmm = ForceQMMM(at, mask, qm, mm, buffer_width=2 * qm.rc)
        at.calc = qmmm
        opt = FIRE(at)
        opt.run(fmax=1e-3)
        us.append(at.positions - at0.positions)

    # compute error in energy norm |\nabla u - \nabla u_ref|
    def strain_error(at0, u_ref, u, cutoff, mask):
        I, J = neighbor_list('ij', at0, cutoff)
        I, J = np.array([(i, j) for i, j in zip(I, J) if mask[i]]).T
        v = u_ref - u
        dv = np.linalg.norm(v[I, :] - v[J, :], axis=1)
        return np.linalg.norm(dv)

    du_global = [
        strain_error(at0, u_ref, u, 1.5 * sigma, np.ones(len(r))) for u in us
    ]
    du_local = [strain_error(at0, u_ref, u, 1.5 * sigma, r < 3.0) for u in us]

    print('du_local', du_local)
    print('du_global', du_global)

    # check local errors are monotonically decreasing
    assert np.all(np.diff(du_local) < 0)

    # check global errors are monotonically converging
    assert np.all(np.diff(du_global) < 0)

    # biggest QM/MM should match QM result
    assert du_local[-1] < 1e-10
    assert du_global[-1] < 1e-10
示例#23
0
# 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
示例#24
0
    def collect_data_and_fit(self):
        """
        collect output of KKR calculations and perform eos fitting to collect results
        """
        self.report('INFO: collect kkr results and fit data')
        calc_uuids = self.ctx.kkr_calc_uuids
        etot = []
        for iic in range(len(calc_uuids)):
            uuid = calc_uuids[iic]
            n = load_node(uuid)
            try:
                d_result = n.outputs.output_kkr_scf_wc_ParameterResults.get_dict(
                )
                self.report(
                    'INFO: extracting output of calculation {}: successful={}, rms={}'
                    .format(uuid, d_result[u'successful'],
                            d_result[u'convergence_value']))
                if d_result[u'successful']:
                    pk_last_calc = d_result['last_calc_nodeinfo']['pk']
                    n2 = load_node(pk_last_calc)
                    scale = self.ctx.scale_factors[iic]
                    ener = n2.outputs.output_parameters.get_dict(
                    )['total_energy_Ry']
                    rms = d_result[u'convergence_value']
                    scaled_struc = self.ctx.scaled_structures[iic]
                    v = scaled_struc.get_cell_volume()
                    if rms <= self.ctx.rms_threshold:  # only take those calculations which
                        etot.append([scale, ener, v, rms])
                    else:
                        warn = 'rms of calculation with uuid={} not low enough ({} > {})'.format(
                            uuid, rms, self.ctx.rms_threshold)
                        self.report('WARNING: {}'.format(warn))
                        self.ctx.warnings.append(warn)
            except:
                warn = 'calculation with uuid={} not successful'.format(uuid)
                self.report('WARNING: {}'.format(warn))
                self.ctx.warnings.append(warn)

        # collect calculation outcome
        etot = array(etot)
        self.report('INFO: collected data from calculations= {}'.format(etot))

        # check if at least 3 points were successful (otherwise fit does not work)
        if len(etot) < 3:
            return self.exit_codes.ERROR_NOT_ENOUGH_SUCCESSFUL_CALCS

        scalings = etot[:, 0]
        rms = etot[:, -1]
        # convert to eV and per atom units
        etot = etot / len(scaled_struc.sites)  # per atom values
        etot[:, 1] = etot[:, 1] * get_Ry2eV()  # convert energy from Ry to eV
        volumes, energies = etot[:, 2], etot[:, 1]

        # do multiple fits to data
        self.report('INFO: output of fits:')
        self.report('{:18} {:8} {:7} {:7}'.format('fitfunc', 'v0', 'e0', 'B'))
        self.report('-----------------------------------------')
        fitnames = self.ctx.fitnames
        alldat = []
        fitdata = {}
        for fitfunc in fitnames:
            try:
                eos = EquationOfState(volumes, energies, eos=fitfunc)
                v0, e0, B = eos.fit()
                fitdata[fitfunc] = [v0, e0, B]
                alldat.append([v0, e0, B])
                self.report('{:16} {:8.3f} {:7.3f} {:7.3f}'.format(
                    fitfunc, v0, e0, B))
            except:  # capture all errors and mark fit as unsuccessful
                self.ctx.warnings.append(
                    'fit unsuccessful for {} function'.format(fitfunc))
                if fitfunc == self.ctx.fitfunc_gs_out:
                    self.ctx.successful = False
        alldat = array(alldat)
        self.report('-----------------------------------------')
        self.report('{:16} {:8.3f} {:7.3f} {:7.3f}'.format(
            'mean', mean(alldat[:, 0]), mean(alldat[:, 1]), mean(alldat[:,
                                                                        2])))
        self.report('{:16} {:8.3f} {:7.3f} {:7.3f}'.format(
            'std', std(alldat[:, 0]), std(alldat[:, 1]), std(alldat[:, 2])))

        # store results in context
        self.ctx.volumes = volumes
        self.ctx.energies = energies
        self.ctx.scalings = scalings
        self.ctx.rms = rms
        self.ctx.fitdata = fitdata
        self.ctx.fit_mean_values = {
            '<v0>': mean(alldat[:, 0]),
            '<e0>': mean(alldat[:, 1]),
            '<B>': mean(alldat[:, 2])
        }
        self.ctx.fit_std_values = {
            's_v0': std(alldat[:, 0]),
            's_e0': std(alldat[:, 1]),
            's_B': std(alldat[:, 2])
        }
示例#25
0
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))
示例#26
0
"""

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')
示例#27
0
文件: plot_a.py 项目: thonmaker/gpaw
def lattice_constant(volumes, energies):
    eos = EquationOfState(volumes, energies)
    v, e, B = eos.fit()
    a = (v * 4)**(1 / 3)
    return a
示例#28
0
    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.")
示例#29
0
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
示例#30
0
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