@@ -145,6 +145,46 @@ def test_reduced_raw_value(ket: AngularKetBase[AllKnown]) -> None:
145145 assert np .isclose (raw ** 2 , ket_m .calc_matrix_element (ket_m , "raw_value_" + op + "_2" , kappa = 0 , q = 0 )) # type: ignore [arg-type]
146146
147147
148+ @pytest .mark .parametrize ("ket" , TEST_KETS )
149+ def test_reduced_spin_squared (ket : AngularKetBase [AllKnown ]) -> None :
150+ op : AngularMomentumQuantumNumbers
151+ coupling_schemes : list [CouplingScheme ] = ["LS" , "JJ" , "FJ" ]
152+ for scheme in coupling_schemes :
153+ state = ket .to_state (scheme )
154+ for op in state .kets [0 ].quantum_number_names :
155+ # the squared spin operator is diagonal in the scheme's own basis with eigenvalue qn * (qn + 1),
156+ # so for a superposition the reduced matrix element is the weighted average over the components
157+ exp_squared = sum (coeff ** 2 * s_ket .get_qn (op ) * (s_ket .get_qn (op ) + 1 ) for coeff , s_ket in state )
158+ reduced_squared = exp_squared * np .sqrt (2 * ket .f_tot + 1 )
159+ assert np .isclose (reduced_squared , state .calc_reduced_matrix_element (state , "squared_" + op , kappa = 0 )) # type: ignore [arg-type]
160+
161+
162+ def test_spin_squared_expectation_value () -> None :
163+ """The expectation value of s^2 must be s(s+1) for good quantum numbers and match the sum rule otherwise."""
164+ ket = AngularKetFJ (l_r = 0 , j_r = 0.5 , f_c = 1 , m = 0.5 , f_tot = 0.5 , species = "Yb171" )
165+
166+ # s_r and s_c are good quantum numbers in every ket, so <s^2> = s(s+1) = 3/4
167+ assert np .isclose (ket .calc_matrix_element (ket , "squared_s_r" , 0 , q = 0 ), 0.75 )
168+ assert np .isclose (ket .calc_matrix_element (ket , "squared_s_c" , 0 , q = 0 ), 0.75 )
169+
170+ # s_tot is not a good quantum number of an FJ ket, so <s_tot^2> is a weighted average
171+ # over the LS decomposition: sum_i |c_i|^2 * s_tot_i * (s_tot_i + 1)
172+ expected = sum (coeff ** 2 * ls_ket .s_tot * (ls_ket .s_tot + 1 ) for coeff , ls_ket in ket .to_state ("LS" ))
173+ assert np .isclose (ket .calc_matrix_element (ket , "squared_s_tot" , 0 , q = 0 ), expected )
174+
175+ # <s^2> must also equal the sum over all final states and components q of the squared
176+ # matrix elements of the (rank-1) spin operator: <s^2> = sum_{f,q} |<f|s_q|ket>|^2
177+ finals = [
178+ AngularKetFJ (l_r = 0 , j_r = 0.5 , f_c = f_c , m = m / 2 , f_tot = f_tot , species = "Yb171" )
179+ for f_c in (0 , 1 )
180+ for f_tot in {abs (f_c - 0.5 ), f_c + 0.5 }
181+ for m in range (- int (2 * f_tot ), int (2 * f_tot ) + 1 , 2 )
182+ ]
183+ for op in ("s_r" , "s_c" ):
184+ sum_rule = sum (f .calc_matrix_element (ket , op , 1 , q = q ) ** 2 for f in finals for q in (- 1 , 0 , 1 ))
185+ assert np .isclose (sum_rule , ket .calc_matrix_element (ket , "squared_" + op , 0 , q = 0 )) # type: ignore [arg-type]
186+
187+
148188@pytest .mark .parametrize (("ket1" , "ket2" ), TEST_KET_PAIRS )
149189def test_matrix_elements_in_different_coupling_schemes (
150190 ket1 : AngularKetBase [AllKnown ], ket2 : AngularKetBase [AllKnown ], coupling_scheme : CouplingScheme
0 commit comments