mirror of
https://github.com/vale981/fibre_walk_project_code
synced 2025-03-04 09:21:38 -05:00
BROKEN: implement full quantum walk
This commit is contained in:
parent
1ba49cb5f6
commit
bf6d138826
5 changed files with 185 additions and 38 deletions
|
@ -1 +0,0 @@
|
|||
hiro@Phillips.176003:1716495937
|
|
@ -15,7 +15,7 @@ def transient_rabi():
|
|||
δ=1 / 4,
|
||||
g_0=0.02,
|
||||
laser_detuning=0,
|
||||
Δ=0,
|
||||
ω_c=0,
|
||||
N=3,
|
||||
measurement_detuning=1,
|
||||
rwa=False,
|
||||
|
@ -29,7 +29,7 @@ def transient_rabi():
|
|||
f, (_, ax) = plot_simulation_result(
|
||||
make_figure(), t, signal, params, window=(params.lifetimes(15), t[-1])
|
||||
)
|
||||
plot_sidebands(ax, params)
|
||||
plot_rabi_sidebands(ax, params)
|
||||
f.suptitle("Transient Rabi oscillation")
|
||||
|
||||
|
||||
|
@ -42,7 +42,7 @@ def steady_rabi():
|
|||
δ=1 / 4,
|
||||
g_0=0.02,
|
||||
laser_detuning=0,
|
||||
Δ=0,
|
||||
ω_c=0,
|
||||
N=3,
|
||||
measurement_detuning=1,
|
||||
rwa=False,
|
||||
|
@ -55,7 +55,7 @@ def steady_rabi():
|
|||
f, (_, ax) = plot_simulation_result(
|
||||
make_figure(), t, signal, params, window=(params.lifetimes(8), t[-1])
|
||||
)
|
||||
plot_sidebands(ax, params)
|
||||
plot_rabi_sidebands(ax, params)
|
||||
|
||||
f.suptitle("Steady State Rabi oscillation. No Rabi Sidebands.")
|
||||
|
||||
|
@ -69,7 +69,7 @@ def noisy_transient_rabi():
|
|||
δ=1 / 4,
|
||||
g_0=0.02,
|
||||
laser_detuning=0,
|
||||
Δ=0,
|
||||
ω_c=0,
|
||||
N=3,
|
||||
measurement_detuning=1,
|
||||
rwa=False,
|
||||
|
@ -88,7 +88,7 @@ def noisy_transient_rabi():
|
|||
f, (_, ax) = plot_simulation_result(
|
||||
make_figure(), t, signal, params, window=(params.laser_off_time, t[-1])
|
||||
)
|
||||
plot_sidebands(ax, params)
|
||||
plot_rabi_sidebands(ax, params)
|
||||
|
||||
f.suptitle(f"Transient Rabi oscillation with noise strength {noise_strength}.")
|
||||
|
||||
|
@ -104,7 +104,7 @@ def ringdown_after_rabi():
|
|||
δ=1 / 4,
|
||||
g_0=0.02,
|
||||
laser_detuning=laser_detuning,
|
||||
Δ=0,
|
||||
ω_c=0,
|
||||
N=3,
|
||||
measurement_detuning=2,
|
||||
rwa=False,
|
||||
|
@ -139,7 +139,7 @@ def sweep():
|
|||
δ=1 / 4,
|
||||
g_0=0.0,
|
||||
laser_detuning=-2,
|
||||
Δ=0,
|
||||
ω_c=0,
|
||||
N=3,
|
||||
measurement_detuning=0,
|
||||
rwa=False,
|
||||
|
@ -150,6 +150,6 @@ def sweep():
|
|||
signal = output_signal(t, solution.y, params)
|
||||
|
||||
f, (_, ax) = plot_simulation_result(make_figure(), t, signal, params)
|
||||
plot_sidebands(ax, params)
|
||||
plot_rabi_sidebands(ax, params)
|
||||
# ax.set_xlim(0.73, 0.77)
|
||||
f.suptitle("Transient Rabi oscillation")
|
||||
|
|
46
scripts/experiments/004_full_nm_walk_tests.py
Normal file
46
scripts/experiments/004_full_nm_walk_tests.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
from rabifun.system import *
|
||||
from rabifun.plots import *
|
||||
from rabifun.utilities import *
|
||||
|
||||
# %% interactive
|
||||
|
||||
|
||||
def test_collective_mode_rabi():
|
||||
"""This is couples to a linear combination of bathe modes in stead of to a single one, but the result is pretty much the same."""
|
||||
params = Params(
|
||||
η=0.01,
|
||||
Ω=1,
|
||||
δ=1 / 4,
|
||||
g_0=0.01,
|
||||
laser_detuning=0,
|
||||
ω_c=0.00,
|
||||
N=2,
|
||||
N_couplings=2,
|
||||
measurement_detuning=0,
|
||||
rwa=False,
|
||||
flat_energies=True,
|
||||
)
|
||||
|
||||
# params.laser_off_time = params.lifetimes(5)
|
||||
t = time_axis(params, 15, 0.01)
|
||||
solution = solve(t, params)
|
||||
print(RuntimeParams(params))
|
||||
# signal = output_signal(t, solution.y, params)
|
||||
|
||||
# f, (_, ax) = plot_simulation_result(
|
||||
# make_figure(), t, signal, params, window=(params.lifetimes(5), t[-1])
|
||||
# )
|
||||
# # ax.axvline(params.laser_off_time)
|
||||
# plot_rabi_sidebands(ax, params)
|
||||
|
||||
fig = make_figure()
|
||||
ax = fig.subplots()
|
||||
|
||||
rotsol = in_rotating_frame(t, solution.y, params)
|
||||
|
||||
ax.plot(t, np.abs(rotsol)[1])
|
||||
ax.plot(t, np.abs(rotsol)[2])
|
||||
ax.plot(t, np.abs(rotsol)[3])
|
||||
# ax.plot(t, np.abs(rotsol)[4])
|
||||
# ax.plot(t, np.abs(in_rotating_frame(t, solution.y, params))[2])
|
||||
# ax.plot(t, np.abs(in_rotating_frame(t, solution.y, params))[3])
|
|
@ -1,5 +1,5 @@
|
|||
from plot_utils import *
|
||||
from .system import Params
|
||||
from .system import Params, RuntimeParams
|
||||
from .analysis import fourier_transform
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
@ -37,7 +37,7 @@ def plot_simulation_result(
|
|||
ax2.set_xlim(0, params.Ω * (params.N))
|
||||
ax3 = ax2.twinx()
|
||||
|
||||
ax2.plot(freq, np.abs(fft))
|
||||
ax2.plot(freq, np.abs(fft) ** 2)
|
||||
# ax2.set_yscale("log")
|
||||
ax2.set_title("FFT")
|
||||
ax2.set_xlabel("ω [linear]")
|
||||
|
@ -57,7 +57,7 @@ def plot_simulation_result(
|
|||
return (ax1, ax2)
|
||||
|
||||
|
||||
def plot_sidebands(ax, params: Params):
|
||||
def plot_rabi_sidebands(ax, params: Params):
|
||||
"""Visualize the frequency of the sidebands.
|
||||
|
||||
:param ax: axis to plot on
|
||||
|
@ -68,20 +68,21 @@ def plot_sidebands(ax, params: Params):
|
|||
first_sidebands = np.abs(
|
||||
-(params.laser_detuning + params.measurement_detuning)
|
||||
+ np.array([1, -1]) * energy / 2
|
||||
+ params.Δ / 2
|
||||
+ params.ω_c / 2
|
||||
)
|
||||
second_sidebands = (
|
||||
params.Ω * (1 - params.δ)
|
||||
- (params.laser_detuning + params.measurement_detuning)
|
||||
+ np.array([1, -1]) * energy / 2
|
||||
- params.Δ / 2
|
||||
- params.ω_c / 2
|
||||
)
|
||||
|
||||
ax.axvline(
|
||||
params.ω_eom / (2 * np.pi) - params.measurement_detuning,
|
||||
color="black",
|
||||
label="steady state",
|
||||
)
|
||||
for ω in RuntimeParams(params).drive_frequencies:
|
||||
ax.axvline(
|
||||
ω - params.measurement_detuning,
|
||||
color="black",
|
||||
label="steady state",
|
||||
)
|
||||
|
||||
for n, sideband in enumerate(first_sidebands):
|
||||
ax.axvline(
|
||||
|
|
|
@ -11,6 +11,13 @@ class Params:
|
|||
N: int = 2
|
||||
"""Number of bath modes."""
|
||||
|
||||
N_couplings: int = 2
|
||||
"""Number of bath modes to couple to.
|
||||
|
||||
To test the RWA it is useful to couple less than the full
|
||||
complement of modes.
|
||||
"""
|
||||
|
||||
Ω: float = 1
|
||||
"""Free spectral range of the system in *frequency units*."""
|
||||
|
||||
|
@ -24,8 +31,11 @@ class Params:
|
|||
g_0: float = 0.01
|
||||
"""Drive amplitude in units of :any:`Ω`."""
|
||||
|
||||
Δ: float = 0.0
|
||||
"""Detuning of the EOM drive in *frequency units*."""
|
||||
α: float = 0.0
|
||||
"""The exponent of the spectral density of the bath."""
|
||||
|
||||
ω_c: float = 0.0
|
||||
"""The cutoff frequency of the bath."""
|
||||
|
||||
laser_detuning: float = 0.0
|
||||
"""Detuning of the laser relative to the _A_ mode."""
|
||||
|
@ -48,6 +58,13 @@ class Params:
|
|||
detuning of the laser.
|
||||
"""
|
||||
|
||||
flat_energies: bool = False
|
||||
"""Whether to use a flat distribution of bath energies."""
|
||||
|
||||
def __post_init__(self):
|
||||
if self.N_couplings > self.N:
|
||||
raise ValueError("N_couplings must be less than or equal to N.")
|
||||
|
||||
def periods(self, n: float):
|
||||
"""
|
||||
Returns the number of periods of the system that correspond to
|
||||
|
@ -65,17 +82,17 @@ class Params:
|
|||
@property
|
||||
def rabi_splitting(self):
|
||||
"""The Rabi splitting of the system in *frequency units*."""
|
||||
return np.sqrt((self.Ω * self.g_0) ** 2 + self.Δ**2)
|
||||
if not self.flat_energies:
|
||||
raise ValueError("Rabi splitting is only defined for flat energies.")
|
||||
|
||||
@property
|
||||
def ω_eom(self):
|
||||
"""The frequency of the EOM drive as *angular frequency*."""
|
||||
return 2 * np.pi * (self.Ω * (1 - self.δ) - self.Δ)
|
||||
return np.sqrt((self.Ω * self.g_0) ** 2 + (self.ω_c * self.Ω) ** 2)
|
||||
|
||||
|
||||
class RuntimeParams:
|
||||
"""Secondary Parameters that are required to run the simulation."""
|
||||
|
||||
__slots__ = ["Ωs", "drive_frequencies", "drive_amplitudes"]
|
||||
|
||||
def __init__(self, params: Params):
|
||||
Ωs = 2 * np.pi * params.Ω * np.concatenate(
|
||||
[[-1 * params.δ, params.δ], np.arange(1, params.N + 1)]
|
||||
|
@ -83,6 +100,13 @@ class RuntimeParams:
|
|||
|
||||
self.Ωs = Ωs
|
||||
|
||||
self.drive_frequencies, self.drive_amplitudes = (
|
||||
drive_frequencies_and_amplitudes(params)
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.__class__.__name__}(Ωs={self.Ωs}, drive_frequencies={self.drive_frequencies}, drive_amplitudes={self.drive_amplitudes})"
|
||||
|
||||
|
||||
def time_axis(params: Params, lifetimes: float, resolution: float = 1):
|
||||
"""Generate a time axis for the simulation.
|
||||
|
@ -101,19 +125,24 @@ def time_axis(params: Params, lifetimes: float, resolution: float = 1):
|
|||
)
|
||||
|
||||
|
||||
def eom_drive(t, x, d, ω):
|
||||
def eom_drive(t, x, ds, ωs, rwa):
|
||||
"""The electrooptical modulation drive.
|
||||
|
||||
:param t: time
|
||||
:param x: amplitudes
|
||||
:param d: drive amplitude
|
||||
:param ω: drive frequency
|
||||
:param ds: drive amplitudes
|
||||
:param ωs: linear drive frequencies
|
||||
"""
|
||||
|
||||
stacked = np.repeat([x], len(x), 0)
|
||||
|
||||
stacked = np.sum(stacked, axis=1)
|
||||
driven_x = d * np.sin(ω * t) * stacked
|
||||
if rwa:
|
||||
stacked[1, 2 : 2 + len(ωs)] *= ds * np.exp(-1j * 2 * np.pi * ωs * t)
|
||||
stacked[2 : 2 + len(ωs), 1] *= ds * np.exp(1j * 2 * np.pi * ωs * t)
|
||||
driven_x = np.sum(stacked, axis=1)
|
||||
else:
|
||||
stacked = np.sum(stacked, axis=1)
|
||||
driven_x = np.sum(ds * np.sin(2 * np.pi * ωs * t)) * stacked
|
||||
|
||||
return driven_x
|
||||
|
||||
|
@ -122,7 +151,10 @@ def laser_frequency(params: Params, t: np.ndarray):
|
|||
"""The frequency of the laser light as a function of time."""
|
||||
base = 2 * np.pi * (params.laser_detuning + params.Ω * params.δ)
|
||||
if params.dynamic_detunting[1] == 0:
|
||||
return base
|
||||
if np.isscalar(t):
|
||||
return base
|
||||
|
||||
return np.repeat(base, len(t))
|
||||
|
||||
return base + 2 * np.pi * (
|
||||
params.dynamic_detunting[0] * t / params.dynamic_detunting[1]
|
||||
|
@ -137,11 +169,15 @@ def make_righthand_side(runtime_params: RuntimeParams, params: Params):
|
|||
|
||||
if params.rwa:
|
||||
x[0] = 0
|
||||
x[3:] = 0
|
||||
x[2 + params.N_couplings :] = 0
|
||||
|
||||
if (params.drive_off_time is None) or (t < params.drive_off_time):
|
||||
differential += eom_drive(
|
||||
t, x, 2 * np.pi * params.Ω * params.g_0, params.ω_eom
|
||||
t,
|
||||
x,
|
||||
runtime_params.drive_amplitudes,
|
||||
runtime_params.drive_frequencies,
|
||||
params.rwa,
|
||||
)
|
||||
|
||||
if (params.laser_off_time is None) or (t < params.laser_off_time):
|
||||
|
@ -151,7 +187,7 @@ def make_righthand_side(runtime_params: RuntimeParams, params: Params):
|
|||
|
||||
if params.rwa:
|
||||
differential[0] = 0
|
||||
differential[3:] = 0
|
||||
differential[2 + params.N_couplings :] = 0
|
||||
|
||||
return -1j * differential
|
||||
|
||||
|
@ -175,7 +211,7 @@ def solve(t: np.ndarray, params: Params):
|
|||
(np.min(t), np.max(t)),
|
||||
initial,
|
||||
vectorized=False,
|
||||
# max_step=0.01 * np.pi / (params.Ω * params.N),
|
||||
max_step=0.01 * np.pi / (params.Ω * params.N),
|
||||
t_eval=t,
|
||||
)
|
||||
|
||||
|
@ -186,7 +222,15 @@ def in_rotating_frame(
|
|||
"""Transform the amplitudes to the rotating frame."""
|
||||
Ωs = RuntimeParams(params).Ωs
|
||||
|
||||
return amplitudes * np.exp(1j * Ωs[:, None].real * t[None, :])
|
||||
detunings = np.concatenate(
|
||||
[[0, 0], drive_detunings(params), np.zeros(params.N - params.N_couplings)]
|
||||
)
|
||||
|
||||
return amplitudes * np.exp(
|
||||
1j
|
||||
* (Ωs[:, None].real - detunings[:, None] + laser_frequency(params, t)[None, :])
|
||||
* t[None, :]
|
||||
)
|
||||
|
||||
|
||||
def output_signal(t: np.ndarray, amplitudes: np.ndarray, params: Params):
|
||||
|
@ -202,3 +246,60 @@ def output_signal(t: np.ndarray, amplitudes: np.ndarray, params: Params):
|
|||
* t
|
||||
)
|
||||
).imag
|
||||
|
||||
|
||||
def bath_energies(params: Params) -> np.ndarray:
|
||||
"""Return the energies (drive detunings) of the bath modes."""
|
||||
|
||||
return np.arange(1, params.N_couplings + 1) * params.ω_c / params.N_couplings
|
||||
|
||||
|
||||
def ohmic_spectral_density(
|
||||
ω: np.ndarray, g_0: float, α: float, ω_c: float
|
||||
) -> np.ndarray:
|
||||
"""The spectral density of an Ohmic bath."""
|
||||
|
||||
mask = (ω > ω_c) | (ω < 0)
|
||||
|
||||
ret = np.empty_like(ω)
|
||||
ret[mask] = 0
|
||||
ret[~mask] = g_0**2 * (α + 1) / (ω_c ** (α + 1)) * (ω**α)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def drive_detunings(params: Params) -> np.ndarray:
|
||||
"""Return the drive detunings of the bath modes in frequency units."""
|
||||
|
||||
if params.flat_energies:
|
||||
Δs = np.repeat(params.ω_c, params.N_couplings)
|
||||
else:
|
||||
Δs = bath_energies(params)
|
||||
|
||||
return Δs * params.Ω
|
||||
|
||||
|
||||
def drive_frequencies_and_amplitudes(params: Params) -> tuple[np.ndarray, np.ndarray]:
|
||||
"""
|
||||
Return the linear frequencies and amplitudes of the drives based
|
||||
on the ``params``.
|
||||
"""
|
||||
|
||||
Δs = drive_detunings(params)
|
||||
if params.flat_energies:
|
||||
amplitudes = np.ones_like(Δs)
|
||||
else:
|
||||
amplitudes = (
|
||||
ohmic_spectral_density(
|
||||
Δs, params.g_0 * params.Ω, params.α, params.ω_c * params.Ω
|
||||
)
|
||||
* params.ω_c
|
||||
* params.Ω
|
||||
/ Params.N_couplings
|
||||
)
|
||||
|
||||
amplitudes /= np.sum(amplitudes)
|
||||
amplitudes = 2 * np.pi * params.Ω * params.g_0 * np.sqrt(amplitudes)
|
||||
|
||||
ωs = ((np.arange(1, params.N_couplings + 1) - params.δ) * params.Ω) - Δs
|
||||
return ωs, amplitudes
|
||||
|
|
Loading…
Add table
Reference in a new issue