Ejemplo n.º 1
0
def ase_dynmat(args):
    from gpaw import GPAW
    from ase.phonons import Phonons
    from ase.dft.kpoints import BandPath

    calc = GPAW(args.GPW)
    phonon = Phonons(calc.get_atoms(), name=args.name, delta=args.displacement)
    phonon.read(acoustic=args.acoustic, symmetrize=args.symmetrize, method=args.method)
    return phonon.compute_dynamical_matrix([0, 0, 0], phonon.D_N)
def getLJeigenvaluesB(X, S, epsilon, sigma, rc, getForceMatrix):
    from ase import Atoms
    from ase.build import bulk
    from ase.calculators.lj import LennardJones
    from ase.phonons import Phonons
    import numpy as np
    from scipy import linalg as LA
    calc = LennardJones(sigma=sigma, epsilon=epsilon, rc=rc)
    # chemStr = 'H' + str(len(X))
    # atoms = Atoms(chemStr, X, calculator=calc )
    atoms = Atoms(getChemStr(S), X, calculator=calc)
    energy = atoms.get_potential_energy()
    eig = []
    if getForceMatrix:
        ph = Phonons(atoms, calc)
        ph.run()
        ph.read(acoustic=True)
        ph.clean()

        f = ph.get_force_constant()
        (l, m, n) = f.shape
        if l == 1:
            ff = np.reshape(f, (m, n))
        else:
            print("error")
        #
        eig = LA.eigvalsh(ff)  # eig is a numpy array
    #
    return energy, [float("{0:.5f}".format(eig[i])) for i in range(len(eig))]
Ejemplo n.º 3
0
    def __init__(self, atoms, *args, **kwargs):
        RamanData.__init__(self, atoms, *args, **kwargs)

        for key in ['txt', 'exext', 'exname']:
            kwargs.pop(key, None)
        kwargs['name'] = kwargs.get('name', self.name)
        self.vibrations = Phonons(atoms, *args, **kwargs)

        self.delta = self.vibrations.delta
        self.indices = self.vibrations.indices

        self.kpts = (1, 1, 1)
Ejemplo n.º 4
0
def get_dos(
        model,
        posinp,
        device="cpu",
        supercell=(6, 6, 6),
        qpoints=[30, 30, 30],
        npts=1000,
        width=0.004,
):
    if isinstance(posinp, str):
        atoms = posinp_to_ase_atoms(Posinp.from_file(posinp))
    elif isinstance(posinp, Posinp):
        atoms = posinp_to_ase_atoms(posinp)
    else:
        raise ValueError("The posinp variable is not recognized.")

    if isinstance(model, str):
        model = load_model(model, map_location=device)
    elif isinstance(model, torch.nn.Module):
        pass
    else:
        raise ValueError("The model variable is not recognized.")

    # Bugfix to make older models work with PyTorch 1.6
    # Hopefully temporary
    for mod in model.modules():
        if not hasattr(mod, "_non_persistent_buffers_set"):
            mod._non_persistent_buffers_set = set()

    assert len(supercell) == 3, "Supercell should be a length 3 object."
    assert len(qpoints) == 3, "Qpoints should be a length 3 object."
    supercell = tuple(supercell)

    cutoff = float(model.state_dict()
                   ["representation.interactions.0.cutoff_network.cutoff"])
    calculator = SpkCalculator(
        model,
        device=device,
        energy="energy",
        forces="forces",
        environment_provider=AseEnvironmentProvider(cutoff),
    )
    ph = Phonons(atoms, calculator, supercell=supercell, delta=0.02)
    ph.run()
    ph.read(acoustic=True)
    dos = ph.get_dos(kpts=qpoints).sample_grid(npts=npts, width=width)
    ph.clean()
    return Dos(dos.energy * 8065.6, dos.weights[0])
Ejemplo n.º 5
0
def phonon_run(runID, save_to_db=False, plot_bands=False):
    print("Running ID %d" % (runID))
    db = connect(db_name)
    atoms = db.get_atoms(id=runID)
    #view(atoms)
    #atoms = bulk("Al")
    #atoms = atoms*(2,1,1)
    #calc = EAM(potential="/home/davidkl/Documents/EAM/Al-LEA.eam.alloy")
    calc = EAM(potential="/home/davidkl/Documents/EAM/mg-al-set.eam.alloy")
    atoms.set_calculator(calc)
    #calc = gp.GPAW( mode=gp.PW(600), xc="PBE", kpts=(4,4,4), nbands="120%", symmetry="off" )
    #atoms.set_calculator(calc)
    ph = Phonons(atoms,
                 calc,
                 supercell=(3, 3, 3),
                 name=wrk + "/phonon_files/phonon%d" % (runID))
    ph.run()
    #return
    ph.read(acoustic=True)
    omega_e, dos_e = ph.dos(kpts=(30, 30, 30), npts=1000, delta=5E-4)
    if (plot_bands):
        points = ibz_points['fcc']
        G = points['Gamma']
        X = points['X']
        W = points['W']
        K = points['K']
        L = points['L']
        U = points['U']
        point_names = ['$\Gamma$', 'X', 'U', 'L', '$\Gamma$', 'K']
        path = [G, X, U, L, G, K]

        path_kc, q, Q = bandpath(path, atoms.cell, 100)
        omega_kn = 1000.0 * ph.band_structure(path_kc)

        figb = plt.figure()
        axb = figb.add_subplot(1, 1, 1)
        for n in range(len(omega_kn[0])):
            omega_n = omega_kn[:, n]
            axb.plot(q, omega_n)
        plt.show()

    if (save_to_db):
        # Store the results in the database
        db.update(runID, has_dos=True)

        manager = cpd.PhononDOS_DB(db_name)

        # Extract relevant information from the atoms database
        row = db.get(id=runID)
        name = row.name
        atID = row.id
        manager.save(name=name, atID=atID, omega_e=omega_e, dos_e=dos_e)
Ejemplo n.º 6
0
 def test_hessian(self):
     for calc in [{(1, 1): LennardJonesQuadratic(1, 1, 3), (1, 2): LennardJonesQuadratic(1.5, 0.8, 2.4), (2, 2): LennardJonesQuadratic(0.5, 0.88, 2.64)}]:
         atoms = io.read("KA256_Min.xyz")
         atoms.center(vacuum=5.0)
         b = calculator.PairPotential(calc)
         H_analytical = b.calculate_hessian_matrix(atoms, "dense")
         # Numerical
         ph = Phonons(atoms, b, supercell=(1, 1, 1), delta=0.001)
         ph.run()
         ph.read(acoustic=False)
         ph.clean()
         H_numerical = ph.get_force_constant()[0, :, :]
         self.assertArrayAlmostEqual(H_analytical, H_numerical, tol=0.03)
Ejemplo n.º 7
0
 def test_hessian(self):
     for calc in [{
         (1, 1): LennardJonesQuadratic(1, 1, 3),
         (1, 2): LennardJonesQuadratic(1.5, 0.8, 2.4),
         (2, 2): LennardJonesQuadratic(0.5, 0.88, 2.64)
     }]:
         atoms = io.read("KA256_Min.xyz")
         atoms.center(vacuum=5.0)
         b = calculator.PairPotential(calc)
         H_analytical = b.calculate_hessian_matrix(atoms, "dense")
         # Numerical
         ph = Phonons(atoms, b, supercell=(1, 1, 1), delta=0.001)
         ph.run()
         ph.read(acoustic=False)
         ph.clean()
         H_numerical = ph.get_force_constant()[0, :, :]
         self.assertArrayAlmostEqual(H_analytical, H_numerical, tol=0.03)
Ejemplo n.º 8
0
class RamanPhonons(RamanData):
    def __init__(self, atoms, *args, **kwargs):
        RamanData.__init__(self, atoms, *args, **kwargs)

        for key in ['txt', 'exext', 'exname']:
            kwargs.pop(key, None)
        kwargs['name'] = kwargs.get('name', self.name)
        self.vibrations = Phonons(atoms, *args, **kwargs)

        self.delta = self.vibrations.delta
        self.indices = self.vibrations.indices

        self.kpts = (1, 1, 1)

    @property
    def kpts(self):
        return self._kpts

    @kpts.setter
    def kpts(self, kpts):
        if not hasattr(self, '_kpts') or kpts != self._kpts:
            self._kpts = kpts
            self.kpts_kc = monkhorst_pack(self.kpts)
            if hasattr(self, 'im_r'):
                del self.im_r  # we'll have to recalculate

    def calculate_energies_and_modes(self):
        if not self._already_read:
            if hasattr(self, 'im_r'):
                del self.im_r
            self.read()

        if not hasattr(self, 'im_r'):
            self.timer.start('band_structure')
            omega_kl, u_kl = self.vibrations.band_structure(
                self.kpts_kc, modes=True, verbose=self.verbose)

            self.im_r = self.vibrations.m_inv_x
            self.om_Q = omega_kl.ravel().real  # energies in eV
            self.modes_Qq = u_kl.reshape(len(self.om_Q), 3 * len(self.atoms))
            self.modes_Qq /= self.im_r
            self.om_v = self.om_Q

            # pre-factors for one vibrational excitation
            with np.errstate(divide='ignore', invalid='ignore'):
                self.vib01_Q = np.where(self.om_Q > 0,
                                        1. / np.sqrt(2 * self.om_Q), 0)
            # -> sqrt(amu) * Angstrom
            self.vib01_Q *= np.sqrt(u.Ha * u._me / u._amu) * u.Bohr
            self.timer.stop('band_structure')
