Source code for epyr.physics.constants

"""
Physical constants for EPR/NMR spectroscopy
All values from 2022 CODATA recommendations with proper units and uncertainties
Constants available in both SI and CGS units.
"""

from typing import Optional, Tuple, Union

import numpy as np

try:
    from ..logging_config import get_logger
except ImportError:
    import logging

    def get_logger(name):
        return logging.getLogger(name)


logger = get_logger(__name__)


# ============================================================================
# FUNDAMENTAL PHYSICAL CONSTANTS (2022 CODATA) - SI Units
# ============================================================================

# Free electron g-factor (dimensionless)
# The g-factor relates the magnetic moment to the angular momentum
# for a free electron: μ = -g μ_B S/ℏ
# 2022 CODATA recommended values
GFREE = 2.00231930436092

# Bohr magneton in SI units (J T⁻¹)
# The fundamental quantum of magnetic moment for an electron.
# μ_B = eℏ/(2m_e)
# 2022 CODATA recommended values
BMAGN = 9.2740100657e-24  # J T⁻¹

# Planck constant in SI units (J⋅s = J⋅Hz⁻¹)
# Fundamental constant relating energy to frequency: E = hν
# Exact value since 2019 SI redefinition.
PLANCK = 6.62607015e-34  # J⋅s

# Reduced Planck constant ℏ = h/(2π) in SI units (J⋅s)
HBAR = PLANCK / (2 * np.pi)

# Speed of light in vacuum in SI units (m⋅s⁻¹)
# Exact value by definition since 1983.
CLIGHT = 299792458  # m⋅s⁻¹

# Boltzmann constant in SI units (J⋅K⁻¹)
# Relates temperature to energy: E = k_B T
# Exact value since 2019 SI redefinition.
BOLTZM = 1.380649e-23  # J⋅K⁻¹ (exact)

# Avogadro constant in SI units (mol⁻¹)
# Number of constituent particles per mole.
# Exact value since 2019 SI redefinition.
AVOGADRO = 6.02214076e23  # mol⁻¹ (exact)

# Nuclear magneton in SI units (J⋅T⁻¹)
# Fundamental quantum of magnetic moment for nucleons.
# μ_N = eℏ/(2m_p) where m_p is the proton mass.
# 2022 CODATA recommended values
NMAGN = 5.0507837393e-27  # J⋅T⁻¹

# Elementary charge in SI units (C)
# Exact value since 2019 SI redefinition
ECHARGE = 1.602176634e-19  # C (exact)

# Electron volt in SI units (J)
# Energy equivalent to one electron volt: 1 eV = e × 1 V
# Exact since charge is exact
EVOLT = ECHARGE  # J


# ============================================================================
# FUNDAMENTAL PHYSICAL CONSTANTS - CGS Units
# ============================================================================

# Free electron g-factor (dimensionless, same in all unit systems)
GFREE_CGS = GFREE

# Bohr magneton in CGS units (erg G⁻¹)
# Conversion: 1 J T⁻¹ = 1000 erg G⁻¹
BMAGN_CGS = BMAGN * 1000  # erg G⁻¹

# Planck constant in CGS units (erg⋅s)
# Conversion: 1 J = 1e7 erg
PLANCK_CGS = PLANCK * 1e7  # erg⋅s

# Reduced Planck constant ℏ = h/(2π) in CGS units (erg⋅s)
HBAR_CGS = PLANCK_CGS / (2 * np.pi)

# Speed of light in vacuum in CGS units (cm⋅s⁻¹)
# Conversion: 1 m = 100 cm
CLIGHT_CGS = CLIGHT * 100  # cm⋅s⁻¹

# Boltzmann constant in CGS units (erg⋅K⁻¹)
# Conversion: 1 J = 1e7 erg
BOLTZM_CGS = BOLTZM * 1e7  # erg⋅K⁻¹

# Avogadro constant in CGS units (mol⁻¹, same in all unit systems)
AVOGADRO_CGS = AVOGADRO

# Nuclear magneton in CGS units (erg⋅G⁻¹)
# Conversion: 1 J T⁻¹ = 1000 erg G⁻¹
NMAGN_CGS = NMAGN * 1000  # erg⋅G⁻¹

# Elementary charge in CGS units (esu, same as statcoulomb)
# Conversion: 1 C = 2.997924580e9 esu (from c in units)
ECHARGE_CGS = ECHARGE * 2.997924580e9  # esu

# Electron volt in CGS units (erg)
# Conversion: 1 J = 1e7 erg
EVOLT_CGS = EVOLT * 1e7  # erg


# ============================================================================
# BACKWARD COMPATIBILITY FUNCTIONS
# ============================================================================


