def get_simulation_parameters(L, lattice_depths, confining_depth, site_number = 100):
    L = np.array(L, ndmin = 1).round().astype(int)
    L = L[L>1]
    lattice_depths = np.array(lattice_depths, ndmin = 1)
    while lattice_depths.size < L.size:
        lattice_depths = np.append(lattice_depths, lattice_depths[-1])

    # compute transverse tunneling and on-site overlap integral
    momenta, fourier_vecs, _ = mathieu_solution(confining_depth, 1, site_number)
    J_T = tunneling_1D(confining_depth, momenta, fourier_vecs)
    K_T = pair_overlap_1D(momenta, fourier_vecs)

    # compute everything we need along the primary axes
    momenta = [ None ] * L.size
    fourier_vecs = [ None ] * L.size
    energies = [ None ] * L.size
    J_0 = np.zeros(L.size)
    K_0 = np.zeros(L.size)

    for ii in range(L.size):
        momenta[ii], fourier_vecs[ii], energies[ii] = \
            mathieu_solution(lattice_depths[ii], 1, site_number)
        energies[ii] -= np.mean(energies[ii],0)
        J_0[ii] = tunneling_1D(lattice_depths[ii], momenta[ii], fourier_vecs[ii])
        K_0[ii] = pair_overlap_1D(momenta[ii], fourier_vecs[ii])
    momenta = np.array(momenta)
    fourier_vecs = np.array(fourier_vecs)
    energies = np.array(energies)

    return L, J_0, J_T, K_0, K_T, momenta, fourier_vecs, energies
Esempio n. 2
0
def get_J_O(depth, stretch):
    depth_S = depth * stretch**2
    momenta_S, fourier_vecs_S, _ = mathieu_solution(depth_S, bands,
                                                    site_number)
    tunneling_rate_S = tunneling_1D(depth_S, momenta_S, fourier_vecs_S)
    tunneling_rate = tunneling_rate_S / stretch**2
    tunneling_rate *= recoil_energy_Hz

    rabi_ratio = abs(
        laser_overlap(np.pi, momenta_S, fourier_vecs_S, 1) /
        laser_overlap(np.pi, momenta_S, fourier_vecs_S))

    return tunneling_rate, rabi_ratio * rabi_frequency
Esempio n. 3
0
def renormalized_coupling(coupling,
                          lattice_depths,
                          bands=15,
                          site_number=100,
                          precision=10,
                          backwards=False,
                          harmonic=False):

    mean_depth = gmean(lattice_depths)  # geometric mean of lattice depths
    w_eff = np.sqrt(2 * mean_depth /
                    m_SR87_LU)  # effective angular harmonic trap frequency

    # two-atom ground-state overlap integral
    if not harmonic:
        overlap_factor = 1
        for depth in lattice_depths:
            momenta, fourier_vecs, _ = mathieu_solution(
                depth, bands, site_number)
            overlap_factor *= pair_overlap_1D(momenta, fourier_vecs)
    else:
        # determine ground-state two-body overlap integral in a harmonic oscillator
        HO_length = mean_depth**(
            -1 / 4)  # harmonic oscillator length in lattice units
        overlap_factor = np.sqrt(2 / np.pi) / (4 * np.pi) / HO_length**3

    unknown_coupling = sym.symbols("G")
    if not backwards:  # compute an in-trap scattering length from a harmonic one
        E_free = coupling * overlap_factor / w_eff
        E_lattice = unknown_coupling * overlap_factor / w_eff
    else:  # compute harmonic scattering length from an in-trap one
        E_free = unknown_coupling * overlap_factor / w_eff
        E_lattice = coupling * overlap_factor / w_eff

    # coefficients of series expansion of the right hand side of our expression
    c_0 = 1
    c_1 = 1 - np.log(2)
    c_2 = -np.pi**2 / 24 - np.log(2) + 1 / 2 * np.log(2)**2
    series = c_0 + c_1 * E_lattice + c_2 * E_lattice**2
    null_expression = 1 / E_free - 1 / E_lattice * series

    return min(real_positive_roots(null_expression, unknown_coupling,
                                   precision),
               key=lambda x: abs(x / coupling - 1))
