Ejemplo n.º 1
0
def dos(filename, plot=False, output='dos.csv', width=0.1):
    """Calculate density of states.
    
    filename: str
        Name of restart-file.
    plot: bool
        Show a plot.
    output: str
        Name of CSV output file.
    width: float
        Width of Gaussians.
    """
    calc = GPAW(filename, txt=None)
    dos = DOS(calc, width)
    D = [dos.get_dos(spin) for spin in range(calc.get_number_of_spins())]
    if output:
        fd = sys.stdout if output == '-' else open(output, 'w')
        for x in zip(dos.energies, *D):
            print(*x, sep=', ', file=fd)
        if output != '-':
            fd.close()
    if plot:
        import matplotlib.pyplot as plt
        for y in D:
            plt.plot(dos.energies, y)
        plt.show()
Ejemplo n.º 2
0
def dos(filename, plot=False, output='dos.csv', width=0.1):
    """Calculate density of states.
    
    filename: str
        Name of restart-file.
    plot: bool
        Show a plot.
    output: str
        Name of CSV output file.
    width: float
        Width of Gaussians.
    """
    from gpaw import GPAW
    from ase.dft.dos import DOS
    calc = GPAW(filename, txt=None)
    dos = DOS(calc, width)
    D = [dos.get_dos(spin) for spin in range(calc.get_number_of_spins())]
    if output:
        fd = sys.stdout if output == '-' else open(output, 'w')
        for x in zip(dos.energies, *D):
            print(*x, sep=', ', file=fd)
        if output != '-':
            fd.close()
    if plot:
        import matplotlib.pyplot as plt
        for y in D:
            plt.plot(dos.energies, y)
        plt.show()
Ejemplo n.º 3
0
    def get_dos(self, spin=None, **kwargs):
        """
        The total DOS.

        Uses the ASE DOS module, and returns a tuple with
        (energies, dos).
        """
        from ase.dft.dos import DOS
        dos = DOS(self, **kwargs)
        e = dos.get_energies()
        d = dos.get_dos(spin=spin)
        return e, d
Ejemplo n.º 4
0
def create_ase_object(objtype, dct):
    # We just try each object type one after another and instantiate
    # them manually, depending on which kind it is.
    # We can formalize this later if it ever becomes necessary.
    if objtype == 'cell':
        from ase.cell import Cell
        dct.pop('pbc', None)  # compatibility; we once had pbc
        obj = Cell(**dct)
    elif objtype == 'bandstructure':
        from ase.spectrum.band_structure import BandStructure
        obj = BandStructure(**dct)
    elif objtype == 'bandpath':
        from ase.dft.kpoints import BandPath
        obj = BandPath(path=dct.pop('labelseq'), **dct)
    elif objtype == 'atoms':
        from ase import Atoms
        obj = Atoms.fromdict(dct)
    elif objtype == 'densityofstates':
        from ase.dft.dos import DOS
        obj = DOS(**dct)
    elif objtype == 'griddoscollection':
        from ase.spectrum.doscollection import GridDOSCollection
        obj = GridDOSCollection.fromdict(dct)
    else:
        raise ValueError('Do not know how to decode object type {} '
                         'into an actual object'.format(objtype))
    assert obj.ase_objtype == objtype
    return obj
Ejemplo n.º 5
0
    def get_dos(self, width=0.15, method='gaussian', npts=501):
        """
        density of states.

        :param width: smearing width
        :param method: 'gaussian'| 'tetra'
        :param npts: number of DOS energies.

        :returns:
          energies, dos. two ndarray.
        TODO: implement spin resolved DOS.
        """
        if method == 'tetra':
            dos = tetrahedronDosClass(self, width, npts=npts)
        else:
            dos = DOS(self, width, window=None, npts=npts)
        return dos.get_energies(), dos.get_dos()
Ejemplo n.º 6
0
    def get_dos(self, width=None, smearing='gaussian', npts=501):
        """
        density of states.

        :param width: smearing width
        :param method: 'gaussian'| 'tetra'
        :param npts: number of DOS energies.

        :returns:
          energies, dos. two ndarray.
        TODO: implement spin resolved DOS.
        """
        if width is None:
            width = self._width
        if smearing == 'tetra':
            raise NotImplementedError('tetrahedron DOS not implemented')
            #dos = tetrahedronDosClass(self, width, npts=npts)
        else:
            dos = DOS(self, width, window=None, npts=npts)
        return dos.get_energies(), dos.get_dos()
Ejemplo n.º 7
0
def test_dos():
    from ase.atoms import Atoms
    from ase.calculators.singlepoint import SinglePointDFTCalculator
    from ase.calculators.singlepoint import SinglePointKPoint
    from ase.dft.dos import DOS

    atoms = Atoms('H')
    eFermi = [0, 1]
    kpts = [SinglePointKPoint(1, 0, 0), SinglePointKPoint(1, 1, 0)]
    kpts[0].eps_n = [-2, -1, 1]
    kpts[0].f_n = [1, 0, 0]
    kpts[1].eps_n = [-2.5, -1.5, 0.5]
    kpts[1].f_n = [1, 0, 0]

    calc = SinglePointDFTCalculator(atoms, efermi=eFermi)
    calc.kpts = kpts

    DOS(calc)
Ejemplo n.º 8
0
    def get_dos(self,kpoints=None,width=0.1,window=None,npts=201,spin=None):
        """
        calculate density of states.

        :param kpoints: set k-points for DOS calculation.
        :param width: smearing width
        :param window: energy windown. e.g. [-5,5]
        :param npts: number of points.
        :param spin: No use here. Just to keep with the ase API.
        """
        if kpoints is not None:
            self.params['calculation']='nscf'
            self.kpts=['automatic',kpoints]
            self.params['occupations']='tetrahedra'
            self.initialize(self.atoms)
            self.calculate()
            self.read_output()
        mydos=DOS(self,width=width,window=window,npts=201)
        self.dos_energies=mydos.get_energies()
        self.dos=mydos.get_dos()
        if self.spin_polarized:
            self.dos_up=mydos.get_dos(spin=0)
            self.dos_down=mydos.get_dos(spin=1)
