CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-periodictable

Extensible periodic table of the elements with support for mass, density and X-ray/neutron scattering information

Pending
Overview
Eval results
Files

formulas.mddocs/

Chemical Formulas

Parse chemical formulas, calculate molecular properties, create mixtures by weight or volume, and perform isotope substitutions with full support for composite material calculations and property estimation.

Capabilities

Formula Parsing

Parse chemical formula strings into Formula objects with automatic composition analysis and property calculation capabilities.

def formula(compound: str = None, density: float = None, 
           natural_density: float = None, name: str = None,
           table: PeriodicTable = None) -> Formula:
    """
    Parse chemical formula string into Formula object.
    
    Args:
        compound: Chemical formula string (e.g., 'H2O', 'CaCO3', 'C6H12O6')
        density: Known density in g/cm³
        natural_density: Density with natural isotope abundances
        name: Descriptive name for the compound
        table: Custom periodic table to use for parsing
        
    Returns:
        Formula object with composition and properties
    """

Usage examples:

import periodictable as pt

# Simple molecules
water = pt.formula("H2O")
methane = pt.formula("CH4") 
glucose = pt.formula("C6H12O6")

# Complex formulas with parentheses
calcium_phosphate = pt.formula("Ca3(PO4)2")
hydrated_salt = pt.formula("CuSO4·5H2O", name="Copper sulfate pentahydrate")

# With known density
quartz = pt.formula("SiO2", density=2.65, name="Quartz")

# Isotope-specific formulas
heavy_water = pt.formula("D2O", name="Heavy water")
carbon13_methane = pt.formula("13CH4")

# Formula with charges
sodium_chloride = pt.formula("NaCl")  # Neutral overall

Mixture Creation by Weight

Create homogeneous mixtures by specifying weight percentages of different materials with automatic density and property calculations.

def mix_by_weight(*args, density: float = None, 
                 natural_density: float = None, name: str = None,
                 table: PeriodicTable = None) -> Formula:
    """
    Create mixture apportioned by weight percentages.
    
    Args:
        *args: Alternating formula/weight pairs (formula1, weight1, formula2, weight2, ...)
        density: Known density of mixture
        natural_density: Density with natural abundances
        name: Descriptive name for mixture
        table: Custom periodic table
        
    Returns:
        Formula representing the mixture
    """

Usage examples:

import periodictable as pt

# Simple mixture: 80% H2O, 20% D2O by weight
water_mixture = pt.mix_by_weight("H2O", 80, "D2O", 20, name="Mixed water")

# Complex mixture
steel_alloy = pt.mix_by_weight(
    "Fe", 95.0,      # 95% iron
    "C", 0.8,        # 0.8% carbon  
    "Mn", 2.0,       # 2% manganese
    "Si", 1.2,       # 1.2% silicon
    "Cr", 1.0,       # 1% chromium
    density=7.85,
    name="Carbon steel"
)

# Using Formula objects
concrete_mix = pt.mix_by_weight(
    pt.formula("Ca(OH)2"), 15,    # Lime
    pt.formula("SiO2"), 60,       # Silica
    pt.formula("Al2O3"), 25,      # Alumina  
    name="Concrete mixture"
)

print(f"Steel composition: {steel_alloy.atoms}")
print(f"Steel density: {steel_alloy.density} g/cm³")

Mixture Creation by Volume

Create homogeneous mixtures by specifying volume percentages with density calculations based on component volumes.

def mix_by_volume(*args, density: float = None,
                 natural_density: float = None, name: str = None,
                 table: PeriodicTable = None) -> Formula:
    """
    Create mixture apportioned by volume percentages.
    
    Args:
        *args: Alternating formula/volume pairs (formula1, vol1, formula2, vol2, ...)
        density: Known density of mixture  
        natural_density: Density with natural abundances
        name: Descriptive name for mixture
        table: Custom periodic table
        
    Returns:
        Formula representing the mixture
    """

Usage examples:

import periodictable as pt

# Air composition by volume
air = pt.mix_by_volume(
    "N2", 78.08,      # Nitrogen
    "O2", 20.95,      # Oxygen
    "Ar", 0.93,       # Argon
    "CO2", 0.04,      # Carbon dioxide
    name="Air at STP"
)

# Liquid mixture
ethanol_water = pt.mix_by_volume(
    pt.formula("C2H5OH", density=0.789), 40,  # 40% ethanol by volume
    pt.formula("H2O", density=1.0), 60,       # 60% water by volume
    name="40% ethanol solution"
)

