Source code for optmat.gas.gases

# SPDX-FileCopyrightText: 2026 John C. Travers and contributors
#
# SPDX-License-Identifier: MIT

"""The gas species the package curates data for.

The registry contains five noble gases and ten molecular gases.
Each carries the few fixed facts the rest of the package relies on: its electron count
(the Thomas-Reiche-Kuhn sum rule ``S(0)`` of its dipole oscillator-strength
distribution) and the name of its equation of state in CoolProp, where one exists.
"""

from dataclasses import dataclass
from enum import StrEnum
from typing import Final

from optmat.exceptions import OptmatError

__all__ = ["Gas", "GasInfo", "as_gas", "info"]


[docs] class Gas(StrEnum): """A gas species, named by its chemical formula.""" He = "He" Ne = "Ne" Ar = "Ar" Kr = "Kr" Xe = "Xe" H2 = "H2" D2 = "D2" N2 = "N2" O2 = "O2" CH4 = "CH4" SF6 = "SF6" N2O = "N2O" CO2 = "CO2" O3 = "O3" CO = "CO"
[docs] @dataclass(frozen=True) class GasInfo: """Fixed facts about one species. Attributes ---------- gas : Gas The species. electrons : int Number of electrons per atom or molecule: the Thomas-Reiche-Kuhn sum rule ``S(0)`` of the dipole oscillator-strength distribution. fluid : str or None CoolProp's name of the fluid for the real-gas equation of state, or None where CoolProp has none (ozone). atomic : bool True for the noble gases, which have no vibrational or rotational structure and so no infrared resonances. """ gas: Gas electrons: int fluid: str | None atomic: bool
_INFO: Final[dict[Gas, GasInfo]] = { info.gas: info for info in ( GasInfo(Gas.He, 2, "Helium", atomic=True), GasInfo(Gas.Ne, 10, "Neon", atomic=True), GasInfo(Gas.Ar, 18, "Argon", atomic=True), GasInfo(Gas.Kr, 36, "Krypton", atomic=True), GasInfo(Gas.Xe, 54, "Xenon", atomic=True), # Normal hydrogen and deuterium: CoolProp's equilibrium forms, as in solprop. GasInfo(Gas.H2, 2, "Hydrogen", atomic=False), GasInfo(Gas.D2, 2, "Deuterium", atomic=False), GasInfo(Gas.N2, 14, "Nitrogen", atomic=False), GasInfo(Gas.O2, 16, "Oxygen", atomic=False), GasInfo(Gas.CH4, 10, "Methane", atomic=False), GasInfo(Gas.SF6, 70, "SulfurHexafluoride", atomic=False), GasInfo(Gas.N2O, 22, "NitrousOxide", atomic=False), GasInfo(Gas.CO2, 22, "CarbonDioxide", atomic=False), GasInfo(Gas.O3, 24, None, atomic=False), GasInfo(Gas.CO, 14, "CarbonMonoxide", atomic=False), ) }
[docs] def as_gas(gas: Gas | str) -> Gas: """Return the :class:`Gas` named by ``gas``. Parameters ---------- gas : Gas or str A species or its formula, e.g. ``"Ar"``. Returns ------- Gas The species. Raises ------ OptmatError If ``gas`` names no curated species. Examples -------- >>> as_gas("Ar") <Gas.Ar: 'Ar'> """ try: return Gas(gas) except ValueError as exc: known = ", ".join(g.value for g in Gas) msg = f"unknown gas {gas!r}; curated species are {known}" raise OptmatError(msg) from exc
[docs] def info(gas: Gas | str) -> GasInfo: """Return the fixed facts about a species. Parameters ---------- gas : Gas or str The species. Returns ------- GasInfo Its electron count, equation-of-state name and whether it is atomic. Examples -------- >>> info("Xe").electrons 54 """ return _INFO[as_gas(gas)]