import mmf_setup
mmf_setup.nbinit()
This cell adds /home/docs/checkouts/readthedocs.org/user_builds/gpe/checkouts/latest/src to your path, and contains some definitions for equations and some CSS for styling the notebook. If things look a bit strange, please try the following:
- Choose "Trust Notebook" from the "File" menu.
- Re-execute this cell.
- Reload the notebook.
Two-Component BECs (BEC2)#
Here and in the file bec2.py we present code that solves the GPE
for a two-component system. The energy density and equations of motion are:
For the standard GPE, the equation of state is:
This structure is supported in an augmented state.data array of shape (2, N_x, N_y, N_z) where the first index refers to indices a or b. Note now that functions like integrate(), get_N(), and braket() now return arrays of shape (2,) instead of scalars.
Twisted Boundary Conditions#
Instead of a periodic box, one can work with twisted boundary conditions whereby
To implement such boundary conditions, we use the periodic function
when computing the FFT. To compute derivatives, we must thus first apply this shift to the wavefunction to get a periodic function, then take the FFT, then use momenta that have been shifted by \(-\phi/L\) etc.
%pylab inline --no-import-all
from IPython.display import display, clear_output
from gpe import bec2
%pylab is deprecated, use %matplotlib inline and import the required libraries.
Populating the interactive namespace from numpy and matplotlib
[I 03:36:21 root] Patching zope.interface.document.asReStructuredText to format code
[I 03:36:21 numexpr.utils] NumExpr defaulting to 2 threads.
reload(bec2)
from gpe.bec2 import State, u
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[4], line 1
----> 1 reload(bec2)
2 from gpe.bec2 import State, u
NameError: name 'reload' is not defined
s = State(Nxyz=(128,), Lxyz=(40 * u.micron,), N=1e5)
s.plot()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[5], line 1
----> 1 s = State(Nxyz=(128,), Lxyz=(40 * u.micron,), N=1e5)
2 s.plot()
NameError: name 'State' is not defined
Testing#
To test the code, we will set \(g=0\) and use the exact solution for the Harmonic Oscillator:
def get_err(N=128, L=24 * u.micron):
s = State(Nxyz=(N,), Lxyz=(L,), N=1e5)
s.gs = 0, 0, 0
a = np.sqrt(u.hbar / u.m / s.ws[0])
x = s.xyz[0]
psi_0 = np.exp(-((x / a) ** 2) / 2.0)
s[...] = psi_0[None, :]
s.normalize()
dy = s.empty()
s.compute_dy_dt(dy=dy, subtract_mu=True)
return abs(dy[...]).max()
Ns = 2 ** np.arange(2, 8)
errs = map(get_err, Ns)
plt.semilogy(Ns, errs, "-+")
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[6], line 1
----> 1 def get_err(N=128, L=24 * u.micron):
2 s = State(Nxyz=(N,), Lxyz=(L,), N=1e5)
3 s.gs = 0, 0, 0
4 a = np.sqrt(u.hbar / u.m / s.ws[0])
NameError: name 'u' is not defined
Why are \(L=23\)microns and \(N=2^6\) optimal?
s = State(Nxyz=(46,), Lxyz=(23 * u.micron,))
a = np.sqrt(u.hbar / u.m / s.ws[0])
L, N = s.Lxyz[0], s.Nxyz[0]
k_max = np.pi * (N - 2) / L # For Khalid...
print k_max, np.max(s.kxyz[0])
print np.exp(-((L / 2 / a) ** 2) / 2) # Wavefunction drops by factor of macheps
Cell In[7], line 5
print k_max, np.max(s.kxyz[0])
^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
psi_0 = s.xyz[0] * np.exp(-((s.xyz[0] / a) ** 2) / 2)
plt.semilogy(
np.fft.fftshift(s.kxyz[0]).ravel(),
np.fft.fftshift(abs(np.fft.fft(psi_0))).ravel(),
"-+",
)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[8], line 1
----> 1 psi_0 = s.xyz[0] * np.exp(-((s.xyz[0] / a) ** 2) / 2)
2 plt.semilogy(
3 np.fft.fftshift(s.kxyz[0]).ravel(),
4 np.fft.fftshift(abs(np.fft.fft(psi_0))).ravel(),
NameError: name 's' is not defined
So we see that for the ground state \(k\) needs to go up to \(6\).
Exact Solution with Interactions#
Consider now a state with \(\psi_a = e^{-(x/a)^2/2}\) and \(\psi_b = e^{-(x/b)^2/2}\).
%pylab inline --no-import-all
from IPython.display import display, clear_output
from gpe import bec2
reload(bec2)
from gpe.bec2 import State, u
s = State(Nxyz=(64,), Lxyz=(23 * u.micron,), N=1e5)
a = np.sqrt(u.hbar / u.m / s.ws[0])
x = s.xyz[0]
psi_0 = np.exp(-((x / a) ** 2) / 2)
class State1(State):
def __init__(self, *v, **kw):
State.__init__(self, *v, **kw)
a = np.sqrt(u.hbar / u.m / self.ws[0])
x = self.xyz[0]
k = 1.0 / 2.0 / a ** 2
psi_0 = 4.0 * np.exp(-((x / a) ** 2) / 2)
n_0 = abs(psi_0) ** 2
g_aa, g_bb, g_ab = self.gs
self._V_ext = (
u.hbar ** 2 / 2.0 / u.m * (4 * (k * x) ** 2 - 2 * k) - g_aa * n_0,
u.hbar ** 2 / 2.0 / u.m * (4 * (k * x) ** 2 - 2 * k) - g_bb * n_0,
0 * n_0,
)
self.data[...] = psi_0
self.get_Vext = lambda: self._V_ext
self.pre_evolve_hook()
s = State1(Nxyz=(64,), Lxyz=(23 * u.micron,))
s.plot()
plt.plot(x, s.get_Vext()[0])
dy = s.empty()
s.compute_dy_dt(dy=dy, subtract_mu=False)
abs(dy[...]).max()
%pylab is deprecated, use %matplotlib inline and import the required libraries.
Populating the interactive namespace from numpy and matplotlib
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[9], line 5
1 get_ipython().run_line_magic('pylab', 'inline --no-import-all')
2 from IPython.display import display, clear_output
3 from gpe import bec2
4
----> 5 reload(bec2)
6 from gpe.bec2 import State, u
7
8 s = State(Nxyz=(64,), Lxyz=(23 * u.micron,), N=1e5)
NameError: name 'reload' is not defined
from mmfutils.contexts import NoInterrupt
from pytimeode.evolvers import EvolverSplit, EvolverABM
from IPython.display import display, clear_output
s = State1(Nxyz=(64 * 4,), Lxyz=(23 * u.micron,))
assert np.allclose(s._N, s.get_N())
s[...] = 1.0
s.normalize()
s.cooling_phase = 1j
E_max = u.hbar ** 2 * np.abs(s.kxyz).max() ** 2 / 2.0 / u.m
# e = EvolverSplit(s, dt=0.01*u.hbar/E_max, normalize=True)
e = EvolverABM(s, dt=0.1 * u.hbar / E_max, normalize=True)
with NoInterrupt(ignore=True) as interrupted:
while e.y.t < 4 * u.ms and not interrupted:
e.evolve(100)
plt.clf()
e.y.plot()
display(plt.gcf())
clear_output(wait=True)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[10], line 5
1 from mmfutils.contexts import NoInterrupt
2 from pytimeode.evolvers import EvolverSplit, EvolverABM
3 from IPython.display import display, clear_output
4
----> 5 s = State1(Nxyz=(64 * 4,), Lxyz=(23 * u.micron,))
6 assert np.allclose(s._N, s.get_N())
7
8 s[...] = 1.0
NameError: name 'State1' is not defined
from mmfutils.contexts import NoInterrupt
from pytimeode.evolvers import EvolverSplit, EvolverABM
from IPython.display import display, clear_output
s = State1(Nxyz=(64 * 4,), Lxyz=(23 * u.micron,))
s *= np.sign(s.xyz[0] - 0.5)
s.cooling_phase = 1 + 0.01j
E_max = u.hbar ** 2 * np.abs(s.kxyz).max() ** 2 / 2.0 / u.m
# e = EvolverSplit(s, dt=0.01*u.hbar/E_max, normalize=True)
e = EvolverABM(s, dt=0.5 * u.hbar / E_max, normalize=True)
with NoInterrupt(ignore=True) as interrupted:
while e.y.t < 40 * u.ms and not interrupted:
e.evolve(100)
plt.clf()
e.y.plot()
display(plt.gcf())
clear_output(wait=True)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[11], line 5
1 from mmfutils.contexts import NoInterrupt
2 from pytimeode.evolvers import EvolverSplit, EvolverABM
3 from IPython.display import display, clear_output
4
----> 5 s = State1(Nxyz=(64 * 4,), Lxyz=(23 * u.micron,))
6 s *= np.sign(s.xyz[0] - 0.5)
7 s.cooling_phase = 1 + 0.01j
8
NameError: name 'State1' is not defined
2D Scissor Modes (incomplete)#
We base the physical parameters on a system like [Marago:2001] so we can explore damping of the normal modes of the system. They have trapping frequencies of \(\omega_y=\omega_z = 128\)Hz and \(\omega_x = \sqrt{8}\omega_y\) and \(N = 2\times 10^4\) particles. In the TF approximation at \(T=0\) this corresponds to \(\mu = \)
[Marago:2001]: http://dx.doi.org/10.1103/PhysRevLett.86.3938 (Onofrio Marag`o, Gerald Hechenblaikner, Eleanor Hodby, and Christopher Foot, “Temperature Dependence of Damping and Frequency Shifts of the Scissors Mode of a Trapped Bose-Einstein Condensate”, Phys. Rev. Lett. 86, 3938–3941 (2001) )
%pylab inline --no-import-all
from IPython.display import display, clear_output
%pylab is deprecated, use %matplotlib inline and import the required libraries.
Populating the interactive namespace from numpy and matplotlib
from gpe import bec
reload(bec)
from pytimeode.evolvers import EvolverABM
from mmfutils.contexts import NoInterrupt
from gpe.bec import State, u
s = State()
s.cooling_phase = 1j
s.t = -100 * u.ms
e = EvolverABM(s, dt=0.001)
with NoInterrupt(ignore=True) as interrupted:
while not interrupted:
e.evolve(500)
plt.clf()
e.y.plot()
display(plt.gcf())
clear_output(wait=True)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[13], line 3
1 from gpe import bec
2
----> 3 reload(bec)
4 from pytimeode.evolvers import EvolverABM
5 from mmfutils.contexts import NoInterrupt
6 from gpe.bec import State, u
NameError: name 'reload' is not defined
s = e.get_y()
n = s.get_density()
x, y, z = s.xyz
plt.plot(x.ravel(), n.sum(axis=-1).sum(axis=-1))
s.mu, s._mu
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[14], line 1
----> 1 s = e.get_y()
2 n = s.get_density()
3 x, y, z = s.xyz
4 plt.plot(x.ravel(), n.sum(axis=-1).sum(axis=-1))
NameError: name 'e' is not defined
Bright Solitons#
There is nice integrable 1D model that is useful for testing code in the case of attractive interactions (the so-called focusing NLSEQ):
where \(n_{+} = n_a + n_b\). This corresponds to a coupled set of GPEs with equal attractive interactions \(g_{aa} = g_{bb} = g_{ab} = -g\).
We have the following dimensions:
In the paper, units are scaled so that \(2m = \hbar = 1\). This means that \(g\) provides the length scale for the problem.
from numpy import cos, sin, exp
theta, Gamma = np.random.random(2)
(cos(theta) * exp(-1j * Gamma) + sin(theta) * np.exp(1j * Gamma)) / 2, (
cos(theta + Gamma) - 1j * sin(theta - Gamma)
) / 4
(np.complex128(0.5510033158108356-0.020159308102452346j),
np.complex128(0.24700595507245932-0.01593005327747076j))
%pylab inline --no-import-all
from IPython.display import display, clear_output
from pytimeode.evolvers import EvolverABM
from mmfutils.contexts import NoInterrupt
from gpe import bec2
reload(bec2)
from gpe.bec2 import State2, u
class StateBS(State2):
t0 = u.micron ** 2 * 2 * u.m / u.hbar
def get_Vext(self):
Va = Vb = 0 * self.xyz[0]
return (Va, Vb, self.Omega)
# Paper dimensions
g_ = 2.0
Omega_ = 2.0
theta_ = np.pi / 4.0
b_ = 2.0
s = StateBS(Nxyz=(128,), Lxyz=(4 * u.micron,), N=1e5)
s = StateBS(
Nxyz=(64 * 4,),
Lxyz=(16 * u.micron,),
N=1e5,
gs=(-g_ * u.hbar ** 2 / 2.0 / u.m,) * 3,
Omega=Omega_ * u.hbar ** 2 / 2.0 / u.m,
cooling_phase=1.0j,
)
# Fig 9
g = -g_ * u.hbar ** 2 / 2.0 / u.m
s = StateBS(
Nxyz=(64,),
Lxyz=(16 * u.micron,),
N=1e5,
gs=(g * 1.01, g * 1.01, g * 0.99),
Omega=Omega_ * u.hbar ** 2 / 2.0 / u.m,
cooling_phase=1.0,
)
x = s.xyz[0]
s[0, ...] = (
(np.cos(theta_) + np.sin(theta_)) / 2.0 * b_ / np.cosh(b_ * np.sqrt(g_) * x / 2.0)
)
s[1, ...] = (
(np.cos(theta_) - np.sin(theta_)) / 2.0 * b_ / np.cosh(b_ * np.sqrt(g_) * x / 2.0)
)
# s[...] += np.random.random(s.shape)*0.1
s.plot()
%pylab is deprecated, use %matplotlib inline and import the required libraries.
Populating the interactive namespace from numpy and matplotlib
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[17], line 7
3 from pytimeode.evolvers import EvolverABM
4 from mmfutils.contexts import NoInterrupt
5 from gpe import bec2
6
----> 7 reload(bec2)
8 from gpe.bec2 import State2, u
9
10
NameError: name 'reload' is not defined
e = EvolverABM(s, dt=0.5 / s.E_max / u.hbar)
with NoInterrupt(ignore=True) as interrupted:
while not interrupted:
e.evolve(10)
plt.clf()
e.y.plot()
display(plt.gcf())
clear_output(wait=True)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[18], line 1
----> 1 e = EvolverABM(s, dt=0.5 / s.E_max / u.hbar)
2 with NoInterrupt(ignore=True) as interrupted:
3 while not interrupted:
4 e.evolve(10)
NameError: name 's' is not defined
import sympy
sympy.init_session()
var("a, theta, b, g, x")
psi = a / cosh(x * b * sqrt(g) / 2)
n = psi ** 2
r1, r2 = (-psi.diff(x, x) / 2).trigsimp().simplify(), (g * n * psi).simplify()
r1, r2
IPython console for SymPy 1.14.0 (Python 3.14.4-64-bit) (ground types: python)
These commands were executed:
>>> from sympy import *
>>> x, y, z, t = symbols('x y z t')
>>> k, m, n = symbols('k m n', integer=True)
>>> f, g, h = symbols('f g h', cls=Function)
>>> init_printing()
Documentation can be found at https://docs.sympy.org/1.14.0/
---------------------------------------------------------------------------
KeyboardInterrupt Traceback (most recent call last)
Cell In[20], line 6
2 var("a, theta, b, g, x")
3 psi = a / cosh(x * b * sqrt(g) / 2)
4 n = psi ** 2
5 r1, r2 = (-psi.diff(x, x) / 2).trigsimp().simplify(), (g * n * psi).simplify()
----> 6 r1, r2
File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/decorator/__init__.py:247, in decorate.<locals>.fun(*args, **kw)
245 if not kwsyntax:
246 args, kw = fix(args, kw, sig)
--> 247 return caller(func, *(extras + args), **kw)
File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/sympy/interactive/printing.py:179, in _init_ipython_printing.<locals>._print_latex_png(o)
177 s = '$\\displaystyle %s$' % s
178 try:
--> 179 return _preview_wrapper(s)
180 except RuntimeError as e:
181 debug('preview failed with:', repr(e),
182 ' Falling back to matplotlib backend')
File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/sympy/interactive/printing.py:90, in _init_ipython_printing.<locals>._preview_wrapper(o)
88 exprbuffer = BytesIO()
89 try:
---> 90 preview(o, output='png', viewer='BytesIO', euler=euler,
91 outputbuffer=exprbuffer, extra_preamble=extra_preamble,
92 dvioptions=dvioptions, fontsize=fontsize)
93 except Exception as e:
94 # IPython swallows exceptions
95 debug("png printing:", "_preview_wrapper exception raised:",
96 repr(e))
File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/sympy/printing/preview.py:311, in preview(expr, output, viewer, euler, packages, filename, outputbuffer, preamble, dvioptions, outputTexFile, extra_preamble, fontsize, **latex_settings)
308 raise RuntimeError("latex program is not installed")
310 try:
--> 311 _check_output_no_window(
312 ['latex', '-halt-on-error', '-interaction=nonstopmode',
313 'texput.tex'],
314 cwd=workdir,
315 stderr=STDOUT)
316 except CalledProcessError as e:
317 raise RuntimeError(
318 "'latex' exited abnormally with the following output:\n%s" %
319 e.output)
File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/sympy/printing/preview.py:26, in _check_output_no_window(*args, **kwargs)
24 else:
25 creation_flag = 0 # Default value
---> 26 return check_output(*args, creationflags=creation_flag, **kwargs)
File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/subprocess.py:473, in check_output(timeout, *popenargs, **kwargs)
470 empty = b''
471 kwargs['input'] = empty
--> 473 return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
474 **kwargs).stdout
File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/subprocess.py:557, in run(input, capture_output, timeout, check, *popenargs, **kwargs)
555 with Popen(*popenargs, **kwargs) as process:
556 try:
--> 557 stdout, stderr = process.communicate(input, timeout=timeout)
558 except TimeoutExpired as exc:
559 process.kill()
File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/subprocess.py:1208, in Popen.communicate(self, input, timeout)
1206 self._stdin_write(input)
1207 elif self.stdout:
-> 1208 stdout = self.stdout.read()
1209 self.stdout.close()
1210 elif self.stderr:
KeyboardInterrupt:
sympy.expand_trig