Пример #1
0
def merge_up_down_doses(dos_up, dos_dn):
    """
    Merge the up and down DOSs.
    Args:
    dos_up: Up DOS.
    dos_dn: Down DOS
    Return:
    CompleteDos object
    """
    warnings.warn("This function is not useful anymore. VasprunBSLoader deals \
                   with spin case.")
    cdos = Dos(
        dos_up.efermi,
        dos_up.energies,
        {
            Spin.up: dos_up.densities[Spin.up],
            Spin.down: dos_dn.densities[Spin.down]
        },
    )

    if hasattr(dos_up, "pdos") and hasattr(dos_dn, "pdos"):
        pdoss = {}
        for site in dos_up.pdos:
            pdoss.setdefault(site, {})
            for orb in dos_up.pdos[site]:
                pdoss[site].setdefault(orb, {})
                pdoss[site][orb][Spin.up] = dos_up.pdos[site][orb][Spin.up]
                pdoss[site][orb][Spin.down] = dos_dn.pdos[site][orb][Spin.down]

        cdos = CompleteDos(dos_up.structure, total_dos=cdos, pdoss=pdoss)

    return cdos
Пример #2
0
 def get_dos_from_id(self, task_id):
     """
     Overrides the get_dos_from_id for the MIT gridfs format.
     """
     args = {'task_id': task_id}
     fields = ['calculations']
     structure = self.get_structure_from_id(task_id)
     dosid = None
     for r in self.query(fields, args):
         dosid = r['calculations'][-1]['dos_fs_id']
     if dosid != None:
         self._fs = gridfs.GridFS(self.db, 'dos_fs')
         with self._fs.get(dosid) as dosfile:
             s = dosfile.read()
             try:
                 d = json.loads(s)
             except:
                 s = zlib.decompress(s)
                 d = json.loads(s)
             tdos = Dos.from_dict(d)
             pdoss = {}
             for i in range(len(d['pdos'])):
                 ados = d['pdos'][i]
                 all_ados = {}
                 for j in range(len(ados)):
                     orb = Orbital.from_vasp_index(j)
                     odos = ados[str(orb)]
                     all_ados[orb] = {Spin.from_int(int(k)): v
                                      for k, v
                                      in odos['densities'].items()}
                 pdoss[structure[i]] = all_ados
             return CompleteDos(structure, tdos, pdoss)
     return None
Пример #3
0
 def read_gap_from_doscar(self, doscar):
     from pymatgen.electronic_structure.dos import Dos
     fp = open(doscar)
     lines = fp.readlines()
     energies = []
     dos = []
     efermi = float(lines[5].split()[3])
     if len(lines[6].split()) == 5:  # spin up and dn
         spin = 2
     elif len(lines[6].split()) == 3:
         spin = 0  # no spin
     for i in range(6, len(lines)):
         energies.append(float(lines[i].split()[0]))
         if spin == 2:
             dos.append(
                 float(lines[i].split()[1]) + float(lines[i].split()[2]))
         else:
             dos.append(float(lines[i].split()[1]))
     return {
         'efermi':
         efermi,
         'mygap':
         np.array(
             [Dos(efermi, energies, {
                 'spin': dos
             }).get_gap(spin='spin')])
     }
Пример #4
0
    def get_dos(self, partial_dos=False, npts_mu=10000, T=None):
        """
            Return a Dos object interpolating bands

            Args:
                partial_dos: if True, projections will be interpolated as well
                    and partial doses will be return. Projections must be available
                    in the loader.
                npts_mu: number of energy points of the Dos
                T: parameter used to smooth the Dos
        """
        spin = self.data.spin if isinstance(self.data.spin, int) else 1

        energies, densities, vvdos, cdos = BL.BTPDOS(self.eband,
                                                     self.vvband,
                                                     npts=npts_mu)
        if T is not None:
            densities = BL.smoothen_DOS(energies, densities, T)

        tdos = Dos(self.efermi / units.eV, energies / units.eV,
                   {Spin(spin): densities})

        if partial_dos:
            tdos = self.get_partial_doses(tdos=tdos, npts_mu=npts_mu, T=T)

        return tdos
Пример #5
0
 def get_dos_from_id(self, task_id):
     """
     Overrides the get_dos_from_id for the MIT gridfs format.
     """
     args = {'task_id': task_id}
     fields = ['calculations']
     structure = self.get_structure_from_id(task_id)
     dosid = None
     for r in self.query(fields, args):
         dosid = r['calculations'][-1]['dos_fs_id']
     if dosid != None:
         self._fs = gridfs.GridFS(self.db, 'dos_fs')
         with self._fs.get(dosid) as dosfile:
             s = dosfile.read()
             try:
                 d = json.loads(s)
             except:
                 s = zlib.decompress(s)
                 d = json.loads(s)
             tdos = Dos.from_dict(d)
             pdoss = {}
             for i in range(len(d['pdos'])):
                 ados = d['pdos'][i]
                 all_ados = {}
                 for j in range(len(ados)):
                     orb = Orbital.from_vasp_index(j)
                     odos = ados[str(orb)]
                     all_ados[orb] = {
                         Spin.from_int(int(k)): v
                         for k, v in odos['densities'].items()
                     }
                 pdoss[structure[i]] = all_ados
             return CompleteDos(structure, tdos, pdoss)
     return None
def get_dos(db_file):
    """ return density of states object from the database """    
    d1, d2, d3, d4 = get_collections(db_file)
    db = get_db(db_file)
    fs = gridfs.GridFS(db, 'dos_fs')
    dos_fs_id = d4["calcs_reversed"][0]["dos_fs_id"]
    dos_json = zlib.decompress(fs.get(dos_fs_id).read())
    dos_dict = json.loads(dos_json.decode())
    return Dos.from_dict(dos_dict)
Пример #7
0
    def from_dict(data):
        def _make_float_array(a):
            res = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
            for i in range(3):
                for j in range(3):
                    res[i][j] = float(a[i][j])
            return res

        def _make_float_hall(a):
            return [i for i in a[:27]]

        return BoltztrapAnalyzer(
            float(data['gap']), [float(d) for d in data['mu_steps']],
            {int(d): [_make_float_array(v) for v in data['cond'][d]]
             for d in data['cond']},
            {int(d): [_make_float_array(v) for v in data['seebeck'][d]]
             for d in data['seebeck']},
            {int(d): [_make_float_array(v) for v in data['kappa'][d]]
             for d in data['kappa']},
            {int(d): [_make_float_hall(v) for v in data['hall'][d]]
             for d in data['hall']},
            {'p': [float(d) for d in data['doping']['p']],
             'n': [float(d) for d in data['doping']['n']]},
            {'p': {int(d): [float(v) for v in data['mu_doping']['p'][d]]
                   for d in data['mu_doping']['p']},
             'n': {int(d): [float(v) for v in data['mu_doping']['n'][d]]
                   for d in data['mu_doping']['n']}},
            {'p': {int(d): [_make_float_array(v)
                            for v in data['seebeck_doping']['p'][d]]
                   for d in data['seebeck_doping']['p']},
             'n': {int(d): [_make_float_array(v)
                            for v in data['seebeck_doping']['n'][d]]
                   for d in data['seebeck_doping']['n']}},
            {'p': {int(d): [_make_float_array(v)
                            for v in data['cond_doping']['p'][d]]
                   for d in data['cond_doping']['p']},
             'n': {int(d): [_make_float_array(v)
                            for v in data['cond_doping']['n'][d]]
                   for d in data['cond_doping']['n']}},
            {'p': {int(d): [_make_float_array(v)
                            for v in data['kappa_doping']['p'][d]]
                   for d in data['kappa_doping']['p']},
             'n': {int(d): [_make_float_array(v)
                            for v in data['kappa_doping']['n'][d]]
                   for d in data['kappa_doping']['n']}},
            {'p': {int(d): [_make_float_hall(v)
                            for v in data['hall_doping']['p'][d]]
                   for d in data['hall_doping']['p']},
             'n': {int(d): [_make_float_hall(v)
                            for v in data['hall_doping']['n'][d]]
                   for d in data['hall_doping']['n']}},
            Dos.from_dict(data['dos']), data['carrier_conc'], data['dos_partial'],
            data['vol'], str(data['warning']))