Ejemplo n.º 9
0
from jasp import *
from ase.dft.dos import DOS
import matplotlib.pyplot as plt
with jasp('molecules/simple-co') as calc: # we already ran this!
    dos = DOS(calc)
    plt.plot(dos.get_energies(), dos.get_dos())
    plt.xlabel('Energy - $E_f$ (eV)')
    plt.ylabel('DOS')
# make sure you save the figure outside the with statement, or provide
# the correct relative or absolute path to where you want it.
plt.savefig('images/co-dos.png')
Ejemplo n.º 10
0
from ase.atoms import Atoms
from ase.calculators.singlepoint import SinglePointDFTCalculator
from ase.calculators.singlepoint import SinglePointKPoint
from ase.dft.dos import DOS


atoms = Atoms('H')
eFermi = [0, 1]
kpts = [SinglePointKPoint(1, 0, 0), SinglePointKPoint(1, 1, 0)]
kpts[0].eps_n = [-2, -1, 1]
kpts[0].f_n = [1, 0, 0]
kpts[1].eps_n = [-2.5, -1.5, 0.5]
kpts[1].f_n = [1, 0, 0]

calc = SinglePointDFTCalculator(atoms, efermi=eFermi)
calc.kpts = kpts

dos = DOS(calc)
Ejemplo n.º 11
0
class BandStructure:
    '''outline of class to facilitate band structure calculations
    '''
    def __init__(self, atoms, BZpath=[], npoints=10, outnc='harris.nc'):
        """Headline here ... XXX.

        atoms is an ase.Atoms object with calculator
        attached. Presumably the self-consistent charge density has
        already been calculated, otherwise, it will be.

        BZpath is a list of tuples describing the path through the
        Brillouin zone. The tuples have the form (label, kpt), e.g. ::

          [('$\Gamma$',[0.0, 0.0, 0.0]),
           ('X',[0.0, 0.5, 0.5]),
           ('L',[0.5, 0.0, 0.0]),
           ('$\Gamma$',[0.0, 0.0, 0.0])]

        the label is used in the figure and can include latex markup.

        npoints is the number of points on each segment. It can either
        be a constant, which is used for every segment, or a list of
        integers that is an integer for each segment.
        """

        self.atoms = atoms
        self.calc = atoms.get_calculator()
        #first, we make sure the charge density is up to date.
        self.calc.get_charge_density()
        self.ef = self.calc.get_ef()  #self-consistent fermi level

        self.labels = [x[0] for x in BZpath]
        self.kpt_path = [np.array(x[1], dtype=np.float) for x in BZpath]
        self.npoints = npoints

        #first, setup the kpt path
        kpts = []
        #start at second kpt and go to second to last segment
        nsegments = len(self.kpt_path) - 1
        for i in range(nsegments - 1):

            #get number of points on path. this counts the first point
            try:
                i_npt = npoints[i]
            except TypeError:
                i_npt = npoints

            #this is the vector connecting the two endpoint kpts of a segment
            kdiff = self.kpt_path[i + 1] - self.kpt_path[i]

            #make a vector of evenly spaced intervals, one longer than needed
            #because we chop off the last entry.
            for j in np.linspace(0, 1, i_npt + 1)[0:-1]:
                k = self.kpt_path[i] + j * kdiff
                #shift by small random amount to break symmetry and
                #prevent time-inversion reduction
                krand = (1. + np.random.random(3)) / 1.e4

                k += krand
                kpts.append(k)

        #now fill in the last segment, and end on the last point
        try:
            i_npt = npoints[-1]
        except TypeError:
            i_npt = npoints

        kdiff = self.kpt_path[-1] - self.kpt_path[-2]
        for j in np.linspace(0, 1, i_npt + 1)[1:]:
            k = self.kpt_path[-2] + j * kdiff
            #shift by small random amount to break symmetry and
            #prevent time-inversion reduction
            krand = (1. + np.random.random(3)) / 1.e4
            k += krand
            kpts.append(k)

        #these are now the points needed for the Harris calculation.
        self.kpts = kpts

        self.dos = DOS(self.calc)
        self.dos_energies = self.dos.get_energies()
        self.dos_dos = self.dos.get_dos()

        #try to avoid rerunning the calculation if it is already done!
        if os.path.exists(outnc):
            self.calc = Jacapo(outnc)
        else:
            print('calculation of harris required')
            self.calc.set_nc(outnc)
            #self.calc.debug=10

            #save some time by not calculating stress
            self.calc.set_stress(False)

            #this seems to be necessary sometimes
            self.calc.delete_ncattdimvar(outnc, ncdims=['number_plane_waves'])

            #this has to come after removing number_of_planewaves
            self.calc.set_kpts(self.kpts)

            #freeze charge density
            self.calc.set_charge_mixing(updatecharge='No')
            #and, run calculation
            self.calc.calculate()

    def plot(self):
        '''
        Make an interactive band-structure plot.

        clicking on a band will make it thicker and print which band was selected.
        '''

        # kpoints = self.calc.get_ibz_kpoints()

        eigenvalues = self.calc.get_all_eigenvalues() - self.ef
        #eigenvalues = np.array([self.calc.get_eigenvalues(kpt=i)-self.ef
        #                        for i in range(len(kpoints))])

        self.handles = []  #used to get band indexes from plot

        fig = plt.figure()
        #plot DOS in figure
        ax = fig.add_subplot(122)
        ax.plot(self.dos_dos, self.dos_energies)
        plt.title('self-consistent Total DOS')
        ax.set_xticks([])
        ax.set_yticks([])
        ax.set_ylim([-20, 20])

        ax = fig.add_subplot(121)
        ax.set_title('Band structure')

        def onpick(event):
            'make picked line bolder, set oldline back to regular thickness'
            self.lastartist.set_linewidth(1)
            self.lastartist = thisline = event.artist
            thisline.set_linewidth(5)
            plt.draw()  #needed to update linewidth

            print('Band %i selected' % self.handles.index(thisline))
            #you could insert code here to plot wavefunction, etc...

        fig.canvas.mpl_connect('pick_event', onpick)

        #we use indices for x. the tick labels are not shown and the distance
        #appears unimportant
        xdata = list(range(len(eigenvalues)))

        nkpts, nbands = eigenvalues.shape
        for i in range(nbands):
            #eigenvalues has shape(nkpts,nbands)
            #note the comma after line_handle
            line_handle, = ax.plot(xdata,
                                   eigenvalues[:, i],
                                   '.-',
                                   ms=1,
                                   picker=2)
            self.handles.append(line_handle)

        self.lastartist = self.handles[-1]

        #plot Fermi level
        ax.plot([0, len(self.kpts)], [0, 0], 'k--', label='$E_f$')

        plt.xlabel('|k|')
        plt.ylabel('$E-E_f$ (eV)')

        #set xtick locations and labels
        xtick_locs = np.zeros(len(self.kpt_path))
        try:
            #this means the npoints is a list
            # i_npt = self.npoints[0]
            for j, npt in enumerate(1, self.npoints):
                xtick_locs[j] = xtick_locs[j - 1] + npt
        except TypeError:
            #npoints is a single number
            for j in range(1, len(self.labels)):
                xtick_locs[j] = xtick_locs[j - 1] + self.npoints

        #the last location is off by one, so we fix it.
        xtick_locs[-1] -= 1

        ax.set_xlim([xtick_locs[0], xtick_locs[-1]])
        ax.set_xticks(xtick_locs)
        ax.set_xticklabels(self.labels)

        #this seems reasonable to avoid very deep energy states and high energy states
        ax.set_ylim([-20, 20])

        plt.show()

        return fig
