Source code for pymatgen.core.molecular_orbitals

# coding: utf-8
# Copyright (c) Pymatgen Development Team.
# Distributed under the terms of the MIT License.

"""
This module implements a MolecularOrbital class to represent band character in
solids. Usefull for predicting PDOS character from structural information.
"""

from itertools import chain, combinations

from pymatgen.core.periodic_table import Element
from pymatgen.core.composition import Composition


[docs]class MolecularOrbitals: """ Represents the character of bands in a solid. The input is a chemical formula, since no structural characteristics are taken into account. The band character of a crystal emerges from the atomic orbitals of the constituant ions, hybridization/covalent bonds, and the spin-orbit interaction (ex: Fe2O3). Right now the orbitals are only built from the uncharged atomic species. Functionality can be improved by: 1) calculate charged ion orbital energies 2) incorportate the coordination enviornment to account for covalant bonds The atomic orbital energies are stored in pymatgen.core.periodic_table.JSON >>> MOs = MolecularOrbitals('SrTiO3') >>> MOs.band_edges {'HOMO':['O','2p',-0.338381], 'LUMO':['Ti','3d',-0.17001], 'metal':False} """ def __init__(self, formula): """ Args: chemical formula as a string. formula must have integer subscripts Ex: 'SrTiO3' Attributes: composition: the composition as a dictionary. Ex: {'Sr': 1, 'Ti': 1, 'O', 3} elements: the dictionary keys for the composition elec_neg: the maximum pairwise electronegetivity difference aos: the consituant atomic orbitals for each element as a dictionary band_edges: dictionary containing the highest occupied molecular orbital (HOMO), lowest unocupied molecular orbital (LUMO), and whether the material is predicted to be a metal """ self.composition = Composition(formula).as_dict() self.elements = self.composition.keys() for subscript in self.composition.values(): if not float(subscript).is_integer(): raise ValueError('composition subscripts must be integers') self.elec_neg = self.max_electronegativity() self.aos = {str(el): [[str(el), k, v] for k, v in Element(el).atomic_orbitals.items()] for el in self.elements} self.band_edges = self.obtain_band_edges()
[docs] def max_electronegativity(self): """ Returns: The maximum pairwise electronegativity difference. """ maximum = 0 for e1, e2 in combinations(self.elements, 2): if abs(Element(e1).X - Element(e2).X) > maximum: maximum = abs(Element(e1).X - Element(e2).X) return maximum
[docs] def aos_as_list(self): """ Returns: A list of atomic orbitals, sorted from lowest to highest energy. The orbitals energies in eV are represented as [['O', '1s', -18.758245], ['O', '2s', -0.871362], ['O', '2p', -0.338381]] Data is obtained from https://www.nist.gov/pml/data/atomic-reference-data-electronic-structure-calculations """ return sorted(chain.from_iterable( [self.aos[el] * int(self.composition[el]) for el in self.elements] ), key=lambda x: x[2])
[docs] def obtain_band_edges(self): """ Fill up the atomic orbitals with available electrons. Returns: HOMO, LUMO, and whether it's a metal. """ orbitals = self.aos_as_list() electrons = Composition(self.composition).total_electrons partial_filled = [] for orbital in orbitals: if electrons <= 0: break if 's' in orbital[1]: electrons += -2 elif 'p' in orbital[1]: electrons += -6 elif 'd' in orbital[1]: electrons += -10 elif 'f' in orbital[1]: electrons += -14 partial_filled.append(orbital) if electrons != 0: homo = partial_filled[-1] lumo = partial_filled[-1] else: homo = partial_filled[-1] try: lumo = orbitals[len(partial_filled)] except Exception: lumo = None return {'HOMO': homo, 'LUMO': lumo, 'metal': homo == lumo}