Walkthrough 6: The Oqtant BEC simulator¶
This notebook runs locally and on Oqtant hardware and uses 1 job
Introduction¶
The Oqtant simulator provides a theoretical simulation of a pure Bose-Einstein condensate in a magnetic trap with the same trap frequencies as the Oqtant hardware. The simulator is a useful tool for designing experiments to run on Oqtant hardware as it is always available! The simulation runs locally on your computer.
Simulation jobs require an Oqtant account and use the same workflow as normal jobs, but do NOT count against your job quota or daily limit.
The Oqtant simulator is a theorietical tool for exploring BEC. The simulator does not simulate the Oqtant hardware, rather it is an additional tool for learning and experimenting with quantum matter.
This, along with all our example notebooks are publicly available for download from our GitLab repository.
Simulator jobs are run locally and totally free! There is no limit to the number of simulations you may run per day with OqtAPI. However, the simulator still requires a valid authentication/token to use QuantumMatterFactory
methods. These tokens last for 2 hours and may be refreshed by re-evaluating the first 2 cells only. There is no need to restart the kernel to refresh your token.
Job limits and usage are displayed in every authenticated notebook whether you are running simulator or hardware jobs, which may exist in the same notebook (like this one!).
Imports and user authentication¶
from oqtant.schemas.quantum_matter import QuantumMatterFactory, QuantumMatter
from IPython.display import HTML
from matplotlib import pyplot as plt
qmf = QuantumMatterFactory()
Authenticate automatically¶
The easiest way to authenticate as an Oqtant user is to execute the following cell. This will activate a widget that will let you sign in.
If popups are blocked, or you are on a system that does not support this method, please follow the steps just below to authenticate manually instead.
Note that currently the automatic authentication method is only compatible with classic jupyter notebooks, and not jupyter lab, nanohub, binder, colab, etc.
qmf.get_login()
Authenticate manually¶
If you cannot use the automatic authentication method above, you can instead authenticate using a slightly more manual process:
- Copy your access token from oqtant.infleqtion.com/oqtantAPI
- Paste that token just below and execute the cell (the if statement keeps the code from executing if you already authenticated above)
if qmf.login.access_token == "":
qmf.login.access_token = "Paste your token here between the quotes!"
Get client¶
At this point you should have a valid access token and be able to establish a client for communicating with the Oqtant REST service. Executing the cell just below should show your current job quota limits.
qmf.get_client()
Create barrier objects as desired.¶
View the barrier dynamics and adjust as necessary. The simulator supports all of the same painted potential features as the hardware experiment.
barrier1 = qmf.create_barrier(
positions=[0, 0],
heights=[0, 3],
widths=[1, 1],
times=[0, 6],
shape="GAUSSIAN",
)
barrier1.evolve(duration=4, height=3)
barrier2 = qmf.create_barrier(
positions=[-10, -10],
heights=[0, 3],
widths=[1, 1],
times=[0, 6],
shape="GAUSSIAN",
)
barrier2.evolve(duration=4, height=3)
barrier2.show_dynamics()
Instantiate a matter object¶
Note: the time required for the simulation to complete is proportional to the lifetime of the experiment you have designed. Long lifetimes >10ms may take several minutes to complete.
sim_matter = qmf.create_quantum_matter(
barriers=[barrier1, barrier2], lifetime=10, image="IN_TRAP"
)
sim_matter.show_potential([2, 8, 9], ylimits=[0, 8])
Submit the simulation job¶
Simulated jobs are indicated with the sim=True
argument.
sim_matter.submit(sim=True)
submitted simulation
Retrieve the job results¶
This is the step that will run slowly for long lifetimes: calculating and preparing the output of the simulator. Under the hood, this step finds the ground state of the simulated system, and evolves the wave function in time in the presence of the optical potentials specified by the matter object.
Note: simulated jobs are not assigned an id or stored in the Oqtant database. All data management is left to the user. Use the local save/load functionality to preserve simulation results between python sessions.
sim_matter.get_result()
ground state calculation in progress ground state calculation complete trapped simulation in progress trapped simulation complete Simulation complete.
Save simulator outputs to file¶
Simulator jobs are run locally. In order to retrieve simulator inputs or outputs outside of your current python session, you must save them to a file. Please note that only Oqtant job outputs are saved in the resulting file:
output
input
name
temperature
- this is not used, all sim temperatures = 0lifetime
image
time_of_flight
rf_evap
- this is not used. no evaporation in sim jobsrf_shield
- this is not used. no shield in sim jobsbarriers
landscape
lasers
- this is not used. no laser pulses in sim jobsnote
Additonal simulator outputs in sim_matter.sim
, are not saved. Please take care to save all desired simulator outputs to additional files before ending your session.
sim_matter.write_to_file(file_path="your_file_path.txt")
Wrote file: "your_file_path.txt"
Load simulator outputs from file¶
sim_matter_loaded.sim
is not populated, so only sim_matter.output
is available for results. To re-produce simulator outputs, re-run the simulation using sim_matter
. Take care to include refresh=False
when loading a simulator job from file. Locally run simulations cannot be refreshed from the Oqtant server; they are only available from your local storage.
sim_matter_loaded = qmf.load_matter_from_file(
file_path="your_file_path.txt", refresh=False
)
print(sim_matter_loaded.status)
COMPLETE
Duplicate a simulation loaded from file¶
The easiest way to copy a simulation job for re-run (on hardware or simulation) is to create a QuantumMatter
object directly from the input object, rather than using qmf.create_quantum_matter()
sim_matter_rerun = QuantumMatter.from_input(
name="test_sim_rerun", input=sim_matter_loaded.input, client=qmf.client
)
sim_matter_rerun.submit(sim=True)
submitted simulation
View simulator results¶
Simulator results are interpolated to the resolution of the in-trap imaging system, so they are easily compared to experimental results. Use the output
object methods to investigate the results.
A note on simulator-generated IT OD images¶
When the Oqtant hardware captures an in-trap image, the number of atoms detected is affected by the presence of the magnetic trap. Spatially varying magnetic fields (check out sim_matter.show_potential
) also complicate the calculation of atom number in hardware experimental in-trap images. For this reason, Oqtant in-trap images are not returned with an atom number.
Conversely, the simulator has perfect detection because every atom is accounted for. In order to produce simulator in-trap image outputs which are an approximate indicator of hardware performance, simulator in-trap images have been systematically corrected to match the offset in atom number observed in experiment. The result is an in-trap image with a hardware-like peak OD, which displays fewer atoms. If you wish to calculate atom currents or total atoms in any specific region, please use the un-corrected outputs in sim_matter.sim.get_column_densities
. Read more about Oqtant hardware imaging here: Oqtant imaging tech note
sim_matter.output.plot_it(grid_on=False)
Additional simulation outputs¶
The simulation object in OqtAPI comes with lots of fun visualization tools to explore the quantum wave function of your simulated BEC. These outputs cannot be generated in a single shot of the experiment due to the destructive nature of imaging.
View and animate sample density at arbitrary times¶
The simulation grid size depends on whether the requested time (in ms) is within the in-trap experiment, or during TOF expansion. Show and access the cartesian column densities of the sample along both axes of the trap.
Note the conversion from simulator length units to microns.
time = 1
col_y, col_x, slice_y, slice_x = sim_matter.sim.get_column_densities(time_ms=time)
_, _, x_1d = sim_matter.sim.get_grids(time)
plt.plot(x_1d, slice_x)
plt.xlabel("X ($\\mu$m)")
plt.ylabel("Density (Atoms/ $\\mu$m ^2)")
plt.title("Simulator X slice at t = " + str(time) + "ms")
plt.show()
sim_matter.sim.show_column_densities(times_ms=[1.0], slices=True)
Density animations are only available during the in-trap portion of the experiment¶
If you wish to animate this portion, you may access column densitites for time-of-flight using sim_matter.sim.get_column_densities
and create your own animation!
den = sim_matter.sim.animate_density(frame_interval=1, show_potential=True)
HTML(den.to_jshtml())
Animate the density profile of the condensate¶
X is along the long axis of the trap.
profiles = sim_matter.sim.animate_profiles(frame_interval=2)
HTML(profiles.to_jshtml())
View and animate phase of the condensate¶
The phase of the condensate wave function determines the flow and energy of condensed atoms. In particular, spatial changes in the phase indicate currents of condensed atoms, while changes in the phase in time reflect energies.
Plot the phase information (in cylindrical coordinates) at arbitrary times, and produce animations for the in-trap portion of the experiment.
# visualize the quantum phase. useful to the user but no hardwaree equivalent output. cylindrical coordinates with x defining the long axis and R defining the radial axis.
sim_matter.sim.show_phase([0.1, 5, 10], figsize=(3, 3))
phase = sim_matter.sim.animate_phase(frame_interval=1, show_potential=True)
HTML(phase.to_jshtml())
View and animate the flow of atoms in the condensate¶
This may also be called the atom current. Positive currents flow to the right, negative to the left.
# total current along the x-direction. useful to a user but no hardware equivalent output.
sim_matter.sim.show_current([9], figsize=(6, 4))
flow = sim_matter.sim.animate_current(frame_interval=1)
HTML(flow.to_jshtml())
Simulate the same job in time of flight¶
sim_matter_tof = qmf.create_quantum_matter(
barriers=[barrier1, barrier2], lifetime=10, time_of_flight=10
)
sim_matter_tof.submit(sim=True)
submitted simulation
sim_matter_tof.get_result()
ground state calculation in progress ground state calculation complete trapped simulation in progress trapped simulation complete time-of-flight simulation in progress Simulation complete.d TOF 19.979 of 20.000ms
sim_matter_tof.output.plot_tof(figsize=(5, 5))
exp_matter = qmf.create_quantum_matter(
barriers=[barrier1, barrier2], lifetime=10, image="IN_TRAP"
)
# exp_matter.submit()
exp_matter.get_result()
print(exp_matter.status)
exp_matter.output.plot_it()
Memory and evaluation time considerations¶
The available memory and time required to evaluate an Oqtant simulator job depend principally on the length of the different experimental stages specified. Memory and time do not scale significantly with experiment complexity (i.e. number of snapshots or barriers). TOF stage duration dominates evaluation time due to the larger grid size. For more information about grid size, see the simulator technical note.
Benchmarking of the simulator¶
Initial benchmarking was performed on simulation (.get_result()
) only. Generating simulation outputs using access or plotting methods (get_column_densities
, show_column_densities
) or any animations will incur additional processing time and memory usage. Benchmarking performed on the the following machine:
A practical upper limit for the benchmark hardware: an experiment of 80ms with 20ms TOF (maximum length) ran in ~25 mins.