[docs] def gfree(return_uncertainty: bool = False) -> Union[float, Tuple[float, float]]: """ Free electron g-factor (dimensionless). Parameters: ----------- return_uncertainty : bool If True, return (value, standard_uncertainty) Returns: -------- float or tuple Free electron g-factor (dimensionless) References: ----------- 2022 CODATA recommended values """ uncertainty = 0.00000000000036 if return_uncertainty: return GFREE, uncertainty return GFREE
[docs] def bmagn(return_uncertainty: bool = False) -> Union[float, Tuple[float, float]]: """ Bohr magneton in SI units (J T⁻¹). Parameters: ----------- return_uncertainty : bool If True, return (value, standard_uncertainty) Returns: -------- float or tuple Bohr magneton in J T⁻¹ References: ----------- 2022 CODATA recommended values """ uncertainty = 0.0000000029e-24 if return_uncertainty: return BMAGN, uncertainty return BMAGN
[docs] def planck() -> float: """ Planck constant in SI units (J⋅s = J⋅Hz⁻¹). Returns: -------- float Planck constant in J⋅s References: ----------- 2019 SI redefinition, exact value """ return PLANCK
[docs] def hbar() -> float: """ Reduced Planck constant ℏ = h/(2π) in SI units (J⋅s). Returns: -------- float Reduced Planck constant in J⋅s """ return HBAR
[docs] def clight() -> float: """ Speed of light in vacuum in SI units (m⋅s⁻¹). Returns: -------- float Speed of light in m⋅s⁻¹ References: ----------- 1983 SI redefinition, exact value """ return CLIGHT
[docs] def boltzm(return_uncertainty: bool = False) -> Union[float, Tuple[float, float]]: """ Boltzmann constant in SI units (J⋅K⁻¹). Parameters: ----------- return_uncertainty : bool If True, return (value, standard_uncertainty) Returns: -------- float or tuple Boltzmann constant in J⋅K⁻¹ References: ----------- 2019 SI redefinition, exact value """ if return_uncertainty: return BOLTZM, 0.0 # Exact since 2019 return BOLTZM
[docs] def avogadro(return_uncertainty: bool = False) -> Union[float, Tuple[float, float]]: """ Avogadro constant in SI units (mol⁻¹). Parameters: ----------- return_uncertainty : bool If True, return (value, standard_uncertainty) Returns: -------- float or tuple Avogadro constant in mol⁻¹ References: ----------- 2019 SI redefinition, exact value """ if return_uncertainty: return AVOGADRO, 0.0 # Exact since 2019 return AVOGADRO
[docs] def nmagn(return_uncertainty: bool = False) -> Union[float, Tuple[float, float]]: """ Nuclear magneton in SI units (J⋅T⁻¹). Parameters: ----------- return_uncertainty : bool If True, return (value, standard_uncertainty) Returns: -------- float or tuple Nuclear magneton in J⋅T⁻¹ References: ----------- 2022 CODATA recommended values """ uncertainty = 0.0000000016e-27 if return_uncertainty: return NMAGN, uncertainty return NMAGN
[docs] def echarge(return_uncertainty: bool = False) -> Union[float, Tuple[float, float]]: """ Elementary charge in SI units (C). Parameters: ----------- return_uncertainty : bool If True, return (value, standard_uncertainty) Returns: -------- float or tuple Elementary charge in C References: ----------- 2019 SI redefinition, exact value """ if return_uncertainty: return ECHARGE, 0.0 # Exact since 2019 return ECHARGE
[docs] def evolt(return_uncertainty: bool = False) -> Union[float, Tuple[float, float]]: """ Electron volt in SI units (J). Parameters: ----------- return_uncertainty : bool If True, return (value, standard_uncertainty) Returns: -------- float or tuple Electron volt in J References: ----------- 2019 SI redefinition, exact value (e × 1V) """ if return_uncertainty: return EVOLT, 0.0 # Exact since 2019 return EVOLT
# ============================================================================ # EPR-SPECIFIC FUNCTIONS # ============================================================================
[docs] def gamma_hz(g_factor: Optional[float] = None) -> float: """ Calculate gyromagnetic ratio in Hz/T for any g-factor. The gyromagnetic ratio relates frequency to magnetic field: ν = γ B where γ = g μ_B / h Parameters: ----------- g_factor : float, optional g-factor (defaults to free electron g-factor) Returns: -------- float Gyromagnetic ratio in Hz/T Examples: --------- >>> # Free electron gyromagnetic ratio >>> gamma_e = gamma_hz() >>> print(f"Free electron: {gamma_e:.3e} Hz/T") >>> # Custom g-factor >>> gamma_custom = gamma_hz(2.005) >>> print(f"g=2.005: {gamma_custom:.3e} Hz/T") >>> # Calculate resonance frequency >>> B = 0.34 # Tesla (X-band field) >>> freq = gamma_hz() * B >>> print(f"X-band frequency: {freq/1e9:.2f} GHz") """ if g_factor is None: g_factor = GFREE return g_factor * BMAGN / PLANCK
[docs] def magnetic_field_to_frequency( B_tesla: float, g_factor: Optional[float] = None ) -> float: """ Convert magnetic field to resonance frequency. Uses the fundamental EPR/NMR relation: ν = γB = gμ_B B/h Parameters: ----------- B_tesla : float Magnetic field in Tesla g_factor : float, optional g-factor (defaults to free electron g-factor) Returns: -------- float Resonance frequency in Hz Examples: --------- >>> # X-band EPR at ~9.5 GHz >>> B = 0.34 # Tesla >>> freq = magnetic_field_to_frequency(B) # Hz >>> print(f"Frequency: {freq/1e9:.2f} GHz") """ return gamma_hz(g_factor) * B_tesla
[docs] def frequency_to_magnetic_field( freq_hz: float, g_factor: Optional[float] = None ) -> float: """ Convert frequency to magnetic field. Parameters: ----------- freq_hz : float Frequency in Hz g_factor : float, optional g-factor (defaults to free electron g-factor) Returns: -------- float Magnetic field in Tesla Examples: --------- >>> # What field for 9.5 GHz EPR? >>> freq = 9.5e9 # Hz >>> B = frequency_to_magnetic_field(freq) >>> print(f"Magnetic field: {B*1000:.1f} mT") """ return freq_hz / gamma_hz(g_factor)
[docs] def thermal_energy(temperature_k: float) -> float: """ Thermal energy k_B T at given temperature. Parameters: ----------- temperature_k : float Temperature in Kelvin Returns: -------- float Thermal energy in J Examples: --------- >>> # Room temperature thermal energy >>> E_thermal = thermal_energy(295) # K >>> print(f"kT = {E_thermal/(1.602176634e-19):.3f} meV") """ return BOLTZM * temperature_k
[docs] def wavelength_to_frequency(wavelength_m: float) -> float: """ Convert wavelength to frequency. Parameters: ----------- wavelength_m : float Wavelength in meters Returns: -------- float Frequency in Hz Examples: --------- >>> # 3 cm microwave wavelength >>> freq = wavelength_to_frequency(0.03) # m >>> print(f"Frequency: {freq/1e9:.1f} GHz") """ return CLIGHT / wavelength_m
# ============================================================================ # PHYSICAL CONSTANTS SUMMARY # ============================================================================
[docs] def constants_summary(): """Print summary of all physical constants with units and values.""" logger.info("EPyR Tools Physical Constants") logger.info("=" * 50) logger.info("All values from 2022 CODATA recommendations") logger.info("") logger.info("SI Units:") si_constants = [ ("Free electron g-factor", GFREE, "dimensionless"), ("Bohr magneton", BMAGN, "J⋅T⁻¹"), ("Nuclear magneton", NMAGN, "J⋅T⁻¹"), ("Planck constant", PLANCK, "J⋅s"), ("Reduced Planck constant", HBAR, "J⋅s"), ("Speed of light", CLIGHT, "m⋅s⁻¹"), ("Boltzmann constant", BOLTZM, "J⋅K⁻¹"), ("Avogadro constant", AVOGADRO, "mol⁻¹"), ("Elementary charge", ECHARGE, "C"), ("Electron volt", EVOLT, "J"), ] for name, value, unit in si_constants: logger.info(f" {name:<30}: {value:.6e} {unit}") logger.info("") logger.info("CGS Units:") cgs_constants = [ ("Free electron g-factor", GFREE_CGS, "dimensionless"), ("Bohr magneton", BMAGN_CGS, "erg⋅G⁻¹"), ("Nuclear magneton", NMAGN_CGS, "erg⋅G⁻¹"), ("Planck constant", PLANCK_CGS, "erg⋅s"), ("Reduced Planck constant", HBAR_CGS, "erg⋅s"), ("Speed of light", CLIGHT_CGS, "cm⋅s⁻¹"), ("Boltzmann constant", BOLTZM_CGS, "erg⋅K⁻¹"), ("Avogadro constant", AVOGADRO_CGS, "mol⁻¹"), ("Elementary charge", ECHARGE_CGS, "esu"), ("Electron volt", EVOLT_CGS, "erg"), ] for name, value, unit in cgs_constants: logger.info(f" {name:<30}: {value:.6e} {unit}") logger.info("") logger.info("EPR Examples:") # Free electron gyromagnetic ratio gamma_free = gamma_hz() logger.info(f" Free electron γ/2π: {gamma_free:.3e} Hz/T") # X-band EPR freq_xband = 9.5e9 # Hz B_xband = frequency_to_magnetic_field(freq_xband) logger.info(f" X-band EPR (9.5 GHz): {B_xband*1000:.1f} mT") # Room temperature thermal energy E_thermal = thermal_energy(295) # K logger.info(f" Room temperature kT: {E_thermal/(1.602176634e-19)*1000:.2f} meV")
if __name__ == "__main__": constants_summary()