def getLJeigenvalues(listOfPositions, epsilon, sigma, rc, getForceMatrix):
    from ase import Atoms
    from ase.build import bulk
    from ase.calculators.lj import LennardJones
    from ase.phonons import Phonons
    import numpy as np
    from scipy import linalg as LA
    # from gpaw import GPAW, FermiDirac
    # calc = LennardJones() #a.set_calculator(calc)

    # atoms = bulk('Si', 'diamond', a=5.4)
    # atoms = bulk('H', 'fcc', a=1.1, cubic=True)
    #atoms = Atoms('N3', [(0, 0, 0), (0, 0, 1.1), (0, 0, 2.2)], calculator=LennardJones() )
    # atoms = Atoms('H2', [(0, 0, 0), (0, 0, 1.12246)], calculator=LennardJones() )
    # calc = GPAW(kpts=(5, 5, 5), h=0.2, occupations=FermiDirac(0.))

    chemStr = 'H' + str(len(listOfPositions))
    calc = LennardJones(sigma=sigma, epsilon=epsilon, rc=rc)
    atoms = Atoms(chemStr, listOfPositions, calculator=calc)

    energy = atoms.get_potential_energy()

    eig = []
    if getForceMatrix:
        ph = Phonons(atoms, calc)
        ph.run()
        ph.read(acoustic=True)
        ph.clean()

        f = ph.get_force_constant()
        # f
        # f.size
        (l, m, n) = f.shape
        if l == 1:
            ff = np.reshape(f, (m, n))
        else:
            print("error")
        #
        # ff
        eig = LA.eigvalsh(ff)  # eig is a numpy array
    #
    return energy, [float("{0:.5f}".format(eig[i])) for i in range(len(eig))]
 def getEnergyAndEigen(self, aseStruct):
     aseStruct.set_calculator(self.calc)
     energy = aseStruct.get_potential_energy()
     eig = []
     ph = Phonons(aseStruct, self.calc)
     ph.run()
     ph.read(acoustic=True)
     ph.clean()
     f = ph.get_force_constant()
     (l, m, n) = f.shape
     if l == 1:
         ff = np.reshape(f, (m, n))
     else:
         print("error")
     #
     eig = LA.eigvalsh(ff)  # eig is a numpy array
     #
     return energy, [
         float("{0:.5f}".format(eig[i])) for i in range(len(eig))
     ]
Ejemplo n.º 11
0
    def get_phonons(self, kpts=(50, 50, 50), npts=5000):
        """Calculate the phonon spectrum and DOS.

        Parameters
        ----------
        kpts : tuple
            Number of points in each directions of the k-space grid.
        npts : int
            Number of energy points to calculate the DOS at.

        """
        self.phonons = Phonons(self.atoms,
                               self.calc(),
                               supercell=self.supercell_size,
                               delta=0.05,
                               name=self.name)
        self.phonons.run()
        # Read forces and assemble the dynamical matrix
        self.phonons.read(acoustic=True)
        self.phonon_kpts_mp = monkhorst_pack(kpts)
        self.phonon_energy_mp = self.phonons.band_structure(
            self.phonon_kpts_mp)
        self.phonon_energy, self.phonon_dos = \
            self.phonons.dos(kpts=kpts, npts=npts, delta=5e-4)
def getLJeigenvalues2B(X, S, epsilon, sigma, rc, getForceMatrix, aCell):
    from ase import Atoms
    from ase.build import bulk
    from ase.phonons import Phonons
    import numpy as np
    from scipy import linalg as LA
    from ase import Atom, Atoms
    from lammpslib import LAMMPSlib

    # chemStr = 'H' + str(len(X))
    # struct = Atoms(chemStr, X, cell=(aCell, aCell, aCell), pbc=True)
    struct = Atoms(getChemStr(S), X, cell=(aCell, aCell, aCell), pbc=True)
    lammps_header = ["units       metal"]
    cmds          = [ "pair_style  mlip  /Users/chinchay/Documents/9_Git/reverseEnergyPartitioning/mlip_LJ.ini",\
                      "pair_coeff  * * " ]
    mylammps = LAMMPSlib(
        lmpcmds=cmds,
        atom_types={1: 1},
        keep_alive=True,
        log_file=
        '/Users/chinchay/Documents/9_Git/reverseEnergyPartitioning/log.txt')
    struct.set_calculator(mylammps)
    energy = struct.get_potential_energy()
    eig = []
    if getForceMatrix:
        ph = Phonons(struct, mylammps)
        ph.run()
        ph.read(acoustic=True)
        ph.clean()
        f = ph.get_force_constant()
        (l, m, n) = f.shape
        if l == 1:
            ff = np.reshape(f, (m, n))
        else:
            print("error")
        #
        eig = LA.eigvalsh(ff)  # eig is a numpy array
    #
    return energy, [float("{0:.5f}".format(eig[i])) for i in range(len(eig))]
Ejemplo n.º 13
0
def test_crystal_thermo(asap3, testdir):
    atoms = bulk('Al', 'fcc', a=4.05)
    calc = asap3.EMT()
    atoms.calc = calc
    energy = atoms.get_potential_energy()

    # Phonon calculator
    N = 7
    ph = Phonons(atoms, calc, supercell=(N, N, N), delta=0.05)
    ph.run()

    ph.read(acoustic=True)
    phonon_energies, phonon_DOS = ph.dos(kpts=(4, 4, 4), npts=30, delta=5e-4)

    thermo = CrystalThermo(phonon_energies=phonon_energies,
                           phonon_DOS=phonon_DOS,
                           potentialenergy=energy,
                           formula_units=4)
    thermo.get_helmholtz_energy(temperature=298.15)
        },
        'H': {
            'L': -1,
            'U': 0.0,
            'J': 0.0
        }
    },
    ldauprint=2,
    lmaxmix=6,
    lorbit=11,
)
#__|

#| - Phonon Calculation
from ase.phonons import Phonons
ph = Phonons(new_atoms, calc, supercell=(1, 1, 1))
#ph.run()
ph.read(method='frederiksen', acoustic=True)

phonon_energies, phonon_DOS = ph.dos(kpts=(40, 40, 40), npts=3000, delta=5e-4)

# Calculate the Helmholtz free energy
potentialenergy = 0.0
from ase.thermochemistry import CrystalThermo
thermo = CrystalThermo(phonon_energies=phonon_energies,
                       phonon_DOS=phonon_DOS,
                       potentialenergy=potentialenergy,
                       formula_units=1)
F = thermo.get_helmholtz_energy(temperature=298.15)