Esempio n. 4
0
 def U_J(depth):
     momenta, fourier_vecs, _ = mathieu_solution(depth, 1, site_number)
     J_0 = tunneling_1D(depth, momenta, fourier_vecs)
     K_0 = pair_overlap_1D(momenta, fourier_vecs)
     return g_int_LU[1] * K_0**lattice_dim * K_T**(3 - lattice_dim) / J_0
Esempio n. 5
0
##########################################################################################
# compute squeezing and make plots
##########################################################################################

lattice_dim = 1
tau_vals = np.linspace(0, max_tau, time_steps)

plt.figure(figsize=figsize)
plt.title(r"${}$".format(title))

for ii, N in enumerate(N_vals):
    color = colors[ii]

    # determine primary lattice depth which optimally satisfies our target U_int / J_0
    momenta, fourier_vecs, _ = mathieu_solution(confining_depth, 1,
                                                site_number)
    K_T = pair_overlap_1D(momenta, fourier_vecs)
    J_T = tunneling_1D(confining_depth, momenta, fourier_vecs)

    def U_J(depth):
        momenta, fourier_vecs, _ = mathieu_solution(depth, 1, site_number)
        J_0 = tunneling_1D(depth, momenta, fourier_vecs)
        K_0 = pair_overlap_1D(momenta, fourier_vecs)
        return g_int_LU[1] * K_0**lattice_dim * K_T**(3 - lattice_dim) / J_0

    lattice_depth = minimize_scalar(lambda x: abs(U_J(x) - U_J_target),
                                    method="bounded",
                                    bounds=lattice_depth_bounds).x

    # get simulation parameters and on-site interaction energy
    L, J_0, J_T, K_0, K_T, momenta, fourier_vecs, energies = \
Esempio n. 6
0
summary_info = False
connectivity_info = False

##########################################################################################
# fixed and derived lattice parameters
##########################################################################################

nuclear_splitting_per_gauss = 110  # 2\pi Hz / Gauss / nuclear spin
nuclear_splitting = magnetic_field * nuclear_splitting_per_gauss

# lattice depths in units of "stretched" recoil energies
V_P_S = V_P * stretch_P**2
V_T_S = V_T * stretch_T**2

# solve mathieu equation along primary and transverse axes
momenta_P_S, fourier_vecs_P_S, _ = mathieu_solution(V_P_S, bands, site_number)
momenta_T_S, fourier_vecs_T_S, _ = mathieu_solution(V_T_S, bands, site_number)

# compute overlap integrals and tunneling rates in stretched recoil energies
K_P_S = pair_overlap_1D(momenta_P_S, fourier_vecs_P_S)
K_T_S = pair_overlap_1D(momenta_T_S, fourier_vecs_T_S)
tunneling_rate_P_S = tunneling_1D(V_P_S, momenta_P_S, fourier_vecs_P_S)
tunneling_rate_T_S = tunneling_1D(V_T_S, momenta_T_S, fourier_vecs_T_S)

# overlap integrals and tunneling rates in regular recoil energies
K_P = K_P_S / stretch_P
K_T = K_T_S / stretch_T
tunneling_rate_P = tunneling_rate_P_S / stretch_P**2
tunneling_rate_T = tunneling_rate_T_S / stretch_T**2