Пример #8
0
    def from_dict(data):
        def _make_float_array(a):
            res = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
            for i in range(3):
                for j in range(3):
                    res[i][j] = float(a[i][j])
            return res

        def _make_float_hall(a):
            return [i for i in a[:27]]

        return BoltztrapAnalyzer(
            float(data['gap']), [float(d) for d in data['mu_steps']],
            {int(d): [_make_float_array(v) for v in data['cond'][d]]
             for d in data['cond']},
            {int(d): [_make_float_array(v) for v in data['seebeck'][d]]
             for d in data['seebeck']},
            {int(d): [_make_float_array(v) for v in data['kappa'][d]]
             for d in data['kappa']},
            {int(d): [_make_float_hall(v) for v in data['hall'][d]]
             for d in data['hall']},
            {'p': [float(d) for d in data['doping']['p']],
             'n': [float(d) for d in data['doping']['n']]},
            {'p': {int(d): [float(v) for v in data['mu_doping']['p'][d]]
                   for d in data['mu_doping']['p']},
             'n': {int(d): [float(v) for v in data['mu_doping']['n'][d]]
                   for d in data['mu_doping']['n']}},
            {'p': {int(d): [_make_float_array(v)
                            for v in data['seebeck_doping']['p'][d]]
                   for d in data['seebeck_doping']['p']},
             'n': {int(d): [_make_float_array(v)
                            for v in data['seebeck_doping']['n'][d]]
                   for d in data['seebeck_doping']['n']}},
            {'p': {int(d): [_make_float_array(v)
                            for v in data['cond_doping']['p'][d]]
                   for d in data['cond_doping']['p']},
             'n': {int(d): [_make_float_array(v)
                            for v in data['cond_doping']['n'][d]]
                   for d in data['cond_doping']['n']}},
            {'p': {int(d): [_make_float_array(v)
                            for v in data['kappa_doping']['p'][d]]
                   for d in data['kappa_doping']['p']},
             'n': {int(d): [_make_float_array(v)
                            for v in data['kappa_doping']['n'][d]]
                   for d in data['kappa_doping']['n']}},
            {'p': {int(d): [_make_float_hall(v)
                            for v in data['hall_doping']['p'][d]]
                   for d in data['hall_doping']['p']},
             'n': {int(d): [_make_float_hall(v)
                            for v in data['hall_doping']['n'][d]]
                   for d in data['hall_doping']['n']}},
            Dos.from_dict(data['dos']), data['dos_partial'], data['carrier_conc'], 
            data['vol'], str(data['warning']))
Пример #9
0
    def _get_tdos(filename):
        energies, data, efermi, nsp = _read_dos_data(tdos_file,
                                                     check_tdos=True)

        if nsp == 1:
            # densities = np.array(data[0]).reshape((ne, 1))
            densities = {Spin.up: data[0]}
        elif nsp == 2:
            #densities = np.concatenate((data[0], data[1]), axis=1)
            densities = {Spin.up: data[0], Spin.down: data[1]}
        else:
            raise ValueError('There can\'t be {} spin channels, that makes '
                             'no sense!'.format(nsp))
        return Dos(efermi, energies, densities)
Пример #10
0
def merge_up_down_doses(dos_up, dos_dn):
    cdos = Dos(dos_up.efermi, dos_up.energies,
               {Spin.up: dos_up.densities[Spin.up], Spin.down: dos_dn.densities[Spin.down]})

    if hasattr(dos_up, 'pdos') and hasattr(dos_dn, 'pdos'):
        pdoss = {}
        for site in dos_up.pdos:
            pdoss.setdefault(site, {})
            for orb in dos_up.pdos[site]:
                pdoss[site].setdefault(orb, {})
                pdoss[site][orb][Spin.up] = dos_up.pdos[site][orb][Spin.up]
                pdoss[site][orb][Spin.down] = dos_dn.pdos[site][orb][Spin.down]

        cdos = CompleteDos(dos_up.structure, total_dos=cdos, pdoss=pdoss)

    return cdos
Пример #11
0
    def get_dos(self,
                partial_dos=False,
                npts_mu=10000,
                T=None,
                progress=False):
        """
        Return a Dos object interpolating bands

        Args:
            partial_dos: if True, projections will be interpolated as well
                and partial doses will be return. Projections must be available
                in the loader.
            npts_mu: number of energy points of the Dos
            T: parameter used to smooth the Dos
            progress: Default False, If True a progress bar is shown when
                partial dos are computed.
        """
        dos_dict = {}
        enr = (self.eband.min(), self.eband.max())
        if self.data.is_spin_polarized:
            h = sum(np.array_split(self.accepted, 2)[0])
            eband_ud = np.array_split(self.eband, [h], axis=0)
            vvband_ud = np.array_split(self.vvband, [h], axis=0)
            spins = [Spin.up, Spin.down]
        else:
            eband_ud = [self.eband]
            vvband_ud = [self.vvband]
            spins = [Spin.up]

        for spin, eb, vvb in zip(spins, eband_ud, vvband_ud):
            energies, densities, vvdos, cdos = BL.BTPDOS(eb,
                                                         vvb,
                                                         npts=npts_mu,
                                                         erange=enr)

            if T:
                densities = BL.smoothen_DOS(energies, densities, T)

            dos_dict.setdefault(spin, densities)

        tdos = Dos(self.efermi / units.eV, energies / units.eV, dos_dict)

        if partial_dos:
            tdos = self.get_partial_doses(tdos, eband_ud, spins, enr, npts_mu,
                                          T, progress)

        return tdos
Пример #12
0
    def calculate_dos(self,
                      dos_estep: float = defaults["performance"]["dos_estep"],
                      dos_width: float = defaults["performance"]["dos_width"]):
        """
        Args:
            dos_estep: The DOS energy step, where smaller numbers give more
                accuracy but are more expensive.
            dos_width: The DOS gaussian smearing width in eV.
        """

        all_energies = np.vstack([self.energies[spin] for spin in self.spins])
        all_energies /= units.eV  # convert from Hartree to eV for DOS

        # add a few multiples of dos_width to emin and emax to account for tails
        pad = dos_width if dos_width else 0
        dos_emin = np.min(all_energies) - pad * 5
        dos_emax = np.max(all_energies) + pad * 5
        npts = int(round((dos_emax - dos_emin) / dos_estep))

        logger.debug("DOS parameters:")
        log_list(["emin: {:.2f} eV".format(dos_emin),
                  "emax: {:.2f} eV".format(dos_emax),
                  "broadening width: {} eV".format(dos_width)])

        emesh, densities = DOS(all_energies.T, erange=(dos_emin, dos_emax),
                               npts=npts)

        if dos_width:
            densities = gaussian_filter1d(densities, dos_width /
                                          (emesh[1] - emesh[0]))

        # integrate up to Fermi level to get number of electrons
        efermi = self._efermi / units.eV
        energy_mask = emesh <= efermi + pad
        nelect = scipy.trapz(densities[energy_mask], emesh[energy_mask])

        logger.debug("Intrinsic DOS Fermi level: {:.4f}".format(efermi))
        logger.debug("DOS contains {:.3f} electrons".format(nelect))

        dos = Dos(efermi, emesh, {Spin.up: densities})
        self.dos_weight = 1 if self._soc or len(self.spins) == 2 else 2
        self.dos = FermiDos(dos, structure=self.structure,
                            dos_weight=self.dos_weight)