#dyn = QuasiNewton(atoms, logfile=name+'.log', trajectory=name+'.traj')
Ejemplo n.º 15
0
def main():
    ''' Read in parameters for EAM calc '''
    with open('HA4/results/fit_potential_output_full.txt', 'r') as textfile:
        line = next(textfile)
        line = line.split(',')
        A = float(line[0])
        lmbd = float(line[1])
        D = float(line[2])
        mu2 = float(line[3])

    # with open('HAlea')
    # ''' Optimization parameters '''
    # A = 1000  # eV
    # lmbd = 3  # Å^(-1)
    # D = 5  # Å
    # mu2 = 1  # 2  # Å^(-1)
    # param_0 = [A, lmbd, D, mu2]
    ''' Strains and stuff '''
    eV_to_J = 1.60217662 * 10**(-19)
    angstrom_to_meter = 1e-10
    calc = get_calc((A, lmbd, D, mu2))
    # calc = EMT()
    e1 = 0.01
    e6 = 0.01
    energies = []
    C11_vec = []
    C12_vec = []
    B_vec = []

    x = np.linspace(0, 0.5, 100)
    for i in x:
        e1 = i
        e6 = i

        # C11-C12
        al_bulk = bulk('Al', 'fcc', a=4.032, cubic=True)
        al_bulk.set_calculator(calc)
        ep_mat_1 = np.array([[e1, 0, 0], [0, -e1, 0],
                             [0, 0, e1**2 / (1 - e1**2)]])
        energies.append(al_bulk.get_potential_energy())
        cell_0 = al_bulk.get_cell()
        # al_bulk.set_cell(np.dot((np.eye(3) + ep_mat_1), np.transpose(cell_0)))
        al_bulk.set_cell(np.dot((np.eye(3) + ep_mat_1),
                                cell_0))  # Yields same result
        energies.append(al_bulk.get_potential_energy())

        # print(cell_0 / al_bulk.get_cell())
        # print(cell_0)
        # print(al_bulk.get_cell())

        V = al_bulk.get_volume()  #4 * al_bulk.get_volume()
        delta_E = energies[-1] - energies[0]
        C11_minus_C12 = delta_E / (V * e1**2)
        # print('Hola', C11_minus_C12 * eV_to_J / (angstrom_to_meter**3 * 1e9))

        # C11+C12
        al_bulk = bulk('Al', 'fcc', a=4.032, cubic=True)
        al_bulk.set_calculator(calc)

        e2 = e1
        ep_mat_12 = np.array([[e1, 0, 0], [0, e2, 0], [0, 0, 0]])

        energies.append(al_bulk.get_potential_energy())

        V = al_bulk.get_volume(
        )  #4 * al_bulk.get_volume()  # Equilibrium cell volume
        cell_0 = al_bulk.get_cell()
        al_bulk.set_cell(np.dot((np.eye(3) + ep_mat_12), cell_0))
        energies.append(al_bulk.get_potential_energy())
        delta_E = energies[-1] - energies[0]
        C11_plus_C12 = delta_E / (V * e1**2)
        # print(C11_plus_C12)

        # C11 and C12
        C11 = (C11_minus_C12 + C11_plus_C12) / 2
        C12 = C11_plus_C12 - C11

        C11_vec.append(C11 * eV_to_J / (angstrom_to_meter**3 * 1e9))
        C12_vec.append(C12 * eV_to_J / (angstrom_to_meter**3 * 1e9))

        B_vec.append(
            ((C11 + 2 * C12) / 3) * eV_to_J / (angstrom_to_meter**3 * 1e9))

    plt.figure()
    plt.plot(x, C11_vec)
    plt.plot(x, C12_vec)
    plt.plot(x, B_vec)
    plt.set_xlabel(
        r'Displacement factor $\varepsilon_1 = \varepsilon_2 \varepsilon_6 $')
    plt.set_ylabel('Elastic constants/Bulk modulus [GPa]')
    plt.show()

    # C44
    al_bulk = bulk('Al', 'fcc', a=4.032, cubic=True)
    al_bulk.set_calculator(calc)
    cell_0 = al_bulk.get_cell()

    ep_mat_6 = np.array([[0, 0.5 * e6, 0], [0.5 * e6, 0, 0],
                         [0, 0, e6**2 / (4 - e6**2)]])

    al_bulk.set_cell(np.dot((np.eye(3) + ep_mat_6), cell_0))
    energies.append(al_bulk.get_potential_energy())
    V = 4 * al_bulk.get_volume()
    delta_E = energies[-1] - energies[0]
    C44 = 2 * delta_E / (V * e6**2)
    # print(C44)

    B = (C11 + 2 * C12) / 3

    # print('C11: ', C11 * eV_to_J / (angstrom_to_meter**3 * 1e9))
    # print('C12: ', C12 * eV_to_J / (angstrom_to_meter**3 * 1e9))
    B_SI = B * eV_to_J / (angstrom_to_meter)**3
    B_GPa = B_SI / 1e9
    # print('B', B_GPa)

    c_prim = (C11 * C12) / 2
    ''' Phonon calculator '''
    al_bulk = bulk('Al', 'fcc', a=4.032)
    N = 7
    ph = Phonons(al_bulk, calc, supercell=(N, N, N), delta=0.05)
    ph.run()

    # Read forces and assemble the dynamical matrix
    ph.read(acoustic=True, banana=True)

    # High-symmetry points in the Brillouin zone
    points = ibz_points['fcc']
    G = points['Gamma']
    X = points['X']
    W = points['W']
    K = points['K']
    L = points['L']
    U = points['U']

    point_names = ['$\Gamma$', 'X', 'U', 'L', '$\Gamma$', 'K']
    path = [G, X, U, L, G, K]

    # Band structure in meV
    path_kc, q, Q = bandpath(path, al_bulk.cell, 100)
    omega_kn = 1000 * ph.band_structure(path_kc)

    # # Check band path
    # fig = plt.figure()
    # ax = fig.add_subplot(111, projection='3d')
    # ax.plot(path_kc[:,0], path_kc[:,1], path_kc[:,2])
    # plt.show()

    # Calculate phonon DOS
    # omega_e, dos_e = ph.dos(kpts=(50, 50, 50), npts=5000, delta=5e-4)
    # omega_e *= 1000
    #
    # # Plot the band structure and DOS
    # plt.figure(1, (8, 6))
    # plt.axes([.1, .07, .67, .85])
    # for n in range(len(omega_kn[0])):
    #     omega_n = omega_kn[:, n]
    #     plt.plot(q, omega_n, 'k-', lw=2)
    #
    # plt.xticks(Q, point_names, fontsize=18)
    # plt.yticks(fontsize=18)
    # plt.xlim(q[0], q[-1])
    # plt.ylabel("Frequency ($\mathrm{meV}$)", fontsize=22)
    # plt.grid('on')
    #
    # plt.axes([.8, .07, .17, .85])
    # plt.fill_between(dos_e, omega_e, y2=0, color='lightgrey', edgecolor='k', lw=1)
    # plt.ylim(0, 35)
    # plt.xticks([], [])
    # plt.yticks([], [])
    # plt.xlabel("DOS", fontsize=18)
    # plt.show()
    ''' Sound velocity '''
    # point_names = ['$\Gamma$', 'X']
    path_100 = [G, X]

    # Band structure in meV
    # Return list of k-points, list of x-coordinates and list of x-coordinates of special points.
    path_kc_100, q_100, Q_100 = bandpath(path_100, al_bulk.cell, 100)
    omega_kn_100 = 1000 * ph.band_structure(path_kc_100)

    # # Find the longitudinal curve (the one that is not initially overlapping)
    # print(omega_kn_100[0:10,0])
    # print(omega_kn_100[0:10,1])
    # print(omega_kn_100[0:10,2]) # <-- This one!

    k = np.sqrt(path_kc_100[:, 0]**2 + path_kc_100[:, 1]**2 +
                path_kc_100[:, 2]**2)  # [Å^-1]
    convert_meV_to_1_over_s = (1 / 1000) * (1 / (6.582119514 * 10**(-16)))
    # print(omega_kn_100[1,2])

    omega_long_at_q_to_0 = omega_kn_100[1, 2] * convert_meV_to_1_over_s
    # omega_long_at_q_to_1 = omega_kn_100[2,2] * convert_meV_to_1_over_s

    c_s = omega_long_at_q_to_0 * 10**(-10) / k[1]  # Speed of sound, [m/s]
    # c_s = 10**(-10) * ((omega_long_at_q_to_1 - omega_long_at_q_to_0)  / (k[2] - k[1])) # Speed of sound, [m/s]
    print(c_s)
    #
    # convert_u_to_kg = 1.66054 * 10**(-27)
    # convert_kg_to_eV_c2 = (2.99792 * 10**8)**2
    # m_Al = al_bulk.get_masses()[0] * convert_u_to_kg * convert_kg_to_eV_c2 # [eV * (s^2/m^2)]
    # nbr_of_atoms_UC = 4 # Number of atoms per unit cell for fcc
    # V_Al = nbr_of_atoms_UC * al_bulk.get_volume() # [Å^3]
    # rho_Al = m_Al * nbr_of_atoms_UC / V_Al # [eV * (s^2/m^2) / Å^3]
    # young = c_s**2 * rho_Al
    #
    # print(C11)
    # print(young)

    plt.figure()
    plt.plot(q_100, omega_kn_100)
    plt.show()
