Source code for starkzee.atomic_data

import json
import os
from dataclasses import dataclass
from typing import Optional, List

[docs] @dataclass class AtomicState: """Explicitly represents an atomic quantum state.""" energy: float n: int l: Optional[int] = None j: Optional[float] = None spin: Optional[float] = None def __repr__(self): parts = [f"n={self.n}"] if self.l is not None: parts.append(f"l={self.l}") if self.j is not None: parts.append(f"j={self.j}") if self.spin is not None: parts.append(f"s={self.spin}") parts_str = ", ".join(parts) return f"AtomicState({parts_str}, energy={self.energy})"
[docs] def get_data_path() -> str: """Returns the absolute path to the data directory.""" current_dir = os.path.dirname(os.path.abspath(__file__)) return os.path.join(current_dir, "data", "atomic_levels.json")
[docs] def load_levels(atom: str, fine_structure: bool) -> List[AtomicState]: """Load atomic states from the JSON database. Parameters ---------- atom : str Chemical symbol of the element (e.g. ``'H'``, ``'He'``). fine_structure : bool If ``True``, load :math:`(n, l, j)`-resolved levels (``fine_structure_true`` section); otherwise load shell-averaged levels (``fine_structure_false`` section). Returns ------- list of AtomicState Atomic states ordered as stored in the JSON file, with energies in cm\ :sup:`-1` above the ground state. Raises ------ ValueError If *atom* or the requested fine-structure section is absent from the database. """ data_path = get_data_path() with open(data_path, 'r') as f: database = json.load(f) if atom not in database: raise ValueError(f"Atom '{atom}' not found in database.") config_key = "fine_structure_true" if fine_structure else "fine_structure_false" if config_key not in database[atom]: raise ValueError(f"Configuration '{config_key}' not found for atom '{atom}'.") raw_levels = database[atom][config_key] states = [] for level_data in raw_levels: state = AtomicState( energy=level_data["energy"], n=level_data["n"], l=level_data.get("l"), j=level_data.get("j"), spin=level_data.get("spin") ) states.append(state) return states
[docs] def calculate_wavenumber(upper_state: AtomicState, lower_state: AtomicState, lambda_shift: float = 0.0) -> float: """Compute the transition wavenumber between two atomic states. Parameters ---------- upper_state : AtomicState Upper energy level. lower_state : AtomicState Lower energy level. lambda_shift : float, optional Additional shift added to the computed wavenumber (default 0.0). Returns ------- float Transition wavenumber :math:`E_u - E_l + \lambda_\mathrm{shift}` in cm\ :sup:`-1`. Raises ------ ValueError If *upper_state* has lower energy than *lower_state*. """ base_wavenumber = upper_state.energy - lower_state.energy if base_wavenumber < 0: raise ValueError("Upper state must have higher energy than lower state.") return base_wavenumber + lambda_shift