Пример #13
0
def get_cdos():
    for n in range(1, 74):
        pdos = defaultdict(dict)
        atom = ''
        orb = ''
        for a in atoms:
            if os.path.exists(f'pwscf.pdos_atm#{n}({a})_wfc#{1}(s)'):
                atom = Element(a)
        if atom == '':
            continue
        for l, o in enumerate(orbital):
            if os.path.exists(f'pwscf.pdos_atm#{n}({str(atom)})_wfc#{l + 1}({o})'):
                orb = OrbitalType(l)
                data = np.genfromtxt(f'pwscf.pdos_atm#{n}({str(atom)})_wfc#{l + 1}({orb.name})')
                pdos[orb][Spin.up] = data[:, 1]
                pdos[orb][Spin.down] = data[:, 2]
                energies = data[:,0]
        pdoss.append(pdos)
    efermi = fermi_fromfile('report.scf')
    total_density= six.moves.reduce(add_densities, [six.moves.reduce(add_densities, p.values()) for p in pdoss])
    total_dos = Dos(efermi, energies, total_density)
    s = Structure.from_file('123.cif')
    return CompleteDos(s, total_dos, pdoss)
Пример #14
0
def get_dos_plot(vasprun_file: str,
                 cbm_vbm: list = None,
                 pdos_type: str = "element",
                 specific: list = None,
                 orbital: list = True,
                 xlim: list = None,
                 ymaxs: list = None,
                 zero_at_efermi: bool = True,
                 legend: bool = True,
                 crop_first_value: bool = True,
                 show_spg: bool = True,
                 symprec: float = SYMMETRY_TOLERANCE,
                 angle_tolerance: float = ANGLE_TOL):
    """

    Args:
        vasprun_file (str):
            vasprun.xml-type file name
        cbm_vbm (list):
            List of [cbm, vbm]
        pdos_type (str): Plot type of PDOS.
            "element": PDOS grouped by element type
            "site": PDOS grouped by equivalent sites
            "none": PDOS are not grouped.
        specific (list): Show specific PDOS. If list elements are integers,
            PDOS at particular sites are shown. If elements are shown,
            PDOS of particular elements are shown.
            ["1", "2"] --> At site 1 and 2 compatible with pdos_type = "none"
            ["Mg", "O"] --> Summed at Mg and O sites coompatible with
                            pdos_type = "element"
        orbital (bool):
            Whether to show orbital decomposed PDOS.
        xlim (list):
            Specifies the x-axis limits. Set to None for automatic determination.
        ymaxs (list):
            Specifies the maxima of absolute y-axis limits.
        zero_at_efermi (bool):
            Whether to show the plot in the absolute scale.
        legend (bool):
            Whether to show the figure legend.
        crop_first_value (bool):
            Whether to crop the fist DOS.
        show_spg (bool):
            Whether to show space group number in the title.
        symprec (float):
            Symprec for determining the equivalent sites.
    """

    v = Vasprun(vasprun_file, ionic_step_skip=True, parse_eigen=False)
    if v.converged_electronic is False:
        logger.warning("SCF is not attained in the vasp calculation.")

    complete_dos = v.complete_dos

    # check cbm
    if cbm_vbm is None:
        if complete_dos.get_gap() > 0.1:
            cbm_vbm = complete_dos.get_cbm_vbm()

    structure = v.final_structure

    dos = OrderedDict()
    # The CompleteDos behaves as DOS for total dos.
    dos["Total"] = complete_dos

    if specific and specific[0].isdigit():
        if pdos_type is not "none":
            logger.warning(
                "pdos_type is changed from {} to none".format(pdos_type))
        pdos_type = "none"
    elif specific and specific[0].isalpha():
        if pdos_type is not "none":
            logger.warning(
                "pdos_type is changed from {} to element".format(pdos_type))
        pdos_type = "element"

    sga = None
    grouped_indices = defaultdict(list)
    if pdos_type == "element":
        for indices, s in enumerate(structure):
            grouped_indices[str(s.specie)].append(indices)
    elif pdos_type == "site":
        # equivalent_sites: Equivalent site indices from SpacegroupAnalyzer.
        sga = SpacegroupAnalyzer(structure=structure,
                                 symprec=symprec,
                                 angle_tolerance=angle_tolerance)
        symmetrized_structure = sga.get_symmetrized_structure()
        # equiv_indices = [[0], [1], [2, 3], [4, 5]]
        equiv_index_lists = symmetrized_structure.equivalent_indices

        for l in equiv_index_lists:
            name = str(structure[l[0]].specie) + " " \
                   + sga.get_symmetry_dataset()["wyckoffs"][l[0]]
            grouped_indices[name] = l

    elif pdos_type == "none":
        for indices, s in enumerate(structure):
            grouped_indices[str(s.specie) + " site:" +
                            str(indices)].append(indices)
    else:
        raise KeyError("The given pdos_type is not supported.")

    # TODO: Add specific handling
    # if specific:
    #     tmp = defaultdict(list)
    #     for key, value in grouped_indices.items():
    #         if pdos_type == "element" and key in specific:
    #             tmp[key] = value
    #         else:
    #             # type(index) is str
    #             index = ''.join(c for c in key if c.isdigit())
    #             if index in specific:
    #                 tmp[key] = value
    #     grouped_indices = tmp

    # efermi is set to VBM if exists.
    efermi = cbm_vbm[1] if cbm_vbm else complete_dos.efermi
    complete_dos.efermi = efermi
    energies = complete_dos.energies

    for key, value in grouped_indices.items():
        for indices in value:
            site = structure[indices]
            if orbital:
                for orb, pdos in complete_dos.get_site_spd_dos(site).items():
                    # " " is used for grouping the plots.
                    if pdos_type == "none":
                        name = key + " " + str(orb)
                    else:
                        name = \
                            key + " #" + str(len(value)) + " " + str(orb)
                    density = divide_densities(pdos.densities, len(value))
                    if name in dos:
                        density = add_densities(dos[name].densities, density)
                        dos[name] = Dos(efermi, energies, density)
                    else:
                        dos[name] = Dos(efermi, energies, density)
            else:
                name = key + "(" + str(len(key)) + ")"
                pdos = complete_dos.get_site_dos(site)
                if name in dos:
                    dos[name] = add_densities(dos[name], pdos)
                else:
                    dos[name] = pdos

    # use complete_dos.efermi for total dos.
    plotter = ViseDosPlotter(zero_at_efermi=zero_at_efermi)
    plotter.add_dos_dict(dos)

    if xlim is None:
        xlim = [-10, 10]

    if ymaxs:
        ylims = [[-y, y] for y in ymaxs] \
            if v.incar.get("ISPIN", 1) == 2 else [[0, y] for y in ymaxs]
    else:
        energies = complete_dos.energies - efermi
        tdos_max = max_density(complete_dos.densities, energies, xlim,
                               crop_first_value)
        tdos_max *= 1.1
        ylims = [[-tdos_max, tdos_max]] if v.incar.get("ISPIN", 1) == 2 \
            else [[0, tdos_max]]

        pdos_max = 0.0
        for k, d in dos.items():
            if k == "Total":
                continue
            pdos_max = \
                max(max_density(d.densities, energies, xlim), pdos_max)

        pdos_max *= 1.1
        ylims.append([-pdos_max, pdos_max] if v.incar.get("ISPIN", 1) ==
                     2 else [0, pdos_max])

        print("y-range", ylims)

    if show_spg:
        if sga is None:
            sga = SpacegroupAnalyzer(structure, symprec=symprec)
        sg_num_str = str(sga.get_space_group_number())
        sg = f" {sga.get_space_group_symbol()} ({sg_num_str})"
        print(f"Space group number: {sg}")
        title = f"{structure.composition} SG: {sg}"
    else:
        title = str(structure.composition)

    return plotter.get_plot(xlim=xlim,
                            ylims=ylims,
                            cbm_vbm=cbm_vbm,
                            legend=legend,
                            crop_first_value=crop_first_value,
                            title=title)
