Example #1
0
def get_electrostatic_potentials(outcar, atoms):
    """
    :param outcar: content of the OUTCAR file (list of strings)
    :param atoms: number of atoms of each atomic species (list of integers)
    :return: electrostatic averaged potentials
    """

    index_potentials = bf.grep(
        outcar, 'average (electrostatic) potential at core',
        nb_found=1)[0][1]  # index where the potentials are
    index_potentials_end = [
        g for f, g in zip(outcar, range(len(outcar)))
        if (f == ' ') & (g > index_potentials)
    ][0]  # first blank line after the potentials

    potentials_str = outcar[
        index_potentials +
        3:index_potentials_end]  # all of potentials as strings
    potentials_atom_nb = np.concatenate(
        [[float(f) for f in re.split('     |-', q)[1:]]
         for q in potentials_str])  # All potentials and corresponding atom
    potentials = [-f[1] for f in np.split(potentials_atom_nb, len(atoms))]

    if len(potentials) != len(atoms):
        raise bf.PydefImportError(
            'Number of electrostatic potentials retrieved and number are not consistent'
        )
    return dict(zip(list(atoms), potentials))
Example #2
0
def get_kpoints_weight(outcar, nkpts):
    """
    :param outcar: content of the OUTCAR file (list of strings)
    :param nkpts: number of kpoints (int)
    :return:
    """

    index_weight = bf.grep(outcar,
                           'k-points in reciprocal lattice and weights',
                           nb_found=1)[0][1]
    index_weight_end = [
        g for f, g in zip(outcar, range(len(outcar)))
        if (f == ' ') & (g > index_weight)
    ][0]

    kpoints_weights_str = outcar[index_weight + 1:index_weight_end]
    kpoints_weights = np.transpose([[float(f) for f in q.split()]
                                    for q in kpoints_weights_str])[-1]

    if len(kpoints_weights) != nkpts:
        raise bf.PydefImportError(
            'Number of kpoint weights retrieved and number of kpoints are not consistent'
        )
    else:
        return kpoints_weights
Example #3
0
def get_cell_parameters(outcar):
    """
    :param outcar: content of the outcar file (list of strings)
    :return: cristallographic parameters of the cell
    """
    index = bf.grep(outcar, 'direct lattice vectors')[0][
        1]  # location of the cristallographic parameters in the OUTCAR
    return [[float(f) for f in g.split()[:3]]
            for g in outcar[index + 1:index + 4]]
Example #4
0
def get_functional(outcar):
    """ Retrieve the functional used from the outcar data
    :param outcar: content of the OUTCAR file (list of strings)
    :return: functional of used
    """

    # Default values
    functional = 'other'  # used for display inline
    functional_title = 'other'  # used for display in matplotlib

    lexch = bf.grep(outcar, 'LEXCH   =', 0, 'internal', 'str', 1)
    lhfcalc = bf.grep(outcar, 'LHFCALC =', 0, 'Hartree', 'str', 1)
    hfscreen = bf.grep(outcar, 'HFSCREEN=', 0, 'screening', 'float', 1)
    gw = bf.grep(outcar,
                 'Response functions by sum over occupied states:',
                 nb_found=2)

    if lexch == '2' and lhfcalc == 'F':
        functional = 'LDA'
        functional_title = 'LDA'
    if lexch == '8' and lhfcalc == 'F':
        functional = 'GGA'
        functional_title = 'GGA'
    if lexch == '8' and lhfcalc == 'T':
        if hfscreen == 0.2:
            functional = 'HSE'
            functional_title = 'HSE'
        if hfscreen == 0.0:
            functional = 'PBE0'
            functional_title = 'PBE0'
    if gw is not None:
        nelm = bf.grep(outcar, 'NELM    =', 0, 'number', 'int', 1)
        if nelm == 1:
            functional = 'G0W0@GGA'
            functional_title = 'G_0W_0@GGA'
        elif nelm > 1:
            functional = 'GW0@GGA'
            functional_title = 'GW_0@GGA'

    return functional, functional_title
Example #5
0
def get_atoms_positions(outcar, atoms):
    """
    :param outcar: content of the outcar file (list of strings)
    :param atoms: number of atoms of each atomic species (list of integers)
    :return: position of each atom as a dictionary
    """

    index_beg = bf.grep(
        outcar,
        'position of ions in cartesian coordinates  (Angst):',
        nb_found=1)[0][1] + 1  # index of the first atom position
    index_end = [
        f[1] for f in bf.grep(outcar, '---------') if f[1] > index_beg
    ][0] - 3  # index of the last atom position
    atoms_positions = [[float(f) for f in g.split()]
                       for g in outcar[index_beg:index_end]]

    # Check that the number of positions retrieved is equal to the number of atoms
    if len(atoms_positions) != len(atoms):
        raise bf.PydefImportError(
            "The number of atoms positions is not consistent with the total number of atoms"
        )
    else:
        return dict(zip(atoms, atoms_positions))
