Giter Site home page Giter Site logo

qtc-umd / rydiqule Goto Github PK

View Code? Open in Web Editor NEW
10.0 1.0 2.0 3.22 MB

Rydberg Sensor Interactive Quantum Physics Module

License: Apache License 2.0

Shell 0.01% Python 50.40% Jupyter Notebook 49.60%
atomic-physics atomic-sensors electrometry quantum-optics rydberg

rydiqule's Introduction

rydiqule

The Rydberg Interactive Quantum module is a modeling library designed to simulate the response of Rydberg atoms to arbitrary input RF waveforms. It also functions as a general master equation solver based on the semi-classical density matrix method.

PyPI Conda Version Python Version License Docs

Please cite as

B. N Miller, D. H. Meyer, T. Virtanen, C. M O'Brien, and K. C. Cox, RydIQule: A Graph-based paradigm for modeling Rydberg and atomic sensors, Computer Physics Communications, 294, 108952 (2024) https://doi.org/10.1016/j.cpc.2023.108952

Installation

Installation is done via pip or conda. See below for detailed instructions.

In all cases, it is highly recommended to install rydiqule in a virtual environment.

Conda installation (recommended)

Installation via conda is recommended for rydiqule. It handles dependency installation as well as a virtual environment to ensure packages do not conflict with other usages on the same system. Finally, the numpy provided by anaconda has been compiled against optimized BLAS/LAPACK implementations, which results in much better performance in rydiqule itself.

Assuming you have not already created a separate environment for RydIQule (recommended), run the following to create a new environment:

(base) ~/> conda create -n rydiqule python=3.11
(base) ~/> conda activate rydiqule

RydIQule currently requires python >3.8. For a new installation, it is recommended to use the newest supported python.

Now install via rydiqule's anaconda channel. This channel provides rydiqule as well as its dependencies that are not available in the default anaconda channel. If one of these dependencies is outdated, please raise an issue with the vendoring repository.

(rydiqule) ~/> conda install -c rydiqule rydiqule

If you would like to install rydiqule in editable mode to locally modify its source, this must be done using pip. Follow the above to install rydiqule and its dependencies, then run the following to uninstall rydiqule as provided by conda and install the editable local repository.

(rydiqule) ~/> conda remove rydiqule --force
# following must be run from root of local repository
(rydiqule) ~/> pip install -e .

Note that editable installations require git. This can be provided by a system-wide installation or via conda in the virtual environment (conda install git).

While rydiqule is a pure python package (ie it is platform independent), its core dependency ARC is not. If a pre-built package of ARC is not available for your platform in our anaconda channel, you will need to install ARC via pip to build it locally before installing rydiqule. To see what architectures are supported, please see the vendoring repository.

Pure pip installation

To install normally, run:

pip install rydiqule

This command will use pip to install all necessary dependencies.

To install in an editable way (which allows edits of the source code), run the following from the root directory of the cloned repository:

pip install -e .

Editable installation requires git to be installed.

Confirm installation

Proper installation can be confirmed by executing the following commands in a python terminal.

>>> import rydiqule as rq
>>> rq.about()

        Rydiqule
    ================

Rydiqule Version:     1.1.0
Installation Path:    ~\Miniconda3\envs\rydiqule\lib\site-packages\rydiqule

      Dependencies
    ================

NumPy Version:        1.24.3
SciPy Version:        1.10.1
Matplotlib Version:   3.7.1
ARC Version:          3.3.0
Python Version:       3.9.16
Python Install Path:  ~\Miniconda3\envs\rydiqule
Platform Info:        Windows (AMD64)
CPU Count:            12
Total System Memory:  128 GB

Updating an existing installation

Upgrading an existing installation is simple. Simply run the appropriate upgrade command for the installation method used.

For conda installations, run the following command to upgrade rydiqule

conda upgrade rydiqule

For pip, you can use the installation command to upgrade. Optionally, include the update flag to greedily update dependencies as well.

pip install -U rydiqule

This command will also install any new dependencies that are required.

