def compound_name(formula): periodic_table = PeriodicTable() ions = Ions() common_compounds = CommonCompounds() if formula in common_compounds: return common_compounds[formula] root = parse_formula(formula) components = root[0].children if len(components) == 2: cation = _find_ion(components[0], periodic_table, ions) anion = _find_ion(components[1], periodic_table, ions) first = cation.name if isinstance(cation.charge, list): total_charge = abs(int(components[1].count) * anion.charge) first += ('(' + ('I' * total_charge) + ')') second = anion.name if '-' in first: first = first.replace('-', '') if '-' in second: second = second.split('-')[0] + 'ide' #TODO there is probably a better way to do this if anion.charge != -1 and cation.charge != 1: first = prefix(components[0].count, cation.symbol[0]) + first second = prefix(components[1].count, anion.symbol[0]) + second return first + ' ' + second else: return 'unknown'
def test_parse_formula_N2H4_as_liquid(): actual = parse_formula('N2H4(l)') expected = FormulaRoot('N2H4(l)', []) expected.children.append( CompoundNode(Count(1), 'N2H4', [AtomNode(Count(2), 'N'), AtomNode(Count(4), 'H')], CompoundState.LIQUID)) assert actual == expected
def test_parse_formula_HCl(): actual = parse_formula('HCl') #expected = [(Decimal('1.000'), 'H'), (Decimal('1.000'), 'Cl')] expected = FormulaRoot('HCl', []) expected.children.append( FormulaNode(Count(1), 'HCl', FormulaNodeType.COMPOUND, [ FormulaNode(Count(1), 'H', FormulaNodeType.ATOM, []), FormulaNode(Count(1), 'Cl', FormulaNodeType.ATOM, []) ])) assert actual == expected
def test_parse_formula_K2SO4(): actual = parse_formula('K2SO4') expected = FormulaRoot('K2SO4', []) expected.children.append( FormulaNode(Count(1), 'K2SO4', FormulaNodeType.COMPOUND, [ FormulaNode(Count(2), 'K', FormulaNodeType.ATOM, []), FormulaNode(Count(1), 'SO4', FormulaNodeType.POLYATOMIC_ION, [ FormulaNode(Count(1), 'S', FormulaNodeType.ATOM, []), FormulaNode(Count(4), 'O', FormulaNodeType.ATOM, []) ]) ])) assert actual == expected
def test_parse_formula_BaOH2(): actual = parse_formula('Ba(OH)2') expected = FormulaRoot('Ba(OH)2', []) expected.children.append( FormulaNode(Count(1), 'Ba(OH)2', FormulaNodeType.COMPOUND, [ FormulaNode(Count(1), 'Ba', FormulaNodeType.ATOM, []), FormulaNode(Count(2), 'OH', FormulaNodeType.POLYATOMIC_ION, [ FormulaNode(Count(1), 'O', FormulaNodeType.ATOM, []), FormulaNode(Count(1), 'H', FormulaNodeType.ATOM, []) ]) ])) assert actual == expected
def molar_mass(formula: str) -> Measurement: """Calculates the molar mass of a compound""" if isinstance(formula, list): atoms = formula else: atoms = parse_formula(formula).flatten() total_mass = Measurement("0", GRAMS / MOLES) table = PeriodicTable() for index, atom in enumerate(atoms): count, symbol = atom mass = Scinot(table[symbol].atomic_mass) product = Measurement(mass * count, GRAMS / MOLES) total_mass += product return total_mass
def composition( formula: str, mass: Measurement = grams('1.000')) -> [Component]: composition = Composition() elements = parse_formula(formula).flatten() _molar_mass = molar_mass(elements) for element in elements: count, symbol = element _mass_percent = molar_mass(symbol) / _molar_mass _mass_percent = _mass_percent.value.decimal() * int(count) _mass = mass * _mass_percent _mass_percent = round(_mass_percent * 100, 2) composition.append(Component(count, symbol, _mass, _mass_percent)) return composition
def test_parse_formula_Fe2O3_combined_with_H2O(): actual = parse_formula('Fe2O3*[3/2]H2O') expected = FormulaRoot('Fe2O3*[3/2]H2O', []) expected.children.append( FormulaNode(Count(1), 'Fe2O3', FormulaNodeType.COMPOUND, [ FormulaNode(Count(2), 'Fe', FormulaNodeType.ATOM, []), FormulaNode(Count(3), 'O', FormulaNodeType.ATOM, []) ])) expected.children.append( FormulaNode(Count('1.5'), 'H2O', FormulaNodeType.COMPOUND, [ FormulaNode(Count(2), 'H', FormulaNodeType.ATOM, []), FormulaNode(Count(1), 'O', FormulaNodeType.ATOM, []) ])) assert actual == expected
def test_flatten_formula_Fe2O3_combined_with_H2O(): actual = parse_formula('Fe2O3*[3/2]H2O').flatten() expected = [(Count(2), 'Fe'), (Count('9/2'), 'O'), (Count(3), 'H')] assert actual == expected