Ejemplo n.º 1
0
    def test_steady_state_intensity(self):
        """Test the steady state intensity scaling"""

        # use both integers and floats
        intensity_list = [1e-3, 1e-1, 0.3, 1, 1.0, 2, 10., 1.2e4]

        ion = Ca43(B=5e-4, level_filter=[ground_level, P32])
        s_idx = ion.index(ground_level, 4)
        p_idx = ion.index(P32, +5)

        rates = Rates(ion)
        delta = ion.delta(s_idx, p_idx)

        for I in intensity_list:
            Lasers = [Laser("393", q=+1, I=I, delta=delta)]  # resonant
            trans = rates.get_transitions(Lasers)

            Np_ss = _steady_state_population(I)
            # transition rates normalised by A coefficient
            dNp_dt = (trans[p_idx, p_idx] * Np_ss
                      + trans[p_idx, s_idx] * (1 - Np_ss))
            dNp_dt = dNp_dt / (trans[p_idx, p_idx] + trans[p_idx, s_idx])
            self.assertAlmostEqual(0., dNp_dt, places=7)
            dNs_dt = (trans[s_idx, p_idx] * Np_ss
                      + trans[s_idx, s_idx] * (1 - Np_ss))
            dNs_dt = dNs_dt / (trans[s_idx, p_idx] + trans[s_idx, s_idx])
            self.assertAlmostEqual(0., dNs_dt, places=7)
Ejemplo n.º 2
0
    def test_steady_state_detuning(self):
        """Test steady state detuning dependence"""

        # assume 1 saturation intensity
        ion = Ca43(B=5e-4, level_filter=[ground_level, P32])
        s_idx = ion.index(ground_level, 4)
        p_idx = ion.index(P32, +5)

        rates = Rates(ion)
        delta = ion.delta(s_idx, p_idx)

        Lasers = [Laser("393", q=+1, I=1., delta=delta)]  # resonant
        trans = rates.get_transitions(Lasers)
        line_width = abs(trans[p_idx, p_idx] + trans[p_idx, s_idx])

        # detuning scan relative to linewidth
        norm_detuning = [-1e4, 2.3e1, 2, -4, 0.5, 0]
        for det in norm_detuning:
            I_eff = 1/(4 * det**2 + 1)
            Np_ss = _steady_state_population(I_eff)

            Lasers = [Laser("393", q=+1, I=1., delta=delta + line_width*det)]
            trans = rates.get_transitions(Lasers)

            # transition rates normalised by A coefficient
            dNp_dt = (trans[p_idx, p_idx] * Np_ss
                      + trans[p_idx, s_idx] * (1 - Np_ss))
            dNp_dt = dNp_dt / (trans[p_idx, p_idx] + trans[p_idx, s_idx])
            self.assertAlmostEqual(0., dNp_dt, places=7)
            dNs_dt = (trans[s_idx, p_idx] * Np_ss
                      + trans[s_idx, s_idx] * (1 - Np_ss))
            dNs_dt = dNs_dt / (trans[s_idx, p_idx] + trans[s_idx, s_idx])
            self.assertAlmostEqual(0., dNs_dt, places=7)
Ejemplo n.º 3
0
 def test_multi_transition(self):
     """Test with lasers on multiple transitions (see #15)"""
     ion = Ca43(B=146e-4)
     rates = Rates(ion)
     Lasers = [
         Laser("397", q=0, I=1, delta=0),
         Laser("866", q=0, I=1, delta=0),
     ]
     rates.get_transitions(Lasers)
Ejemplo n.º 4
0
 def test_multi_laser(self):
     """Test with multiple lasers on one transition"""
     ion = Ca43(B=146e-4)
     rates = Rates(ion)
     Lasers = [
         Laser("397", q=0, I=1, delta=0),
         Laser("397", q=+1, I=1, delta=0),
     ]
     rates.get_transitions(Lasers)