If using an editable install, simply replacing the files in the same directory is sufficient. Though it is recommended to also run the appropriate pip update command as well to capture updated dependencies.

pip install -U -e .

Dependencies

This package requires installation of the excellent ARC package, which is used to get Rydberg atomic properties. It also requires other standard computation dependenices, such as numpy, scipy, matplotlib, etc. These dependencies will be automatically installed if not already present.

Rydiqule's performance does depend on these depedencies. In particular, numpy can be compiled with a variety of backends that implements BLAS and LAPACK routines that can have different performance for different computer architectures. When using Windows, it is recommended to install numpy from conda, which is built against the IntelMKL and has generally shown the best performance for Intel-based PCs.

Optional timesolver backend dependencies include the numbakit-ode and CyRK packages. Both are available via pip or our anaconda channel. They can be installed automatically via the optional extras specification for the pip command.

pip install rydiqule[backends]

For conda installations, these dependencies must be installed manually.

conda install -c rydiqule CyRK numbakit-ode

Documentation

Documentation is available online at readthedocs. PDF or EPUB formats of the documentation can be downloaded from the online documentation.

Examples

Example jupyter notebooks that demonstrate RydIQule can be found in the examples subdirectory. Printouts of these notebooks are available in the documentation as well.

Support

Creation of this software was supported in part by the Defense Advanced Research Projects Agency (DARPA) Quantum Apertures program, DEVCOM Army Research Laboratory, and the Quantum Technology Center at the University of Maryland.

Disclaimer

The views, opinions and/or findings expressed are those of the authors and should not be interpreted as representing the official views or policies of the Department of Defense or the U.S. Government.

Contact

The github repository is for code distribution only. While we monitor it, we will not directly respond to issues or pull requests posted to it. If you would like a response from the developers, please e-mail [email protected] or [email protected]

rydiqule's People

Contributors

dihm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

petermao sdmoore

rydiqule's Issues

Confusion in Doppler velocity documentation and code

This issue is NOT reporting any error in calculation! I am only documenting some confusion that I encountered using Rydiqule.

There are many parameters that get used to describe thermal velocity of an ideal gas:

  1. 1-D standard deviation in the velocity: $\sqrt{kT/m}$ (aka, $\sigma$, the world over).
  2. most-probable speed: $\sqrt{2kT/m}$ (favored by Rydiqule)
  3. 3-D RMS speed: $\sqrt{3kT/m}$
  4. average speed: $\sqrt{\frac{8kT}{\pi m}}$, (favored by ARC)

Documentation

At the top level, in cell and sensor, the documentation on how to specify kvec using the most-probable speed is consistent with the underlying code:

kvec: sequence, optional
A three-element iterable that defines the
atomic doppler shift on a particular coupling field.
It should have magntiude equal to the doppler shift (in the units of Mrad/s)
of an atom moving at the Maxwell-Boltzmann distribution most probable
speed, `vP=np.sqrt(2*kB*T/m)`. I.E. `np.linalg.norm(kvec)=2*np.pi/lambda*vP`.

However, in doppler_utils.doppler_classes, most-probable speed is called "sigma", but it is really $\sqrt{2}\sigma$. The default value of 2.0 is reasonable, corresponding to ~2.8$\sigma$, but it takes a bit of diving into the code to confirm that it is a sensible default. I would have preferred a default range of $\pm 3\sigma$.
https://github.com/QTC-UMD/rydiqule/blob/e6f90608088502d7e733f0eb768b60aa4595dfe8/src/rydiqule/doppler_utils.py#L193-L195

Code

In doppler_utils.gaussian3d, the prefactor and return value are calculated for a Gaussian with $\sigma = 1/\sqrt{2}$, not 1 as claimed.

prefactor = np.power(1/(np.pi),spatial_dim*0.5)
return prefactor*np.exp(-np.square(Vs).sum(axis=0))

should be

    prefactor = np.power(1/(2*np.pi),spatial_dim*0.5)

    return prefactor*np.exp(-0.5*np.square(Vs).sum(axis=0))

but this would require changes to all of the methods of doppler_classes and likely other bits of code-surgery.