# on-site interaction energies
Esempio n. 7
0
def energy_correction_coefficients(lattice_depths,
                                   site_number,
                                   pt_order=3,
                                   bands=13):
    assert (pt_order >= 1)

    momenta_x, fourier_vecs_x, _ = mathieu_solution(lattice_depths[0], bands,
                                                    site_number)
    momenta_y, fourier_vecs_y, _ = mathieu_solution(lattice_depths[1], bands,
                                                    site_number)
    momenta_z, fourier_vecs_z, _ = mathieu_solution(lattice_depths[2], bands,
                                                    site_number)
    a_2_1 = (pair_overlap_1D(momenta_x, fourier_vecs_x) *
             pair_overlap_1D(momenta_y, fourier_vecs_y) *
             pair_overlap_1D(momenta_z, fourier_vecs_z))

    momenta_list = [momenta_x, momenta_y, momenta_z]
    fourier_vecs_list = [fourier_vecs_x, fourier_vecs_y, fourier_vecs_z]
    a_prime_2_1 = momentum_coupling_overlap_3D(momenta_list, fourier_vecs_list)

    if pt_order == 1:
        return [a_2_1, a_prime_2_1]

    x, y, z = 0, 1, 2  # axis indices
    lattice_depths = np.sort(lattice_depths)

    # compute all 1-D band energies, spatial wavefunction overlaps, and tunneling rates
    band_energies = np.zeros((3, bands))
    K_1D = np.zeros((3, bands, bands, bands))
    if pt_order > 2:
        K_t_1D = np.zeros((3, bands, bands))
        t_1D = np.zeros((3, bands))
    for axis in range(3):
        # if any of the lattice depths are the same, we can recycle our calculations
        if axis > 0 and lattice_depths[axis] == lattice_depths[axis - 1]:
            band_energies[axis, :] = band_energies[axis - 1, :]
            K_1D[axis, :, :, :] = K_1D[axis - 1, :, :, :]
            if pt_order > 2:
                K_t_1D[axis, :, :] = K_t_1D[axis - 1, :, :]
                t_1D[axis, :] = t_1D[axis - 1, :]
            continue

        # otherwise compute everything for this lattice depth
        momenta, fourier_vecs, energies = mathieu_solution(
            lattice_depths[axis], bands, site_number)
        band_energies[axis, :] = np.mean(energies, 0)
        band_energies[axis, :] -= band_energies[axis, 0]

        for nn in range(bands):
            if pt_order > 2:
                t_1D[axis, nn] = tunneling_1D(lattice_depths[axis], momenta,
                                              fourier_vecs, nn)
            for mm in range(nn, bands):
                if pt_order > 2:
                    K_t_1D[axis, nn, mm] = pair_overlap_1D(momenta,
                                                           fourier_vecs,
                                                           nn,
                                                           mm,
                                                           neighbors=1)
                    K_t_1D[axis, mm, nn] = K_t_1D[axis, nn, mm]

                for ll in range(bands):
                    K_1D[axis, nn, mm,
                         ll] = pair_overlap_1D(momenta, fourier_vecs, nn, mm,
                                               ll)
                    K_1D[axis, mm, nn, ll] = K_1D[axis, nn, mm, ll]

    K = np.prod(K_1D[:, 0, 0, 0])

    if pt_order == 2:

        # collect all (even) band indices to loop over
        even_bands = [(n_x, n_y, n_z) for n_z in range(0, bands, 2)
                      for n_y in range(n_z, bands, 2)
                      for n_x in range(n_y, bands, 2)]

        # second order spatial overlap factor
        a_3_2 = 0
        for n_x, n_y, n_z in even_bands[1:]:
            K_n = K_1D[x, n_x, 0, 0] * K_1D[y, n_y, 0, 0] * K_1D[z, n_z, 0, 0]
            E_n = band_energies[x, n_x] + band_energies[
                y, n_y] + band_energies[z, n_z]
            a_3_2 += K_n**2 / E_n * len(set(permutations([n_x, n_y, n_z])))

            return a_2_1, a_prime_2_1, a_3_2

    # collect all band indices to loop over
    all_bands = ((n_x, n_y, n_z) for n_z in range(bands)
                 for n_y in range(n_z, bands) for n_x in range(n_y, bands))

    # second and third order spatial overlap factors
    a_3_2, a_3_3_1, a_3_3_2, a_4_3_1, a_4_3_2, a_4_3_3, a_5_3, g_2_2, g_3_2_1, g_3_2_2 \
        = np.zeros(10)
    for n_x, n_y, n_z in all_bands:
        n_permutations = len(set(permutations([n_x, n_y, n_z])))
        E_n = band_energies[x, n_x] + band_energies[y,
                                                    n_y] + band_energies[z,
                                                                         n_z]
        K_n = K_1D[x, n_x, 0, 0] * K_1D[y, n_y, 0, 0] * K_1D[z, n_z, 0, 0]

        parity_x = n_x % 2
        parity_y = n_y % 2
        parity_z = n_z % 2

        if E_n != 0 and K_n != 0:
            K_t_n = K_n * (K_t_1D[x, n_x, 0] / K_1D[x, n_x, 0, 0] +
                           K_t_1D[y, n_y, 0] / K_1D[y, n_y, 0, 0] +
                           K_t_1D[z, n_z, 0] / K_1D[z, n_z, 0, 0]) / 3
            t_n = (t_1D[x, n_x] + t_1D[y, n_y] + t_1D[z, n_z]) / 3

            a_3_2 += K_n**2 / E_n * n_permutations
            a_5_3 += K_n**2 / E_n**2 * n_permutations
            g_3_2_1 += K_n * K_t_n / E_n * n_permutations
            g_3_2_2 += t_n * K_n**2 / E_n**2 * n_permutations

        for m_x, m_y, m_z in cartesian_product(range(parity_x, bands, 2),
                                               range(parity_y, bands, 2),
                                               range(parity_z, bands, 2)):

            E_m = band_energies[x, m_x] + band_energies[
                y, m_y] + band_energies[z, m_z]
            E_mn = E_n + E_m

            if E_mn == 0: continue

            K_m = K_1D[x, m_x, 0, 0] * K_1D[y, m_y, 0, 0] * K_1D[z, m_z, 0, 0]
            K_mn = K_1D[x, m_x, n_x, 0] * K_1D[y, m_y, n_y, 0] * K_1D[z, m_z,
                                                                      n_z, 0]

            if E_n != 0:
                a_4_3_1 += K_mn * K_m * K_n / (E_mn * E_n) * n_permutations

            if E_n != 0 and E_m != 0:
                K_m_n = K_1D[x, m_x, 0, n_x] * K_1D[y, m_y, 0,
                                                    n_y] * K_1D[z, m_z, 0, n_z]
                a_4_3_2 += K_m * K_m_n * K_n / (E_m * E_n) * n_permutations

            a_4_3_3 += (K_mn / E_mn)**2 * n_permutations

            if K_mn == 0: continue

            K_t_mn = K_mn * (K_t_1D[x, n_x, n_x] / K_1D[x, m_x, n_x, 0] +
                             K_t_1D[x, n_y, n_y] / K_1D[x, m_y, n_y, 0] +
                             K_t_1D[x, n_z, n_z] / K_1D[x, m_z, n_z, 0]) / 3
            g_2_2 += K_mn * K_t_mn / E_mn * n_permutations

            for l_x, l_y, l_z in cartesian_product(range(parity_x, bands, 2),
                                                   range(parity_y, bands, 2),
                                                   range(m_z, bands, 2)):

                E_l = band_energies[x, l_x] + band_energies[
                    y, l_y] + band_energies[z, l_z]
                E_ln = E_l + E_n
                multiplicity = n_permutations * (1 if l_z == m_z else 2)

                if E_ln == 0 or E_mn == 0: continue

                K_ln = K_1D[x, l_x, n_x, 0] * K_1D[y, l_y, n_y,
                                                   0] * K_1D[z, l_z, n_z, 0]
                K_l_m = K_1D[x, l_x, 0, m_x] * K_1D[y, l_y, 0,
                                                    m_y] * K_1D[z, l_z, 0, m_z]

                a_3_3_1 += K_mn * K_l_m * K_ln / (E_mn * E_ln) * multiplicity

            for l_x, l_y, l_z in cartesian_product(range(0, bands, 2),
                                                   repeat=3):

                E_l = band_energies[x, l_x] + band_energies[
                    y, l_y] + band_energies[z, l_z]

                if E_l == 0 or E_mn == 0: continue

                K_l = K_1D[x, l_x, 0, 0] * K_1D[y, l_y, 0, 0] * K_1D[z, l_z, 0,
                                                                     0]
                K_lmn = K_1D[x, n_x, m_x, l_x] * K_1D[y, n_y, m_y,
                                                      l_y] * K_1D[z, n_z, m_z,
                                                                  l_z]

                fac = K_l * K_mn / (E_l * E_mn) * n_permutations
                a_3_3_2 += fac * (K_lmn - K_l * K_mn / K)

    a_4_3_3 *= K
    a_5_3 *= K

    return a_2_1, a_prime_2_1, a_3_2, \
        a_3_3_1, a_3_3_2, \
        a_4_3_1, a_4_3_2, a_4_3_3, \
        a_5_3, g_2_2, g_3_2_1, g_3_2_2
