55import scipy
66import numpy as np
77import warnings
8- import itertools
8+ import itertools
9+ import math
910
1011import scipy .constants
1112from scipy .constants import Boltzmann , e
@@ -185,25 +186,26 @@ def __init__(self, atom_flag: AtomFlags, atomic_states: List[A_QState],
185186 self .temp = temp # K
186187 self .beam_area = beam_area
187188 self .density = self .atom .arc_atom .getNumberDensity (self .temp )
188- self .atom_mass = self .atom .arc_atom .mass
189+ self .atom_mass : float = self .atom .arc_atom .mass
189190 if beam_diam is None :
190- self .beam_diameter = 2.0 * np .sqrt (beam_area / np .pi )
191+ self .beam_diameter = 2.0 * math .sqrt (beam_area / np .pi )
191192 else :
192193 self .beam_diameter = beam_diam
193194
194195 if gamma_transit is None :
195- gamma_transit = 1E-6 * np .sqrt (8 * Boltzmann * self .temp / (self .atom_mass * np .pi )
196- )/ (self .beam_diameter / 2 * np .sqrt (2 * np .log (2 )))
196+ gamma_transit = 1E-6 * math .sqrt (8 * Boltzmann * self .temp / (self .atom_mass * np .pi )
197+ )/ (self .beam_diameter / 2 * math .sqrt (2 * math .log (2 )))
197198 self .gamma_transit = gamma_transit
198199
199200 # most probable speed for a 3D Maxwell-Boltzmann distribution
200201 # used when defining doppler averaging
201- self .vP = np .sqrt (2 * Boltzmann * self .temp / self .atom_mass )
202+ self .vP = math .sqrt (2 * Boltzmann * self .temp / self .atom_mass )
202203
203204 self ._add_state_energies ()
204205 self ._add_state_lifetimes ()
205206 self ._add_decoherence_rates ()
206207 self ._add_gamma_mismatches (gamma_mismatch )
208+ self .add_transit_broadening (gamma_transit )
207209
208210
209211 def set_experiment_values (self ,
@@ -341,7 +343,7 @@ def level_ordering(self) -> List[A_QState]:
341343
342344
343345 @property
344- def kappa (self ):
346+ def kappa (self ) -> float :
345347 """Property to calculate the kappa value of the system.
346348
347349 The value is computed with the following formula Eq. 5 of
@@ -369,7 +371,7 @@ def kappa(self):
369371 return self ._kappa
370372
371373 if self .probe_tuple is None :
372- raise RydiquleError ("Cell.probe_tuple not set. Either set manually or add at least one coupling before calculation." )
374+ raise RydiquleError ("Cell.probe_tuple not set. Add at least one coupling before calculation." )
373375
374376 ground_manifold = self .states_with_spec (self .probe_tuple [0 ])
375377 excited_manifold = self .states_with_spec (self .probe_tuple [1 ])
@@ -394,6 +396,7 @@ def kappa(self):
394396 dipole_moment = self .atom .get_dipole_matrix_element (probe_g_nlj , probe_e_nlj , q = q )* a0 * e
395397
396398 kappa = calc_kappa (omega_rad , dipole_moment , self .density )
399+ self ._kappa = kappa
397400
398401 return kappa
399402
@@ -433,7 +436,7 @@ def kappa(self):
433436
434437
435438 @property
436- def eta (self ):
439+ def eta (self ) -> float :
437440 """Get the eta value for the system.
438441
439442 The value is computed with the following formula Eq. 7 of
@@ -459,7 +462,7 @@ def eta(self):
459462 if hasattr (self , "_eta" ):
460463 return self ._eta
461464 if self .probe_tuple is None :
462- raise RydiquleError ("Cell.probe_tuple not set. Either set manually or add at least one coupling before calculation." )
465+ raise RydiquleError ("Cell.probe_tuple not set. Add at least one coupling before calculation." )
463466
464467 ground_manifold = self .states_with_spec (self .probe_tuple [0 ])
465468 excited_manifold = self .states_with_spec (self .probe_tuple [1 ])
@@ -483,12 +486,13 @@ def eta(self):
483486 omega_rad = self .atom .get_transition_frequency (probe_g_nlj , probe_e_nlj )* 2.0 * np .pi
484487 dipole_moment = self .atom .get_dipole_matrix_element (probe_g_nlj , probe_e_nlj , q = q )* a0 * e
485488 eta = calc_eta (omega_rad , dipole_moment , self .beam_area )
489+ self ._eta = eta
486490
487491 return eta
488492
489493
490494 @eta .setter
491- def eta (self , value ):
495+ def eta (self , value : float ):
492496 """Setter for the eta attribute.
493497
494498 Updates the self._eta class attribute.
@@ -519,7 +523,7 @@ def eta(self):
519523
520524
521525 @property
522- def probe_freq (self ):
526+ def probe_freq (self ) -> float :
523527 """Get the probe transition frequency, in rad/s.
524528
525529 Note that for :class:`~.Cell`, probing transition frequency is calculated using only
@@ -535,6 +539,8 @@ def probe_freq(self):
535539
536540 if hasattr (self , '_probe_freq' ):
537541 return self ._probe_freq
542+ if self .probe_tuple is None :
543+ raise RydiquleError ("Cell.probe_tuple not set. Add at least one coupling before calculation." )
538544
539545 probe_lower_manifold = self .states_with_spec (self .probe_tuple [0 ])
540546 probe_upper_manifold = self .states_with_spec (self .probe_tuple [1 ])
@@ -544,11 +550,14 @@ def probe_freq(self):
544550
545551 energy_lower = self .atom .get_state_energy (A_QState (n1 , l1 , j1 ), s = 0.5 )* 2 * np .pi
546552 energy_upper = self .atom .get_state_energy (A_QState (n2 , l2 , j2 ), s = 0.5 )* 2 * np .pi
553+
554+ probe_freq = abs (energy_upper - energy_lower )
555+ self ._probe_freq = probe_freq
547556
548- return np . abs ( energy_upper - energy_lower )
557+ return probe_freq
549558
550559 @probe_freq .setter
551- def probe_freq (self , value ):
560+ def probe_freq (self , value : float ):
552561 """Setter for the probe_freq attribute.
553562
554563 Updates the self._probe_freq class attribute.
@@ -737,7 +746,8 @@ def add_single_coupling(
737746 Coherent Couplings:
738747 ((5, 0, 0.5),(5, 1, 1.5)): {rabi_frequency: 2.0, detuning: 1.0, phase: 0, kvec: (0, 0, 0), label: probe, coherent_cc: 1, dipole_moment: 2.44, q: 0}
739748 Decoherent Couplings:
740- ((5, 1, 1.5),(5, 0, 0.5)): {gamma_transition: 38.11316}
749+ ((5, 0, 0.5),(5, 0, 0.5)): {gamma_transit: 0.40697}
750+ ((5, 1, 1.5),(5, 0, 0.5)): {gamma_transition: 38.11316, gamma_transit: 0.40697}
741751 Energy Shifts:
742752 None
743753
@@ -755,7 +765,8 @@ def add_single_coupling(
755765 Coherent Couplings:
756766 ((5, 0, 0.5),(5, 1, 1.5)): {rabi_frequency: 2.0, detuning: 1.0, phase: 0, kvec: (0, 0, 0), label: probe, coherent_cc: 1, dipole_moment: 2.44, q: 0}
757767 Decoherent Couplings:
758- ((5, 1, 1.5),(5, 0, 0.5)): {gamma_transition: 38.11}
768+ ((5, 0, 0.5),(5, 0, 0.5)): {gamma_transit: 0.40696}
769+ ((5, 1, 1.5),(5, 0, 0.5)): {gamma_transition: 38.113, gamma_transit: 0.40696}
759770 Energy Shifts:
760771 None
761772
@@ -772,7 +783,8 @@ def add_single_coupling(
772783 Coherent Couplings:
773784 ((5, 0, 0.5),(5, 1, 1.5)): {rabi_frequency: 1.177, detuning: 1.0, phase: 0, kvec: (0, 0, 0), label: probe, coherent_cc: 1, dipole_moment: 2.44, q: 0}
774785 Decoherent Couplings:
775- ((5, 1, 1.5),(5, 0, 0.5)): {gamma_transition: 38.11}
786+ ((5, 0, 0.5),(5, 0, 0.5)): {gamma_transit: 0.40696}
787+ ((5, 1, 1.5),(5, 0, 0.5)): {gamma_transition: 38.11, gamma_transit: 0.40696}
776788 Energy Shifts:
777789 None
778790
@@ -787,7 +799,8 @@ def add_single_coupling(
787799 Coherent Couplings:
788800 ((5, 0, 0.5),(5, 1, 1.5)): {rabi_frequency: 4.3, detuning: 1.0, phase: 0, kvec: (0, 0, 0), label: probe, coherent_cc: 1, dipole_moment: 2.44, q: 0}
789801 Decoherent Couplings:
790- ((5, 1, 1.5),(5, 0, 0.5)): {gamma_transition: 38.11}
802+ ((5, 0, 0.5),(5, 0, 0.5)): {gamma_transit: 0.4117}
803+ ((5, 1, 1.5),(5, 0, 0.5)): {gamma_transition: 38.113, gamma_transit: 0.4117}
791804 Energy Shifts:
792805 None
793806
@@ -904,7 +917,7 @@ def add_single_coupling(
904917 lam = abs (self .atom .get_transition_wavelength (state1 , state2 )) # in m
905918 kvec = 2 * np .pi / lam * np .asarray (kunit )* 1e-6 # scaled to Mrad/m
906919 else :
907- raise RydiquleError (f'Coupling { states } has un-normalized |kunit|={ np .sqrt (k_norm_sq ):.2f} !=1' )
920+ raise RydiquleError (f'Coupling { states } has un-normalized |kunit|={ math .sqrt (k_norm_sq ):.2f} !=1' )
908921
909922 super ().add_single_coupling (states = states ,
910923 rabi_frequency = passed_rabi ,
@@ -1066,7 +1079,7 @@ def _add_gamma_mismatches(self, method:Union[str, dict]="ground"):
10661079 `gamma_transition` values on edges leaving that state. However, it is not always
10671080 desirable to account for all states in this way for simplicity or computational
10681081 complexity reasons. This function allows the :class:`~.Cell` to account for any
1069- differences in these values that arise as a result of excluding physicalstates from a
1082+ differences in these values that arise as a result of excluding physical states from a
10701083 :class:`~.Cell`. There are multiple ways to resolve these discrepancies, specified by
10711084 the `method` argument, which is detailed in the `Parameters` section.
10721085
@@ -1155,8 +1168,9 @@ def _add_gamma_mismatch_to_ground(self, state: A_QState):
11551168 m_j = None if g .m_j is None else "all"
11561169 (f , m_f ) = (None , None ) if g .f is None else ("all" ,"all" )
11571170 ground_manifold = A_QState (g .n , g .l , g .j , m_j = m_j , f = f , m_f = m_f )
1171+ degeneracy = len (self .states_with_spec (ground_manifold ))
11581172
1159- self .add_decoherence ((state , ground_manifold ), gamma = (lifetime - transition_total ), label = "mismatch" )
1173+ self .add_decoherence ((state , ground_manifold ), gamma = (lifetime - transition_total )/ degeneracy , label = "mismatch" )
11601174
11611175
11621176 def _add_gamma_mismatch_to_all (self , state :A_QState ):
@@ -1180,18 +1194,21 @@ def _add_gamma_mismatch_to_all(self, state:A_QState):
11801194
11811195 transition_total = sum (e [2 ] for e in out_edges )
11821196
1183- #if they dom't match, we add a decoherence to the entire ground state manifold
1184- #that matches what remains
1197+ #if they dom't match, we proportionally increase existing decoherences to make up the difference
11851198 if not np .isclose (transition_total , lifetime ):
1186- #construct the dictionary of coupling coefficients coefficients
1187- cc = {
1188- (s1 , s2 ):gamma / transition_total for s1 , s2 , gamma in out_edges
1189- if gamma
1190- }
1191-
1199+ gamma_total_mismatch = lifetime - transition_total
11921200 out_states_list = [s2 for _ , s2 , _ in out_edges ]
1193- self .add_decoherence_group ([state ], out_states_list , gamma = transition_total , coupling_coefficients = cc , label = "mismatch" )
1194-
1201+ if len (out_states_list ) > 1 :
1202+ #construct the dictionary of coupling coefficients
1203+ cc = {
1204+ (s1 , s2 ):gamma / transition_total for s1 , s2 , gamma in out_edges
1205+ if gamma
1206+ }
1207+
1208+ self .add_decoherence_group ([state ], out_states_list , gamma = gamma_total_mismatch , coupling_coefficients = cc , label = "mismatch" )
1209+ else :
1210+ self .add_single_decoherence ((state , out_states_list [0 ]), gamma_total_mismatch ,
1211+ label = 'mismatch' )
11951212
11961213 def _validate_input_states (self , atomic_states : List [A_QState ]):
11971214 """Helper function to check that input states are compatible and defined"""
0 commit comments