Example #6
0
def get_band_occupation(outcar, nkpts, functional, nbands):
    """
    :param outcar: content of the outcar file (list of strings)
    :param nkpts: number of kpoints (int)
    :param functional: functional used (string)
    :param nbands: number of bands (int)
    :return: last energy and occupation of the bands for each kpoint
    """

    kpoints_indices = [f[1] for f in bf.grep(outcar, 'k-point ')[-nkpts:]
                       ]  # last k-points occupation calculated

    if functional != 'G0W0@GGA' and functional != 'GW0@GGA':
        nb_bands = [[
            g
            for f, g in zip(outcar, range(len(outcar))) if (f == '') & (g > h)
        ][0] for h in kpoints_indices
                    ][0] - kpoints_indices[0] - 2  # number of bands

        # check that the number of bands found is consistence with the number if bands retrieved previously
        if nb_bands != nbands:
            raise bf.PydefImportError(
                'The number of bands retrieved from the kpoints is not consistent'
            )

        bands_str = [outcar[f + 2:f + nb_bands + 2] for f in kpoints_indices
                     ]  # band occupation for each k-points as strings
        col_index = 1  # index of the column containing the energy

    else:
        nb_bands = [[
            g
            for f, g in zip(outcar, range(len(outcar))) if (f == '') & (g > h)
        ][0] for h in kpoints_indices
                    ][1] - kpoints_indices[0] - 6  # number of bands

        bands_str = [outcar[f + 3:f + 3 + nb_bands] for f in kpoints_indices
                     ]  # band occupation for each k-points as strings
        col_index = 2  # index of the column containing the energy

    bands_data = [
        np.transpose([[float(s) for s in f.split()] for f in q])
        for q in bands_str
    ]  # band occupation for each k-points
    return [[f[col_index], f[-1]] for f in bands_data
            ]  # return energy and occupation for each k-point
