def diagonalize_critical_floquet_system(trap_freq, lattice_depth, site_spacing_um, gamma, n_sites, floquet_m_radius, sort=True): """Build and diagonalize the Floquet problem for breathing lattice Inputs: trap_freq: Harmonic trapping frequency, E/h (Hz) units lattice_depth: Lattice depth parameter V_0 before a cos (not cos^2), E/h (Hz) site_spacing_um: Lattice site spacing, in microns gamma: Drive amplitude parameter, 0<gamma<1 n_sites: Number of sites to include in the lattice, should be odd floquet_m_radius: Number of Floquet couplings to use, generates 2m+1 blocks Optional Inputs: sort [True]: If True, output eigenvalues and eigenvectors are return in order of increasing eigenvalue Globals Accessed: sim_mass? Returns 3 tuple: drive: critical drive frequency used evals: eigenvalues of floquet Hamiltonian (possibly sorted, not modulus) evecs: eigenvectors of floquet Hamiltonian (possibly sorted) """ # Compute needed coefficients n_floquet = 2*floquet_m_radius + 1 lattice_tunneling = tunneling_J(lattice_depth, lattice_recoil_energy(site_spacing_um)) jsq_scale = gen_jsq_coeffs(site_spacing_um, trap_freq, gamma, n_floquet) h0_scale = dc.all_chis(dc.y(gamma)) crit_drive = dc.crit_drive_freq(dc.y(gamma), trap_freq) # Build up floquet problem jsq_block = on_site_jsq(n_sites) tun_block = tunneling_block(n_sites, lattice_tunneling) floquet_h = build_floquet_jsq(jsq_block, floquet_m_radius, jsq_scale) floquet_h = add_tunneling_blocks(floquet_h, floquet_m_radius, tun_block, h0_scale) floquet_h = add_floquet_diag(floquet_h, floquet_m_radius, crit_drive) # Some consistency checks, warn but do not stop. if not np.allclose(floquet_h.T, floquet_h): # More stringent, requires only real entries logger.warn("Symmetry test failed for this gamma {}".format(gamma)) if not np.allclose(np.conj(floquet_h.T), floquet_h): logger.warn("Conjugate transpose test failed for this gamma {}".format(gamma)) # Diagonalize, return results, copies because the inner workings of h5py aren't clear to me evals, evecs = LA.eigh(floquet_h) # Uses faster algo than eig(), guaranteed real evals too! if sort: sort_order = np.argsort(evals) return crit_drive, evals[sort_order], evecs[:, sort_order] else: return crit_drive, evals, evecs
def build_sys(u_over_j, j_tunn, trap_freq, drive_freq, basis_states, floquet_radius, gamma): drive_y = drive_coefficients.y(gamma) drive_freq = drive_coefficients.crit_drive_freq(drive_y, trap_freq) m_list = np.arange(-floquet_radius, floquet_radius + 1) raw_int = fock_basis.onsite_interactions(basis_states) raw_hop = -j_tunn * fock_basis.nearest_neighbor_hopping(basis_states) raw_jsq_onsite = fock_basis.onsite_offset( fock_basis.jsq_offset(basis_states.shape[1]), basis_states) scale_idxs = np.abs( np.arange((2 * floquet_radius + 1))[np.newaxis, :] - np.arange((2 * floquet_radius + 1))[:, np.newaxis]) small_xi_blocks = drive_coefficients.n_small_xis(2 * floquet_radius + 1, drive_y)[scale_idxs] big_xi_blocks = drive_coefficients.n_big_xis(2 * floquet_radius + 1, drive_y)[scale_idxs] jsq_prescale = tpf * (np.square(trap_freq * small_xi_blocks) - np.square(drive_freq * big_xi_blocks)) chi = drive_coefficients.all_chis(drive_y) chi_blocks = (np.diag(np.full(2 * floquet_radius + 1, chi[0])) + np.diag(np.full(2 * floquet_radius, chi[1]), k=1) + np.diag(np.full(2 * floquet_radius, chi[1]), k=-1) + np.diag(np.full(2 * floquet_radius - 1, chi[2]), k=2) + np.diag(np.full(2 * floquet_radius - 1, chi[2]), k=-2)) floquet_interactions = 0.5 * u_over_j * j_tunn * np.kron( chi_blocks, raw_int) floquet_diag = np.kron(np.diag(m_list), np.diag(np.full(basis_states.shape[0], drive_freq))) floquet_tunneling = np.kron(chi_blocks, raw_hop) floquet_offsets = np.kron(jsq_prescale, raw_jsq_onsite) return floquet_interactions + floquet_diag + floquet_tunneling + floquet_offsets
def gen_jsq_coeffs(site_spacing_um, trap_freq, gamma, n_floquet): """Generate the j^2 operators prefactors for the driven system Inputs: site_spacing_um: Site spacing, in microns trap_freq: Harmonic trap frequency in Hz (Natural f, not omega) gamma: Drive amplitude n_floquet: number of Floquet couplings required""" # In paper, prefactor is 1/2 m * a^2 * (ang freq ^2), since we're requiring nat. freq, need 4 pi^2 prefactor = 2.0 * np.pi * np.pi * sim_mass * um2 * site_spacing_um * site_spacing_um/h crit_xis = dc.n_crit_xis(n_floquet, dc.y(gamma)) return (prefactor * trap_freq * trap_freq * crit_xis)
labelLines(all_lines, align=False) for idx in np.arange(4): plt.loglog(gammas, np.flipud(np.abs(small[:,idx+1])), label=idx, c='k') #ls=(':' if big[1,idx] < 0 else 'solid'), c=kelly_colors[idx]) ax.set_title('$|\\xi_n| = |(\\kappa^{2})_n|$') ax.set_xlabel('$\\gamma$') plt.xlim(1e-5,0.5) plt.ylim(1e-12, 10) plt.setp(ax.get_yticklabels(), visible=False) ax.tick_params(axis='both', which='both', direction='in', bottom=True, left=True, top=True, right=True) # Chis chis = np.empty((3, len(gammas))) for idx, gamma in enumerate(gammas): chis[:, idx] = dc.all_chis(dc.y(gamma)) ax1.loglog(gammas, chis.T) ax1.set_title('$\\chi_n = (\\kappa^{-2})_n$') ax1.set_xlabel('$\\gamma$') plt.xlim(1e-5,0.5) plt.ylim(1e-12, 10) ax.xaxis.set_minor_locator(locmin) ax.xaxis.set_minor_formatter(matplotlib.ticker.NullFormatter()) ax1.xaxis.set_minor_locator(locmin) ax1.xaxis.set_minor_formatter(matplotlib.ticker.NullFormatter()) ax1.tick_params(axis='both', which='both', direction='in', bottom=True, left=True, top=True, right=True) fig.tight_layout() plt.subplots_adjust(wspace=0.0) fig.savefig(outdir + 'fourier_loglog.pdf', dpi=300, pad_inches=0)
# In[133]: for idx, gamma in enumerate(gamma_vals): plt.plot(np.full(len(results[idx]), gamma), np.mod(results[idx] + 200., 1000.) - 200., ',k') plt.ylim(-200, 800) plt.xlim(0, 0.5) plt.savefig('/home/zachsmith/Desktop/lines.png', dpi=300) # In[152]: f_drive = np.empty(len(gamma_vals)) for idx, gamma in enumerate(gamma_vals): plt.plot(np.full(len(results[idx]), gamma), results[idx], ',k') f_drive[idx] = drive_coefficients.crit_drive_freq( drive_coefficients.y(gamma), 25.) plt.plot(gamma_vals, 0.5 * f_drive + 60, 'r') plt.plot(gamma_vals, -0.5 * f_drive + 60, 'r') plt.plot(gamma_vals, np.full(len(gamma_vals), 60), '--r') plt.ylim(-0, 100) plt.xlim(0, 0.5) plt.tight_layout() plt.savefig('/home/zachsmith/Desktop/lines.png', dpi=300) # In[92]: for idx, gamma in enumerate(gamma_vals): plt.plot(np.full(len(results[idx]), gamma), results[idx], ',k') plt.ylim(-100, 200) plt.xlim(0, 0.5) plt.tight_layout()
def diagonalize_floquet_system(trap_freq, lattice_depth, site_spacing_um, drive_freq, gamma, n_mathieu_basis, n_h0_states, floquet_m_radius, sort=True): """Build and diagonalize the Floquet problem for breathing lattice Inputs: trap_freq: Harmonic trapping frequency, E/h (Hz) units lattice_depth: Lattice depth parameter V_0 before a cos (not cos^2), E/h (Hz) site_spacing_um: Lattice site spacing, in microns drive_freq: Natural drive frequency, in (Hz) gamma: Drive amplitude parameter, 0<gamma<1 n_mathieu_basis: Number of basis vectors to use in underlying mathieu function computation n_h0_states: Number of states to keep in time-averaged Hamiltonian, this is the size of the H-space in the Floquet problem floquet_m_radius: Number of Floquet couplings to use, generates 2m+1 blocks Optional Inputs: sort [True]: If True, output eigenvalues and eigenvectors are return in order of increasing eigenvalue Globals Accessed: sim_mass? Returns 3 tuple: h0_states: eigenstates of time-averaged Hamiltonian/basis states for floquet Hamiltonian evals: eigenvalues of floquet Hamiltonian (possibly sorted, not modulus) evecs: eigenvectors of floquet Hamiltonian (possibly sorted) """ # Compute needed coefficients n_floquet = 2 * floquet_m_radius + 1 lattice_tunneling = tunneling_J(lattice_depth, lattice_recoil_energy(site_spacing_um)) raw_jsq_scale = gen_jsq_coeffs(site_spacing_um, drive_freq, trap_freq, gamma, n_floquet) h0_jsq_scale = raw_jsq_scale[0] h0_scale_factors = dc.all_chis(dc.y(gamma)) adj_jsq_scale = adjust_jsq_coefs(raw_jsq_scale, h0_scale_factors) # Find solution to time-averaged part h0_en, h0_states = h0.lattice_plus_trap_sitespace(n_mathieu_basis, n_h0_states, lattice_tunneling, h0_jsq_scale) # Build up floquet problem jsq_op = h0.jsq_op_statespace(h0_states) floquet_h = build_floquet_jsq(jsq_op, floquet_m_radius, adj_jsq_scale) floquet_h = add_h0_diags(floquet_h, floquet_m_radius, h0_en, h0_scale_factors) floquet_h = add_floquet_diag(floquet_h, floquet_m_radius, drive_freq) # Some consistency checks, warn but do not stop. if not np.allclose(floquet_h.T, floquet_h): # More stringent, requires only real entries logger.warn("Symmetry test failed for this gamma {}".format(gamma)) if not np.allclose(np.conj(floquet_h.T), floquet_h): logger.warn( "Conjugate transpose test failed for this gamma {}".format(gamma)) # Diagonalize, return results, copies because the inner workings of h5py aren't clear to me evals, evecs = LA.eigh( floquet_h) # Uses faster algo than eig(), guaranteed real evals too! if sort: sort_order = np.argsort(evals) return h0_states.T, evals[sort_order], evecs[:, sort_order] else: return h0_states.T, evals, evecs