Ejemplo n.º 16
0
class ThermalProperties(object):
    """Class with methods to calculate thermal properties of a structure within the QHA

    Attributes
    ----------
    name : str
        Base name for the files used for the phonon calculations.
    structure : ATAT2EMT
        ATAT structure file describing the primitive cell.
    atoms : ase.Atoms
        Atoms object with the primitive cell.
    calc : ase.Calculator
        Callable returning a Calculator to use for all energy and force calculations.
    n_atoms : int
        Number of atoms in the primitive cell.
    temperature : Iterable of float
        Temperatures at which to calculate temperature dependent properties.
    strains : Iterable of float
        Strains to apply to the atoms for volume dependent properties.
    strained_thermo : list of ThermalProperties
        List with classes for the thermal properties of strained versions of the atoms object.
    sjeos : SJEOS
        Class to fit the equation of state at constant temperature.
    base_dir : str
        Base directory for the calculations. (WARNING: not fully implemented)
    verbosity : int >= 0
        Verbosity level.
    do_plotting : bool
        Determines if the plottings are activated.
    supercell_size : tuple of 3 int
        Size of the supercell to do the phonon calculations.
    thermo : ase.CrystalThermo
        Class to delegate the calculation of some thermodynamic properties.
    phonons : ase.Phonons
        Class to perform phonon calculations using the supercell approach.
    phonon_kpts_mp : (N, 3) np.ndarray
        Monkhorst-Pack k-point grid.
    phonon_energy_mp : (N,) np.ndarray
        Energies of the corresponding MP k-points.
    phonon_energy : np.ndarray
        Energies to calculate the Phonon density of states.
    phonon_dos : np.ndarray
        Phonon density of states at given energies.

    Parameters
    ----------
    atoms :
    calc :
    supercell_size :
    atat_structure :
    plot :
    verbosity :
    name :

    """
    def __init__(self,
                 atoms=None,
                 calc=None,
                 supercell_size=5,
                 atat_structure=None,
                 plot=False,
                 verbosity=0,
                 name='thermo'):
        # relaxed structure
        self.name = name
        self.structure = None
        self.atoms = None
        self.calc = None
        self.n_atoms = 0
        self.temperature = None
        self.strains = None
        self.strained_thermo = []
        if atoms is not None and atat_structure is not None:
            print('ERROR: only atoms OR atat_structure can be specified')
            return
        if atoms is not None:
            self.atoms = atoms
            self.n_atoms = len(self.atoms)
            if self.atoms.calc is None:
                assert calc is not None
                self.atoms.set_calculator(calc())
                self.calc = calc
            else:
                self.calc = atoms.calc
        elif atat_structure is not None:
            assert calc is not None
            self.calc = calc
            self.structure = ATAT2EMT(atat_structure,
                                      calc(),
                                      to_niggli=True,
                                      verbosity=verbosity)
            self.structure.atoms.wrap()
            self.atoms = self.structure.atoms
            self.n_atoms = len(self.atoms)
        # isgn = spglib.get_symmetry_dataset(self.atoms, symprec=1e-3)['number']
        # self.symmetry = el.crystal_system(isgn)
        self.sjeos = SJEOS()

        self.base_dir = os.getcwd()
        self.verbosity = verbosity
        self.do_plotting = plot

        if isinstance(supercell_size, int):
            self.supercell_size = (supercell_size, supercell_size,
                                   supercell_size)
        else:
            assert len(supercell_size) == 3
            self.supercell_size = supercell_size

        self.get_phonons()

        self.thermo = CrystalThermo(
            phonon_energies=self.phonon_energy,
            phonon_DOS=self.phonon_dos,
            potentialenergy=self.atoms.get_potential_energy(),
            formula_units=self.n_atoms)

    def set_temperature(self, temperature, save_at='.'):
        """Set the temperature grid.

        Parameters
        ----------
        temperature : iterable of float
            Iterable containing the temperatures at which to calculate the properties.
        save_at : string
            Path (relative or absolute) in which to store the value.

        """
        if save_at is not None:
            if not os.path.exists(save_at):
                os.makedirs(save_at)
            save_name = os.path.join(save_at, 'T.dat')
            np.savetxt(save_name, temperature)
        self.temperature = temperature

    def get_phonons(self, kpts=(50, 50, 50), npts=5000):
        """Calculate the phonon spectrum and DOS.

        Parameters
        ----------
        kpts : tuple
            Number of points in each directions of the k-space grid.
        npts : int
            Number of energy points to calculate the DOS at.

        """
        self.phonons = Phonons(self.atoms,
                               self.calc(),
                               supercell=self.supercell_size,
                               delta=0.05,
                               name=self.name)
        self.phonons.run()
        # Read forces and assemble the dynamical matrix
        self.phonons.read(acoustic=True)
        self.phonon_kpts_mp = monkhorst_pack(kpts)
        self.phonon_energy_mp = self.phonons.band_structure(
            self.phonon_kpts_mp)
        self.phonon_energy, self.phonon_dos = \
            self.phonons.dos(kpts=kpts, npts=npts, delta=5e-4)

    def get_volume_phonons(self, nvolumes=5, max_strain=0.02):
        """Calculate the volume dependent phonons.

        Parameters
        ----------
        nvolumes : int > 0
            Number of volumes to calculate the phonon spectrum.
        max_strain : float > 0
            Maximum (isotropic) strain used to deform equilibrium volume.

        """
        strains = np.linspace(-max_strain, max_strain, nvolumes)
        load = False
        if self.strains is None:
            self.strains = strains
        else:
            if not (strains == self.strains).all():
                self.strains = strains
                self.strained_thermo = []
            else:
                load = True
        strain_matrices = [np.eye(3) * (1 + s) for s in self.strains]
        atoms = self.atoms
        cell = atoms.cell
        for i, s in enumerate(strain_matrices):
            satoms = atoms.copy()
            satoms.set_cell(np.dot(cell, s.T), scale_atoms=True)
            if load:
                pass
            else:
                satoms.set_calculator(None)
                sthermo = ThermalProperties(satoms,
                                            self.calc,
                                            name='thermo_{:.2f}'.format(
                                                self.strains[i]))
                self.strained_thermo.append(sthermo)

    def get_volume_energy(self, temperature=None, nvolumes=5, max_strain=0.02):
        """Return the volume dependent (Helmholtz) energy.

        Parameters
        ----------
        temperature : float > 0
            Temeprature at which the volume-energy curve is calculated.
        nvolumes : int > 0
            Number of volumes to calculate the energy at.
        max_strain : float > 0
            Maximum (isotropic) strain used to deform equilibrium volume.
        save_at : string
            Path (relative or absolute) in which to store the value.

        Returns
        -------
        volume : list of double
            Volumes at which the entropy was calculated.
        energy : list of double
            Helmholtz energy for each of the volumes.

        """
        if temperature is None and self.temperature is None:
            print(
                'ERROR. You nee to specify a temperature for the calculations.'
            )
            return
        elif temperature is None:
            temperature = self.temperature

        if isinstance(temperature, collections.Iterable):
            volume_energy = [
                self.get_volume_energy(T, nvolumes, max_strain)
                for T in temperature
            ]
            return volume_energy

        self.get_volume_phonons(nvolumes, max_strain)

        energy = []
        volume = []
        for sthermo in self.strained_thermo:
            energy.append(
                sthermo.get_helmholtz_energy(temperature, save_at=None))
            volume.append(sthermo.atoms.get_volume())

        return volume, energy

    def get_volume_entropy(self,
                           temperature=None,
                           nvolumes=5,
                           max_strain=0.02):
        """Return the volume dependent entropy.

        Parameters
        ----------
        temperature : float > 0
            Temeprature at which the volume-entropy curve is calculated.
        nvolumes : int > 0
            Number of volumes to calculate the entropy at.
        max_strain : float > 0
            Maximum (isotropic) strain used to deform equilibrium volume.
        save_at : string
            Path (relative or absolute) in which to store the value.

        Returns
        -------
        volume : list of double
            Volumes at which the entropy was calculated.
        entropy : list of double
            Entropy for each of the volumes.

        """
        if temperature is None and self.temperature is None:
            print(
                'ERROR. You nee to specify a temperature for the calculations.'
            )
            return
        elif temperature is None:
            temperature = self.temperature

        if isinstance(temperature, collections.Iterable):
            volume_entropy = [
                self.get_volume_entropy(T, nvolumes, max_strain)
                for T in temperature
            ]
            return volume_entropy

        self.get_volume_phonons(nvolumes, max_strain)

        entropy = []
        volume = []
        for sthermo in self.strained_thermo:
            entropy.append(sthermo.get_entropy(temperature, save_at=None))
            volume.append(sthermo.atoms.get_volume())

        return volume, entropy

    def get_entropy(self, temperature=None, save_at='.'):
        """Return entropy per atom in eV / atom.

        Parameters
        ----------
        temperature : float > 0
            Temeprature at which the Helmholtz energy is calculated.
        save_at : string
            Path (relative or absolute) in which to store the value.

        Returns
        -------
        entropy : float
            Entropy in eV / atom

        Notes
        -----
        To convert to SI units, divide by units.J.
        At the moment only vibrational entropy is included. Electronic entropy can
        be included if the calculator provides the electronic DOS.

        """
        if temperature is None and self.temperature is None:
            print(
                'ERROR. You nee to specify a temperature for the calculations.'
            )
            return
        elif temperature is None:
            temperature = self.temperature

        if save_at is not None:
            if not os.path.exists(save_at):
                os.makedirs(save_at)
            save_name = os.path.join(save_at, 'S.dat')

        if isinstance(temperature, collections.Iterable):
            vib_entropy = [
                self.get_entropy(T, save_at=None) for T in temperature
            ]
            if save_at is not None:
                np.savetxt(save_name, vib_entropy)
            return np.array(vib_entropy)
        if temperature == 0.:
            if save_at is not None:
                np.savetxt(save_name, np.asarray([0.]))
            return 0.

        vib_entropy = self.thermo.get_entropy(temperature, self.verbosity)
        if save_at is not None:
            np.savetxt(save_name, vib_entropy)
        return vib_entropy

    def get_helmholtz_energy(self, temperature=None, save_at='.'):
        """Return Helmholtz energy per atom in eV / atom.

        Parameters
        ----------
        temperature : float > 0
            Temeprature at which the Helmholtz energy is calculated.
        save_at : string
            Path (relative or absolute) in which to store the value.

        Returns
        -------
        helmholtz_energy : float
            Helmholtz energy in eV / atom

        Notes
        -----
        To convert to SI units, divide by units.J.

        """
        if temperature is None and self.temperature is None:
            print(
                'ERROR. You nee to specify a temperature for the calculations.'
            )
            return
        elif temperature is None:
            temperature = self.temperature

        if save_at is not None:
            if not os.path.exists(save_at):
                os.makedirs(save_at)
            save_name = os.path.join(save_at, 'F.dat')

        if isinstance(temperature, collections.Iterable):
            helmholtz_energy = [
                self.get_helmholtz_energy(T, save_at=None) for T in temperature
            ]
            if save_at is not None:
                np.savetxt(save_name, helmholtz_energy)
            return np.array(helmholtz_energy)
        if temperature == 0.:
            helmholtz_energy = self.get_zero_point_energy(
            ) + self.thermo.potentialenergy
            if save_at is not None:
                np.savetxt(save_name, helmholtz_energy)
            return helmholtz_energy

        helmholtz_energy = self.thermo.get_helmholtz_energy(
            temperature, self.verbosity)
        if save_at is not None:
            np.savetxt(save_name, helmholtz_energy)
        return helmholtz_energy

    def get_internal_energy(self, temperature=None, save_at='.'):
        """Return internal energy per atom in eV / atom.

        Parameters
        ----------
        temperature : float > 0
            Temeprature at which the internal energy is calculated.
        save_at : string
            Path (relative or absolute) in which to store the value.

        Returns
        -------
        internal_energy : float
            Internal energy in eV / atom

        Notes
        -----
        To convert to SI units, divide by units.J.

        """
        if temperature is None and self.temperature is None:
            print(
                'ERROR. You nee to specify a temperature for the calculations.'
            )
            return
        elif temperature is None:
            temperature = self.temperature

        if save_at is not None:
            if not os.path.exists(save_at):
                os.makedirs(save_at)
            save_name = os.path.join(save_at, 'U.dat')

        if isinstance(temperature, collections.Iterable):
            internal_energy = [
                self.get_internal_energy(T, save_at=None) for T in temperature
            ]
            if save_at is not None:
                np.savetxt(save_name, internal_energy)
            return np.array(internal_energy)
        if temperature == 0.:
            internal_energy = self.get_zero_point_energy(
            ) + self.thermo.potentialenergy
            if save_at is not None:
                np.savetxt(save_name, internal_energy)
            return internal_energy

        internal_energy = self.thermo.get_internal_energy(
            temperature, self.verbosity)

        if save_at is not None:
            np.savetxt(save_name, internal_energy)

        return internal_energy

    def get_zero_point_energy(self):
        """Return the Zero Point Energy in eV / atom.

        Returns
        -------
        zpe: float
            Zero point energy in eV / atom.

        """
        zpe_list = self.phonon_energy / 2.
        zpe = np.trapz(zpe_list * self.phonon_dos,
                       self.phonon_energy) / self.n_atoms
        return zpe

    def get_specific_heat(self, temperature=None, save_at='.'):
        """Return heat capacity per atom in eV / atom K.
        
        Parameters
        ----------
        temperature : float > 0
            Temeprature at which the specific heat is calculated.
        save_at : string
            Path (relative or absolute) in which to store the value.

        Returns
        -------
        C_V : float
            Specific heat in eV / atom K
            
        Notes
        -----
        To convert to SI units, multiply by (units.mol / units.J).

        """
        if temperature is None and self.temperature is None:
            print(
                'ERROR. You nee to specify a temperature for the calculations.'
            )
            return
        elif temperature is None:
            temperature = self.temperature

        if save_at is not None:
            if not os.path.exists(save_at):
                os.makedirs(save_at)
            save_name = os.path.join(save_at, 'Cv.dat')

        if isinstance(temperature, collections.Iterable):
            C_V = [
                self.get_specific_heat(T, save_at=None) for T in temperature
            ]
            if save_at is not None:
                np.savetxt(save_name, C_V)
            return np.array(C_V)

        if temperature == 0.:
            if save_at is not None:
                np.savetxt(save_name, np.asarray([0.]))
            return 0.

        if self.phonon_energy[0] == 0.:
            self.phonon_energy = np.delete(self.phonon_energy, 0)
            self.phonon_dos = np.delete(self.phonon_dos, 0)
        i2kT = 1. / (2. * units.kB * temperature)
        arg = self.phonon_energy * i2kT
        C_v = units.kB * arg**2 / np.sinh(arg)**2
        C_V = np.trapz(C_v * self.phonon_dos,
                       self.phonon_energy) / self.n_atoms
        if save_at is not None:
            np.savetxt(save_name, np.asarray([C_V]))
        return C_V

    def get_thermal_expansion(self,
                              temperature=None,
                              exp_norm_temp=None,
                              nvolumes=5,
                              max_strain=0.02,
                              ntemperatures=5,
                              delta_t=1.,
                              save_at='.'):
        """Return the isotropic volumetric thermal expansion in K^-1.
        
        Parameters
        ----------
        temperature : float > 0
            Temeprature at which the expansion coefficient is calculated.
        exp_norm_temp : float > 0
            Temperature for the normalization of the thermal expansion (usually to compare with experiment).
        nvolumes : int > 0
            Number of volumes to fit the equation of state to extract equilibrium volumes.
        max_strain : float > 0
            Maximum strain used to fit the equation of state to extract equilibrium volumes.
        ntemperatures : int > 0
            Number of temperatures to approximate the temperature derivative of the volume.
        delta_t : float >0
            Temperature step to approximate the temperature derivative of the volume.
        save_at : string
            Path (relative or absolute) in which to store the value.

        Returns
        -------
            : double
            Isotropic volumetric thermal expansion in K^-1

        """
        if temperature is None and self.temperature is None:
            print(
                'ERROR. You nee to specify a temperature for the calculations.'
            )
            return
        elif temperature is None:
            temperature = self.temperature

        if save_at is not None:
            if not os.path.exists(save_at):
                os.makedirs(save_at)
            save_name = os.path.join(save_at, 'thermal_expansion.dat')

        if isinstance(temperature, collections.Iterable):
            alpha_v = [
                self.get_thermal_expansion(T,
                                           exp_norm_temp,
                                           nvolumes,
                                           max_strain,
                                           ntemperatures,
                                           delta_t,
                                           save_at=None) for T in temperature
            ]
            if save_at is not None:
                np.savetxt(save_name, alpha_v)
            return np.array(alpha_v)

        max_delta_t = (ntemperatures - 1) * delta_t
        if temperature - max_delta_t / 2. > 0.:
            temperatures = np.linspace(temperature - max_delta_t / 2.,
                                       temperature + max_delta_t / 2.,
                                       ntemperatures)
            t0 = (ntemperatures - 1) / 2
            mode = 'c'
        else:
            ntemperatures = (ntemperatures + 2) / 2
            temperatures = np.linspace(temperature,
                                       temperature + max_delta_t / 2.,
                                       ntemperatures)
            t0 = 0
            mode = 'f'
        print(temperatures, ntemperatures)
        # 1.- Get V-F points
        Vs = []
        Fs = []
        for T in temperatures:
            V, F = self.get_volume_energy(T, nvolumes, max_strain)
            Vs.append(V)
            Fs.append(F)
        # 2.- Fit EOS to V-F points for each T
        self.sjeos.clean()
        for i in range(ntemperatures):
            V = np.asarray(Vs[i])
            F = np.asarray(Fs[i])
            self.sjeos.fit(V, F)
        # 3.- Numerical derivative dV/dT
        V0s = self.sjeos.get_equilibrium_volume(mean=True)
        fd = FD(temperatures)
        dV_dT = fd.derivative(1, t0, V0s, acc_order=2, mode=mode)
        if self.do_plotting:
            plt.plot(temperatures, V0s)
        # 4a.- Normalize by volume at temperature (same as derivative)
        if exp_norm_temp is None:
            return dV_dT / V0s[(ntemperatures - 1) / 2]
        # 4b.- Normalize by volume at some give reference temperature (different from derivative)
        V, F = self.get_volume_energy(exp_norm_temp, nvolumes, max_strain)
        self.sjeos.clean()
        self.sjeos.fit(np.asarray(V), np.asarray(F))
        V_norm = self.sjeos.get_equilibrium_volume(mean=True)
        alpha_v = dV_dT / V_norm
        if save_at is not None:
            np.savetxt(save_name, alpha_v)
        return alpha_v

    def get_gruneisen(self,
                      temperature=None,
                      nvolumes=5,
                      max_strain=0.02,
                      save_at='.'):
        r"""Return the Gr\"uneisen parameter.

        Parameters
        ----------
        temperature : float > 0
            Temeprature at which the expansion coefficient is calculated.
        nvolumes : int > 0
            Number of volumes to fit the equation of state to extract equilibrium volumes.
        max_strain : float > 0
            Maximum strain used to fit the equation of state to extract equilibrium volumes.
        save_at : string
            Path (relative or absolute) in which to store the value.

        Returns
        -------
        gruneisen : double
            Gr\"uneisen parameter.

        Notes
        -----
        The Gr\"uneisen parameter is calculated as

        .. math ::
            \gamma=\frac{C_v}{V}\left.\frac{\partial S}{\partial V}\right|_T

        """
        if temperature is None and self.temperature is None:
            print(
                'ERROR. You nee to specify a temperature for the calculations.'
            )
            return
        elif temperature is None:
            temperature = self.temperature

        if save_at is not None:
            if not os.path.exists(save_at):
                os.makedirs(save_at)
            save_name = os.path.join(save_at, 'gruneisen.dat')

        if isinstance(temperature, collections.Iterable):
            gruneisen = [
                self.get_gruneisen(T, nvolumes, max_strain, save_at=None)
                for T in temperature
            ]
            if save_at is not None:
                np.savetxt(save_name, gruneisen)
            return gruneisen

        self.get_volume_phonons(nvolumes, max_strain)
        C_V = self.get_specific_heat(temperature)

        V, F = self.get_volume_energy(temperature, nvolumes, max_strain)
        self.sjeos.clean()
        self.sjeos.fit(np.asarray(V), np.asarray(F))
        V_0 = self.sjeos.get_equilibrium_volume(mean=True)[0]

        V, S = self.get_volume_entropy(temperature, nvolumes, max_strain)
        fd = FD(V)
        dS_dV = fd.derivative(1, nvolumes / 2, S, acc_order=2, mode='c')
        gruneisen = dS_dV * V_0 / C_V
        """
        phonon_energy_mp = []
        volumes = []
        hw_V = [[] for i in range(len(self.phonon_energy_mp.ravel()))]
        for sthermo in self.strained_thermo:
            volumes.append(sthermo.atoms.get_volume())
            phonon_energy_mp.append(sthermo.phonon_energy_mp.ravel())
            for j, hw in enumerate(phonon_energy_mp[-1]):
                hw_V[j].append(hw)

        fd = FD(volumes)
        gruneisen_i = np.empty_like(phonon_energy_mp[0])
        for i, hw in enumerate(hw_V):
            dhw_dV = fd.derivative(1, nvolumes/2, hw, acc_order=2, mode='c')
            # print(dhw_dV, hw[nvolumes/2], dhw_dV * volumes[nvolumes/2] / hw[nvolumes/2])
            gruneisen_i[i]\
                = - dhw_dV * volumes[nvolumes/2] / hw[nvolumes/2]

        self.hw_V = hw_V
        self.volumes = volumes

        i2kT = 1. / (2. * units.kB * temperature)
        arg = phonon_energy_mp[nvolumes/2] * i2kT
        C_v = units.kB * arg ** 2 / np.sinh(arg) ** 2

        # print(C_V, C_v, gruneisen_i, volumes)
        # gruneisen = np.trapz(C_v * gruneisen_i * self.phonon_dos, self.phonon_energy) / C_V
        gruneisen = np.sum(C_v * gruneisen_i) / np.sum(C_v)

        print(gruneisen, gruneisen_S)
        plt.scatter(temperature, gruneisen, color='r')
        plt.scatter(temperature, gruneisen_S, color='g')
        """
        if save_at is not None:
            np.savetxt(save_name, gruneisen)

        return gruneisen