print(f"Air molecular composition: {air.hill}")
print(f"Ethanol solution density: {ethanol_water.density:.3f} g/cm³")

Formula Properties and Calculations

Access comprehensive molecular properties including mass, charge, composition analysis, and derived quantities.

class Formula:
    """Chemical formula with composition and property calculations."""
    
    # Core composition
    atoms: dict                    # Dictionary mapping atoms to counts
    mass: float                   # Molecular mass in atomic mass units (u)
    molecular_mass: float         # Molecular mass in grams
    
    # Physical properties  
    density: float                # Mass density in g/cm³
    natural_density: float        # Density with natural isotopes
    
    # Chemical properties
    charge: int                   # Net electrical charge
    hill: str                    # Formula in Hill notation (C, H, others alphabetical)
    
    # Composition analysis
    mass_fraction: dict          # Fractional mass of each component
    
    def natural_mass_ratio(self) -> float:
        """Ratio of natural to isotope-substituted mass."""

Usage examples:

import periodictable as pt

# Create and analyze glucose
glucose = pt.formula("C6H12O6", density=1.54)

# Basic properties
print(f"Molecular formula: {glucose.hill}")           # C6H12O6
print(f"Molecular mass: {glucose.mass:.2f} u")        # 180.16 u
print(f"Mass in grams: {glucose.molecular_mass:.2e} g") # 2.99e-22 g
print(f"Density: {glucose.density} g/cm³")            # 1.54

# Composition analysis
print("Mass fractions:")
for atom, fraction in glucose.mass_fraction.items():
    print(f"  {atom.symbol}: {fraction:.3f}")

# Atomic composition  
print("Atomic composition:")
for atom, count in glucose.atoms.items():
    print(f"  {atom.symbol}: {count}")

# For charged species
salt = pt.formula("Na+Cl-")  # Conceptual - parser handles neutral compounds
print(f"Net charge: {salt.charge}")  # 0 (neutral overall)

Isotope Substitution

Replace specific elements with isotopes to study isotope effects on properties and scattering characteristics.

def replace(self, source, target, portion: float = 1) -> 'Formula':
    """
    Create new formula with isotope substitution.
    
    Args:
        source: Element to replace (Element, Isotope, or Ion)
        target: Replacement isotope/element
        portion: Fraction to replace (0-1, default 1 for complete)
        
    Returns:
        New Formula with substitution applied
    """

Usage examples:

import periodictable as pt

# Deuteration of water
water = pt.formula("H2O")
heavy_water = water.replace(pt.H, pt.D)  # Replace all H with D
print(f"H2O mass: {water.mass:.3f} u")         # ~18.015 u
print(f"D2O mass: {heavy_water.mass:.3f} u")   # ~20.028 u

# Partial deuteration (50%)
partial_d2o = water.replace(pt.H, pt.D, portion=0.5)
print(f"50% deuterated mass: {partial_d2o.mass:.3f} u")

# Carbon-13 labeling in glucose
glucose = pt.formula("C6H12O6")
c13_glucose = glucose.replace(pt.C, pt.C[13])  # All carbon to C-13
print(f"Natural glucose: {glucose.mass:.3f} u")
print(f"C-13 glucose: {c13_glucose.mass:.3f} u")

# Partial labeling
glucose_1c13 = glucose.replace(pt.C, pt.C[13], portion=1/6)  # One C-13
print(f"One C-13 glucose: {glucose_1c13.mass:.3f} u")

Volume and Density Estimation

Estimate molecular volumes and densities using crystallographic data and packing factors for materials without known densities.

def volume(self, packing_factor: str = None, **kwargs) -> float:
    """
    Estimate unit cell volume using atomic radii and packing factors.
    
    Args:
        packing_factor: Crystal structure ('cubic', 'fcc', 'bcc', 'hcp', 'diamond')
        **kwargs: Additional crystallographic parameters
        
    Returns:
        Estimated volume in Ų
    """

Available packing factors and their values:

PACKING_FACTORS = {
    'cubic': π/6,                 # Simple cubic (52.4%)
    'bcc': π*√3/8,               # Body-centered cubic (68.0%) 
    'fcc': π/√18,                # Face-centered cubic (74.0%)
    'hcp': π/√18,                # Hexagonal close-packed (74.0%)
    'diamond': π*√3/16           # Diamond structure (34.0%)
}

Usage examples:

import periodictable as pt