My opinions

  1. Anything called Gaussian should return a proper Gaussian.
  2. Any well-documented velocity is fine, but it would be best if Rydiqule and ARC would agree.

Hyperfine states with Cell

I'm running into issues with using hyperfine states with Cell. I'm specifying the states using the notation [n, l, j, F, mF] as the documentation suggests, but I'm getting TypeErrors.

It looks like the list for each state is getting passed to the ARC function getRabiFrequency(), but the number of arguments being passed is incompatible. It also seems like the getRabiFrequency function expects arguments in the fine basis [n, l, j, mj]. It's not clear to me how or if Rydiqule handles conversion from the coupled hyperfine basis [n, l, j, F, mF] to the fine basis [n, l, j, mj], especially since the coupled hyperfine basis states are generally superpositions of the uncoupled basis states [n, l, j, mj, i, mi].

An error is not raised if I manually compute the hyperfine transition Rabi frequencies to input in the Cell couplings.

Example code:

import rydiqule as rq
import numpy as np

states = [[6, 0, 0.5, 4, 0], [6, 1, 1.5, 5, 0]]

probe = {'states': (0,1), 'beam_power': 1e-3, 'beam_waist': 1e-3, 'detuning': 0}

cell = rq.Cell('Cs', states[0], states[1], beam_area = np.pi*probe['beam_waist']**2)
cell.add_couplings(probe)