Ejemplo n.º 17
0
# Tests the phonon-based perturbation and velocity distribution
# for thermal equilibration in MD.

rng = RandomState(17)

atoms = bulk('Pd')
atoms *= (3, 3, 3)
avail = [atomic_numbers[sym] for sym in ['Ni', 'Cu', 'Pd', 'Ag', 'Pt', 'Au']]
atoms.numbers[:] = rng.choice(avail, size=len(atoms))
atoms.calc = EMT()

opt = FIRE(atoms, trajectory='relax.traj')
opt.run(fmax=0.001)
positions0 = atoms.positions.copy()

phonons = Phonons(atoms, EMT(), supercell=(1, 1, 1), delta=0.05)

try:
    phonons.run()
    phonons.read()  # Why all this boilerplate?
finally:
    phonons.clean()
matrices = phonons.get_force_constant()

K = matrices[0]
T = 300 * units.kB

atoms.calc = EMT()
Epotref = atoms.get_potential_energy()

temps = []
Ejemplo n.º 18
0
                 'omega_e': Omega_e
             })


# Setup crystal and EMT calculator
atoms = bulk('Fe', 'bcc', a=2.86)
calc = GPAW(mode=PW(600),
            nbands=-60,
            xc='PBE',
            kpts=(5, 5, 5),
            symmetry={'point_group': False},
            occupations=FermiDirac(0.1))
