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

constants-utilities.mddocs/

Constants and Utilities

Fundamental physical constants, crystallographic calculations, uncertainty parsing, periodic table data visualization tools, and biomolecule support for scientific applications.

Capabilities

Physical Constants

Fundamental physical constants used throughout the periodictable package for calculations and unit conversions.

# From periodictable.constants module
avogadro_number: float = 6.02214076e23      # Avogadro's number (mol⁻¹)
planck_constant: float = 6.62607015e-34     # Planck constant (J⋅Hz⁻¹)
electron_volt: float = 1.602176634e-19      # Electron volt (J/eV)  
speed_of_light: float = 299792458           # Speed of light (m/s)
electron_radius: float = 2.8179403205e-15   # Classical electron radius (m)
neutron_mass: float = 1.00866491606         # Neutron mass (u)
atomic_mass_constant: float = 1.66053906892e-27  # Atomic mass unit (kg/u)
electron_mass: float = 5.485799090441e-4    # Electron mass (u)

Usage examples:

from periodictable.constants import *
import periodictable as pt

# Unit conversions
print(f"Avogadro's number: {avogadro_number:.6e} mol⁻¹")
print(f"eV to Joules: {electron_volt:.6e} J/eV")
print(f"Speed of light: {speed_of_light} m/s")

# Molecular mass calculations
water = pt.formula("H2O")
mass_grams = water.mass * atomic_mass_constant * 1000  # Convert to grams
molecules_per_mole = avogadro_number
molar_mass = mass_grams * molecules_per_mole
print(f"Water molar mass: {molar_mass:.2f} g/mol")

# Energy calculations
lambda_cu = 1.5418  # Å, Cu K-alpha
energy_joules = planck_constant * speed_of_light / (lambda_cu * 1e-10)
energy_ev = energy_joules / electron_volt
energy_kev = energy_ev / 1000
print(f"Cu K-alpha: {lambda_cu} Å = {energy_kev:.3f} keV")

# Classical electron radius in X-ray calculations
print(f"Electron radius: {electron_radius:.6e} m")

Crystallographic Utilities

Calculate unit cell volumes and properties for crystallographic applications and density estimations.

def cell_volume(a: float = None, b: float = None, c: float = None,
               alpha: float = None, beta: float = None, 
               gamma: float = None) -> float:
    """
    Calculate crystallographic unit cell volume.
    
    Args:
        a, b, c: Unit cell lengths in Ångström
        alpha, beta, gamma: Unit cell angles in degrees
        
    Returns:
        Unit cell volume in ų (cubic Ångström)
        
    Note:
        For cubic: provide a only
        For tetragonal: provide a, c
        For orthorhombic: provide a, b, c
        For hexagonal: provide a, c (gamma=120° assumed)
        For general case: provide all parameters
    """

Usage examples:

from periodictable.util import cell_volume
import math

# Cubic crystal (e.g., simple cubic silicon)
a_cubic = 5.43  # Å, silicon lattice parameter
vol_cubic = cell_volume(a=a_cubic)
print(f"Cubic Si unit cell: {vol_cubic:.2f} ų")

# Face-centered cubic (real silicon structure)
a_fcc = 5.43  # Å
vol_fcc = cell_volume(a=a_fcc)  # Same as cubic for FCC primitive cell
atoms_per_unit_cell = 8  # FCC has 8 atoms per conventional cell
vol_per_atom = vol_fcc / atoms_per_unit_cell
print(f"Si volume per atom: {vol_per_atom:.2f} ų/atom")

# Hexagonal (e.g., graphite)
a_hex = 2.46  # Å
c_hex = 6.71  # Å  
vol_hex = cell_volume(a=a_hex, c=c_hex, gamma=120)
print(f"Hexagonal graphite: {vol_hex:.2f} ų")

# Orthorhombic
a_ortho, b_ortho, c_ortho = 4.0, 5.0, 6.0  # Å
vol_ortho = cell_volume(a=a_ortho, b=b_ortho, c=c_ortho)
print(f"Orthorhombic cell: {vol_ortho:.2f} ų")

# General triclinic case  
vol_triclinic = cell_volume(a=5.0, b=6.0, c=7.0, 
                           alpha=85, beta=90, gamma=95)
