Hα stick spectrum and broadened profile
Script: examples/example_halpha.py
Side-by-side comparison of the discrete transition stick spectrum
(discrete_transitions) and the static Stark-Zeeman broadened profile
at B = 0, 3, and 10 T, at two electron densities
(\(N_e = 10^{17}\) and \(10^{19}\) m-3), showing the
transition from the Zeeman-dominated to the Stark-dominated regime.
Code
1"""
2example_halpha.py — H Balmer-alpha (n=3→2) Stark-Zeeman profiles.
3
4Shows static profiles for B = 1, 5, 10 T at two electron densities:
5 • Ne = 10^20 m^-3 : Zeeman-dominated (±5 meV window)
6 • Ne = 10^23 m^-3 : Stark-dominated (±30 meV window)
7Te = 5 eV throughout.
8
9Run:
10 python example_halpha.py
11
12Produces: example_halpha.png
13"""
14
15import numpy as np
16import matplotlib.pyplot as plt
17import sys, os
18sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
19
20from starkzee.static_profile import calculate_static_profile, discrete_transitions
21from starkzee.utils import reduced_mass_rydberg_ev
22
23# ── Parameters ────────────────────────────────────────────────────────────────
24
25Z, n_u, n_l = 1, 3, 2
26A = 1 # atomic mass (1 = H)
27Te_ev = .5
28Ti_ev = .5
29E0 = (Z**2) * reduced_mass_rydberg_ev(Z, A) * (1.0 / n_l**2 - 1.0 / n_u**2)
30
31B_VALS = [0.0, 3.0, 10.0] # Tesla
32NE_ROWS = [
33 (1e17, 1.0), # (Ne m^-3, detuning half-range meV)
34 (1e19, 1.0),
35]
36NPTS = 500 # Voigt bakes in Doppler; grid only needs to resolve ~Doppler width (~50 ueV)
37
38POL_COLOR = {0: "#e74c3c", -1: "#3498db", 1: "#2ecc71"}
39
40# ── Precompute stick spectra (field-independent per B) ────────────────────────
41
42print("Computing stick spectra …")
43sticks = {}
44for B in B_VALS:
45 sticks[B] = discrete_transitions(
46 n_u=n_u, n_l=n_l, Z=Z, B=B,
47 fine_structure=True, min_strength=0
48 )
49
50# ── Figure ────────────────────────────────────────────────────────────────────
51
52fig, axes = plt.subplots(2, 3, figsize=(14, 8), constrained_layout=True)
53
54for row, (Ne, det_range) in enumerate(NE_ROWS):
55 ne_exp = int(np.log10(Ne))
56 det_mev = np.linspace(-det_range, det_range, NPTS)
57 energies = E0 + det_mev * 1e-3
58
59 for col, B in enumerate(B_VALS):
60 ax = axes[row, col]
61
62 print(f" B={B:.0f} T, Ne=1e{ne_exp} m^-3 ...", flush=True)
63
64 pi, sp, sm = calculate_static_profile(
65 n_u=n_u, n_l=n_l, Z=Z, B=B,
66 Ne_m3=Ne, Te_ev=Te_ev,
67 energies_ev=energies,
68 num_f=25, num_mu=8,
69 fine_structure=True,
70 frequency_dependent_width=True,
71 Ti_ev=Ti_ev, species='H',
72 )
73
74 # 90° transverse: I = I_π + ½(I_σ+ + I_σ−)
75 transverse = pi + 0.5 * (sp + sm)
76 norm = transverse.max() or 1.0
77
78 # Centre detuning on the intensity-weighted centroid so that the
79 # fine-structure blueshift does not break the visual σ+/σ− symmetry.
80 E_center = float(np.sum(energies * transverse) / np.sum(transverse))
81 det_plot = (energies - E_center) * 1e3 # meV from FS line center
82
83 # ── Profile curves ────────────────────────────────────────────────
84 ax.fill_between(det_plot, transverse / norm, alpha=0.10, color="k")
85 ax.plot(det_plot, transverse / norm, "k", lw=1.8, label="Transverse")
86 ax.plot(det_plot, pi / norm, color=POL_COLOR[0],
87 lw=1.1, ls="--", alpha=0.85, label="π")
88 ax.plot(det_plot, 0.5*(sp+sm) / norm, color=POL_COLOR[-1],
89 lw=1.1, ls=":", alpha=0.85, label="½(σ+σ−)")
90
91 # ── Stick spectrum overlay (scaled to 0.45 of plot height) ────────
92 tr = sticks[B]
93 det_stk = (tr["energy_ev"] - E_center) * 1e3
94 s_stk = tr["strength"] / tr["strength"].max() * 0.45
95 for q in [0, -1, 1]:
96 mask = (tr["q"] == q) & (np.abs(det_stk) <= det_range)
97 if mask.any():
98 ax.vlines(det_stk[mask], 0, s_stk[mask],
99 colors=POL_COLOR[q], alpha=0.35, lw=1.0)
100 ax.plot(det_stk[mask], s_stk[mask], '.',
101 color=POL_COLOR[q], alpha=0.35, lw=1.0)
102
103 # ── Axes decoration ───────────────────────────────────────────────
104 ax.set_title(
105 f"B = {B:.0f} T | $N_e = 10^{{{ne_exp}}}$ m$^{{-3}}$",
106 fontsize=10
107 )
108 ax.set_xlabel("Detuning from line center (meV)", fontsize=9)
109 ax.set_ylabel("Norm. intensity", fontsize=9)
110 ax.set_xlim(-det_range, det_range)
111 ax.set_ylim(0, 1.15)
112 ax.axhline(0, color="grey", lw=0.4)
113 ax.tick_params(labelsize=8)
114
115 if row == 0 and col == 0:
116 ax.legend(fontsize=8, framealpha=0.75, loc="upper right")
117
118print("Done. Saving example_halpha.png …")
119
120fig.suptitle(
121 f"H Balmer-α (n=3→2, Z=1) · Static Stark-Zeeman + Doppler ·"
122 f" $T_e = T_i$ = {Te_ev:.1f} eV",
123 fontsize=13
124)
125plt.savefig("example_halpha.png", dpi=150, bbox_inches="tight")
126plt.show()
Result
Transverse profile (with π and ½(σ++σ−) components) and the zero-field stick spectrum overlaid, across a grid of B and \(N_e\) values.