Quadratic Zeeman polarization wings
Script: examples/reproduce_halpha_wings.py
Demonstrates the polarization-wing effect at B = 500 T and B = 1000 T: at
high field the quadratic Zeeman term shifts the
3p(\(m_l=\pm1\)) → 2s transitions away from the main Hα cluster,
creating distinct shoulders/wings in the σ± components that only appear when
quadratic_zeeman=True. A modest ion temperature (Ti_ev=Te) is used so
the underlying Stark-Zeeman components — narrower than natural linewidth at
this low density — are resolved on the plotted grid rather than
undersampled.
Code
1#!/usr/bin/env python3
2"""
3reproduce_halpha_wings.py
4=========================
5Focused examination of Hα (n=3→2, Z=1) σ+, σ−, π polarization components
6at B = 500 T and B = 1000 T, comparing with and without the quadratic
7(diamagnetic) Zeeman term.
8
9Physical picture
10----------------
11Without QZ all σ+ (or all σ−) Hα transitions are degenerate at
12 E_σ+ = E0 + μ_B·B (all Δml=+1 components)
13 E_σ− = E0 − μ_B·B
14
15With QZ the diagonal shift of each |n,l,ml⟩ state is
16 ΔE_QZ = (e²B²/8mₑ) · ⟨r²⟩_nl · ⟨sin²θ⟩_{l,ml}
17
18For n=3 the relevant shifts (B=1000 T):
19 3p, ml=±1: +8.87 meV ← LARGEST in n=3
20 3s, ml=0 : +8.50 meV
21 3d, ml=±2: +6.65 meV
22 3d, ml=±1: +4.43 meV
23 3d, ml=0 : +3.69 meV
24
25For n=2:
26 2s, ml=0 : +1.72 meV
27 2p, ml=±1: +1.48 meV
28 2p, ml=0 : +0.74 meV
29
30The dominant oscillator-strength contributor is 3d→2p (radial dipole ≈4.75 a₀).
31The 3p→2s transitions (radial dipole ≈3.06 a₀, oscillator fraction ~21 %)
32have LARGER n=3 QZ shifts, so they appear as a separate shoulder:
33
34 σ+ wing: 3p(ml=+1) → 2s(ml=0) at E0 + μ_B·B + (8.87−1.72) = E0+μ_B·B+7.1 meV
35 σ− wing: 3p(ml=−1) → 2s(ml=0) at E0 − μ_B·B + (8.87−1.72) = E0−μ_B·B+7.1 meV
36 → this is ~7 meV NEARER to E0 than the main 3d cluster
37
38These wings are ONLY present with quadratic_zeeman=True.
39"""
40
41import numpy as np
42import matplotlib.pyplot as plt
43import sys, os
44sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
45
46from starkzee.static_profile import calculate_static_profile
47from starkzee.utils import reduced_mass_rydberg_ev, BOHR_MAGNETON_EV_T
48
49# ── parameters ───────────────────────────────────────────────────────────────
50Z, n_u, n_l = 1, 3, 2
51Ne, Te = 1e17, 5.0
52E0 = (Z**2) * reduced_mass_rydberg_ev(Z, 1) * (1.0/n_l**2 - 1.0/n_u**2)
53
54# Fine energy grid — wide enough to cover both σ± at B=1000 T
55DET_HALF = 0.10 # ±100 meV
56NPTS = 4000
57det = np.linspace(-DET_HALF, DET_HALF, NPTS) # eV
58energies = E0 + det
59
60# ── compute profiles ─────────────────────────────────────────────────────────
61results = {}
62for B in [500.0, 1000.0]:
63 print(f" B={int(B)} T: without QZ …", end=" ", flush=True)
64 pi_nq, sp_nq, sm_nq = calculate_static_profile(
65 n_u, n_l, Z, B, Ne, Te, energies,
66 num_f=30, num_mu=8,
67 use_screening=True, quadratic_zeeman=False,
68 frequency_dependent_width=False, Ti_ev=Te)
69 print("done. With QZ …", end=" ", flush=True)
70 pi_yq, sp_yq, sm_yq = calculate_static_profile(
71 n_u, n_l, Z, B, Ne, Te, energies,
72 num_f=30, num_mu=8,
73 use_screening=True, quadratic_zeeman=True,
74 frequency_dependent_width=False, Ti_ev=Te)
75 print("done.")
76 results[B] = dict(
77 pi_nq=pi_nq, sp_nq=sp_nq, sm_nq=sm_nq,
78 pi_yq=pi_yq, sp_yq=sp_yq, sm_yq=sm_yq,
79 )
80
81# ── plot ─────────────────────────────────────────────────────────────────────
82det_meV = det * 1e3 # meV axis
83
84fig, axes = plt.subplots(2, 3, figsize=(15, 9), sharey='row')
85fig.suptitle(
86 r"H$\alpha$ (n=3→2, Z=1) polarization wings from quadratic Zeeman"
87 "\n"
88 r"$N_e = 10^{17}$ m$^{-3}$, $T_e = 5$ eV — solid: with QZ, dashed: without QZ",
89 fontsize=12)
90
91pol_labels = [r"$\pi$", r"$\sigma^+$", r"$\sigma^-$"]
92pol_keys = [("pi_nq", "pi_yq"), ("sp_nq", "sp_yq"), ("sm_nq", "sm_yq")]
93pol_colors = ["tab:blue", "tab:red", "tab:green"]
94
95for row, B in enumerate([500.0, 1000.0]):
96 r = results[B]
97 zeeman_meV = BOHR_MAGNETON_EV_T * B * 1e3
98
99 # Expected wing positions (meV from E0)
100 # QZ shifts at this B (all scale as B²):
101 coeff = (1.60218e-19 * B**2 * (5.29177e-11)**2 / (8 * 9.10938e-31)) * 1e3 # meV
102 qz_3p_pm1 = coeff * 180 * 4/5 # n=3,l=1,ml=±1: r2=180, sin2=4/5
103 qz_3d_ml2 = coeff * 126 * 6/7 # n=3,l=2,ml=±2: r2=126, sin2=6/7
104 qz_2s = coeff * 42 * 2/3 # n=2,l=0,ml=0
105 qz_2p_pm1 = coeff * 30 * 4/5 # n=2,l=1,ml=±1
106
107 wing_sigp_meV = zeeman_meV + (qz_3p_pm1 - qz_2s)
108 wing_sigm_meV = -zeeman_meV + (qz_3p_pm1 - qz_2s)
109 main_sigp_meV = zeeman_meV + (qz_3d_ml2 - qz_2p_pm1)
110 main_sigm_meV = -zeeman_meV + (qz_3d_ml2 - qz_2p_pm1)
111
112 for col, (label, (nq_key, yq_key), color) in enumerate(
113 zip(pol_labels, pol_keys, pol_colors)):
114 ax = axes[row, col]
115 nq = r[nq_key]
116 yq = r[yq_key]
117 peak = max(yq.max(), nq.max(), 1e-20)
118
119 ax.plot(det_meV, nq / peak, 'k--', lw=1.2, alpha=0.8, label='No QZ')
120 ax.plot(det_meV, yq / peak, color=color, lw=1.8, label='With QZ')
121
122 # Annotate expected wing positions
123 if col == 1: # σ+
124 ax.axvline(wing_sigp_meV, color='orange', ls=':', lw=1.2,
125 label=f'3p(ml=+1)→2s wing\n({wing_sigp_meV:.1f} meV)')
126 ax.axvline(main_sigp_meV, color='gray', ls=':', lw=1.0,
127 label=f'3d cluster edge\n({main_sigp_meV:.1f} meV)')
128 if col == 2: # σ−
129 ax.axvline(wing_sigm_meV, color='orange', ls=':', lw=1.2,
130 label=f'3p(ml=−1)→2s wing\n({wing_sigm_meV:.1f} meV)')
131 ax.axvline(main_sigm_meV, color='gray', ls=':', lw=1.0,
132 label=f'3d cluster edge\n({main_sigm_meV:.1f} meV)')
133
134 ax.set_xlabel('Detuning from $E_0$ (meV)', fontsize=10)
135 ax.set_ylabel('Normalized intensity', fontsize=9)
136 ax.set_title(f'B = {int(B)} T — {label}', fontsize=11)
137 ax.legend(fontsize=7.5, loc='upper right')
138 ax.grid(True, alpha=0.25)
139 ax.set_xlim(-100, 100)
140 ax.set_ylim(-0.02, None)
141
142plt.tight_layout()
143out = "halpha_wings.png"
144plt.savefig(out, dpi=200, bbox_inches='tight')
145print(f"\nSaved {out}")
146plt.show()
Result
π, σ+, σ− components at B = 500 T and B = 1000 T; solid = with quadratic Zeeman, dashed = without. The 3p→2s wing is resolved as a distinct shoulder at B = 1000 T.