Ejemplo n.º 12
0
    def __init__(self, atoms, BZpath=[], npoints=10, outnc='harris.nc'):
        """Headline here ... XXX.

        atoms is an ase.Atoms object with calculator
        attached. Presumably the self-consistent charge density has
        already been calculated, otherwise, it will be.

        BZpath is a list of tuples describing the path through the
        Brillouin zone. The tuples have the form (label, kpt), e.g. ::

          [('$\Gamma$',[0.0, 0.0, 0.0]),
           ('X',[0.0, 0.5, 0.5]),
           ('L',[0.5, 0.0, 0.0]),
           ('$\Gamma$',[0.0, 0.0, 0.0])]

        the label is used in the figure and can include latex markup.

        npoints is the number of points on each segment. It can either
        be a constant, which is used for every segment, or a list of
        integers that is an integer for each segment.
        """

        self.atoms = atoms
        self.calc = atoms.get_calculator()
        #first, we make sure the charge density is up to date.
        self.calc.get_charge_density()
        self.ef = self.calc.get_ef()  #self-consistent fermi level

        self.labels = [x[0] for x in BZpath]
        self.kpt_path = [np.array(x[1], dtype=np.float) for x in BZpath]
        self.npoints = npoints

        #first, setup the kpt path
        kpts = []
        #start at second kpt and go to second to last segment
        nsegments = len(self.kpt_path) - 1
        for i in range(nsegments - 1):

            #get number of points on path. this counts the first point
            try:
                i_npt = npoints[i]
            except TypeError:
                i_npt = npoints

            #this is the vector connecting the two endpoint kpts of a segment
            kdiff = self.kpt_path[i + 1] - self.kpt_path[i]

            #make a vector of evenly spaced intervals, one longer than needed
            #because we chop off the last entry.
            for j in np.linspace(0, 1, i_npt + 1)[0:-1]:
                k = self.kpt_path[i] + j * kdiff
                #shift by small random amount to break symmetry and
                #prevent time-inversion reduction
                krand = (1. + np.random.random(3)) / 1.e4

                k += krand
                kpts.append(k)

        #now fill in the last segment, and end on the last point
        try:
            i_npt = npoints[-1]
        except TypeError:
            i_npt = npoints

        kdiff = self.kpt_path[-1] - self.kpt_path[-2]
        for j in np.linspace(0, 1, i_npt + 1)[1:]:
            k = self.kpt_path[-2] + j * kdiff
            #shift by small random amount to break symmetry and
            #prevent time-inversion reduction
            krand = (1. + np.random.random(3)) / 1.e4
            k += krand
            kpts.append(k)

        #these are now the points needed for the Harris calculation.
        self.kpts = kpts

        self.dos = DOS(self.calc)
        self.dos_energies = self.dos.get_energies()
        self.dos_dos = self.dos.get_dos()

        #try to avoid rerunning the calculation if it is already done!
        if os.path.exists(outnc):
            self.calc = Jacapo(outnc)
        else:
            print('calculation of harris required')
            self.calc.set_nc(outnc)
            #self.calc.debug=10

            #save some time by not calculating stress
            self.calc.set_stress(False)

            #this seems to be necessary sometimes
            self.calc.delete_ncattdimvar(outnc, ncdims=['number_plane_waves'])

            #this has to come after removing number_of_planewaves
            self.calc.set_kpts(self.kpts)

            #freeze charge density
            self.calc.set_charge_mixing(updatecharge='No')
            #and, run calculation
            self.calc.calculate()