Ejemplo n.º 5
0
    def test_LF(self):
        """ Check that, in the low-field, our scattering rates match a more
        direct calculation. """
        ion = Ca43(B=1e-8)
        ion.calc_Epole()
        Gamma_ion = ion.Gamma
        I = ion.I
        Idim = int(np.rint(2*I+1))
        Gamma = np.zeros((ion.num_states, ion.num_states))

        for name, transition in ion.transitions.items():
            A = transition.A
            lower = transition.lower
            upper = transition.upper
            Ju = upper.J
            Jl = lower.J
            Jdim_l = int(np.rint(2*Jl+1))
            l_dim = Idim*Jdim_l

            dJ = Ju-Jl
            dL = upper.L - lower.L
            if dJ in [-1, 0, +1] and dL in [-1, 0, +1]:
                order = 1
            elif abs(dJ) in [0, 1, 2] and abs(dL) in [0, 1, 2]:
                order = 2
            else:
                raise ValueError("Unsupported transition order {}"
                                 .format(order))

            subspace = np.r_[ion.slice(lower), ion.slice(upper)]

            for l_ind in list(subspace[:l_dim]):
                for u_ind in list(subspace[l_dim:]):
                    Fl = ion.F[l_ind]
                    Fu = ion.F[u_ind]
                    Ml = ion.M[l_ind]
                    Mu = ion.M[u_ind]
                    q = Mu - Ml
                    if q not in range(-order, order+1):
                        continue

                    Gamma[l_ind, u_ind] = A*(
                        (2*Ju+1)
                        * (2*Fl+1)
                        * (2*Fu+1)
                        * (wigner_3j(Fu, order, Fl, -Mu, q, Ml))**2
                        * (wigner_6j(Ju, I, Fu, Fl, order, Jl)**2))

            subspace = np.ix_(subspace, subspace)
            scale = np.max(np.max(np.abs(Gamma[subspace])))
            eps = np.max(np.max(np.abs(Gamma[subspace]-Gamma_ion[subspace])))
            self.assertTrue(eps/scale < 1e-4)
Ejemplo n.º 6
0
    def test_rates_relations(self):
        """Test the spontaneous rates satisfy relations in net rates

        This relation is used in the steady states tests."""
        intensity_list = [1e-3, 1e-1, 0.3, 1, 1.0, 2, 10., 1.2e4]

        ion = Ca43(B=5e-4, level_filter=[ground_level, P32])
        s_idx = ion.index(ground_level, 4)
        p_idx = ion.index(P32, +5)

        rates = Rates(ion)
        delta = ion.delta(s_idx, p_idx)
        for I in intensity_list:
            Lasers = [Laser("393", q=+1, I=I, delta=delta)]  # resonant
            trans = rates.get_transitions(Lasers)

            spont = rates.get_spont()
            r = spont[p_idx, p_idx] / (trans[p_idx, p_idx]+trans[p_idx, s_idx])
            self.assertAlmostEqual(r, 1., places=7)
Ejemplo n.º 7
0
def main():
    t_ax = np.linspace(0, 100e-6, 100)
    I = 0.02  # 393 intensity

    ion = Ca43(B=146e-4)
    stretch = ion.index(ground_level, 4)

    rates = Rates(ion)
    delta = ion.delta(stretch, ion.index(P32, +5))
    Lasers = [Laser("393", q=+1, I=I, delta=delta)]  # resonant 393 sigma+
    trans = rates.get_transitions(Lasers)

    Vi = np.zeros((ion.num_states, 1))  # initial state
    Vi[stretch] = 1  # start in F=4, M=+4
    shelved = np.zeros(len(t_ax))
    for idx, t in np.ndenumerate(t_ax):
        Vf = expm(trans*t)@Vi
        shelved[idx] = sum(Vf[ion.slice(shelf)])

    plt.plot(t_ax*1e6, shelved)
    plt.ylabel('Shelved Population')
    plt.xlabel('Shelving time (us)')
    plt.grid()
    plt.show()
Ejemplo n.º 8
0
import numpy as np

from ion_phys.ions.ca43 import Ca43, ground_level
from ion_phys.utils import (field_insensitive_point, d2f_dB2)

if __name__ == '__main__':
    # all seems about correct (e.g. agrees with TPH thesis) but expect some
    # numerical inaccuracy, particularly around the second-order field
    # sensitivities. To improve we should add a special case to the derivative
    # calculation that uses the BR formula!
    ion = Ca43(level_filter=[ground_level])

    print("Field-independent points:")
    for M3 in range(-3, +3 + 1):
        for q in [-1, 0, 1]:
            ion.setB(1e-4)
            F4 = ion.index(ground_level, M3 - q, F=4)
            F3 = ion.index(ground_level, M3, F=3)
            B0 = field_insensitive_point(ion, F4, F3)
            if B0 is not None:
                ion.setB(B0)
                f0 = ion.delta(F4, F3)
                d2fdB2 = d2f_dB2(ion, F4, F3)
                print("4, {} --> 3, {}: {:.6f} GHz @ {:.5f} G ({:.3e} Hz/G^2)".
                      format(M3 - q, M3, f0 / (2 * np.pi * 1e6), B0 * 1e4,
                             d2fdB2 / (2 * np.pi) * 1e-8))
            else:
                print("4, {} --> 3, {}: none found".format(M3 - q, M3))