Esempio n. 8
0
J_0 = pd.Series(data = np.zeros(shallow.size), index = shallow)
K_0 = pd.Series(data = np.zeros(shallow.size), index = shallow)

J_T = pd.Series(data = np.zeros(deep.size), index = deep)
K_T = pd.Series(data = np.zeros(deep.size), index = deep)

zero_frame = pd.DataFrame(data = np.zeros((shallow.size,deep.size)),
                          index = shallow, columns = deep)
U_int_1D = zero_frame.copy(deep = True)
U_int_2D = zero_frame.copy(deep = True)
phi_opt_1D = zero_frame.copy(deep = True)
phi_opt_2D = zero_frame.copy(deep = True)

for depth in shallow:
    momenta, fourier_vecs, energies = mathieu_solution(depth, bands, site_number)
    J_0.at[depth] = tunneling_1D(depth, momenta, fourier_vecs)
    K_0.at[depth] = pair_overlap_1D(momenta, fourier_vecs)
for depth in deep:
    momenta, fourier_vecs, energies = mathieu_solution(depth, bands, site_number)
    J_T.at[depth] = tunneling_1D(depth, momenta, fourier_vecs)
    K_T.at[depth] = pair_overlap_1D(momenta, fourier_vecs)

def h_std(dim,V_0,phi): return 2**(1+dim/2) * J_0.at[V_0] * np.sin(phi/2)