Пример #15
0
    def _parse_doscar(self):
        doscar = self._doscar

        tdensities = {}
        f = open(doscar)
        natoms = int(f.readline().split()[0])
        efermi = float([f.readline() for nn in range(4)][3].split()[17])
        dos = []
        orbitals = []
        for atom in range(natoms + 1):
            line = f.readline()
            ndos = int(line.split()[2])
            orbitals.append(line.split(';')[-1].split())
            line = f.readline().split()
            cdos = np.zeros((ndos, len(line)))
            cdos[0] = np.array(line)
            for nd in range(1, ndos):
                line = f.readline().split()
                cdos[nd] = np.array(line)
            dos.append(cdos)
        f.close()

        doshere = np.array(dos[0])
        energies = doshere[:, 0]
        if not self._is_spin_polarized:
            tdensities[Spin.up] = doshere[:, 1]
            pdoss = []
            spin = Spin.up
            for atom in range(natoms):
                pdos = defaultdict(dict)
                data = dos[atom + 1]
                _, ncol = data.shape
                orbnumber = 0
                for j in range(1, ncol):
                    orb = orbitals[atom + 1][orbnumber]
                    pdos[orb][spin] = data[:, j]
                    orbnumber = orbnumber + 1
                pdoss.append(pdos)
        else:
            tdensities[Spin.up] = doshere[:, 1]
            tdensities[Spin.down] = doshere[:, 2]
            pdoss = []
            for atom in range(natoms):
                pdos = defaultdict(dict)
                data = dos[atom + 1]
                _, ncol = data.shape
                orbnumber = 0
                for j in range(1, ncol):
                    if j % 2 == 0:
                        spin = Spin.down
                    else:
                        spin = Spin.up
                    orb = orbitals[atom + 1][orbnumber]
                    pdos[orb][spin] = data[:, j]
                    if j % 2 == 0:
                        orbnumber = orbnumber + 1
                pdoss.append(pdos)
        self._efermi = efermi
        self._pdos = pdoss
        self._tdos = Dos(efermi, energies, tdensities)
        self._energies = energies
        self._tdensities = tdensities
        final_struct = self._final_structure

        pdossneu = {final_struct[i]: pdos for i, pdos in enumerate(self._pdos)}

        self._completedos = LobsterCompleteDos(final_struct, self._tdos,
                                               pdossneu)
Пример #16
0
def read_tdos(bands_file,
              bin_width=0.01,
              gaussian=None,
              padding=None,
              emin=None,
              emax=None,
              efermi_to_vbm=True):
    """Convert DOS data from CASTEP .bands file to Pymatgen/Sumo format

    The data is binned into a regular series using np.histogram

    Args:
        bands_file (:obj:`str`): Path to CASTEP prefix.bands output file. The
            k-point positions, weights and eigenvalues are read from this file.
        bin_width (:obj:`float`, optional): Spacing for DOS energy axis
        gaussian (:obj:`float` or None, optional): Width of Gaussian broadening
            function
        padding (:obj:`float`, optional): Energy range above and below occupied
            region. (This is not used if xmin and xmax are set.)
        emin (:obj:`float`, optional): Minimum energy value for output DOS)
        emax (:obj:`float`, optional): Maximum energy value for output DOS
        efermi_to_vbm (:obj:`bool`, optional):
            If a bandgap is detected, modify the stored Fermi energy
            so that it lies at the VBM.

    Returns:
        :obj:`pymatgen.electronic_structure.dos.Dos`
    """

    header = _read_bands_header_verbose(bands_file)

    logging.info("Reading band eigenvalues...")
    _, weights, eigenvalues = read_bands_eigenvalues(bands_file, header)

    calc_efermi = header['e_fermi'][0] * _ry_to_ev * 2
    if efermi_to_vbm and not _is_metal(eigenvalues, calc_efermi):
        logging.info("Setting energy zero to VBM")
        efermi = _get_vbm(eigenvalues, calc_efermi)
    else:
        logging.info("Setting energy zero to Fermi energy")
        efermi = calc_efermi

    emin_data = min(eigenvalues[Spin.up].flatten())
    emax_data = max(eigenvalues[Spin.up].flatten())
    if Spin.down in eigenvalues:
        emin_data = min(emin_data, min(eigenvalues[Spin.down].flatten()))
        emax_data = max(emax_data, max(eigenvalues[Spin.down].flatten()))

    if padding is None and gaussian:
        padding = gaussian * 3
    elif padding is None:
        padding = 0.5

    if emin is None:
        emin = emin_data - padding
    if emax is None:
        emax = emax_data + padding

    # Shift sampling window to account for zeroing at VBM/EFermi
    emin += efermi
    emax += efermi

    bins = np.arange(emin, emax + bin_width, bin_width)
    energies = (bins[1:] + bins[:-1]) / 2

    # Add rows to weights for each band so they are aligned with eigenval data
    weights = weights * np.ones([eigenvalues[Spin.up].shape[0], 1])

    dos_data = {
        spin: np.histogram(eigenvalue_set, bins=bins, weights=weights)[0]
        for spin, eigenvalue_set in eigenvalues.items()
    }

    dos = Dos(efermi, energies, dos_data)
    if gaussian:
        dos.densities = dos.get_smeared_densities(gaussian)

    return dos