print(f"Triclinic cell: {vol_triclinic:.2f} ų")

# Density calculation from unit cell
silicon = pt.formula("Si")
atoms_per_cell = 8  # Diamond cubic
cell_vol_cm3 = vol_cubic * 1e-24  # Convert ų to cm³
mass_per_cell = atoms_per_cell * silicon.mass * 1.66054e-24  # u to g
calculated_density = mass_per_cell / cell_vol_cm3
print(f"Calculated Si density: {calculated_density:.2f} g/cm³")

Uncertainty Parsing

Parse scientific notation with uncertainties in parenthetical format commonly used in scientific literature.

def parse_uncertainty(s: str) -> tuple:
    """
    Parse uncertainty notation like "23.0035(12)" into value and uncertainty.
    
    Args:
        s: String with uncertainty notation
        
    Returns:
        tuple: (value, uncertainty) as floats
        
    Examples:
        "23.0035(12)" -> (23.0035, 0.0012)
        "1.234(5)" -> (1.234, 0.005)  
        "456.78(123)" -> (456.78, 1.23)
    """

Usage examples:

from periodictable.util import parse_uncertainty

# Scientific measurements with uncertainties
measurements = [
    "23.0035(12)",      # NIST atomic mass format
    "1.234(5)",         # Standard uncertainty notation
    "456.78(123)",      # Large uncertainty
    "0.0012345(67)",    # Small values
    "1234567(89)"       # Integer-like with uncertainty
]

print("Parsed uncertainties:")
for measurement in measurements:
    value, uncertainty = parse_uncertainty(measurement)
    print(f"{measurement:12s} -> {value} ± {uncertainty}")

# Use in atomic mass calculations
import periodictable as pt

# Simulate parsing atomic mass with uncertainty
mass_string = "55.845(2)"  # Iron atomic mass with uncertainty
mass_value, mass_uncertainty = parse_uncertainty(mass_string)

print(f"\nIron atomic mass: {mass_value} ± {mass_uncertainty} u")
print(f"Relative uncertainty: {mass_uncertainty/mass_value:.2e}")

# Error propagation example
iron = pt.Fe
print(f"Tabulated Fe mass: {iron.mass} u")
print(f"Difference from parsed: {abs(iron.mass - mass_value):.6f} u")

Periodic Table Visualization

Create visual representations and formatted tables of periodic table data for analysis and presentation.

def table_plot(data, form: str = "line", label: str = None, 
              title: str = None) -> None:
    """
    Plot periodic table data in various formats.
    
    Args:
        data: Dictionary mapping elements to values, or property name string
        form: Plot type ("line", "bar", "scatter", "table")
        label: Y-axis label for the data
        title: Plot title
        
    Note:
        Requires matplotlib for plotting functionality
    """

Usage examples:

from periodictable.plot import table_plot
import periodictable as pt

# Plot atomic masses
try:
    mass_data = {el: el.mass for el in pt.elements if el.mass}
    table_plot(mass_data, form="line", label="Atomic Mass (u)", 
              title="Atomic Masses vs Atomic Number")

    # Plot densities  
    density_data = {el: el.density for el in pt.elements 
                   if el.density and el.number <= 86}
    table_plot(density_data, form="scatter", label="Density (g/cm³)",
              title="Element Densities")

    # Plot covalent radii (triggers lazy loading)
    radii_data = {}
    for el in pt.elements:
        if el.number <= 54:  # First few periods
            try:
                radii_data[el] = el.covalent_radius
            except (AttributeError, TypeError):
                pass
    
    table_plot(radii_data, form="bar", label="Covalent Radius (Å)",
              title="Covalent Radii")

except ImportError:
    print("Matplotlib required for plotting")

# Create data tables without plotting
elements_subset = [pt.H, pt.He, pt.Li, pt.Be, pt.B, pt.C, pt.N, pt.O]
print("Light element properties:")
print("El  Mass     Density")
for el in elements_subset:
    density = el.density if el.density else "N/A"
    print(f"{el.symbol:2s} {el.mass:8.4f} {density}")

Biomolecule Support

Support for biological molecules including amino acids, nucleic acids, and common biochemical compounds with labile hydrogen tracking.