#
# # Phonon calculator
N = 3
ph = Phonons(atoms, calc, supercell=(N, N, N), delta=0.05)
ph.run()
time.sleep(250)

# Read forces and assemble the dynamical matrix
ph.read()

# High-symmetry points in the Brillouin zone
points = ibz_points['bcc']
G = points['Gamma']
H = points['H']
N = points['N']
P = points['P']

point_names = ['$\Gamma$', 'H', 'P', '$\Gamma$', 'N']
path = [G, H, P, G, N]
Ejemplo n.º 19
0
Archivo: gold.py Proyecto: PHOTOX/fuase
from ase.optimize import QuasiNewton
from ase.phonons import Phonons
from ase.thermochemistry import CrystalThermo

# Set up gold bulk and attach EMT calculator
a = 4.078
atoms = crystal('Au', (0.,0.,0.),
                spacegroup = 225,
                cellpar = [a, a, a, 90, 90, 90],
                pbc = (1, 1, 1))
calc = EMT()
atoms.set_calculator(calc)
qn = QuasiNewton(atoms)
qn.run(fmax = 0.05)
electronicenergy = atoms.get_potential_energy()

# Phonon analysis
N = 5
ph = Phonons(atoms, calc, supercell=(N, N, N), delta=0.05)
ph.run()
ph.read(acoustic=True)
phonon_energies, phonon_DOS = ph.dos(kpts=(40, 40, 40), npts=3000,
                                     delta=5e-4)

# Calculate the Helmholtz free energy
thermo = CrystalThermo(phonon_energies=phonon_energies,
                       phonon_DOS = phonon_DOS,
                       electronicenergy = electronicenergy,
                       formula_units = 4)
F = thermo.get_helmholtz_energy(temperature=298.15)
Ejemplo n.º 20
0
def test_thermochemistry():
    """Tests of the major methods (HarmonicThermo, IdealGasThermo,
    CrystalThermo) from the thermochemistry module."""

    # Ideal gas thermo.
    atoms = Atoms('N2', positions=[(0, 0, 0), (0, 0, 1.1)], calculator=EMT())
    QuasiNewton(atoms).run(fmax=0.01)
    energy = atoms.get_potential_energy()
    vib = Vibrations(atoms, name='idealgasthermo-vib')
    vib.run()
    vib_energies = vib.get_energies()

    thermo = IdealGasThermo(vib_energies=vib_energies,
                            geometry='linear',
                            atoms=atoms,
                            symmetrynumber=2,
                            spin=0,
                            potentialenergy=energy)
    thermo.get_gibbs_energy(temperature=298.15, pressure=2 * 101325.)

    # Harmonic thermo.

    atoms = fcc100('Cu', (2, 2, 2), vacuum=10.)
    atoms.set_calculator(EMT())
    add_adsorbate(atoms, 'Pt', 1.5, 'hollow')
    atoms.set_constraint(
        FixAtoms(indices=[atom.index for atom in atoms
                          if atom.symbol == 'Cu']))
    QuasiNewton(atoms).run(fmax=0.01)
    vib = Vibrations(
        atoms,
        name='harmonicthermo-vib',
        indices=[atom.index for atom in atoms if atom.symbol != 'Cu'])
    vib.run()
    vib.summary()
    vib_energies = vib.get_energies()

    thermo = HarmonicThermo(vib_energies=vib_energies,
                            potentialenergy=atoms.get_potential_energy())
    thermo.get_helmholtz_energy(temperature=298.15)

    # Crystal thermo.
    atoms = bulk('Al', 'fcc', a=4.05)
    calc = EMT()
    atoms.set_calculator(calc)
    energy = atoms.get_potential_energy()

    # Phonon calculator
    N = 7
    ph = Phonons(atoms, calc, supercell=(N, N, N), delta=0.05)
    ph.run()

    ph.read(acoustic=True)
    phonon_energies, phonon_DOS = ph.dos(kpts=(4, 4, 4), npts=30, delta=5e-4)

    thermo = CrystalThermo(phonon_energies=phonon_energies,
                           phonon_DOS=phonon_DOS,
                           potentialenergy=energy,
                           formula_units=4)
    thermo.get_helmholtz_energy(temperature=298.15)

    # Hindered translator / rotor.
    # (Taken directly from the example given in the documentation.)

    vibs = np.array([
        3049.060670, 3040.796863, 3001.661338, 2997.961647, 2866.153162,
        2750.855460, 1436.792655, 1431.413595, 1415.952186, 1395.726300,
        1358.412432, 1335.922737, 1167.009954, 1142.126116, 1013.918680,
        803.400098, 783.026031, 310.448278, 136.112935, 112.939853, 103.926392,
        77.262869, 60.278004, 25.825447
    ])
    vib_energies = vibs / 8065.54429  # Convert to eV from cm^-1.
    trans_barrier_energy = 0.049313  # eV
    rot_barrier_energy = 0.017675  # eV
    sitedensity = 1.5e15  # cm^-2
    rotationalminima = 6
    symmetrynumber = 1
    mass = 30.07  # amu
    inertia = 73.149  # amu Ang^-2

    thermo = HinderedThermo(vib_energies=vib_energies,
                            trans_barrier_energy=trans_barrier_energy,
                            rot_barrier_energy=rot_barrier_energy,
                            sitedensity=sitedensity,
                            rotationalminima=rotationalminima,
                            symmetrynumber=symmetrynumber,
                            mass=mass,
                            inertia=inertia)

    helmholtz = thermo.get_helmholtz_energy(temperature=298.15)
    target = 1.593  # Taken from documentation example.
    assert (helmholtz - target) < 0.001
Ejemplo n.º 21
0
#
#
#
from ase.build import bulk
from ase.calculators.emt import EMT
from ase.phonons import Phonons

# Setup crystal and EMT calculator
atoms = bulk('Al', 'fcc', a=4.05)
#print(atoms)

# Phonon calculator
N = 7
ph = Phonons(atoms, EMT(), supercell=(N, N, N), delta=0.05)
print(ph)
ph.run()

# Read forces and assemble the dynamical matrix
ph.read(acoustic=True)
ph.clean()

#print(atoms.cell.bandpath)

path = atoms.cell.bandpath('GXULGK', npoints=100)
bs = ph.get_band_structure(path)
dos = ph.get_dos(kpts=(20, 20, 20)).sample_grid(npts=100, width=1e-3)

# Plot the band structure and DOS:
import matplotlib.pyplot as plt
fig = plt.figure(1, figsize=(7, 4))
ax = fig.add_axes([.12, .07, .67, .85])
Ejemplo n.º 22
0
import dill as pickle
from ase.build import bulk
from gpaw import GPAW, FermiDirac
from ase.phonons import Phonons
import ase
import numpy as np
atoms = ase.io.read("moo3_bulk.cif")

calc = GPAW(symmetry={'point_group': False},
            mode='lcao',
            basis='szp(dzp)',
            kpts=(6, 6, 3),
            convergence={'density': 1e-7},
            xc='PBE',  # No PBEsol :(
            occupations=FermiDirac(0.01))

ph = Phonons(atoms, calc, supercell=(3, 3, 2), delta=0.05)
ph.run()

ph.read(acoustic=True)
force_constants = ph.get_force_constant()
ph.acoustic(force_constants)
force_constants = ph.symmetrize(force_constants)
np.save("force_constant.npy", force_constants)
with open('phonons.pkl', 'wb') as file:
    pickle.dump(ph, file)
Ejemplo n.º 23
0
# creates: Al_phonon.png Al_mode.gif Al_mode.pdf

from ase.lattice import bulk
from ase.calculators.emt import EMT
from ase.dft.kpoints import ibz_points, get_bandpath
from ase.phonons import Phonons

