|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
| 3 | +import itertools |
3 | 4 | from typing import TYPE_CHECKING |
4 | 5 |
|
5 | 6 | import numpy as np |
6 | 7 | import pytest |
7 | 8 | from rydstate import BasisMQDT, RydbergStateSQDT |
| 9 | +from rydstate.angular.utils import is_unknown |
| 10 | +from rydstate.species import FModelSQDT |
8 | 11 |
|
9 | 12 | if TYPE_CHECKING: |
10 | 13 | from rydstate import RydbergStateMQDT |
@@ -134,3 +137,58 @@ def test_matrix_element_between_mqdt_and_sqdt_state(basis: BasisMQDT) -> None: |
134 | 137 | me = s_mqdt.calc_reduced_matrix_element(p_sqdt, "electric_dipole", unit="e a0") |
135 | 138 | assert np.isfinite(me) |
136 | 139 | assert abs(me) > 0.0 |
| 140 | + |
| 141 | + |
| 142 | +def test_n_of_sqdt_fallback_model_uses_channel_nui() -> None: |
| 143 | + """For SQDT fallback models n is given by the channel nui, not by nu.""" |
| 144 | + basis = BasisMQDT("Yb171", nu=(78.0, 81.0), l_r=(5, 5), m=(0.5, 0.5)) |
| 145 | + assert len(basis.states) > 0 |
| 146 | + |
| 147 | + states_with_shifted_nu = 0 |
| 148 | + for state in basis.states: |
| 149 | + assert isinstance(state.model, FModelSQDT) |
| 150 | + assert len(state.rydberg_kets) == 1 |
| 151 | + |
| 152 | + nui = state.nui[0] |
| 153 | + assert abs(nui - round(nui)) < 1e-9 |
| 154 | + assert state.n == round(nui) |
| 155 | + |
| 156 | + if state.n != round(state.nu): |
| 157 | + states_with_shifted_nu += 1 |
| 158 | + |
| 159 | + assert states_with_shifted_nu > 0 |
| 160 | + |
| 161 | + |
| 162 | +@pytest.mark.parametrize( |
| 163 | + ("species", "m", "l_r", "model_name"), |
| 164 | + [ |
| 165 | + ("Yb174", (0, 0), (0, 0), "S J=0, nu > 2"), |
| 166 | + ("Yb174", (0, 0), (2, 2), "D J=2, nu > 5"), |
| 167 | + ("Yb171", (0.5, 0.5), (1, 1), "P F=1/2, nu > 5.7"), |
| 168 | + ("Yb171", (0.5, 0.5), (1, 1), "P F=3/2, nu > 10"), |
| 169 | + ], |
| 170 | +) |
| 171 | +def test_n_increments_by_one_along_a_rydberg_series( |
| 172 | + species: str, m: tuple[float, float], l_r: tuple[int, int], model_name: str |
| 173 | +) -> None: |
| 174 | + """Within one Rydberg series of an MQDT model, n increases by exactly one from state to state. |
| 175 | +
|
| 176 | + A single MQDT model describes several interleaved Rydberg series (one per channel), so the states |
| 177 | + of a model have to be grouped by their dominant channel before comparing consecutive n. |
| 178 | + """ |
| 179 | + basis = BasisMQDT(species, nu=(40.0, 46.0), l_r=l_r, m=m) |
| 180 | + states = [state for state in basis.states if state.model.name == model_name] |
| 181 | + assert len(states) > 0 |
| 182 | + |
| 183 | + def dominant_channel(state: RydbergStateMQDT) -> int: |
| 184 | + """Return the index of the channel with the largest coefficient (ignoring unknown channels).""" |
| 185 | + known = [(abs(coeff), i) for i, (coeff, ket) in enumerate(state) if not is_unknown(ket.angular.l_r)] |
| 186 | + return max(known)[1] |
| 187 | + |
| 188 | + states.sort(key=lambda state: (dominant_channel(state), state.nu)) |
| 189 | + for channel, series in itertools.groupby(states, key=dominant_channel): |
| 190 | + n_list = [state.n for state in series] |
| 191 | + assert len(n_list) > 1, f"series of channel {channel} is too short to test" |
| 192 | + assert all(n_next - n == 1 for n, n_next in itertools.pairwise(n_list)), ( |
| 193 | + f"n does not increase by one along the series of channel {channel}: {n_list}" |
| 194 | + ) |
0 commit comments