# From periodictable.fasta module
class Molecule:
    """Biomolecule with labile hydrogen support for deuteration studies."""
    
    def __init__(self, formula: str = None, name: str = None, 
                labile: int = 0, charge: int = 0):
        """
        Args:
            formula: Chemical formula
            name: Molecule name
            labile: Number of labile hydrogens
            charge: Net charge
        """

class Sequence(Molecule):
    """Read amino acid and DNA/RNA sequences from FASTA-like strings."""
    
    def __init__(self, sequence: str, molecule_type: str = "protein"):
        """
        Args:
            sequence: FASTA sequence string
            molecule_type: "protein", "DNA", or "RNA"
        """

# Standard biochemical data
AMINO_ACID_CODES: dict       # 20 standard amino acids by single letter
RNA_CODES: dict              # RNA nucleotides (A, U, G, C)
DNA_CODES: dict              # DNA nucleotides (A, T, G, C)
RNA_BASES: dict              # Individual RNA bases
DNA_BASES: dict              # Individual DNA bases
NUCLEIC_ACID_COMPONENTS: dict # Nucleic acid molecular components
LIPIDS: dict                 # Common lipid molecules
CARBOHYDRATE_RESIDUES: dict  # Sugar and carbohydrate units

# Reference SLD values
H2O_SLD: float = -0.5603     # H2O neutron SLD at 20°C (10⁻⁶ Ų⁻²)
D2O_SLD: float = 6.3350      # D2O neutron SLD at 20°C (10⁻⁶ Ų⁻²)

Usage examples:

from periodictable.fasta import *
import periodictable as pt

# Amino acids
print("Standard amino acids:")
for code, amino_acid in list(AMINO_ACID_CODES.items())[:5]:
    print(f"{code}: {amino_acid.name} - {amino_acid.formula}")

# Create peptide sequence
peptide_seq = "MVLSPADKTNVKAAW"  # Sample sequence
protein = Sequence(peptide_seq, molecule_type="protein")
print(f"\nPeptide formula: {protein.formula}")
print(f"Molecular mass: {protein.mass:.2f} u")

# DNA sequence  
dna_seq = "ATCGATCGATCG"
dna = Sequence(dna_seq, molecule_type="DNA")
print(f"DNA formula: {dna.formula}")

# Labile hydrogen tracking for deuteration
# Water molecules
h2o = Molecule("H2O", labile=2)  # Both H are labile
print(f"H2O labile H: {h2o.labile}")

# Reference SLD values for contrast calculations
print(f"\nSolvent SLD values:")
print(f"H2O: {H2O_SLD:.4f} × 10⁻⁶ Ų⁻²")
print(f"D2O: {D2O_SLD:.4f} × 10⁻⁶ Ų⁻²")
print(f"Contrast: {D2O_SLD - H2O_SLD:.4f} × 10⁻⁶ Ų⁻²")

# Lipids and carbohydrates
print("\nBiochemical molecules:")
for name, molecule in list(LIPIDS.items())[:3]:
    print(f"{name}: {molecule.formula}")

for name, molecule in list(CARBOHYDRATE_RESIDUES.items())[:3]:
    print(f"{name}: {molecule.formula}")

Activation Analysis Support

Support for neutron activation analysis calculations including sample preparation and flux environment modeling.

# From periodictable.activation module  
class Sample:
    """Neutron activation sample with composition and irradiation history."""
    
    def __init__(self, formula, mass: float = None, name: str = None):
        """
        Args:
            formula: Sample chemical formula
            mass: Sample mass in grams
            name: Sample identifier
        """

class ActivationEnvironment:
    """Neutron flux environment for activation calculations."""
    
    def __init__(self, flux: float, energy: str = "thermal"):
        """
        Args:
            flux: Neutron flux in n/cm²/s
            energy: Neutron energy spectrum ("thermal", "epithermal", "fast")
        """

class ActivationResult:
    """Results from neutron activation calculations."""
    
    @property
    def activity(self) -> dict:
        """Activities by isotope in Bq."""
    
    @property  
    def dose_rate(self) -> float:
        """Dose rate in μSv/hr at 1m."""

Usage examples:

from periodictable.activation import *
import periodictable as pt