Error message:

  File ~\python scripts\testing\untitled2.py:16
    cell.add_couplings(probe)

  File ~\AppData\Local\miniconda3\envs\rydRelease11\lib\site-packages\rydiqule\sensor.py:366 in add_couplings
    self.add_coupling(states=states, **c_copy, **extra_kwargs)

  File ~\AppData\Local\miniconda3\envs\rydRelease11\lib\site-packages\rydiqule\cell.py:732 in add_coupling
    passed_rabi = np.array([[1e-6*self.atom.getRabiFrequency(*state1, *state2[:-1],

  File ~\AppData\Local\miniconda3\envs\rydRelease11\lib\site-packages\rydiqule\cell.py:732 in <listcomp>
    passed_rabi = np.array([[1e-6*self.atom.getRabiFrequency(*state1, *state2[:-1],

  File ~\AppData\Local\miniconda3\envs\rydRelease11\lib\site-packages\rydiqule\cell.py:732 in <listcomp>
    passed_rabi = np.array([[1e-6*self.atom.getRabiFrequency(*state1, *state2[:-1],

TypeError: getRabiFrequency() takes from 11 to 12 positional arguments but 13 were given

Proper way to couple two lasers to the same transition?

Hi there,

So I am trying to couple state |a> to |b> with two lasers, the ultimate goal is to do some kind of wave mixing scheme in a ladder system. However, I am having trouble achieving this in rydiqule.

The first thing I attempted was to add two couplings independently, so we have Add_Coupling((a,b), laser_1 parameters) Add_Coupling((a,b)laser_2 parameters). The problem with this is that if you check the Hamiltonian before and after the second coupling, what the second coupling will do is simply overwrite the first coupling, so laser1's parameter will be replaced by the laser2 parameter.

The other thing I've tried was instead of solving in steady state, I solve it in the time domain, such that I only need 1 coupling statement. The way this works (or at least what I believe to be) is that since laser1 and laser2 couple the same state, then in a suitable rotating frame, we can have the off-diagonal element be written as O1+O2e^(-iDt )|a><b| where O1,O2 is the rabi frequency corresponding to laser1 and laser2 and D is the detuning of laser2. Now, I'm not sure if the time-dependent scaler function just effectively multiplies it by the rabi frequencies so that you'll see a change in the off-diagonal element but what I have done was I defined f to be f(t)=1+(O2/O1)e^(iDt ) and using this then solving it at large time scale, I did get a sensible answer but have no way of verifying the validity. Also, this method is extremely slow for my purpose and I would avoid it if possible and do a steady solution instead.

additional requirements (libomp)

Running on OSX, CyRK needed an additional package and other minor tweaking for rydiqule to load.

I installed rydiqule from my local clone with

pip install -e .

I use macports for packages and bash as my shell, so the necessary commands were:

sudo port install libomp
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH/opt/local/lib/libomp:

Zipping many parameters

Hello, first, I am very happy to be using Rydiqule! I was trying to do something a little extra, and ran into perhaps a limitation of the system worth discussing, or perhaps someone can show me the work-around, or what I'm doing wrong. I wanted to look at all the Zeeman sub-levels in EIT, and effectively drive many coupling transitions over the same detuning scan, but with varying Rabi frequencies and decay branches on each edge depending on the states it drives. So I'm looking at something like 30 or 42 zipped detuning scans, and I can zip the parameters just fine, but in the raw Hamiltonian representation, is still a [dd.....*d, n * n] matrix.
Using test detuning scans of size 3, I run into issues just looking at sub-sets:
{ Unable to allocate 127. GiB for an array with shape (3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 22) and data type complex128 }

and if I make the whole thing, I see errors in get_hamiltonian()'s mesh_grid and other counting / einsum arrangement functions such as :
{ c:_______\Anaconda3\lib\site-packages\numpy\lib\function_base.py in (.0)
4976 s0 = (1,) * ndim
-> 4977 output = [np.asanyarray(x).reshape(s0[:i] + (-1,) + s0[i + 1:])
4978 for i, x in enumerate(xi)]
ValueError: maximum supported dimension for an ndarray is 32, found 42
}

I don't see this being an easy fix,, and I don't think I'm even asking for anyone to work on it, I'm just curious how one would go about it, give how the rest of the graph-to-hamiltonian pipeline works. A big fix may be to internally write or generate the Hamiltonians where they're already zipped and many parameters scan in the same axis, losing dimensions in the big matrix representation. Perhaps if it were possible to perform a 'hard zip' that re-writes the Hamiltonian dimension, before generating the hamiltonian of that size, that's what I might be hoping for? It seems the issue is when generating and passing this big dimension matrix.
I can also imagine doing a loop over this detuning value as an external work around. It's funny, the issue is that Rydiqule is too generous at incorporating arbitrary parameters, I quickly blew up the dimensionality with p->30!

Any advice on this would be appreciated. Thanks!

Possible sign error in Hamiltonian diagonal elements

Since this is a RWA Hamiltonian, the diagonal elements should have the opposite sign of the detuning.

np.einsum("...ii->...i", hamiltonian)[:] = transition_frequencies

2-level system example

basis_size = 2
gamma = zeros((basis_size,basis_size))
gamma[1,0] = 2

Sensor = rq.Sensor(basis_size)
Sensor.set_gamma_matrix(gamma)

Sensor.add_couplings({'states':(0,1), 'rabi_frequency': 8, 'detuning': 5})

print("H = \n", Sensor.get_hamiltonian().real)
print("EOM_d = \n", rq.sensor_utils._decoherence_term(Sensor.decoherence_matrix()))
print("EOM_H = \n", rq.sensor_utils._hamiltonian_term(Sensor.get_hamiltonian()).imag)

Note that

  • $\Gamma=2$
  • $\delta=5$
  • $\Omega/2=4$
  • EOM_x order of columns (L-R) and rows (T-B) is (00),(01),(10),(11)
H = 
[[0. 4.]
 [4. 5.]]
EOM_d = 
[[ 0.  0.  0.  2.]
 [ 0. -1.  0.  0.]
 [ 0.  0. -1.  0.]
 [ 0.  0.  0. -2.]]
EOM_H = 
[[-0.  4. -4. -0.]
 [ 4.  5. -0. -4.]
 [-4. -0. -5.  4.]
 [-0. -4.  4. -0.]]

$H_{11}$ should be -5, not 5.

Compare this to Cohen-Tannoudfi, Dupont-Roc, Grynberg "Atom-Photon Interactions" (1998), Chapter V, Equations A.13.a-d (p 359) or Steck "Quantum and Atomic Optics" 0.14_2023, Eqn 5.26 (p 155):
image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.