Ejemplo n.º 13
0
def calc_to_dict(calc, **kwargs):
    d = {'doc': '''JSON representation of a VASP calculation.

energy is in eV
forces are in eV/\AA
stress is in GPa (sxx, syy, szz,  syz, sxz, sxy)
magnetic moments are in Bohr-magneton
The density of states is reported with E_f at 0 eV.
Volume is reported in \AA^3
Coordinates and cell parameters are reported in \AA

If atom-projected dos are included they are in the form:
{ados:{energy:data, {atom index: {orbital : dos}}}
'''}
    d['incar'] = {'doc': 'INCAR parameters'}
    d['incar'].update(dict(filter(lambda item: item[1] is not None,
                                  calc.float_params.items())))
    d['incar'].update(dict(filter(lambda item: item[1] is not None,
                                  calc.exp_params.items())))
    d['incar'].update(dict(filter(lambda item: item[1] is not None,
                                  calc.string_params.items())))
    d['incar'].update(dict(filter(lambda item: item[1] is not None,
                                  calc.int_params.items())))
    d['incar'].update(dict(filter(lambda item: item[1] is not None,
                                  calc.bool_params.items())))
    d['incar'].update(dict(filter(lambda item: item[1] is not None,
                                  calc.list_params.items())))
    d['incar'].update(dict(filter(lambda item: item[1] is not None,
                                  calc.dict_params.items())))
    d['input'] = calc.input_params
    d['potcar'] = calc.get_pseudopotentials()
    d['atoms'] = atoms_to_dict(calc.get_atoms())
    d['data'] = {'doc': 'Data from the output of the calculation'}
    atoms = calc.get_atoms()
    d['data']['total_energy'] = atoms.get_potential_energy()
    d['data']['forces'] = atoms.get_forces().tolist()

    # There are times when no stress is calculated
    try:
        stress = atoms.get_stress()
    except NotImplementedError:
        stress = None
    except AssertionError:
        stress = None

    if stress is not None:
        d['data']['stress'] = atoms.get_stress().tolist()
    else:
        d['data']['stress'] = None
    d['data']['fermi_level'] = calc.get_fermi_level()
    d['data']['volume'] = atoms.get_volume()
    if calc.spinpol:
        d['data']['magmom'] = atoms.get_magnetic_moment()

    if (calc.int_params.get('lorbit', 0) >= 10
        or calc.list_params.get('rwigs', None)):
        try:
            d['data']['magmoms'] = atoms.get_magnetic_moments().tolist()
        except AttributeError:
            d['data']['magmoms'] = None
    # store the metadata
    if hasattr(calc, 'metadata'):
        d['metadata'] = calc.metadata

    if kwargs.get('dos', None):
        from ase.dft.dos import DOS
        dos = DOS(calc, width=kwargs.get('width', 0.2))
        e = dos.get_energies()

        d['data']['dos'] = {'doc': 'Total density of states'}
        d['data']['dos']['e'] = e.tolist()

        if calc.spinpol:
            d['data']['dos']['dos-up'] = dos.get_dos(spin=0).tolist()
            d['data']['dos']['dos-down'] = dos.get_dos(spin=1).tolist()
        else:
            d['data']['dos']['dos'] = dos.get_dos().tolist()

    if kwargs.get('ados', None):
        from ase.calculators.vasp import VaspDos
        ados = VaspDos(efermi=calc.get_fermi_level())
        d['data']['ados'] = {'doc': 'Atom projected DOS'}
        nonspin_orbitals_no_phase = ['s', 'p', 'd']
        nonspin_orbitals_phase = ['s', 'py', 'pz', 'px',
                                  'dxy', 'dyz', 'dz2', 'dxz', 'dx2']
        spin_orbitals_no_phase = []
        for x in nonspin_orbitals_no_phase:
            spin_orbitals_no_phase += ['{0}-up'.format(x)]
            spin_orbitals_no_phase += ['{0}-down'.format(x)]

        spin_orbitals_phase = []
        for x in nonspin_orbitals_phase:
            spin_orbitals_phase += ['{0}-up'.format(x)]
            spin_orbitals_phase += ['{0}-down'.format(x)]

        if calc.spinpol and calc.int_params['lorbit'] != 11:
            orbitals = spin_orbitals_no_phase
        elif calc.spinpol and calc.int_params['lorbit'] == 11:
            orbitals = spin_orbitals_phase
        elif calc.int_params['lorbit'] != 11:
            orbitals = nonspin_orbitals_no_phase
        else:
            orbitals = nonspin_orbitals_phase

        for i, atom in enumerate(atoms):
            d['data']['ados']['energy'] = ados.energy.tolist()
            d['data']['ados'][i] = {}
            for orbital in orbitals:
                d['data']['ados'][i][orbital] = ados.site_dos(0, orbital).tolist()

    # convert all numpy arrays to lists
    for key in d:
        try:
            d[key] = d[key].tolist()
        except:
            pass
    for key in d['input']:
        try:
            d['input'][key] = d['input'][key].tolist()
        except:
            pass
    return d
Ejemplo n.º 14
0
def dos(filename, plot=False, output='dos.csv', width=0.1, integrated=False,
        projection=None, emin=None, emax=None, npoints=400, show_total=None):
    """Calculate density of states.

    filename: str
        Name of restart-file.
    plot: bool
        Show a plot.
    output: str
        Name of CSV output file.
    width: float
        Width of Gaussians.
    integrated: bool
        Calculate integrated DOS.

    """
    calc = GPAW(filename, txt=None)
    dos = DOS(calc, width, (emin, emax), npoints)

    nspins = calc.get_number_of_spins()
    spinlabels = [''] if nspins == 1 else [' up', ' dn']

    if projection is None or show_total:
        D = [dos.get_dos(spin) for spin in range(nspins)]
        labels = ['DOS' + sl for sl in spinlabels]
    else:
        D = []
        labels = []
    if projection is not None:
        for p in projection.split(','):
            s, ll = p.split('-')
            if s.isdigit():
                A = [int(s)]
                s = '#' + s
            else:
                A = [a for a, symbol in
                     enumerate(calc.atoms.get_chemical_symbols())
                     if symbol == s]
                if not A:
                    raise ValueError('No such atom: ' + s)
            for spin in range(nspins):
                for l in ll:
                    d = 0.0
                    for a in A:
                        d += ldos(calc, a, spin, l, width, dos.energies)
                    labels.append(s + '-' + l + spinlabels[spin])
                    D.append(d)

    if integrated:
        de = dos.energies[1] - dos.energies[0]
        dos.energies += de / 2
        D = [np.cumsum(d) * de for d in D]
        ylabel = 'iDOS [electrons]'
    else:
        ylabel = 'DOS [electrons/eV]'

    if output:
        fd = sys.stdout if output == '-' else open(output, 'w')
        for x in zip(dos.energies, *D):
            print(*x, sep=', ', file=fd)
        if output != '-':
            fd.close()
    if plot:
        import matplotlib.pyplot as plt
        for y, label in zip(D, labels):
            plt.plot(dos.energies, y, label=label)
        plt.legend()
        plt.ylabel(ylabel)
        plt.xlabel(r'$\epsilon-\epsilon_F$ [eV]')
        plt.show()