# Setup crystal and EMT calculator
atoms = bulk('Al', a=4.05)
calc = EMT()

# Phonon calculator
N = 6
ph = Phonons(atoms, calc, supercell=(N, N, N))
ph.run()

# Read forces and assemble the dynamical matrix
ph.read(acoustic=True)

# High-symmetry points in the Brillouin zone
points = ibz_points['fcc']
G = points['Gamma']
X = points['X']
W = points['W']
K = points['K']
L = points['L']
U = points['U']

point_names = ['$\Gamma$', 'X', 'U', 'L', '$\Gamma$', 'K']
path = [G, X, U, L, G, K]
path_kc, q, Q = get_bandpath(path, atoms.cell, 100)
Ejemplo n.º 24
0
def get_elph_elements(atoms,
                      gpw_name,
                      calc_fd,
                      sc=(1, 1, 1),
                      basename=None,
                      phononname='phonon'):
    """
        Evaluates the dipole transition matrix elements

        Input
        ----------
        params_fd : Calculation parameters used for the phonon calculation
        sc (tuple): Supercell, default is (1,1,1) used for gamma phonons
        basename  : If you want give a specific name (gqklnn_{}.pckl)

        Output
        ----------
        gqklnn.pckl, the electron-phonon matrix elements
    """
    from ase.phonons import Phonons
    from gpaw.elph.electronphonon import ElectronPhononCoupling

    calc_gs = GPAW(gpw_name)
    world = calc_gs.wfs.world

    #calc_fd = GPAW(**params_fd)
    calc_gs.initialize_positions(atoms)
    kpts = calc_gs.get_ibz_k_points()
    nk = len(kpts)
    gamma_kpt = [[0, 0, 0]]
    nbands = calc_gs.wfs.bd.nbands
    qpts = gamma_kpt

    # calc_fd.get_potential_energy()  # XXX needed to initialize C_nM ??????

    # Phonon calculation, We'll read the forces from the elph.run function
    # This only looks at gamma point phonons
    ph = Phonons(atoms=atoms, name=phononname, supercell=sc)
    ph.read()
    frequencies, modes = ph.band_structure(qpts, modes=True)

    if world.rank == 0:
        print("Phonon frequencies are loaded.")

    # Find el-ph matrix in the LCAO basis
    elph = ElectronPhononCoupling(atoms, calc=None, supercell=sc)

    elph.set_lcao_calculator(calc_fd)
    elph.load_supercell_matrix()
    if world.rank == 0:
        print("Supercell matrix is loaded")

    # Non-root processes on GD comm seem to be missing kpoint data.
    assert calc_gs.wfs.gd.comm.size == 1, "domain parallelism not supported"  # not sure how to fix this, sorry

    gcomm = calc_gs.wfs.gd.comm
    kcomm = calc_gs.wfs.kd.comm
    if gcomm.rank == 0:
        # Find the bloch expansion coefficients
        c_kn = np.empty((nk, nbands, calc_gs.wfs.setups.nao), dtype=complex)
        for k in range(calc_gs.wfs.kd.nibzkpts):
            c_k = calc_gs.wfs.collect_array("C_nM", k, 0)
            if kcomm.rank == 0:
                c_kn[k] = c_k
        kcomm.broadcast(c_kn, 0)

        # And we finally find the electron-phonon coupling matrix elements!
        g_qklnn = elph.bloch_matrix(c_kn=c_kn,
                                    kpts=kpts,
                                    qpts=qpts,
                                    u_ql=modes)

    if world.rank == 0:
        print("Saving the elctron-phonon coupling matrix")
        np.save("gqklnn{}.npy".format(make_suffix(basename)),
                np.array(g_qklnn))
Ejemplo n.º 25
0
# creates: Al_phonon.png Al_mode.gif Al_mode.pdf

from ase.structure import bulk
from ase.calculators.emt import EMT
from ase.dft.kpoints import ibz_points, get_bandpath
from ase.phonons import Phonons

# Setup crystal and EMT calculator
atoms = bulk('Al', 'fcc', a=4.05)
calc = EMT()

# Phonon calculator
N = 6
ph = Phonons(atoms, calc, supercell=(N, N, N))
ph.run()

# Read forces and assemble the dynamical matrix
ph.read(acoustic=True)

# High-symmetry points in the Brillouin zone
points = ibz_points['fcc']
G = points['Gamma']
X = points['X']
W = points['W']
K = points['K']
L = points['L']
U = points['U']

point_names = ['$\Gamma$', 'X', 'U', 'L', '$\Gamma$', 'K']
path = [G, X, U, L, G, K]
Ejemplo n.º 26
0
from ase.calculators.emt import EMT
from ase.optimize import QuasiNewton
from ase.phonons import Phonons
from ase.thermochemistry import CrystalThermo

# Set up gold bulk and attach EMT calculator
a = 4.078
atoms = crystal('Au', (0., 0., 0.),
                spacegroup=225,
                cellpar=[a, a, a, 90, 90, 90],
                pbc=(1, 1, 1))
calc = EMT()
atoms.set_calculator(calc)
qn = QuasiNewton(atoms)
qn.run(fmax=0.05)
electronicenergy = atoms.get_potential_energy()

# Phonon analysis
N = 5
ph = Phonons(atoms, calc, supercell=(N, N, N), delta=0.05)
ph.run()
ph.read(acoustic=True)
phonon_energies, phonon_DOS = ph.dos(kpts=(40, 40, 40), npts=3000, delta=5e-4)

# Calculate the Helmholtz free energy
thermo = CrystalThermo(phonon_energies=phonon_energies,
                       phonon_DOS=phonon_DOS,
                       electronicenergy=electronicenergy,
                       formula_units=4)
F = thermo.get_helmholtz_energy(temperature=298.15)
Ejemplo n.º 27
0
# creates: Al_phonon.png Al_mode.gif Al_mode.pdf

from ase.lattice import bulk
from ase.calculators.emt import EMT
from ase.dft.kpoints import ibz_points, get_bandpath
from ase.phonons import Phonons

# Setup crystal and EMT calculator
atoms = bulk('Al', a=4.05)
calc = EMT()

# Phonon calculator
N = 6
ph = Phonons(atoms, calc, supercell=(N, N, N))
ph.run()

# Read forces and assemble the dynamical matrix
ph.read(acoustic=True)

# High-symmetry points in the Brillouin zone
points = ibz_points['fcc']
G = points['Gamma']
X = points['X']
W = points['W']
K = points['K']
L = points['L']
U = points['U']

point_names = ['$\Gamma$', 'X', 'U', 'L', '$\Gamma$', 'K']
path = [G, X, U, L, G, K]
path_kc, q, Q = get_bandpath(path, atoms.cell, 100)
Ejemplo n.º 28
0
# creates: Al_phonon.png
from ase.build import bulk
from ase.calculators.emt import EMT
from ase.phonons import Phonons

# Setup crystal and EMT calculator
atoms = bulk('Al', 'fcc', a=4.05)

# Phonon calculator
N = 7
ph = Phonons(atoms, EMT(), supercell=(N, N, N), delta=0.05)
ph.run()

# Read forces and assemble the dynamical matrix
ph.read(acoustic=True)
ph.clean()

path = atoms.cell.bandpath('GXULGK', npoints=100)
bs = ph.get_band_structure(path)

dos = ph.get_dos(kpts=(20, 20, 20)).sample_grid(npts=100, width=1e-3)

# Plot the band structure and DOS:
import matplotlib.pyplot as plt
fig = plt.figure(1, figsize=(7, 4))
ax = fig.add_axes([.12, .07, .67, .85])

emax = 0.035
bs.plot(ax=ax, emin=0.0, emax=emax)

dosax = fig.add_axes([.8, .07, .17, .85])
 def _calculate_finite_difference_hessian(self, atoms, calculator):
     """Calcualte the Hessian matrix using finite differences."""
     ph = Phonons(atoms, calculator, supercell=(1, 1, 1), delta=1e-6)
     ph.clean()
     ph.run()
     ph.read(acoustic=False)
     ph.clean()
     H_numerical = ph.get_force_constant()[0, :, :]
     return H_numerical
def ase_phonon_calc(
    struct,
    calc=None,
    kpoints=[1, 1, 1],
    ftol=0.01,
    force_clean=False,
    name="asephonon",
):
    """Calculate phonon modes of a molecule using ASE and a given calculator.
    The system will be geometry optimized before calculating the modes. A
    report of the phonon modes will be written to a file and arrays of the
    eigenvectors and eigenvalues returned.

    | Args:
    |   struct (ase.Atoms):     Atoms object with to calculate modes for.
    |   calc (ase.Calculator):  Calculator for energies and forces (if not
    |                           present, use the one from struct)
    |   kpoints (np.ndarray):   Kpoint grid for phonon calculation. If None, just
    |                           do a Vibration modes calculation (default is [1,1,1])
    |   ftol (float):           Tolerance for geometry optimisation (default
    |                           is 0.01 eV/Ang)
    |   force_clean (bool):     If True, force a deletion of all phonon files
    |                           and recalculate them
    | Returns:
    |   evals (float[k-points][modes]):          Eigenvalues of phonon modes
    |   evecs (float[k-points][modes][ions][3]): Eigenvectors of phonon modes
    |   struct (ase.Atoms):                      Optimised structure
    """

    N = len(struct)
    if calc is None:
        calc = struct.calc
    struct = struct.copy()
    calc.atoms = struct
    struct.calc = calc
    dyn = BFGS(struct, trajectory="geom_opt.traj")
    dyn.run(fmax=ftol)

    # Calculate phonon modes
    vib_pbc = kpoints is not None
    if vib_pbc:
        vib = Phonons(struct, calc, name=name)
    else:
        vib = Vibrations(struct, name=name)
    if force_clean:
        vib.clean()
    vib.run()
    if vib_pbc:
        vib.read(acoustic=True)
        path = monkhorst_pack(kpoints)
        evals, evecs = vib.band_structure(path, True)
    else:
        vib.read()
        path = np.zeros((1, 3))
        # One axis added since it's like the gamma point
        evals = np.real(vib.get_energies()[None])
        evecs = np.array([vib.get_mode(i) for i in range(3 * N)])[None]

    # eV to cm^-1
    evals *= ((cnst.electron_volt / cnst.h) / cnst.c) / 100.0
    # Normalise eigenvectors
    evecs /= np.linalg.norm(evecs, axis=(2, 3))[:, :, None, None]

    return ASEPhononData(evals, evecs, path, struct)
