Source code for mendeleev.mendeleev

"""Entry point for the Mendeleev package for instantiating elements and isotopes."""

from typing import List, Union

import sqlalchemy
from sqlalchemy.orm import Session

from .db import get_session, get_engine
from .models import Element, Isotope


__all__ = [
    "get_all_elements",
    "get_attribute_for_all_elements",
    "element",
    "isotope",
]


[docs] def element(ids: Union[int, str]) -> Element: """ Based on the type of the `ids` identifier return either an :py:class:`Element <mendeleev.models.Element>` object from the database, or a list of :py:class:`Element <mendeleev.models.Element>` objects if the `ids` is a list or a tuple of identifiers. Valid identifiers for an element are: *name*, *symbol*, and *atomic number*. Args: ids (str): element identifier Raises: ValueError: when the identifier is not a list/tuple, int or str Example: The element can be identified by symbol >>> from mendeleev import element >>> si = element('Si') >>> si.atomic_number 14 by the atomic number >>> al = element(13) >>> al.name 'Aluminum' or by the name >>> o = element('Oxygen') >>> o.symbol 'O' Mutiple elements can be instantiated simultaneously through as combination of identifiers >>> c, h, o = element(['C', 'Hydrogen', 8]) >>> print(c.name, h.name, o.name) Carbon Hydrogen Oxygen """ if isinstance(ids, (list, tuple)): return [_get_element(i) for i in ids] elif isinstance(ids, (str, int)): return _get_element(ids) else: raise ValueError( "Expected a <list>, <tuple>, <str> or <int>, got: {0:s}".format(type(ids)) )
def _get_element(ids) -> Union[Element, List[Element]]: """ Return an element from the database based on the `ids` identifier passed. Valid identifiers for an element are: *name*, *symbol*, *atomic number*. """ session = get_session() try: if isinstance(ids, str): if len(ids) <= 3 and ids.lower() != "tin": return session.query(Element).filter(Element.symbol == str(ids)).one() else: return session.query(Element).filter(Element.name == str(ids)).one() elif isinstance(ids, int): return session.query(Element).filter(Element.atomic_number == ids).one() raise ValueError("Expecting a <str> or <int>, got: {0:s}".format(type(ids))) except sqlalchemy.exc.NoResultFound: raise ValueError(f"Element not found: {ids}")
[docs] def get_all_elements() -> List[Element]: "Get all elements as a list" session = get_session() elements = session.query(Element).all() session.close() return elements
[docs] def isotope(symbol_or_atn: Union[str, int], mass_number: int) -> Isotope: """ Get an Isotope based on the element symbol and mass number or atomic number and mass number. Args: symbol_or_atn (str or int): either element symbol or atomic number mass_number (int): mass number of the isotope Returns: isotope (Isotope): isotope instance """ session = get_session() if isinstance(symbol_or_atn, int): return ( session.query(Isotope) .filter_by(atomic_number=symbol_or_atn, mass_number=mass_number) .one() ) elif isinstance(symbol_or_atn, str): return ( session.query(Isotope) .join(Element) .filter(Element.symbol == symbol_or_atn, Isotope.mass_number == mass_number) .one() ) else: raise ValueError( "Expecting a <str> or <int>, got: {0:s}".format(type(symbol_or_atn)) )
def ids_to_attr(ids, attr: str = "atomic_number"): """ Convert the element ids: atomic numbers, symbols, element names or a combination of the above to a list of corresponding attributes. Args: ids: list, str or int A list of atomic number, symbols, element names of a combination of them attr: str Name of the desired attribute Returns: out: list List of attributes corresponding to the ids """ if isinstance(ids, (list, tuple)): return [getattr(e, attr) for e in element(ids)] else: return [getattr(element(ids), attr)] def deltaN( id1: Union[str, int], id2: Union[str, int], charge1: int = 0, charge2: int = 0, missingIsZero: bool = True, ) -> float: r""" Calculate the approximate fraction of transferred electrons between elements or ions `id1` and `id2` with charges `charge1` and `charge2` respectively according to the expression .. math:: \Delta N = \frac{\chi_{A} - \chi_{B}}{2(\eta_{A} + \eta_{B})} Args: id1: str or int Element identifier atomic number, symbol or element name id2: str or int Element identifier atomic number, symbol or element name """ session = get_session() atns = ids_to_attr([id1, id2], attr="atomic_number") e1, e2 = [ session.query(Element).filter(Element.atomic_number == a).one() for a in atns ] chi = [ x.en_mulliken(charge=c, missingIsZero=missingIsZero) for x, c in zip([e1, e2], [charge1, charge2]) ] if all(x is not None for x in chi): return (chi[0] - chi[1]) / ( 2.0 * (e1.hardness(charge=charge1) + e2.hardness(charge=charge2)) ) else: return None
[docs] def get_attribute_for_all_elements(attribute: str) -> List: """ Get a list of from a single attribute of all elements in the database. """ engine = get_engine() with Session(engine) as session: return [ getattr(r, attribute) for r in session.query(getattr(Element, attribute)) .order_by(Element.atomic_number) .all() ]