Skip to content

Commit 24ec924

Browse files
RydbergKet start adding matrix_element for electric_dipole_core
1 parent a3eba0b commit 24ec924

2 files changed

Lines changed: 84 additions & 9 deletions

File tree

src/rydstate/rydberg_state/rydberg_ket.py

Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22

33
import logging
44
import math
5-
from typing import TYPE_CHECKING, Any, overload
5+
from typing import TYPE_CHECKING, Any, Literal, overload
66

7+
from rydstate.angular.angular_ket import AngularKetLS
8+
from rydstate.angular.utils import is_unknown
9+
from rydstate.species.element_properties import get_element_properties
10+
from rydstate.species.sqdt import get_sqdt
711
from rydstate.units import MatrixElementOperatorRanks, ureg
812

913
if TYPE_CHECKING:
@@ -31,6 +35,7 @@ def __init__(
3135
) -> None:
3236
r"""Initialize the Rydberg state."""
3337
self.species = species
38+
self.element_properties = get_element_properties(species)
3439
self.angular = angular
3540
self.radial = radial
3641

@@ -56,7 +61,7 @@ def calc_reduced_matrix_element(
5661
@overload
5762
def calc_reduced_matrix_element(self, other: RydbergKet, operator: MatrixElementOperator, unit: str) -> float: ...
5863

59-
def calc_reduced_matrix_element(
64+
def calc_reduced_matrix_element( # noqa: C901, PLR0912
6065
self, other: RydbergKet, operator: MatrixElementOperator, unit: str | None = None
6166
) -> PintFloat | float:
6267
r"""Calculate the reduced matrix element.
@@ -69,6 +74,9 @@ def calc_reduced_matrix_element(
6974
where \hat{O}^{(k_{angular})} is the operator of rank k_angular for which to calculate the matrix element.
7075
k_radial and k_angular are determined from the operator automatically.
7176
77+
For the "electric_dipole" operator, the matrix element of "electric_dipole_rydberg" and "electric_dipole_core"
78+
are calculated separately and added together.
79+
7280
Args:
7381
other: The other Rydberg state for which to calculate the matrix element.
7482
operator: The operator for which to calculate the matrix element.
@@ -80,6 +88,12 @@ def calc_reduced_matrix_element(
8088
The reduced matrix element for the given operator.
8189
8290
"""
91+
if operator == "electric_dipole":
92+
matrix_element = self.calc_reduced_matrix_element(other, "electric_dipole_rydberg", unit)
93+
if self.element_properties.number_valence_electrons == 2:
94+
matrix_element += self.calc_reduced_matrix_element(other, "electric_dipole_core", unit)
95+
return matrix_element
96+
8397
try:
8498
k_radial, k_angular = MatrixElementOperatorRanks[operator]
8599
except KeyError as err:
@@ -99,20 +113,31 @@ def calc_reduced_matrix_element(
99113
# as the same dimensionality as the Bohr magneton (mu = - mu_B (g_l l + g_s s_tot))
100114
# such that - mu * B (where the magnetic field B is given in dimension Tesla) is an energy
101115

102-
elif operator in ["electric_dipole", "electric_quadrupole", "electric_octupole", "electric_quadrupole_zero"]:
116+
elif operator.startswith("electric_"):
117+
angular_operator: Literal["spherical", "spherical_core"]
118+
angular_operator = "spherical" if "core" not in operator else "spherical_core"
103119
# Electric multipole operator: p_{k,q} = e r^k_radial * sqrt(4pi / (2k+1)) * Y_{k_angular,q}(\theta, phi)
104-
angular_matrix_element = self.angular.calc_reduced_matrix_element(other.angular, "spherical", k_angular)
120+
angular_matrix_element = self.angular.calc_reduced_matrix_element(
121+
other.angular, angular_operator, k_angular
122+
)
105123
# Prefactor sqrt(4 pi / (2 k_angular + 1)) for the electric multipole operators, precomputed for performance
106124
prefactor = ELECTRIC_MULTIPOLE_PREFACTORS[k_angular]
107125

108126
else:
109127
raise NotImplementedError(f"Operator {operator} not implemented.")
110128

111129
if angular_matrix_element == 0:
112-
matrix_element = 0.0
113-
else:
130+
return 0
131+
132+
if "core" not in operator:
114133
radial_matrix_element = self.radial.calc_matrix_element(other.radial, k_radial, unit="a.u.")
115-
matrix_element = prefactor * radial_matrix_element * angular_matrix_element
134+
matrix_element = prefactor * angular_matrix_element * radial_matrix_element
135+
else:
136+
core_radial_matrix_element = self._calc_core_radial_matrix_element_au(other, k_radial)
137+
if core_radial_matrix_element == 0:
138+
return 0
139+
rydberg_radial_overlap = self.radial.calc_overlap(other.radial)
140+
matrix_element = prefactor * angular_matrix_element * core_radial_matrix_element * rydberg_radial_overlap
116141

117142
if unit == "a.u.":
118143
return matrix_element
@@ -121,7 +146,7 @@ def calc_reduced_matrix_element(
121146
matrix_element_unit: PintFloat
122147
if operator == "magnetic_dipole":
123148
matrix_element_unit = radial_unit * ureg.Quantity(2, "bohr_magneton")
124-
elif operator in ["electric_dipole", "electric_quadrupole", "electric_octupole", "electric_quadrupole_zero"]:
149+
elif operator.startswith("electric_"):
125150
matrix_element_unit = radial_unit * ureg.Quantity(1, "e")
126151
else:
127152
raise NotImplementedError(f"Operator {operator} not implemented.")
@@ -130,6 +155,52 @@ def calc_reduced_matrix_element(
130155
return matrix_element * matrix_element_unit.to_base_units() # type: ignore [no-any-return]
131156
return matrix_element * matrix_element_unit.to(unit).magnitude
132157

158+
def _calc_core_radial_matrix_element_au(self, other: RydbergKet, k_radial: int) -> float:
159+
r"""Calculate the radial matrix element :math:`\langle self_c | r^{k_{radial}} | other_c \rangle` in a.u.
160+
161+
The core electron is treated as the low-lying valence electron of the corresponding singly charged SQDT ion
162+
(e.g. Yb174_ion for Yb174):
163+
the Rydberg electron is ignored and the radial matrix element is calculated between the two ion states,
164+
where the principal quantum number of each core electron is given by the lowest allowed shell of the ion
165+
for the given l_c.
166+
"""
167+
from rydstate.rydberg_state.rydberg_sqdt import RydbergStateSQDT # noqa: PLC0415
168+
169+
species = self.species
170+
ion_species = f"{species}_ion"
171+
try:
172+
ion_sqdt = get_sqdt(ion_species)
173+
except ValueError:
174+
logger.warning(
175+
"No SQDT data available for the ion species of %s "
176+
"returning 0 for the dipole matrix elemnet core contribution.",
177+
species,
178+
)
179+
return 0.0
180+
181+
kets = {"self": self, "other": other}
182+
ion_states: dict[str, RydbergStateSQDT[Any]] = {}
183+
for ket_name, ket in kets.items():
184+
l_c = ket.angular.l_c
185+
j_c = ket.angular.get_qn("j_c", allow_unknown=True)
186+
f_c = ket.angular.get_qn("f_c", allow_unknown=True)
187+
if is_unknown(l_c) or is_unknown(j_c) or is_unknown(f_c):
188+
return 0.0
189+
190+
angular_ket = AngularKetLS(l_r=l_c, j_tot=j_c, f_tot=f_c, species=ion_species)
191+
192+
# TODO: we should probably also store n_c for the core angular ket in the future
193+
# for now, it is correct to assume that the core electron is
194+
# in the lowest allowed shell of the ion for the given l_c
195+
for n_c in range(l_c + 1, l_c + 15):
196+
if ion_sqdt.is_allowed_shell(n_c, l_c, 0.5):
197+
ion_states[ket_name] = RydbergStateSQDT(ion_species, n_c, angular_ket=angular_ket, sqdt=ion_sqdt)
198+
break
199+
else: # no break
200+
raise ValueError(f"No allowed shell found for ion species {ion_species} with l_c={l_c}.")
201+
202+
return ion_states["self"].radial.calc_matrix_element(ion_states["other"].radial, k_radial, unit="a.u.")
203+
133204
@overload
134205
def calc_matrix_element(
135206
self, other: RydbergKet, operator: MatrixElementOperator, q: int, unit: None = None

src/rydstate/units.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,18 @@
2121
MatrixElementOperator = Literal[
2222
"magnetic_dipole",
2323
"electric_dipole",
24+
"electric_dipole_rydberg",
25+
"electric_dipole_core",
2426
"electric_quadrupole",
2527
"electric_octupole",
2628
"electric_quadrupole_zero",
2729
]
2830
MatrixElementOperatorRanks: dict[MatrixElementOperator, tuple[int, int]] = {
2931
# "operator": (k_radial, k_angular)
3032
"magnetic_dipole": (0, 1),
31-
"electric_dipole": (1, 1),
33+
"electric_dipole": (1, 1), # composed of "electric_dipole_rydberg" and "electric_dipole_core"
34+
"electric_dipole_rydberg": (1, 1),
35+
"electric_dipole_core": (1, 1),
3236
"electric_quadrupole": (2, 2),
3337
"electric_octupole": (3, 3),
3438
"electric_quadrupole_zero": (2, 0),

0 commit comments

Comments
 (0)