Ejemplo n.º 31
0
def aucu_phonons():
    N = 7
    atoms = bulk("Au", crystalstructure="fcc", a=4.08)
    calc = EMT()
    atoms.set_calculator(calc)

    ph = Phonons(atoms, calc, supercell=(N, N, N), delta=0.05)
    ph.run()
    ph.read(acoustic=True)
    ph.clean()
    omega_e_au, dos_e_au = ph.dos(kpts=(50, 50, 50), npts=1000, delta=5E-4)

    atoms = bulk("Cu", crystalstructure="fcc", a=3.62)
    atoms.set_calculator(calc)

    ph = Phonons(atoms, calc, supercell=(N, N, N), delta=0.05)
    ph.run()
    ph.read(acoustic=True)
    ph.clean()
    omega_e_cu, dos_e_cu = ph.dos(kpts=(13, 13, 13), npts=100, delta=5E-4)

    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    ax.plot(omega_e_au * 1000.0, dos_e_au)
    ax.plot(omega_e_cu * 1000.0, dos_e_cu)
    ax.set_xlabel("Energy (meV)")

    logw_au = np.sum(np.log(omega_e_au[1:]) * dos_e_au[1:])
    logw_cu = np.sum(np.log(omega_e_cu[1:]) * dos_e_cu[1:])
    print(logw_au, logw_cu, logw_au - logw_cu)
    plt.show()
Ejemplo n.º 32
0
def test_phonon_md_init(asap3):
    # Tests the phonon-based perturbation and velocity distribution
    # for thermal equilibration in MD.

    EMT = asap3.EMT

    rng = RandomState(17)

    atoms = bulk('Pd')
    atoms *= (3, 3, 3)
    avail = [atomic_numbers[sym]
             for sym in ['Ni', 'Cu', 'Pd', 'Ag', 'Pt', 'Au']]
    atoms.numbers[:] = rng.choice(avail, size=len(atoms))
    atoms.calc = EMT()

    opt = FIRE(atoms, trajectory='relax.traj')
    opt.run(fmax=0.001)
    positions0 = atoms.positions.copy()

    phonons = Phonons(atoms, EMT(), supercell=(1, 1, 1), delta=0.05)

    try:
        phonons.run()
        phonons.read()  # Why all this boilerplate?
    finally:
        phonons.clean()
    matrices = phonons.get_force_constant()

    K = matrices[0]
    T = 300 * units.kB

    atoms.calc = EMT()
    Epotref = atoms.get_potential_energy()

    temps = []
    Epots = []
    Ekins = []
    Etots = []


    for i in range(24):
        PhononHarmonics(atoms, K, T, quantum=True, rng=np.random.RandomState(888 + i))

        Epot = atoms.get_potential_energy() - Epotref
        Ekin = atoms.get_kinetic_energy()
        Ekins.append(Ekin)
        Epots.append(Epot)
        Etots.append(Ekin + Epot)
        temps.append(atoms.get_temperature())

        atoms.positions[:] = positions0

        # The commented code would produce displacements/velocities
        # resolved over phonon modes if we borrow some expressions
        # from the function.  Each mode should contribute on average
        # equally to both Epot and Ekin/temperature
        #
        # atoms1.calc = EMT()
        # atoms1 = atoms.copy()
        # v_ac = np.zeros_like(positions0)
        # D_acs, V_acs = ...
        # for s in range(V_acs.shape[2]):
        #     atoms1.positions += D_acs[:, :, s]
        #     v_ac += V_acs[:, :, s]
        #     atoms1.set_velocities(v_ac)
        #     X1.append(atoms1.get_potential_energy() - Epotref)
        #     X2.append(atoms1.get_kinetic_energy())

        print('energies', Epot, Ekin, Epot + Ekin)



    Epotmean = np.mean(Epots)
    Ekinmean = np.mean(Ekins)
    Tmean = np.mean(temps)
    Terr = abs(Tmean - T / units.kB)
    relative_imbalance = abs(Epotmean - Ekinmean) / (Epotmean + Ekinmean)


    print('epotmean', Epotmean)
    print('ekinmean', Ekinmean)
    print('rel imbalance', relative_imbalance)
    print('Tmean', Tmean, 'Tref', T / units.kB, 'err', Terr)

    assert Terr < 0.1*T / units.kB, Terr  # error in Kelvin for instantaneous velocity
    # Epot == Ekin give or take 2 %:
    assert relative_imbalance < 0.1, relative_imbalance


    if 0:
        import matplotlib.pyplot as plt
        I = np.arange(len(Epots))
        plt.plot(I, Epots, 'o', label='pot')
        plt.plot(I, Ekins, 'o', label='kin')
        plt.plot(I, Etots, 'o', label='tot')
        plt.show()
def getLJeigenvalues2(listOfPositions, epsilon, sigma, rc, getForceMatrix,
                      aCell):
    from ase import Atoms
    from ase.build import bulk
    # from ase.calculators.lj import LennardJones
    from ase.phonons import Phonons
    import numpy as np
    from scipy import linalg as LA
    # from gpaw import GPAW, FermiDirac
    # calc = LennardJones() #a.set_calculator(calc)

    # atoms = bulk('Si', 'diamond', a=5.4)
    # atoms = bulk('H', 'fcc', a=1.1, cubic=True)
    #atoms = Atoms('N3', [(0, 0, 0), (0, 0, 1.1), (0, 0, 2.2)], calculator=LennardJones() )
    # atoms = Atoms('H2', [(0, 0, 0), (0, 0, 1.12246)], calculator=LennardJones() )
    # calc = GPAW(kpts=(5, 5, 5), h=0.2, occupations=FermiDirac(0.))

    # d =  1.122 # = 2**(1/6)
    # a = 10.00
    # struct = Atoms( 'H2', positions=[(0, 0, 0), (0, 0, d)] , cell=(a, a, a), pbc=True )

    chemStr = 'H' + str(len(listOfPositions))
    # struct = Atoms(chemStr, listOfPositions, cell=(aCell, aCell, aCell)) # <<< without pbc=True you would need a very large aCell value!
    struct = Atoms(chemStr,
                   listOfPositions,
                   cell=(aCell, aCell, aCell),
                   pbc=True)
    # struct = Atoms(chemStr, positions=positions , cell=(aCell, aCell, aCell), pbc=True )

    ############################################################################
    # from ase.calculators.lj import LennardJones
    # calc = LennardJones(sigma=sigma, epsilon=epsilon, rc=rc)
    # struct = Atoms(chemStr, listOfPositions, calculator=calc )

    ############################################################################
    from ase import Atom, Atoms
    from lammpslib import LAMMPSlib
    # lammps_header=['units       metal'    ,\
    #                'boundary    p p p '   ,\
    #                "atom_style	atomic"   ,\
    #                "atom_modify	map hash"    ]
    lammps_header = ["units       metal"]
    cmds          = [ "pair_style  mlip  /Users/chinchay/Documents/9_Git/reverseEnergyPartitioning/mlip_LJ.ini",\
                      "pair_coeff  * * " ]
    # cmds = ["pair_style    mlip  /Users/chinchay/Documents/9_Git/reverseEnergyPartitioning/mlip_LJ.ini",\
    #         "pair_coeff    * * "       ,\
    #         "neighbor      1.5 bin "       ]

    # cmds = ["pair_style    mlip  /Users/chinchay/Documents/9_Git/reverseEnergyPartitioning/mlip_test.ini",\
    #         "pair_coeff    * * "       ,\
    #         "neighbor      1.5 bin "       ]

    mylammps = LAMMPSlib(
        lmpcmds=cmds,
        atom_types={1: 1},
        keep_alive=True,
        log_file=
        '/Users/chinchay/Documents/9_Git/reverseEnergyPartitioning/log.txt')
    # struct = Atoms(chemStr, listOfPositions, calculator=mylammps )
    struct.set_calculator(mylammps)
    ############################################################################

    energy = struct.get_potential_energy()

    eig = []
    if getForceMatrix:
        # ph = Phonons(struct, calc)
        ph = Phonons(struct, mylammps)
        ph.run()
        ph.read(acoustic=True)
        ph.clean()

        f = ph.get_force_constant()
        # f
        # f.size
        (l, m, n) = f.shape
        if l == 1:
            ff = np.reshape(f, (m, n))
        else:
            print("error")
        #
        # ff
        eig = LA.eigvalsh(ff)  # eig is a numpy array
    #
    return energy, [float("{0:.5f}".format(eig[i])) for i in range(len(eig))]