Пример #17
0
def read_dos(
    bands_file,
    pdos_file=None,
    cell_file=None,
    bin_width=0.01,
    gaussian=None,
    padding=None,
    emin=None,
    emax=None,
    efermi_to_vbm=True,
    lm_orbitals=None,
    elements=None,
    atoms=None,
    total_only=False,
):
    """Convert DOS data from CASTEP .bands file to Pymatgen/Sumo format

    The data is binned into a regular series using np.histogram

    Args:
        bands_file (:obj:`str`): Path to CASTEP prefix.bands output file. The
            k-point positions, weights and eigenvalues are read from this file.
        bin_width (:obj:`float`, optional): Spacing for DOS energy axis
        gaussian (:obj:`float` or None, optional): Width of Gaussian broadening
            function
        padding (:obj:`float`, optional): Energy range above and below occupied
            region. (This is not used if xmin and xmax are set.)
        emin (:obj:`float`, optional): Minimum energy value for output DOS)
        emax (:obj:`float`, optional): Maximum energy value for output DOS
        efermi_to_vbm (:obj:`bool`, optional):
            If a bandgap is detected, modify the stored Fermi energy
            so that it lies at the VBM.
        elements (:obj:`dict`, optional): The elements and orbitals to extract
            from the projected density of states. Should be provided as a
            :obj:`dict` with the keys as the element names and corresponding
            values as a :obj:`tuple` of orbitals. For example, the following
            would extract the Bi s, px, py and d orbitals::

                {'Bi': ('s', 'px', 'py', 'd')}

            If an element is included with an empty :obj:`tuple`, all orbitals
            for that species will be extracted. If ``elements`` is not set or
            set to ``None``, all elements for all species will be extracted.
        lm_orbitals (:obj:`dict`, optional): The orbitals to decompose into
            their lm contributions (e.g. p -> px, py, pz). Should be provided
            as a :obj:`dict`, with the elements names as keys and a
            :obj:`tuple` of orbitals as the corresponding values. For example,
            the following would be used to decompose the oxygen p and d
            orbitals::

                {'O': ('p', 'd')}

        atoms (:obj:`dict`, optional): Which atomic sites to use when
            calculating the projected density of states. Should be provided as
            a :obj:`dict`, with the element names as keys and a :obj:`tuple` of
            :obj:`int` specifying the atomic indices as the corresponding
            values. The elemental projected density of states will be summed
            only over the atom indices specified. If an element is included
            with an empty :obj:`tuple`, then all sites for that element will
            be included. The indices are 0 based for each element specified in
            the POSCAR. For example, the following will calculate the density
            of states for the first 4 Sn atoms and all O atoms in the
            structure::

                {'Sn': (1, 2, 3, 4), 'O': (, )}

            If ``atoms`` is not set or set to ``None`` then all atomic sites
            for all elements will be considered.

    Returns:
        (:obj:`pymatgen.electronic_structure.dos.Dos`, dict)

        where the dict is either empty or contains a PDOS arranged::

          {species: {orbital: Dos}}
    """

    header = _read_bands_header_verbose(bands_file)

    logging.info("Reading band eigenvalues...")
    _, weights, eigenvalues = read_bands_eigenvalues(bands_file, header)

    calc_efermi = header["e_fermi"][0] * _ry_to_ev * 2
    if efermi_to_vbm and not _is_metal(eigenvalues, calc_efermi):
        logging.info("Setting energy zero to VBM")
        efermi = _get_vbm(eigenvalues, calc_efermi)
    else:
        logging.info("Setting energy zero to Fermi energy")
        efermi = calc_efermi

    emin_data = min(eigenvalues[Spin.up].flatten())
    emax_data = max(eigenvalues[Spin.up].flatten())
    if Spin.down in eigenvalues:
        emin_data = min(emin_data, min(eigenvalues[Spin.down].flatten()))
        emax_data = max(emax_data, max(eigenvalues[Spin.down].flatten()))

    if padding is None and gaussian:
        padding = gaussian * 3
    elif padding is None:
        padding = 0.5

    if emin is None:
        emin = emin_data - padding
    if emax is None:
        emax = emax_data + padding

    # Shift sampling window to account for zeroing at VBM/EFermi
    emin += efermi
    emax += efermi

    bins = np.arange(emin, emax + bin_width, bin_width)
    energies = (bins[1:] + bins[:-1]) / 2

    # Add rows to weights for each band so they are aligned with eigenval data
    weights = weights * np.ones([eigenvalues[Spin.up].shape[0], 1])

    dos_data = {
        spin: np.histogram(eigenvalue_set, bins=bins, weights=weights)[0]
        for spin, eigenvalue_set in eigenvalues.items()
    }

    dos = Dos(efermi, energies, dos_data)

    if pdos_file is not None and not total_only:
        if cell_file is None:
            raise OSError(f"Cell file {cell_file} not found: this must be "
                          "provided for PDOS.")
        pdos_raw = compute_pdos(pdos_file, eigenvalues, weights, bins)
        # Also we, need to read the structure, but have it sorted with increasing
        # atomic numbers
        structure = CastepCell.from_file(
            cell_file).structure.get_sorted_structure(
                key=lambda x: x.species.elements[0].Z)
        pdoss = {}
        for isite, site in enumerate(structure.sites):
            pdoss[site] = pdos_raw[isite]
        # Get the pdos dictionary for potting
        pdos = get_pdos(
            CompleteDos(structure, dos, pdoss),
            lm_orbitals=lm_orbitals,
            elements=elements,
            atoms=atoms,
        )
        # Smear the PDOS
        for orbs in pdos.values():
            for dtmp in orbs.values():
                if gaussian:
                    dtmp.densities = dtmp.get_smeared_densities(gaussian)
    else:
        pdos = {}

    if gaussian:
        dos.densities = dos.get_smeared_densities(gaussian)

    return dos, pdos
Пример #18
0
import pytest

from pymatgen.electronic_structure.dos import CompleteDos, Dos
from pymatgen.core import Site
from pymatgen.electronic_structure.core import Spin, Orbital
from pymatgen.io.vasp import Vasprun

from vise.analyzer.vasp.dos_data import DosDataFromVasp
from vise.analyzer.plot_dos import DosPlotter

efermi = 0.5
energies = [-1, 0, 1]
tdos = [3, 4, 5]
pdos = [1, 2, 3]