# Estimate volume for different crystal structures
silicon = pt.formula("Si")

# Different packing assumptions
vol_diamond = silicon.volume(packing_factor='diamond')  # Diamond structure
vol_fcc = silicon.volume(packing_factor='fcc')          # FCC assumption

print(f"Si diamond structure volume: {vol_diamond:.2f} Ų")
print(f"Si FCC structure volume: {vol_fcc:.2f} Ų")

# For compounds - estimates based on component radii
nacl = pt.formula("NaCl")
nacl_volume = nacl.volume(packing_factor='cubic')
print(f"NaCl estimated volume: {nacl_volume:.2f} Ų")

# Compare with known density
quartz = pt.formula("SiO2", density=2.65)
estimated_vol = quartz.volume()
actual_vol = quartz.mass / (quartz.density * 6.022e23) * 1e24  # Convert to Ų
print(f"SiO2 estimated volume: {estimated_vol:.2f} Ų")
print(f"SiO2 actual volume: {actual_vol:.2f} Ų")

Table Management

Switch formulas between different periodic tables and access custom element data for specialized calculations.

def change_table(self, table: PeriodicTable) -> 'Formula':
    """
    Create equivalent formula using different periodic table.
    
    Args:
        table: Target periodic table with custom data
        
    Returns:
        New Formula using the specified table
    """

Usage examples:

import periodictable as pt
from periodictable.core import PeriodicTable

# Create custom table with modified properties
custom_table = PeriodicTable()
# ... customize table properties ...

# Convert formula to use custom table
water = pt.formula("H2O")
custom_water = water.change_table(custom_table)

print(f"Original table: {water.atoms[pt.H].mass}")
print(f"Custom table: {custom_water.atoms[custom_table.H].mass}")

Utility Functions

Additional functions for formula parsing, composition analysis, and formatting for different output formats.

def count_elements(compound, by_isotope: bool = False) -> dict:
    """
    Count elements in a compound without creating Formula object.
    
    Args:
        compound: Formula string or Formula object
        by_isotope: Count isotopes separately if True
        
    Returns:
        Dictionary of element/isotope counts
    """

def pretty(compound, mode: str = 'unicode') -> str:
    """
    Format chemical formula with subscripts and superscripts.
    
    Args:
        compound: Formula string or Formula object
        mode: Output format ('unicode', 'html', 'latex')
        
    Returns:
        Formatted formula string
    """

def parse_formula(formula_str: str, table: PeriodicTable = None) -> list:
    """
    Parse formula string into list of (element, count) tuples.
    
    Args:
        formula_str: Chemical formula string
        table: Periodic table to use for parsing
        
    Returns:
        List of (atom, count) tuples
    """

Usage examples:

import periodictable as pt
from periodictable.formulas import count_elements, pretty, parse_formula

# Count elements
glucose_counts = count_elements("C6H12O6")
print(glucose_counts)  # {'C': 6, 'H': 12, 'O': 6}

# Format with subscripts
water_pretty = pretty("H2O")
print(water_pretty)  # H₂O (with Unicode subscripts)

caffeine_pretty = pretty("C8H10N4O2", mode='html')  
print(caffeine_pretty)  # C<sub>8</sub>H<sub>10</sub>N<sub>4</sub>O<sub>2</sub>

# Parse formula structure
parsed = parse_formula("Ca(OH)2")
print(parsed)  # [(Ca, 1), (O, 2), (H, 2)]

Types

class Formula:
    """Chemical formula with composition and property calculations."""
    atoms: dict
    mass: float
    molecular_mass: float
    density: float
    natural_density: float
    charge: int
    hill: str
    mass_fraction: dict
    def replace(self, source, target, portion: float = 1) -> 'Formula': ...
    def volume(self, packing_factor: str = None, **kwargs) -> float: ...
    def change_table(self, table: PeriodicTable) -> 'Formula': ...
    def natural_mass_ratio(self) -> float: ...
    def neutron_sld(self, wavelength: float = None, energy: float = None) -> tuple: ...
    def xray_sld(self, energy: float = None, wavelength: float = None) -> tuple: ...

PACKING_FACTORS: dict = {
    'cubic': float,
    'bcc': float, 
    'fcc': float,
    'hcp': float,
    'diamond': float
}

Install with Tessl CLI

npx tessl i tessl/pypi-periodictable

docs

constants-utilities.md

elements.md

formulas.md

index.md

neutron-scattering.md

xray-scattering.md

tile.json