for V_0, V_T in itertools.product(shallow, deep):
    U_int_1D.at[V_0,V_T] = g_int_LU[1] * K_T.at[V_T]**2 * K_0.at[V_0]
    U_int_2D.at[V_0,V_T] = g_int_LU[1] * K_T.at[V_T] * K_0.at[V_0]**2

    def minimization_func(dim,U_int,x):
        return abs(h_std(dim,V_0,x)/U_int.at[V_0,V_T]/h_U_target-1)
excited_lifetime_SI = 10  # seconds; lifetime of excited state (from e --> g decay)

##########################################################################################
# compute all experimental parameters
##########################################################################################

N = np.product(L)
eta = N / np.product(L)
lattice_dim = np.array(L, ndmin=1).size

print("D:", np.size(L))
print("N:", N)
print()

# determine primary lattice depth which optimally satisfies our target U_int / J_0
momenta, fourier_vecs, soc_energies = mathieu_solution(confining_depth, 1,
                                                       site_number)
K_T = pair_overlap_1D(momenta, fourier_vecs)
J_T = tunneling_1D(confining_depth, momenta, fourier_vecs)


def U_J(depth):
    momenta, fourier_vecs, _ = mathieu_solution(depth, 1, site_number)
    J_0 = tunneling_1D(depth, momenta, fourier_vecs)
    K_0 = pair_overlap_1D(momenta, fourier_vecs)
    U = g_int_LU[1] * K_0**lattice_dim * K_T**(3 - lattice_dim)
    return U / J_0


lattice_depth = minimize_scalar(lambda x: abs(U_J(x) - U_J_target),
                                method="bounded",
                                bounds=lattice_depth_bounds).x
Esempio n. 10
0
                         [eigenvalues_4_3_C, 4, e_4_3_C]]:
    for aa in range(len(atom_numbers)):
        conversion = np.array(convert_eigenvalues(
            num, atom_numbers[aa])).astype(float)
        vals[aa, :] = (conversion @ e_X).T

# compute wavefunction broadening estimates
scale_factors = np.zeros((len(atom_numbers), len(lattice_depths), 3))
for dd in range(len(lattice_depths)):
    lattice_depth = lattice_depths[dd]
    print()
    print("lattice_depth:", lattice_depth)
    print("-" * 80)
    print()

    momenta, fourier_vecs, energies = mathieu_solution(lattice_depth,
                                                       max_bands, site_number)

    kinetic_energy = kinetic_overlap_1D(momenta, fourier_vecs)
    pair_overlap = pair_overlap_1D(momenta, fourier_vecs)

    overlaps = energy_correction_coefficients(lattice_depth * np.ones(3),
                                              site_number)
    a_2_1, a_prime_2_1, a_3_2, a_3_3_1, a_3_3_2, a_4_3_1, a_4_3_2, a_4_3_3, a_5_3 \
        = overlaps[:8]

    for aa in range(len(atom_numbers)):
        atom_number = atom_numbers[aa]
        print("atom number:", atom_number)

        # TODO: incorporate effect of renormalization and momentum-dependent coupling
        multi_body_energies = (