Example #7
0
    def __init__(self, OUTCAR, DOSCAR):
        """
        :param OUTCAR: location of the OUTCAR file (string)
        :param DOSCAR: location of the DOSCAR file (string)
        :return: an object containing data on the calculation
        """

        # --------------------------------------------------- OUTCAR ---------------------------------------------------

        self.OUTCAR = OUTCAR
        self.DOSCAR = DOSCAR

        self.outcar = bf.read_file(OUTCAR)  # content of the OUTCAR file

        if self.outcar[0][:6] != ' vasp.':
            raise bf.PydefOutcarError(
                'The given file appears to not be a valid OUTCAR file.')

        # ------------------------------------------- CALCULATION PROPERTIES -------------------------------------------

        self.functional, self.functional_title = get_functional(
            self.outcar)  # functional used
        self.nedos = bf.grep(self.outcar, 'NEDOS =', 0, 'number of ions',
                             'int', 1)  # number of point in the DOS
        self.encut = bf.grep(self.outcar, 'ENCUT  =', 0, 'eV', 'float',
                             1)  # ENCUT used
        self.ediff = bf.grep(self.outcar, 'EDIFF  =', 0, 'stopping', 'float',
                             1)  # EDIFF value
        self.emin = bf.grep(self.outcar, 'EMIN   =', 0, ';', 'float',
                            1)  # minimum energy for the DOS
        self.emax = bf.grep(self.outcar, 'EMAX   =', 0, 'energy-range',
                            'float', 1)  # maximum energy for the DOS
        self.ismear = bf.grep(self.outcar, 'ISMEAR =', 0, ';', 'int',
                              1)  # ISMEAR used
        self.lorbit = bf.grep(self.outcar, 'LORBIT =', 0, '0 simple, 1 ext',
                              'int', 1)  # LORBIT used
        self.isym = bf.grep(self.outcar, 'ISYM   =', 0, '0-nonsym', 'float',
                            1)  # ISYM used
        self.istart = bf.grep(self.outcar, 'ISTART =', 0, 'job', 'float',
                              1)  # ISTART tag

        # --------------------------------------------- SYSTEM PROPERTIES ----------------------------------------------

        self.nb_atoms_tot = bf.grep(self.outcar, 'NIONS =', 0, False, 'int',
                                    1)  # total number of atoms
        self.nb_atoms = [
            int(f) for f in bf.grep(self.outcar, 'ions per type =', 0).split()
        ]  # population of each atomic species
        self.atoms_types = [
            bf.grep(self.outcar, 'VRHFIN =', f, ':')
            for f in range(len(bf.grep(self.outcar, 'VRHFIN =')))
        ]  # atomic species
        self.population = dict(zip(self.atoms_types, self.nb_atoms))
        self.atoms_valence = [
            int(float(f))
            for f in bf.grep(self.outcar, 'ZVAL   =', -1).split()
        ]  # valence of each atomic species
        self.atoms = np.concatenate(
            [[f + ' (' + str(g) + ')' for g in range(1, q + 1)]
             for f, q in zip(self.atoms_types, self.nb_atoms)])  # atoms list
        self.nb_electrons = bf.grep(self.outcar, 'NELECT =', 0, 'total number',
                                    'float', 1)  # total number of electrons
        self.charge = sum(
            np.array(self.nb_atoms) *
            np.array(self.atoms_valence)) - self.nb_electrons
        self.orbitals = [
            f for f in bf.grep(self.outcar, '# of ion', 0, 'tot').split(' ')
            if f != ''
        ]

        # verification of the consistence of the data retrieved
        if self.nb_atoms_tot != sum(self.nb_atoms) or \
                len(self.nb_atoms) != len(self.atoms_types) or \
                len(self.nb_atoms) != len(self.atoms_valence):
            raise bf.PydefImportError(
                'Numbers of atoms retrieved are not consistent')

        self.name, self.display_name = get_system_name(self.atoms_types,
                                                       self.nb_atoms, False)
        self.rname, self.display_rname = get_system_name(
            self.atoms_types, self.nb_atoms, True)

        # --------------------------------------------- CALCULATION RESULT ---------------------------------------------

        # Number of electronic steps
        if self.functional != 'G0W0@GGA' and self.functional != 'GW0@GGA':
            self.nb_iterations = len(bf.grep(
                self.outcar, 'Iteration'))  # for non GW calculations
        else:
            self.nb_iterations = bf.grep(self.outcar, 'NELM    =', 0, 'number',
                                         'int', 1)  # for GW calculations

        # Cristallographic properties
        self.cell_parameters = get_cell_parameters(
            self.outcar)  # cristallographic parameters
        self.atoms_positions = get_atoms_positions(
            self.outcar, self.atoms)  # atoms positions

        # Energy & Density of states
        self.energy = bf.grep(self.outcar, 'free energy    TOTEN  =', -1, 'eV',
                              'float', self.nb_iterations)  # total energy
        self.fermi_energy = bf.grep(self.outcar, ' BZINTS: Fermi energy:', -1,
                                    ';', 'float')  # fermi energy
        if self.ismear == 0:
            self.fermi_energy = bf.grep(self.outcar,
                                        'E-fermi :',
                                        0,
                                        'XC(G=0)',
                                        'float',
                                        nb_found=1)
        self.nkpts = bf.grep(self.outcar, 'NKPTS =', 0, 'k-points in BZ',
                             'int', 1)  # number of k-points
        self.kpoints_weights = get_kpoints_weight(self.outcar, self.nkpts)
        self.nbands = bf.grep(self.outcar, 'NBANDS=', 0, False, 'int',
                              1)  # number of bands
        self.bands_data = get_band_occupation(
            self.outcar, self.nkpts, self.functional,
            self.nbands)  # bands energy and occupation
        self.VBM, self.CBM = get_band_extrema(
            self.bands_data)  # VBM and CBM energies
        self.gap = self.CBM - self.VBM  # electronic gap
        if self.functional != 'G0W0@GGA' and self.functional != 'GW0@GGA':
            self.potentials = get_electrostatic_potentials(
                self.outcar, self.atoms)  # electrostatic averaged potentials
        else:
            self.potentials = None

        # --------------------------------------------------- OTHERS ---------------------------------------------------

        self.ID = ''.join([f + str(g) for f, g in zip(self.atoms_types, self.nb_atoms)]) + '_' + self.functional\
                  + '_q' + str(int(self.charge))
        self.title = self.display_name + ' ' + self.functional_title + ' q=%.0f' % self.charge  # title of the plot

        # --------------------------------------------------- DOSCAR ---------------------------------------------------

        if self.DOSCAR != '':
            self.doscar = bf.read_file(DOSCAR)  # content of the DOSCAR file

            # Check that the OUTCAR and DOSCAR files are consistent
            if self.lorbit == 11:
                if len(self.doscar) != 6 + sum(
                        self.nb_atoms) * (self.nedos + 1) + self.nedos:
                    raise bf.PydefDoscarError(
                        'The DOSCAR file is inconsistent with the OUTCAR file')
            else:
                if len(self.doscar) != 6 + sum(
                        self.nb_atoms
                ):  # Beware of the white line at the end of the file
                    raise bf.PydefDoscarError(
                        'The DOSCAR file is inconsistent with the OUTCAR file')

            dos_data = np.transpose([[float(f) for f in q.split()]
                                     for q in self.doscar[6:self.nedos + 6]
                                     ])[1]
            self.dosmax = max(dos_data)  # maximum value of the total DOS

            self.dpp = Dos_Plot_Parameters(self)  # DOS plot parameters