total_dos = Dos(efermi=efermi, energies=energies, densities={Spin.up: tdos})
pdoses = {
    Site("H", [0, 0, 0]): {
        Orbital.s: {
            Spin.up: pdos
        },
        Orbital.px: {
            Spin.up: pdos
        },
        Orbital.py: {
            Spin.up: pdos
        },
        Orbital.pz: {
            Spin.up: pdos
        },
        Orbital.dxy: {
Пример #19
0
    def get_dos(
        self,
        kpoint_mesh: Union[float, int, List[int]],
        energy_cutoff: Optional[float] = None,
        scissor: Optional[float] = None,
        bandgap: Optional[float] = None,
        estep: float = 0.01,
        width: float = 0.05,
        symprec: float = 0.01,
        fermi_dos: bool = False,
    ) -> Union[Dos, FermiDos]:
        """Calculates the density of states using the interpolated bands.

        Args:
            kpoint_mesh: The k-point mesh as a 1x3 array. E.g.,``[6, 6, 6]``.
                Alternatively, if a single value is provided this will be
                treated as a reciprocal density and the k-point mesh dimensions
                generated automatically.
            energy_cutoff: The energy cut-off to determine which bands are
                included in the interpolation. If the energy of a band falls
                within the cut-off at any k-point it will be included. For
                metals the range is defined as the Fermi level ± energy_cutoff.
                For gapped materials, the energy range is from the VBM -
                energy_cutoff to the CBM + energy_cutoff.
            scissor: The amount by which the band gap is scissored. Cannot
                be used in conjunction with the ``bandgap`` option. Has no
                effect for metallic systems.
            bandgap: Automatically adjust the band gap to this value. Cannot
                be used in conjunction with the ``scissor`` option. Has no
                effect for metallic systems.
            estep: The energy step, where smaller numbers give more
                accuracy but are more expensive.
            width: The gaussian smearing width in eV.
            symprec: The symmetry tolerance used when determining the symmetry
                inequivalent k-points on which to interpolate.
            fermi_dos: Whether to return a FermiDos object, instead of a regular
                Dos.

        Returns:
            The density of states.
        """
        kpoints, weights = get_kpoints(kpoint_mesh,
                                       self._band_structure.structure,
                                       symprec=symprec)

        energies, efermi = self.get_energies(
            kpoints,
            scissor=scissor,
            bandgap=bandgap,
            energy_cutoff=energy_cutoff,
            atomic_units=False,
            return_efermi=True,
        )

        emin = np.min([np.min(spin_eners) for spin_eners in energies.values()])
        emin -= width * 5 if width else 0.1
        emax = np.max([np.max(spin_eners) for spin_eners in energies.values()])
        emax += width * 5 if width else 0.1
        epoints = int(round((emax - emin) / estep))

        dos = {}
        emesh = None
        for spin in self._spins:
            kpoint_weights = np.tile(weights / np.sum(weights),
                                     (len(energies[spin]), 1))
            emesh, dos[spin] = get_dos(
                energies[spin].T,
                erange=(emin, emax),
                npts=epoints,
                weights=kpoint_weights.T,
            )

            if width:
                dos[spin] = gaussian_filter1d(dos[spin],
                                              width / (emesh[1] - emesh[0]))

        if fermi_dos:
            return FermiDos(efermi,
                            emesh,
                            dos,
                            self._band_structure.structure,
                            atomic_units=False)
        else:
            return Dos(efermi, emesh, dos)
Пример #20
0
    def from_file(filename1='feff.inp', filename2='ldos'):
        """"
        Creates FeffLdos object from raw Feff ldos files by
        by assuming they are numbered consequetively, i.e. ldos01.dat
        ldos02.dat...

        Args:
            filename1: input file of run to obtain structure
            filename2: output ldos file of run to obtain dos info, etc.
        """
        ldos_filename = filename2
        header_str = Header.header_string_from_file(filename1)
        header = Header.from_string(header_str)
        structure = header.struct
        nsites = structure.num_sites
        pot_string = FeffPot.pot_string_from_file(filename1)
        dicts = FeffPot.pot_dict_from_string(pot_string)
        pot_dict = dicts[0]

        with zopen(ldos_filename + "00.dat", "r") as fobject:
            f = fobject.readlines()
        efermi = float(f[0].split()[4])

        dos_energies = []
        ldos = {}

        for i in range(1, len(pot_dict) + 1):
            if len(str(i)) == 1:
                ldos[i] = np.loadtxt("{}0{}.dat".format(ldos_filename, i))
            else:
                ldos[i] = np.loadtxt("{}{}.dat".format(ldos_filename, i))

        for i in range(0, len(ldos[1])):
            dos_energies.append(ldos[1][i][0])

        all_pdos = []
        vorb = {
            "s": Orbital.s,
            "p": Orbital.py,
            "d": Orbital.dxy,
            "f": Orbital.f0
        }
        forb = {"s": 0, "p": 1, "d": 2, "f": 3}

        dlength = len(ldos[1])

        for i in range(nsites):
            pot_index = pot_dict[structure.species[i].symbol]
            all_pdos.append(defaultdict(dict))
            for k, v in vorb.items():
                density = [
                    ldos[pot_index][j][forb[k] + 1] for j in range(dlength)
                ]
                updos = density
                downdos = None
                if downdos:
                    all_pdos[-1][v] = {Spin.up: updos, Spin.down: downdos}
                else:
                    all_pdos[-1][v] = {Spin.up: updos}

        pdos = all_pdos
        vorb2 = {0: Orbital.s, 1: Orbital.py, 2: Orbital.dxy, 3: Orbital.f0}
        pdoss = {
            structure[i]: {v: pdos[i][v]
                           for v in vorb2.values()}
            for i in range(len(pdos))
        }

        forb = {"s": 0, "p": 1, "d": 2, "f": 3}

        tdos = [0] * dlength
        for i in range(nsites):
            pot_index = pot_dict[structure.species[i].symbol]
            for v in forb.values():
                density = [ldos[pot_index][j][v + 1] for j in range(dlength)]
                for j in range(dlength):
                    tdos[j] = tdos[j] + density[j]
        tdos = {Spin.up: tdos}

        dos = Dos(efermi, dos_energies, tdos)
        complete_dos = CompleteDos(structure, dos, pdoss)
        charge_transfer = FeffLdos.charge_transfer_from_file(
            filename1, filename2)
        return FeffLdos(complete_dos, charge_transfer)
Пример #21
0
    def get_dos(self,
                kpoint_mesh: Union[float, int, List[int]],
                energy_cutoff: Optional[float] = None,
                scissor: Optional[float] = None,
                bandgap: Optional[float] = None,
                estep: float = 0.01,
                width: float = 0.05,
                symprec: float = 0.01
                ) -> Dos:
        """Calculates the density of states using the interpolated bands.

        Args:
            kpoint_mesh: The k-point mesh as a 1x3 array. E.g.,``[6, 6, 6]``.
                Alternatively, if a single value is provided this will be
                treated as a reciprocal density and the k-point mesh dimensions
                generated automatically.
            energy_cutoff: The energy cut-off to determine which bands are
                included in the interpolation. If the energy of a band falls
                within the cut-off at any k-point it will be included. For
                metals the range is defined as the Fermi level ± energy_cutoff.
                For gapped materials, the energy range is from the VBM -
                energy_cutoff to the CBM + energy_cutoff.
            scissor: The amount by which the band gap is scissored. Cannot
                be used in conjunction with the ``bandgap`` option. Has no
                effect for metallic systems.
            bandgap: Automatically adjust the band gap to this value. Cannot
                be used in conjunction with the ``scissor`` option. Has no
                effect for metallic systems.
            estep: The energy step, where smaller numbers give more
                accuracy but are more expensive.
            width: The gaussian smearing width in eV.
            symprec: The symmetry tolerance used when determining the symmetry
                inequivalent k-points on which to interpolate.

        Returns:
            The density of states.
        """
        kpoints, weights = _get_kpoints(
            kpoint_mesh, self._band_structure.structure, symprec=symprec)

        energies = self.get_energies(
            kpoints, scissor=scissor, bandgap=bandgap,
            energy_cutoff=energy_cutoff, atomic_units=False)

        energies = np.vstack([energies[spin] for spin in self._spins])

        nbands = energies.shape[0]
        nkpts = energies.shape[1]
        emin = np.min(energies) - width * 5
        emax = np.max(energies) + width * 5
        epoints = int(round((emax - emin) / estep))

        # BoltzTraP DOS kpoint_weights don't work as you'd expect so we include
        # the degeneracy manually
        all_energies = np.array([[energies[nb][nk] for nb in range(nbands)]
                                 for nk in range(nkpts)
                                 for _ in range(weights[nk])])

        emesh, dos = DOS(all_energies, erange=(emin, emax), npts=epoints)
        dos = gaussian_filter1d(dos, width / (emesh[1] - emesh[0]))
        dos *= 1 if self._soc or len(self._spins) == 2 else 1

        return Dos(self._band_structure.efermi, emesh, dos)
Пример #22
0
 def setUp(self):
     with open(os.path.join(test_dir, "complete_dos.json"), "r") as f:
         self.dos = Dos.from_dict(json.load(f))
Пример #23
0
from pymatgen import Site
from pymatgen.electronic_structure.dos import Dos
import os

dsp = DosPlotter()

vrun = Vasprun('vasprun.xml')

cdos = vrun.complete_dos

atoms = []
i: Site

dos = {
    'd_in':
    Dos(cdos.efermi, cdos.energies, {Spin.up: np.zeros_like(cdos.energies)}),
    'd_out':
    Dos(cdos.efermi, cdos.energies, {Spin.up: np.zeros_like(cdos.energies)})
}

for i in vrun.final_structure.sites:
    if i.species_string == 'V':
        atoms.append(i)
for j in atoms:
    for n, k in dos.items():
        if n == 'd_in':
            dos[n] = k.__add__(cdos.get_site_orbital_dos(j, Orbital.dxy))
        else:
            dos[n] = k.__add__(cdos.get_site_orbital_dos(j, Orbital.dyz))
            dos[n] = k.__add__(cdos.get_site_orbital_dos(j, Orbital.dxz))
Пример #24
0
    def from_file(feff_inp_file="feff.inp", ldos_file="ldos"):
        """
        Creates LDos object from raw Feff ldos files by
        by assuming they are numbered consecutively, i.e. ldos01.dat
        ldos02.dat...

        Args:
            feff_inp_file (str): input file of run to obtain structure
            ldos_file (str): output ldos file of run to obtain dos info, etc.
        """
        header_str = Header.header_string_from_file(feff_inp_file)
        header = Header.from_string(header_str)
        structure = header.struct
        nsites = structure.num_sites
        parameters = Tags.from_file(feff_inp_file)

        if "RECIPROCAL" in parameters:
            pot_dict = {}
            pot_readstart = re.compile(".*iz.*lmaxsc.*xnatph.*xion.*folp.*")
            pot_readend = re.compile(".*ExternalPot.*switch.*")
            pot_inp = re.sub(r"feff.inp", r"pot.inp", feff_inp_file)
            dos_index = 1
            begin = 0

            with zopen(pot_inp, "r") as potfile:
                for line in potfile:
                    if len(pot_readend.findall(line)) > 0:
                        break

                    if begin == 1:
                        begin += 1
                        continue

                    if begin == 2:
                        z_number = int(line.strip().split()[0])
                        ele_name = Element.from_Z(z_number).name
                        if ele_name not in pot_dict:
                            pot_dict[ele_name] = dos_index
                        else:
                            pot_dict[ele_name] = min(dos_index,
                                                     pot_dict[ele_name])
                        dos_index += 1

                    if len(pot_readstart.findall(line)) > 0:
                        begin = 1
        else:
            pot_string = Potential.pot_string_from_file(feff_inp_file)
            dicts = Potential.pot_dict_from_string(pot_string)
            pot_dict = dicts[0]

        with zopen(ldos_file + "00.dat", "r") as fobject:
            f = fobject.readlines()
        efermi = float(f[0].split()[4])

        dos_energies = []
        ldos = {}

        for i in range(1, len(pot_dict) + 1):
            if len(str(i)) == 1:
                ldos[i] = np.loadtxt(f"{ldos_file}0{i}.dat")
            else:
                ldos[i] = np.loadtxt(f"{ldos_file}{i}.dat")

        for i in range(0, len(ldos[1])):
            dos_energies.append(ldos[1][i][0])

        all_pdos = []
        vorb = {
            "s": Orbital.s,
            "p": Orbital.py,
            "d": Orbital.dxy,
            "f": Orbital.f0
        }
        forb = {"s": 0, "p": 1, "d": 2, "f": 3}

        dlength = len(ldos[1])

        for i in range(nsites):
            pot_index = pot_dict[structure.species[i].symbol]
            all_pdos.append(defaultdict(dict))
            for k, v in vorb.items():
                density = [
                    ldos[pot_index][j][forb[k] + 1] for j in range(dlength)
                ]
                updos = density
                downdos = None
                if downdos:
                    all_pdos[-1][v] = {Spin.up: updos, Spin.down: downdos}
                else:
                    all_pdos[-1][v] = {Spin.up: updos}

        pdos = all_pdos
        vorb2 = {0: Orbital.s, 1: Orbital.py, 2: Orbital.dxy, 3: Orbital.f0}
        pdoss = {
            structure[i]: {v: pdos[i][v]
                           for v in vorb2.values()}
            for i in range(len(pdos))
        }

        forb = {"s": 0, "p": 1, "d": 2, "f": 3}

        tdos = [0] * dlength
        for i in range(nsites):
            pot_index = pot_dict[structure.species[i].symbol]
            for v in forb.values():
                density = [ldos[pot_index][j][v + 1] for j in range(dlength)]
                for j in range(dlength):
                    tdos[j] = tdos[j] + density[j]
        tdos = {Spin.up: tdos}

        dos = Dos(efermi, dos_energies, tdos)
        complete_dos = CompleteDos(structure, dos, pdoss)
        charge_transfer = LDos.charge_transfer_from_file(
            feff_inp_file, ldos_file)
        return LDos(complete_dos, charge_transfer)
Пример #25
0
def read_dos(bands_file,
             pdos_file=None,
             cell_file=None,
             bin_width=0.01,
             gaussian=None,
             padding=None,
             emin=None,
             emax=None,
             efermi_to_vbm=True,
             lm_orbitals=None,
             elements=None,
             atoms=None,
             total_only=False):
    """Convert DOS data from CASTEP .bands file to Pymatgen/Sumo format

    The data is binned into a regular series using np.histogram

    Args:
        bands_file (:obj:`str`): Path to CASTEP prefix.bands output file. The
            k-point positions, weights and eigenvalues are read from this file.
        pdos_bin (:obj:`str`): Path to CASTEP prefix.pdos_bin output file. The
            weights of projected density of states are read from this file.
        bin_width (:obj:`float`, optional): Spacing for DOS energy axis
        gaussian (:obj:`float` or None, optional): Width of Gaussian broadening
            function
        padding (:obj:`float`, optional): Energy range above and below occupied
            region. (This is not used if xmin and xmax are set.)
        emin (:obj:`float`, optional): Minimum energy value for output DOS)
        emax (:obj:`float`, optional): Maximum energy value for output DOS
        efermi_to_vbm (:obj:`bool`, optional):
            If a bandgap is detected, modify the stored Fermi energy
            so that it lies at the VBM.

    Returns:
        (:obj:`pymatgen.electronic_structure.dos.Dos`, dict)

        where the dict is either empty or contains a PDOS arranged::

          {species: {orbital: Dos}}
    """

    header = _read_bands_header_verbose(bands_file)

    logging.info("Reading band eigenvalues...")
    _, weights, eigenvalues = read_bands_eigenvalues(bands_file, header)

    calc_efermi = header['e_fermi'][0] * _ry_to_ev * 2
    if efermi_to_vbm and not _is_metal(eigenvalues, calc_efermi):
        logging.info("Setting energy zero to VBM")
        efermi = _get_vbm(eigenvalues, calc_efermi)
    else:
        logging.info("Setting energy zero to Fermi energy")
        efermi = calc_efermi

    emin_data = min(eigenvalues[Spin.up].flatten())
    emax_data = max(eigenvalues[Spin.up].flatten())
    if Spin.down in eigenvalues:
        emin_data = min(emin_data, min(eigenvalues[Spin.down].flatten()))
        emax_data = max(emax_data, max(eigenvalues[Spin.down].flatten()))

    if padding is None and gaussian:
        padding = gaussian * 3
    elif padding is None:
        padding = 0.5

    if emin is None:
        emin = emin_data - padding
    if emax is None:
        emax = emax_data + padding

    # Shift sampling window to account for zeroing at VBM/EFermi
    emin += efermi
    emax += efermi

    bins = np.arange(emin, emax + bin_width, bin_width)
    energies = (bins[1:] + bins[:-1]) / 2

    # Add rows to weights for each band so they are aligned with eigenval data
    weights = weights * np.ones([eigenvalues[Spin.up].shape[0], 1])

    dos_data = {
        spin: np.histogram(eigenvalue_set, bins=bins, weights=weights)[0]
        for spin, eigenvalue_set in eigenvalues.items()
    }

    dos = Dos(efermi, energies, dos_data)

    if pdos_file is not None and not total_only:
        if cell_file is None:
            raise OSError(f'Cell file {cell_file} not found: this must be '
                          'provided for PDOS.')
        pdos_raw = compute_pdos(pdos_file, eigenvalues, weights, bins)
        # Also we, need to read the structure, but have it sorted with increasing
        # atomic numbers
        structure = CastepCell.from_file(
            cell_file).structure.get_sorted_structure(
                key=lambda x: x.species.elements[0].Z)
        pdoss = {}
        for isite, site in enumerate(structure.sites):
            pdoss[site] = pdos_raw[isite]
        # Get the pdos dictionary for potting
        pdos = get_pdos(CompleteDos(structure, dos, pdoss),
                        lm_orbitals=lm_orbitals,
                        elements=elements,
                        atoms=atoms)
        # Smear the PDOS
        for orbs in pdos.values():
            for dtmp in orbs.values():
                if gaussian:
                    dtmp.densities = dtmp.get_smeared_densities(gaussian)
    else:
        pdos = {}

    if gaussian:
        dos.densities = dos.get_smeared_densities(gaussian)

    return dos, pdos
Пример #26
0
    def from_dict(data):
        def _make_float_array(a):
            res = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
            for i in range(3):
                for j in range(3):
                    res[i][j] = float(a[i][j])
            return res

        def _make_float_hall(a):
            return [i for i in a[:27]]

        return BoltztrapAnalyzer(
            float(data["gap"]),
            [float(d) for d in data["mu_steps"]],
            {int(d): [_make_float_array(v) for v in data["cond"][d]] for d in data["cond"]},
            {int(d): [_make_float_array(v) for v in data["seebeck"][d]] for d in data["seebeck"]},
            {int(d): [_make_float_array(v) for v in data["kappa"][d]] for d in data["kappa"]},
            {int(d): [_make_float_hall(v) for v in data["hall"][d]] for d in data["hall"]},
            {"p": [float(d) for d in data["doping"]["p"]], "n": [float(d) for d in data["doping"]["n"]]},
            {
                "p": {int(d): [float(v) for v in data["mu_doping"]["p"][d]] for d in data["mu_doping"]["p"]},
                "n": {int(d): [float(v) for v in data["mu_doping"]["n"][d]] for d in data["mu_doping"]["n"]},
            },
            {
                "p": {
                    int(d): [_make_float_array(v) for v in data["seebeck_doping"]["p"][d]]
                    for d in data["seebeck_doping"]["p"]
                },
                "n": {
                    int(d): [_make_float_array(v) for v in data["seebeck_doping"]["n"][d]]
                    for d in data["seebeck_doping"]["n"]
                },
            },
            {
                "p": {
                    int(d): [_make_float_array(v) for v in data["cond_doping"]["p"][d]]
                    for d in data["cond_doping"]["p"]
                },
                "n": {
                    int(d): [_make_float_array(v) for v in data["cond_doping"]["n"][d]]
                    for d in data["cond_doping"]["n"]
                },
            },
            {
                "p": {
                    int(d): [_make_float_array(v) for v in data["kappa_doping"]["p"][d]]
                    for d in data["kappa_doping"]["p"]
                },
                "n": {
                    int(d): [_make_float_array(v) for v in data["kappa_doping"]["n"][d]]
                    for d in data["kappa_doping"]["n"]
                },
            },
            {
                "p": {
                    int(d): [_make_float_hall(v) for v in data["hall_doping"]["p"][d]] for d in data["hall_doping"]["p"]
                },
                "n": {
                    int(d): [_make_float_hall(v) for v in data["hall_doping"]["n"][d]] for d in data["hall_doping"]["n"]
                },
            },
            Dos.from_dict(data["dos"]),
            data["carrier_conc"],
            data["dos_partial"],
            data["vol"],
            str(data["warning"]),
        )
Пример #27
0
    def _make_boltztrap_analyzer_from_data(
            data_full, data_hall, data_dos, temperature_steps, mu_steps,
            efermi, gap, doping, data_doping_full, data_doping_hall, vol,
            warning=False):
        """
        Make a BoltztrapAnalyzer object from raw data typically parse from
        files.
        """
        cond = {t: [] for t in temperature_steps}
        seebeck = {t: [] for t in temperature_steps}
        kappa = {t: [] for t in temperature_steps}
        hall = {t: [] for t in temperature_steps}
        carrier_conc = {t: [] for t in temperature_steps}
        dos_full = {'energy': [], 'density': []}
        warning = warning
        new_doping = {'p': [], 'n': []}
        for d in doping:
            if d > 0:
                new_doping['p'].append(d)
            else:
                new_doping['n'].append(-d)

        mu_doping = {'p': {t: [] for t in temperature_steps},
                     'n': {t: [] for t in temperature_steps}}
        seebeck_doping = {'p': {t: [] for t in temperature_steps},
                          'n': {t: [] for t in temperature_steps}}
        cond_doping = {'p': {t: [] for t in temperature_steps},
                       'n': {t: [] for t in temperature_steps}}
        kappa_doping = {'p': {t: [] for t in temperature_steps},
                        'n': {t: [] for t in temperature_steps}}
        hall_doping = {'p': {t: [] for t in temperature_steps},
                       'n': {t: [] for t in temperature_steps}}
        for d in data_full:
            carrier_conc[d[1]].append(d[2])
            tens_cond = [[d[3], d[4], d[5]],
                         [d[6], d[7], d[8]],
                         [d[9], d[10], d[11]]]
            cond[d[1]].append(tens_cond)
            tens_seebeck = [[d[12], d[13], d[14]],
                            [d[15], d[16], d[17]],
                            [d[18], d[19], d[20]]]
            seebeck[d[1]].append(tens_seebeck)
            tens_kappa = [[d[21], d[22], d[23]],
                          [d[24], d[25], d[26]],
                          [d[27], d[28], d[29]]]
            kappa[d[1]].append(tens_kappa)

        for d in data_hall:
            hall_tens = d[3:]
            hall[d[1]].append(hall_tens)

        for d in data_doping_full:
            tens_cond = [[d[2], d[3], d[4]],
                         [d[5], d[6], d[7]],
                         [d[8], d[9], d[10]]]
            tens_seebeck = [[d[11], d[12], d[13]],
                            [d[14], d[15], d[16]],
                            [d[17], d[18], d[19]]]
            tens_kappa = [[d[20], d[21], d[22]],
                          [d[23], d[24], d[25]],
                          [d[26], d[27], d[28]]]

            if d[1] < 0:
                mu_doping['n'][d[0]].append(Energy(d[-1], "Ry").to("eV"))
                cond_doping['n'][d[0]].append(tens_cond)
                seebeck_doping['n'][d[0]].append(tens_seebeck)
                kappa_doping['n'][d[0]].append(tens_kappa)
            else:
                mu_doping['p'][d[0]].append(Energy(d[-1], "Ry").to("eV"))
                cond_doping['p'][d[0]].append(tens_cond)
                seebeck_doping['p'][d[0]].append(tens_seebeck)
                kappa_doping['p'][d[0]].append(tens_kappa)

        for i in range(len(data_doping_hall)):
            hall_tens = [data_hall[i][j] for j in range(3, len(data_hall[i]))]
            if data_doping_hall[i][1] < 0:
                hall_doping['n'][data_doping_hall[i][0]].append(hall_tens)
            else:
                hall_doping['p'][data_doping_hall[i][0]].append(hall_tens)

        for t in data_dos['total']:
            dos_full['energy'].append(t[0])
            dos_full['density'].append(t[1])

        dos = Dos(efermi, dos_full['energy'], {Spin.up: dos_full['density']})
        dos_partial = data_dos['partial']

        return BoltztrapAnalyzer(
            gap, mu_steps, cond, seebeck, kappa, hall, new_doping, mu_doping,
            seebeck_doping, cond_doping, kappa_doping, hall_doping, dos, dos_partial, carrier_conc,
            vol, warning)