Ejemplo n.º 15
0
def calc_to_dict(calc, **kwargs):
    """Convert calc to a dictionary."""
    d = {
        'doc':
        '''JSON representation of a VASP calculation.

energy is in eV
forces are in eV/\AA
stress is in GPa (sxx, syy, szz,  syz, sxz, sxy)
magnetic moments are in Bohr-magneton
The density of states is reported with E_f at 0 eV.
Volume is reported in \AA^3
Coordinates and cell parameters are reported in \AA

If atom-projected dos are included they are in the form:
{ados:{energy:data, {atom index: {orbital : dos}}}
'''
    }
    d['incar'] = {'doc': 'INCAR parameters'}
    d['incar'].update(
        dict(
            filter(lambda item: item[1] is not None,
                   calc.float_params.items())))
    d['incar'].update(
        dict(filter(lambda item: item[1] is not None,
                    calc.exp_params.items())))
    d['incar'].update(
        dict(
            filter(lambda item: item[1] is not None,
                   calc.string_params.items())))
    d['incar'].update(
        dict(filter(lambda item: item[1] is not None,
                    calc.int_params.items())))
    d['incar'].update(
        dict(filter(lambda item: item[1] is not None,
                    calc.bool_params.items())))
    d['incar'].update(
        dict(filter(lambda item: item[1] is not None,
                    calc.list_params.items())))
    d['incar'].update(
        dict(filter(lambda item: item[1] is not None,
                    calc.dict_params.items())))
    d['input'] = calc.input_params
    d['potcar'] = calc.get_pseudopotentials()
    d['atoms'] = atoms_to_dict(calc.get_atoms())
    d['data'] = {'doc': 'Data from the output of the calculation'}
    atoms = calc.get_atoms()
    d['data']['total_energy'] = atoms.get_potential_energy()
    d['data']['forces'] = atoms.get_forces().tolist()

    # There are times when no stress is calculated
    try:
        stress = atoms.get_stress()
    except NotImplementedError:
        stress = None
    except AssertionError:
        stress = None

    if stress is not None:
        d['data']['stress'] = atoms.get_stress().tolist()
    else:
        d['data']['stress'] = None
    d['data']['fermi_level'] = calc.get_fermi_level()
    d['data']['volume'] = atoms.get_volume()
    if calc.spinpol:
        d['data']['magmom'] = atoms.get_magnetic_moment()

    if (calc.int_params.get('lorbit', 0) >= 10
            or calc.list_params.get('rwigs', None)):
        try:
            d['data']['magmoms'] = atoms.get_magnetic_moments().tolist()
        except AttributeError:
            d['data']['magmoms'] = None
    # store the metadata
    if hasattr(calc, 'metadata'):
        d['metadata'] = calc.metadata

    if kwargs.get('dos', None):
        from ase.dft.dos import DOS
        dos = DOS(calc, width=kwargs.get('width', 0.2))
        e = dos.get_energies()

        d['data']['dos'] = {'doc': 'Total density of states'}
        d['data']['dos']['e'] = e.tolist()

        if calc.spinpol:
            d['data']['dos']['dos-up'] = dos.get_dos(spin=0).tolist()
            d['data']['dos']['dos-down'] = dos.get_dos(spin=1).tolist()
        else:
            d['data']['dos']['dos'] = dos.get_dos().tolist()

    if kwargs.get('ados', None):
        from ase.calculators.vasp import VaspDos
        ados = VaspDos(efermi=calc.get_fermi_level())
        d['data']['ados'] = {'doc': 'Atom projected DOS'}
        nonspin_orbitals_no_phase = ['s', 'p', 'd']
        nonspin_orbitals_phase = [
            's', 'py', 'pz', 'px', 'dxy', 'dyz', 'dz2', 'dxz', 'dx2'
        ]
        spin_orbitals_no_phase = []
        for x in nonspin_orbitals_no_phase:
            spin_orbitals_no_phase += ['{0}-up'.format(x)]
            spin_orbitals_no_phase += ['{0}-down'.format(x)]

        spin_orbitals_phase = []
        for x in nonspin_orbitals_phase:
            spin_orbitals_phase += ['{0}-up'.format(x)]
            spin_orbitals_phase += ['{0}-down'.format(x)]

        if calc.spinpol and calc.int_params['lorbit'] != 11:
            orbitals = spin_orbitals_no_phase
        elif calc.spinpol and calc.int_params['lorbit'] == 11:
            orbitals = spin_orbitals_phase
        elif calc.int_params['lorbit'] != 11:
            orbitals = nonspin_orbitals_no_phase
        else:
            orbitals = nonspin_orbitals_phase

        for i, atom in enumerate(atoms):
            d['data']['ados']['energy'] = ados.energy.tolist()
            d['data']['ados'][i] = {}
            for orbital in orbitals:
                d['data']['ados'][i][orbital] = ados.site_dos(
                    0, orbital).tolist()

    # convert all numpy arrays to lists
    for key in d:
        try:
            d[key] = d[key].tolist()
        except:
            pass
    for key in d['input']:
        try:
            d['input'][key] = d['input'][key].tolist()
        except:
            pass
    return d
# Get band structure and dos
Ebs = atoms.calc.band_structure()  # Get the band structure

# if world.rank == 0:
print('Electronic band structure calculated')
kpts = {'size': (40,40,40)}
calc.set(
    kpts = kpts, 
    fixdensity=True,
    symmetry='off',  
)
# Fix the potential
calc.get_potential_energy()

# e, dos = calc.get_dos(spin=0, npts=1001, width=0.5)  # Get energy and density of states
dos = DOS(calc, npts=2000, width=0.1)
d = dos.get_dos()
e = dos.get_energies() 
f = calc.get_fermi_level() 
print('Electronic DOS computed')
e_f = calc.get_fermi_level()  
Edos = {
    'e': e, 
    'dos': d,
    'fermi': e_f
} 