# Create sample for activation analysis
steel_sample = Sample("Fe + 0.8%C + 2%Mn", mass=10.0, name="Steel sample")
aluminum_sample = Sample("Al", mass=5.0, name="Al foil")

# Define neutron environment
reactor_flux = ActivationEnvironment(flux=1e13, energy="thermal")  # n/cm²/s
print(f"Reactor thermal flux: {reactor_flux.flux:.0e} n/cm²/s")

# Calculate activation (conceptual - requires specific implementation)
print(f"Steel sample: {steel_sample.formula}")
print(f"Sample mass: {steel_sample.mass} g")
print(f"Environment: {reactor_flux.energy} neutrons")

Core Utility Functions

Essential utility functions for working with periodic table objects, managing custom tables, and type checking atomic objects.

# Table management functions
def default_table(table=None) -> PeriodicTable:
    """Return the default periodic table unless a specific table is requested."""

def change_table(atom, table) -> Union[Element, Isotope, Ion]:
    """Get the same element, isotope, or ion from a different periodic table."""

# Type checking functions  
def isatom(val) -> bool:
    """Test if value is any atomic object (element, isotope, or ion)."""

def iselement(val) -> bool:
    """Test if value is an element (not isotope or ion)."""

def isisotope(val) -> bool:
    """Test if value is an isotope."""

def ision(val) -> bool:
    """Test if value is an ion."""

Usage examples:

import periodictable as pt
from periodictable.core import (default_table, change_table, 
                               isatom, iselement, isisotope, ision)

# Table management
default = default_table()  # Get the standard table
print(f"Default table contains {len(list(default))} elements")

# Custom table workflow (conceptual)
# custom_table = create_custom_table()  # User-defined table
iron_default = pt.Fe
# iron_custom = change_table(iron_default, custom_table)

# Type checking for safe operations
iron = pt.Fe
iron56 = pt.Fe[56]
iron2_ion = pt.Fe.ion[2]

print(f"Iron is atom: {isatom(iron)}")           # True
print(f"Iron is element: {iselement(iron)}")     # True  
print(f"Iron-56 is isotope: {isisotope(iron56)}")  # True
print(f"Fe²⁺ is ion: {ision(iron2_ion)}")         # True

# Safe property access patterns  
def get_mass_info(atom_obj):
    """Safely extract mass information from any atomic object."""
    if isatom(atom_obj):
        mass = atom_obj.mass
        if isisotope(atom_obj):
            return f"Isotope {atom_obj.symbol}-{atom_obj.isotope}: {mass:.4f} u"
        elif ision(atom_obj):
            charge_sign = "+" if atom_obj.charge > 0 else ""
            return f"Ion {atom_obj.symbol}{charge_sign}{atom_obj.charge}: {mass:.4f} u"
        else:
            return f"Element {atom_obj.symbol}: {mass:.4f} u"
    else:
        return "Not an atomic object"

# Test type checking
for obj in [iron, iron56, iron2_ion, "not_atom"]:
    print(get_mass_info(obj))

Types

# Constants (all float values)
avogadro_number: float
planck_constant: float  
electron_volt: float
speed_of_light: float
electron_radius: float
neutron_mass: float
atomic_mass_constant: float
electron_mass: float

# Biomolecule data (all dict mappings)
AMINO_ACID_CODES: dict
RNA_CODES: dict
DNA_CODES: dict
RNA_BASES: dict
DNA_BASES: dict
NUCLEIC_ACID_COMPONENTS: dict
LIPIDS: dict
CARBOHYDRATE_RESIDUES: dict

# Reference values
H2O_SLD: float
D2O_SLD: float

class Molecule:
    """Biomolecule with labile hydrogen tracking."""
    formula: str
    name: str
    labile: int
    charge: int
    mass: float

class Sequence(Molecule):
    """Biological sequence (protein, DNA, RNA)."""
    def __init__(self, sequence: str, molecule_type: str = "protein"): ...

class Sample:
    """Activation analysis sample."""
    formula: str
    mass: float
    name: str

class ActivationEnvironment:
    """Neutron flux environment."""
    flux: float
    energy: str

class ActivationResult:
    """Activation calculation results."""
    @property
    def activity(self) -> dict: ...
    @property  
    def dose_rate(self) -> 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