Source code for ase.utils.formula

from ase.data import chemical_symbols
from collections import Counter

import sys
# should use math.gcd from python >= 3.5
if sys.version_info.major > 2 and sys.version_info.minor > 4:
    from math import gcd
else:
    from fractions import gcd


# no need to re-create this list at each function call
# non metals, half-metals/metalloid, halogen, noble gas
non_metals = ['H', 'He', 'B', 'C', 'N', 'O', 'F', 'Ne',
              'Si', 'P', 'S', 'Cl', 'Ar',
              'Ge', 'As', 'Se', 'Br', 'Kr',
              'Sb', 'Te', 'I', 'Xe',
              'Po', 'At', 'Rn']

def _count_symbols(numbers):
    """Take a list of atomic numbers and return a ditionary with elemt symbosl
    as keys and occurences as values"""
    if isinstance(numbers, dict):
        count = dict(numbers)
    else:
        count = Counter([chemical_symbols[Z] for Z in numbers])
    return count

def _empirical_symbols(count):
    """Find the least common multiple of all symbols"""
    counts = [c for c in count.values()]
    i = counts[0]
    for j in counts[1:]:
        _gcd = gcd(i,j)
        i=_gcd
    return {k : v//_gcd for k, v in count.items()}


[docs]def formula_hill(numbers, empirical=False): """Convert list of atomic numbers to a chemical formula as a string. Elements are alphabetically ordered with C and H first. If argument `empirical`, element counts will be divided by greatest common divisor to yield an empirical formula""" count = _count_symbols(numbers) if empirical: count = _empirical_symbols(count) result = [(s, count.pop(s)) for s in 'CH' if s in count] result += [(s, count[s]) for s in sorted(count)] return ''.join('{0}{1}'.format(symbol, n) if n > 1 else symbol for symbol, n in result)
[docs]def formula_metal(numbers, empirical=False): """Convert list of atomic numbers to a chemical formula as a string. Elements are alphabetically ordered with metals first. If argument `empirical`, element counts will be divided by greatest common divisor to yield an empirical formula""" count = _count_symbols(numbers) if empirical: count = _empirical_symbols(count) result2 = [(s, count.pop(s)) for s in non_metals if s in count] result = [(s, count[s]) for s in sorted(count)] result += sorted(result2) return ''.join('{0}{1}'.format(symbol, n) if n > 1 else symbol for symbol, n in result)