# Save results
pickle.dump( Ebs, open( "Ebs.p", "wb" ) )  # Save the electronic band structure
pickle.dump( Edos, open( "Edos.p", "wb" ) )  # Save the electronic DOS
# if world.rank == 0:
Ejemplo n.º 17
0
    def add_to_plot(self, readoutfilesobj, label=None):
        """
        |Here you add individual plots that need to be plot and then just plot them with the plot() method
        |Use this method which is a part of the BandPlotterASE class you will have to give the bands to plot using a readoutfilesobj type of object
        """
        try:
            Ef = readoutfilesobj.atoms_objects[0].calc.get_fermi_level()
        except:
            print(f"add_to_plot: Could not read fermi level on scf file")
        try:
            kpts = readoutfilesobj.atoms_bands_objects[
                0].calc.get_ibz_k_points()
        except:
            print(f"add_to_plot: Could not read k points on bands file")

        if self.include_dos or self.plot_only_dos:
            if self.plot_from_QE_dos_file:
                E = []
                dos = []
                with open(readoutfilesobj.dos_file_name, "r") as dos_file:
                    for line in dos_file:
                        # print(line)
                        if "#" not in line:
                            data = line.strip().split()
                            E.append(float(data[0]) - Ef)
                            dos.append(float(data[1]))
                # self.y_to_plot.append(dos)
                # self.x_to_plot.append(E)
                self.dos.append(dos)
                self.E_dos.append(E)
                if self.plot_only_dos:  # Other wise we wil lappend to labels twice sicnce we will do it again at theloading of bands
                    self.labels.append(label)

            else:
                # we are here getting the required information for DOS
                # self.get_dos(readoutfilesobj)
                calc = readoutfilesobj.atoms_nscf_objects[0].calc
                Ef_nscf = readoutfilesobj.atoms_nscf_objects[
                    0].calc.get_fermi_level()
                dos = DOS(calc, width=0.2)
                self.dos.append(dos.get_dos())
                E_nscf = dos.get_energies()
                Ef_diff = Ef - Ef_nscf
                if abs(Ef_diff) >= 0.001:
                    print(
                        f"Warning!!! In {readoutfilesobj.identifier[0]}:\t|E_f_scf-E_f_nscf| = {abs(Ef_diff):.3} eV (>= 0.001 eV); E_f_scf = {Ef} eV,  E_f_nscf = {Ef_nscf} eV"
                    )
                if self.pin_fermi != "scf": self.E_dos.append(E_nscf)
                else: self.E_dos.append([E - Ef_diff for E in E_nscf])

        # Test space for k path and k high symmetry points
        # print(kpts)
        # print(self.plot_only_dos)
        if self.plot_only_dos == False:
            # This is for teh band structure
            path = readoutfilesobj.atoms_bands_objects[0].cell.bandpath(
                npoints=0)
            kinks = find_bandpath_kinks(
                readoutfilesobj.atoms_bands_objects[0].cell, kpts,
                eps=1e-5)  # These are the high symmetry points in use
            pathspec = resolve_custom_points(
                kpts[kinks], path.special_points, eps=1e-5
            )  # This gives the postions for the relevant high symmetry points
            # path.kpts = kpts
            # path.path = pathspec

            klengths = []
            for x in range(0, len(kpts)):
                if x == 0:
                    kdist = np.sqrt((0.0 - kpts[x][0])**2 +
                                    (0.0 - kpts[x][1])**2 +
                                    (0.0 - kpts[x][2])**2)
                    klengths.append(kdist)
                else:
                    kdist = np.sqrt((kpts[x - 1][0] - kpts[x][0])**2 +
                                    (kpts[x - 1][1] - kpts[x][1])**2 +
                                    (kpts[x - 1][2] - kpts[x][2])**2)
                    klengths.append(kdist + klengths[x - 1])

            self.k_locations = []
            for x in range(len(kinks)):
                self.k_locations.append(klengths[kinks[x]])

            self.k_symbols = []
            for x in pathspec:
                if x == "G":
                    self.k_symbols.append("$\Gamma$")
                else:
                    self.k_symbols.append(x)

            energies = []
            for s in range(readoutfilesobj.atoms_bands_objects[0].calc.
                           get_number_of_spins()):
                energies.append([
                    readoutfilesobj.atoms_bands_objects[0].calc.
                    get_eigenvalues(kpt=k, spin=s) for k in range(len(kpts))
                ])
            # print(f"lenght of kpoints: {range(len(kpts))}")
            Energy_to_plot = []
            if self.Ef_shift == True:
                for band in energies[0]:
                    if self.pin_fermi != "nscf":
                        Energy_to_plot.append([E - Ef for E in band])
                    else:
                        Energy_to_plot.append(
                            [E - Ef_nscf for E in band]
                        )  # here the assumption is that if this option is ever reached then the idea is that an nscf calculation has already being done and dos is being plotted.
            tempMain = []
            temp = []
            for x in range(len(Energy_to_plot[0])):
                for kpoint in Energy_to_plot:
                    temp.append(kpoint[x])
                tempMain.append(temp)
                temp = []
            self.y_to_plot.append(tempMain)
            self.x_to_plot.append(klengths)
            self.labels.append(label)
Ejemplo n.º 18
0
import matplotlib.pyplot as plt
from gpaw import GPAW
from ase.dft.dos import DOS

calc = GPAW('groundstate.gpw')
dos = DOS(calc, npts=800, width=0.1)
energies = dos.get_energies()
weights = dos.get_dos()

ax = plt.gca()
ax.plot(energies, weights)
ax.set_xlabel(r'$E - E_{\mathrm{Fermi}}$ [eV]')
ax.set_ylabel('DOS [1/eV]')
plt.savefig('dos.png')
plt.show()
Ejemplo n.º 19
0
        start = time.time()
        # if world.rank == 0:
        print(f'Calculating EOS for Al{N}')

        # Define electron calculator (GPAW)
        calc = GPAW(
            mode=PW(300),  # Lower for computational efficiency
            txt=f'./gpaw-out/EOS_{N}_1core.txt'
        )  # Use the same calculator as in task6
        atoms.set_calculator(calc)
        pot_e = atoms.get_potential_energy()  # Self-constistently optimize the electron density
        # if world.rank == 0:
        print(f'Cluster Al{N} finished potential energy per atom: {pot_e / N:.2f} eV')

        # Get the electronic DOS
        dos = DOS(calc, npts=800, width=0.2)
        
        e = dos.get_energies()
        d = dos.get_dos()
        e_f = calc.get_fermi_level()  
        e -= e_f  # Subtract the Fermi level from the energy    
        
        ##### Get the DOS using the same method as in task6
        # print('Electronic band structure calculated')
        # kpts = {'size': (40,40,40)}
        # calc.set(
        #     kpts = kpts, 
        #     fixdensity=True,
        #     symmetry='off',  
        # )
        # # Fix the potential
Ejemplo n.º 20
0
from jasp import *
from ase.dft.dos import DOS
import matplotlib.pyplot as plt
# get the geometry from another calculation
with jasp('molecules/simple-co') as calc:
    atoms = calc.get_atoms()
