Pancake#
import mmf_setup;mmf_setup.nbinit()
import logging;logging.getLogger('matplotlib').setLevel(logging.CRITICAL)
import matplotlib.pyplot as plt
import numpy as np
%load_ext autoreload
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.
Derivation#
We start by deriving an effective 1D theory expressing \(\Psi(\vect{x}, t) = \phi(\vect{x},t)\psi(z, t)\) and varying the action wrt \(\phi(\vect{x},t)\) which gives:
To be more specific, we now consider a general energy density of the form:
so that the Hamiltonian has the form $\( H_{\vect{x}, \vect{x}'} = \delta^3(\vect{x}-\vect{x}')\left( \frac{-\hbar^2}{2m}\nabla_{\vect{x}'}^2 + f'\bigl(n(\vect{x}, t)\bigr) \right), \qquad \int \d^3{\vect{x}'}H_{\vect{x},\vect{x}'}[n](t)\phi(\vect{x}', t)\psi(z', t) = \frac{-\hbar^2}{2m}\left( \psi(z,t)\nabla^2\phi(\vect{x}, t) +\phi(\vect{x}, t)\nabla_z^2\psi(z,t) \right) + f'\bigl(n(\vect{x}, t)\bigr)\Psi(\vect{x}, t). \)$
The normalization condition for \(\phi\) being independent of \(z\) allows us to neglect the cross-term \(2\nabla_z\phi(\vect{x}, t)\nabla_z\psi(z,t)\) (it can be removed from the Lagrangian by a total derivative which vanishes under physical boundary conditions).
The final effective 1D equation of motion can be expressed as:
The same result can be obtained by expanding the action:
For the usual energy density, this becomes
Gaussian axial profile#
A common strategy is to assume an axial Gaussian:
For \(f(n) = m\omega_z^2 z^2n/2 + gn^2/2\), we thus have
Ignore the term:
assuming that the radial variations of \(\sigma(\vect{x}, t)\) are small compared with the axial energies (something that can be tested during a simulation). Varying this with respect to \(\sigma^2\) and multiplying by \(\sigma^4\), we obtain the equation:
which, after neglecting the \(\sigma_{,\vect{x}}\) terms gives the usual NPSEQ condition:
We can use a few more definitions to make this result simpler.
Recall the definition of the scattering length and the harmonic oscillator length as $\( a = \frac{m g}{4 \pi \hbar^2},\\ a_\perp = \sqrt{\frac{\hbar}{m \omega_\perp}} \)$ respectively.
With some algebra, we get: $\( \sigma^4 = a_\perp^4 \left( 1 + 4\sqrt{2} a \left| \phi \right|^2 \right), \)$
and arguing that only the positive root is relevant; we arrive at the simplified NPSEQ condition: $\( \sigma^2 = a_\perp^2 \sqrt{\left( 1 + 4\sqrt{2} a \left| \phi \right|^2 \right)}. \)$
Central Density#
If the Gaussian is a good approximation, then the central density is related to the 1D integrated density by:
As demonstrated below, if the radial direction is large, the Gaussian ansatz may be poor even though the resulting dynamics might be well captured by this model. In this case, a different approach is required to get the central density based on the TF approximation:
This latter option is provided in by get_central_density(TF=True).
Thomas Fermi Profiles#
To initialize states we typically use a Thomas Fermi approximation. For the usual 2D case, this leads to a profile:
where \(R_{TF}\) is the Thomas Fermi “radius” (for a harmonic potential). (Of course, only positive densities should be used, if the expression is negative, the density should be set to zero.)
For the pancake effective 2D model, this must be modified somewhat. We start with the definition of the Thomas Fermi where \(n_{2D}(R) = 0\), hence \(\sigma^2(R) = \hbar/m\omega_\perp\). At this point, the chemical potential must still be augmented with the transverse energy:
(Note: we have set \(\lambda_\perp = 1\) here since we only consider initializing a state prior to expansion.)
Energy density#
Since we have an expression for the variance in the NPSEQ formalism, $\( \sigma^2 = a_\perp^2 \sqrt{\left( 1 + 4\sqrt{2} a \left| \phi \right|^2 \right)} \)$ we can take it’s first 3 derivatives to see if we can express the energy as a total derivative of some quantity, which we can then interpret as the energy density.
The energy is given as:
Demonstration#
%autoreload
from gpe import disc
expt = disc.Experiment()
#state = expt.get_initial_state()
state = expt.get_state()
state.plot()
#plt.imshow(state.get_density())
[I 20:01:26 root] Patching zope.interface.document.asReStructuredText to format code
[I 20:01:26 numexpr.utils] NumExpr defaulting to 2 threads.
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
Cell In[2], line 2
1 get_ipython().run_line_magic('autoreload', '')
----> 2 from gpe import disc
3
4 expt = disc.Experiment()
5 #state = expt.get_initial_state()
File ~/checkouts/readthedocs.org/user_builds/gpe/checkouts/latest/src/gpe/disc.py:27
22 # from mmfutils.math.bases import PeriodicBasis
23 # from mmfutils.optimize import bracket_monotonic
25 from pytimeode.evolvers import EvolverABM
---> 27 import pytest
29 piston = pytest.importorskip("piston")
30 from piston.mixins import EvolveMixin
ModuleNotFoundError: No module named 'pytest'
---------------------------------------------------------------------------
KeyboardInterrupt Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/stack_data/core.py:391, in Line.render(self, markers, strip_leading_indent, pygmented, escape_html)
389 if pygmented and self.frame_info.scope:
390 assert_(not markers, ValueError("Cannot use pygmented with markers"))
--> 391 start_line, lines = self.frame_info._pygmented_scope_lines
392 result = lines[self.lineno - start_line]
393 if strip_leading_indent:
File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/stack_data/utils.py:145, in cached_property.cached_property_wrapper(self, obj, _cls)
142 if obj is None:
143 return self
--> 145 value = obj.__dict__[self.func.__name__] = self.func(obj)
146 return value
File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/stack_data/core.py:824, in FrameInfo._pygmented_scope_lines(self)
821 ranges = []
823 code = atext.get_text(scope)
--> 824 lines = _pygmented_with_ranges(formatter, code, ranges)
826 start_line = self.source.line_range(scope)[0]
828 return start_line, lines
File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/stack_data/utils.py:166, in _pygmented_with_ranges(formatter, code, ranges)
164 lexer = MyLexer(stripnl=False)
165 try:
--> 166 highlighted = pygments.highlight(code, lexer, formatter)
167 except Exception:
168 # When pygments fails, prefer code without highlighting over crashing
169 highlighted = code
File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/pygments/__init__.py:82, in highlight(code, lexer, formatter, outfile)
77 def highlight(code, lexer, formatter, outfile=None):
78 """
79 This is the most high-level highlighting function. It combines `lex` and
80 `format` in one function.
81 """
---> 82 return format(lex(code, lexer), formatter, outfile)
File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/pygments/__init__.py:64, in format(tokens, formatter, outfile)
62 if not outfile:
63 realoutfile = getattr(formatter, 'encoding', None) and BytesIO() or StringIO()
---> 64 formatter.format(tokens, realoutfile)
65 return realoutfile.getvalue()
66 else:
File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/pygments/formatters/terminal256.py:250, in Terminal256Formatter.format(self, tokensource, outfile)
249 def format(self, tokensource, outfile):
--> 250 return Formatter.format(self, tokensource, outfile)
File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/pygments/formatter.py:124, in Formatter.format(self, tokensource, outfile)
121 if self.encoding:
122 # wrap the outfile in a StreamWriter
123 outfile = codecs.lookup(self.encoding)[3](outfile)
--> 124 return self.format_unencoded(tokensource, outfile)
File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/pygments/formatters/terminal256.py:261, in Terminal256Formatter.format_unencoded(self, tokensource, outfile)
258 while ttype and not_found:
259 try:
260 # outfile.write( "<" + str(ttype) + ">" )
--> 261 on, off = self.style_string[str(ttype)]
263 # Like TerminalFormatter, add "reset colors" escape sequence
264 # on newline.
265 spl = value.split('\n')
File ~/checkouts/readthedocs.org/user_builds/gpe/conda/latest/lib/python3.14/site-packages/pygments/token.py:44, in _TokenType.__repr__(self)
43 def __repr__(self):
---> 44 return 'Token' + (self and '.' or '') + '.'.join(self)
KeyboardInterrupt:
Nx, Ny = state.basis.Nxyz
x = state.x
n = state.get_density()
plt.plot(x, n[Nx//2, :])
state.evolve();