with jasp(
        'molecules/co-ados',
        encut=300,
        xc='PBE',
        rwigs=[1.0, 1.0],  # these are the cutoff radii for projected states
        atoms=atoms) as calc:
    calc.calculate()
    # now get results
    dos = DOS(calc)
    plt.plot(dos.get_energies(), dos.get_dos() + 10)
    ados = VaspDos(efermi=calc.get_fermi_level())
    energies = ados.energy
    plt.plot(energies, ados.dos + 8, label='ADOS')  # these are the total DOS
    c_s = ados.site_dos(0, 's')
    c_p = ados.site_dos(0, 'p')
    o_s = ados.site_dos(1, 's')
    o_p = ados.site_dos(1, 'p')
    c_d = ados.site_dos(0, 'd')
    o_d = ados.site_dos(1, 'd')
    plt.plot(energies, c_s + 6, energies, o_s + 5)
    plt.plot(energies, c_p + 4, energies, o_p + 3)
    plt.plot(energies, c_d, energies, o_d + 2)
    plt.xlabel('Energy - $E_f$ (eV)')
    plt.ylabel('DOS')
    plt.legend(
Ejemplo n.º 21
0
    def __init__(self,
                 atoms,
                 BZpath=[],
                 npoints=10,
                 outnc='harris.nc'):
        """Headline here ... XXX.
        
        atoms is an ase.Atoms object with calculator
        attached. Presumably the self-consistent charge density has
        already been calculated, otherwise, it will be.

        BZpath is a list of tuples describing the path through the
        Brillouin zone. The tuples have the form (label, kpt), e.g. ::

          [('$\Gamma$',[0.0, 0.0, 0.0]),
           ('X',[0.0, 0.5, 0.5]),
           ('L',[0.5, 0.0, 0.0]),
           ('$\Gamma$',[0.0, 0.0, 0.0])]

        the label is used in the figure and can include latex markup.

        npoints is the number of points on each segment. It can either
        be a constant, which is used for every segment, or a list of
        integers that is an integer for each segment.        
        """

        self.atoms = atoms
        self.calc = atoms.get_calculator()
        #first, we make sure the charge density is up to date.
        self.calc.get_charge_density()
        self.ef = self.calc.get_ef() #self-consistent fermi level

        self.labels = [x[0] for x in BZpath]
        self.kpt_path = [np.array(x[1],dtype=np.float) for x in BZpath]
        self.npoints = npoints

        #first, setup the kpt path
        kpts = []
        #start at second kpt and go to second to last segment
        nsegments = len(self.kpt_path) - 1
        for i in range(nsegments-1):
            
            #get number of points on path. this counts the first point
            try:
                i_npt = npoints[i]
            except TypeError:
                i_npt = npoints

            #this is the vector connecting the two endpoint kpts of a segment
            kdiff = self.kpt_path[i+1] - self.kpt_path[i]

            #make a vector of evenly spaced intervals, one longer than needed
            #because we chop off the last entry.
            for j in np.linspace(0,1,i_npt+1)[0:-1]:
                k = self.kpt_path[i] + j*kdiff
                #shift by small random amount to break symmetry and
                #prevent time-inversion reduction
                krand = (1. + np.random.random(3))/1.e4
                
                k += krand
                kpts.append(k)

        #now fill in the last segment, and end on the last point
        try:
            i_npt = npoints[-1]
        except TypeError:
            i_npt = npoints

        kdiff = self.kpt_path[-1] - self.kpt_path[-2]
        for j in np.linspace(0,1,i_npt+1)[1:]:
            k = self.kpt_path[-2] + j*kdiff
            #shift by small random amount to break symmetry and
            #prevent time-inversion reduction
            krand = (1. + np.random.random(3))/1.e4
            k += krand
            kpts.append(k)

        #these are now the points needed for the Harris calculation.
        self.kpts = kpts

        self.dos = DOS(self.calc)
        self.dos_energies = self.dos.get_energies()
        self.dos_dos = self.dos.get_dos()

        #try to avoid rerunning the calculation if it is already done!
        if os.path.exists(outnc):
            self.calc = Jacapo(outnc)
        else:
            print 'calculation of harris required'
            self.calc.set_nc(outnc)
            #self.calc.debug=10

            #save some time by not calculating stress
            self.calc.set_stress(False)
                        
            #this seems to be necessary sometimes
            self.calc.delete_ncattdimvar(outnc,
                                         ncdims=['number_plane_waves'])

            #this has to come after removing number_of_planewaves
            self.calc.set_kpts(self.kpts)
            
            #freeze charge density
            self.calc.set_charge_mixing(updatecharge='No')
            #and, run calculation
            self.calc.calculate()
Ejemplo n.º 22
0
class BandStructure:
    '''outline of class to facilitate band structure calculations
    '''
    def __init__(self,
                 atoms,
                 BZpath=[],
                 npoints=10,
                 outnc='harris.nc'):
        """Headline here ... XXX.
        
        atoms is an ase.Atoms object with calculator
        attached. Presumably the self-consistent charge density has
        already been calculated, otherwise, it will be.

        BZpath is a list of tuples describing the path through the
        Brillouin zone. The tuples have the form (label, kpt), e.g. ::

          [('$\Gamma$',[0.0, 0.0, 0.0]),
           ('X',[0.0, 0.5, 0.5]),
           ('L',[0.5, 0.0, 0.0]),
           ('$\Gamma$',[0.0, 0.0, 0.0])]

        the label is used in the figure and can include latex markup.

        npoints is the number of points on each segment. It can either
        be a constant, which is used for every segment, or a list of
        integers that is an integer for each segment.        
        """

        self.atoms = atoms
        self.calc = atoms.get_calculator()
        #first, we make sure the charge density is up to date.
        self.calc.get_charge_density()
        self.ef = self.calc.get_ef() #self-consistent fermi level

        self.labels = [x[0] for x in BZpath]
        self.kpt_path = [np.array(x[1],dtype=np.float) for x in BZpath]
        self.npoints = npoints

        #first, setup the kpt path
        kpts = []
        #start at second kpt and go to second to last segment
        nsegments = len(self.kpt_path) - 1
        for i in range(nsegments-1):
            
            #get number of points on path. this counts the first point
            try:
                i_npt = npoints[i]
            except TypeError:
                i_npt = npoints

            #this is the vector connecting the two endpoint kpts of a segment
            kdiff = self.kpt_path[i+1] - self.kpt_path[i]

            #make a vector of evenly spaced intervals, one longer than needed
            #because we chop off the last entry.
            for j in np.linspace(0,1,i_npt+1)[0:-1]:
                k = self.kpt_path[i] + j*kdiff
                #shift by small random amount to break symmetry and
                #prevent time-inversion reduction
                krand = (1. + np.random.random(3))/1.e4
                
                k += krand
                kpts.append(k)

        #now fill in the last segment, and end on the last point
        try:
            i_npt = npoints[-1]
        except TypeError:
            i_npt = npoints

        kdiff = self.kpt_path[-1] - self.kpt_path[-2]
        for j in np.linspace(0,1,i_npt+1)[1:]:
            k = self.kpt_path[-2] + j*kdiff
            #shift by small random amount to break symmetry and
            #prevent time-inversion reduction
            krand = (1. + np.random.random(3))/1.e4
            k += krand
            kpts.append(k)

        #these are now the points needed for the Harris calculation.
        self.kpts = kpts

        self.dos = DOS(self.calc)
        self.dos_energies = self.dos.get_energies()
        self.dos_dos = self.dos.get_dos()

        #try to avoid rerunning the calculation if it is already done!
        if os.path.exists(outnc):
            self.calc = Jacapo(outnc)
        else:
            print 'calculation of harris required'
            self.calc.set_nc(outnc)
            #self.calc.debug=10

            #save some time by not calculating stress
            self.calc.set_stress(False)
                        
            #this seems to be necessary sometimes
            self.calc.delete_ncattdimvar(outnc,
                                         ncdims=['number_plane_waves'])

            #this has to come after removing number_of_planewaves
            self.calc.set_kpts(self.kpts)
            
            #freeze charge density
            self.calc.set_charge_mixing(updatecharge='No')
            #and, run calculation
            self.calc.calculate()

        

    def plot(self):
        '''
        Make an interactive band-structure plot.

        clicking on a band will make it thicker and print which band was selected.
        '''

        kpoints = self.calc.get_ibz_kpoints()
        
        eigenvalues = self.calc.get_all_eigenvalues() - self.ef
        #eigenvalues = np.array([self.calc.get_eigenvalues(kpt=i)-self.ef
        #                        for i in range(len(kpoints))])
        
        self.handles = [] #used to get band indexes from plot

        fig = plt.figure()
        #plot DOS in figure
        ax = fig.add_subplot(122)
        ax.plot(self.dos_dos,self.dos_energies)
        plt.title('self-consistent Total DOS')
        ax.set_xticks([])
        ax.set_yticks([])
        ax.set_ylim([-20,20])
        
        ax = fig.add_subplot(121)
        ax.set_title('Band structure')

        def onpick(event):
            'make picked line bolder, set oldline back to regular thickness'
            self.lastartist.set_linewidth(1)
            self.lastartist = thisline = event.artist
            thisline.set_linewidth(5)
            plt.draw() #needed to update linewidth
            
            print 'Band %i selected' % self.handles.index(thisline)
            #you could insert code here to plot wavefunction, etc...
            
        fig.canvas.mpl_connect('pick_event',onpick)

        #we use indices for x. the tick labels are not shown and the distance
        #appears unimportant
        xdata = range(len(eigenvalues))

        nkpts, nbands = eigenvalues.shape
        for i in range(nbands):         
            #eigenvalues has shape(nkpts,nbands)
            #note the comma after line_handle
            line_handle, = ax.plot(xdata,eigenvalues[:,i],'.-',ms=1,picker=2)
            self.handles.append(line_handle)

        self.lastartist = self.handles[-1]
            
        #plot Fermi level
        ax.plot([0,len(self.kpts)],[0,0],'k--',label='$E_f$')
        
        plt.xlabel('|k|')
        plt.ylabel('$E-E_f$ (eV)')

        #set xtick locations and labels
        xtick_locs = np.zeros(len(self.kpt_path))
        try:
            #this means the npoints is a list
            i_npt = self.npoints[0]
            for j,npt in enumerate(1,self.npoints):
                xtick_locs[j] = xtick_locs[j-1] + npt
        except TypeError:
            #npoints is a single number
            for j in range(1,len(self.labels)):
                xtick_locs[j] = xtick_locs[j-1] + self.npoints

        #the last location is off by one, so we fix it.
        xtick_locs[-1] -= 1

        ax.set_xlim([xtick_locs[0],xtick_locs[-1]])        
        ax.set_xticks(xtick_locs)
        ax.set_xticklabels(self.labels)
        
        #this seems reasonable to avoid very deep energy states and high energy states
        ax.set_ylim([-20,20])
        
        plt.show()

        return fig
Ejemplo n.º 23
0
testRun = False
file_name_py = basename(__file__)
file_name = file_name_py.replace('.py','')
file_traj = file_name + '.traj'
start_file = '../In2O3_110_clean.traj'

try:
    sys = Trajectory(file_traj, 'r')[-1]
except (IOError, RuntimeError):
    print(("Importing trajectory file from: %s" % start_file))
    sys = read(start_file)
else:
    print(("Importing trajectory file from: %s" % file_traj))

calc = set_calc_In2O3(sys)
print("Constraints:")
print("\tc: Fix bottom two layers.")
c = FixAtoms(mask=[atom.z < 8 for atom in sys])
sys.set_constraint(c)
if testRun == True:
    run_testRun(sys)
else:
    dos = DOS(calc = calc)
    ds = dos.get_dos()
    es = dos.get_energies()
    print("Energy\tDOS")
    for (e, d) in zip(es, ds):
        print(("%f\t%f" % (e, d)))
print(("Completed %s" % file_name_py))    
Ejemplo n.º 24
0
'''Write DOS to JSON file, starting from GPAW calculator file.
'''

import sys
import json
from gpaw import GPAW
from ase.dft.dos import DOS


if len(sys.argv) != 2:
    raise RuntimeError('I want one and only one argument, the filename!')

filename = sys.argv[1]

calc = GPAW(filename, txt=None)

dos = DOS(calc, width=0.1)

dos_dict = {}
dos_dict['dos'] = list(dos.get_dos())
dos_dict['energies'] = list(dos.get_energies())

out_name = filename + '_dos.json'
with open(out_name, 'w') as outfile:
    json.dump(dos_dict, outfile)

print('DOS written to', out_name)