<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Introduction to Programming with Julia | Bose Research Group</title><link>https://bose-research-group.github.io/courses/computational-sciences-hands-on/01-introduction-to-julia/</link><atom:link href="https://bose-research-group.github.io/courses/computational-sciences-hands-on/01-introduction-to-julia/index.xml" rel="self" type="application/rss+xml"/><description>Introduction to Programming with Julia</description><generator>Hugo Blox Builder (https://hugoblox.com)</generator><language>en-us</language><lastBuildDate>Tue, 25 Feb 2025 00:00:00 +0000</lastBuildDate><image><url>https://bose-research-group.github.io/media/icon_hu_9bd251d90a98e6b2.png</url><title>Introduction to Programming with Julia</title><link>https://bose-research-group.github.io/courses/computational-sciences-hands-on/01-introduction-to-julia/</link></image><item><title>Introduction to Fourier Transform</title><link>https://bose-research-group.github.io/courses/computational-sciences-hands-on/01-introduction-to-julia/fftw/</link><pubDate>Tue, 25 Feb 2025 00:00:00 +0000</pubDate><guid>https://bose-research-group.github.io/courses/computational-sciences-hands-on/01-introduction-to-julia/fftw/</guid><description>&lt;p>Fourier transform relates a function in one space, say the $x$ space, to another
function in the reciprocal space, say the $\xi$ space.&lt;/p>
$$F(\xi) = FT[f](\xi) = \int_{-\infty}^\infty f(x) \exp(-2\pi i\xi x) dx$$
$$f(x) = IFT[F](x) = \int_{-\infty}^\infty F(\xi) \exp(2\pi i\xi x) d\xi$$
&lt;p>The length of the $\xi$ grid is equal to the length of the $x$ grid. Say this
length is $N$. Consequently, for a particular value of $\xi$, the Fourier
integral uses $N$ function evaluations. A naive calculation of the fourier
transform is expensive, scaling as $\mathcal{O}(N^2)$. A much more efficient
implementation is called the Fast Fourier Transform (FFT) which scales as
$\mathcal{O}(N\log(N))$.&lt;/p>
&lt;p>The &lt;a href="https://juliamath.github.io/FFTW.jl/stable/" target="_blank" rel="noopener">FFTW.jl&lt;/a> package provides
implementations of FFT in Julia:
$$F_k = \sum_{m=0}^{N-1} f_m \exp\left(-\frac{2\pi ikm}{N}\right)\quad k=0, \ldots, N-1.$$
This is provided by the function fft. Notice that $k$ is the discretized version
of the $\xi$ variable and $m$ is the one corresponding to $x$. The points where
$k&amp;gt;N/2$ are equivalent to frequencies at $k-N$ by periodicity. To order change
this ordering to go from $-N/2$ to $N/2$, use the fftshift function provided in
the FFTW.jl package. An inverse FFT routine called bfft is provided which
calculates:
$$f_m = \sum_{k=0}^{N-1} F_k \exp\left(\frac{2\pi ikm}{N}\right)\quad m=0, \ldots, N-1.$$
&lt;/p>
&lt;p>One can slowly modify the Fourier transform expression by converting it into a
finite Riemann sum to obtain a formula analogous to the FFT one. Let $x$ be
discretized between $x_\text{min}$ and $x_\text{max}$ in a grid of size $\Delta
x$. The frequency axis will have the same $N$ number of points with a spacing of
$\Delta\xi=\frac{1}{N\Delta x}$. Then the $k$th frequency component will be given as
$$FT[f](k\Delta\xi) = \sum_{m=0}^{N-1} f(x_\text{min}+m\Delta x) \exp\left(-2\pi i k\Delta\xi (x_\text{min}+m\Delta x)\right)\Delta x$$
$$=\exp\left(-2\pi i k\Delta \xi x_\text{min}\right) \Delta x \sum_{m=0}^{N-1} f(x_\text{min}+m\Delta x) \exp\left(-2\pi i k\Delta \xi m \Delta x\right)$$
$$=\exp\left(-2\pi i k\Delta \xi x_\text{min}\right) \Delta x \sum_{m=0}^{N-1} f_m \exp\left(-\frac{2\pi i k m}{N}\right)$$
$$=\exp\left(-2\pi i k\Delta \xi x_\text{min}\right) \Delta x F_k$$
&lt;/p>
&lt;p>Now for the inverse transform:
$$IFT[F](x_\text{min}+m\Delta x) = \sum_{k=0}^{N-1} F_k \exp\left(2\pi i k\Delta\xi (x_\text{min} + m\Delta x)\right)\Delta k$$
$$=\Delta k\sum_{k=0}^{N-1} \underbrace{\exp(2\pi i k\Delta\xi x_\text{min}) F_k}_{G_k} \exp\left(\frac{2\pi i k m}{N}\right)$$
$$=g_m\Delta k$$
&lt;/p>
&lt;p>The details of implementation in Julia are given in &lt;a href="#example-using-fftw">the examples section&lt;/a>.&lt;/p>
&lt;h2 id="uses-in-quantum-mechanics">Uses in Quantum Mechanics&lt;/h2>
&lt;p>Consider a function, say the wave function, in position space, $\psi(x)$. Let us
say that we want to represent that in momentum space and obtain the function
$\tilde{\psi}(p)$.
$$\tilde{\psi}(p) = \langle p|\psi\rangle = \int_{-\infty}^\infty dx \langle p|x\rangle\langle x|\psi\rangle$$
$$= \frac{1}{\sqrt{2\pi\hbar}}\int_{-\infty}^\infty dx \exp\left(-\frac{i p x}{\hbar}\right) \psi(x)$$
Notice that apart from the prefactor of $\frac{1}{\sqrt{2\pi\hbar}}$, the rest
of the expression is a Fourier transform with the replacement $p = 2\pi\hbar\xi$.
$$\tilde{\psi}(p) = \frac{1}{\sqrt{2\pi\hbar}} FT[\psi]\left(\frac{p}{2\pi\hbar}\right)$$
or, equivalently,
$$\tilde{\psi}(2\pi\hbar\xi) = \frac{1}{\sqrt{2\pi\hbar}} FT[\psi]\left(\xi\right)$$
&lt;/p>
&lt;p>Similarly transforming the momentum space wave function back to the position
space involves an inverse Fourier transform with the same definitions.
$$\phi(x) = \frac{1}{\sqrt{2\pi\hbar}}\int_{-\infty}^\infty dp \exp\left(\frac{ipx}{\hbar}\right)\tilde\phi(p)$$
&lt;/p>
&lt;p>To prove that this works, consider transforming the momentum space wave
function, obtained by Fourier transforming $\psi(x)$, back to position space:
$$\psi_b(x) = \frac{1}{\sqrt{2\pi\hbar}}\int_{-\infty}^\infty \tilde\psi(p) \exp\left(\frac{ipx}{\hbar}\right) dp$$
$$=\frac{1}{2\pi\hbar} \int_{-\infty}^\infty FT[\psi]\left(\frac{p}{2\pi\hbar}\right) \exp\left(\frac{ipx}{\hbar}\right) dp$$
$$= \int_{-\infty}^\infty FT[\psi]\left(\xi\right) \exp\left(2\pi i\xi x\right) d\xi$$
$$=IFT[FT[\psi]](x) = \psi(x)$$
We get the original position space wave function back.&lt;/p>
&lt;h3 id="example-using-fftw">Example using FFTW&lt;/h3>
&lt;p>Let us suppose we have a wave packet that is given by:
$$\psi(x) = \frac{1}{(\pi\sigma)^{1/4}} \exp\left(-\frac{x^2}{2\sigma^2} + \frac{ipx}{\hbar}\right)$$
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-julia" data-lang="julia">&lt;span class="line">&lt;span class="cl">&lt;span class="n">dx&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">0.01&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">nsteps&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="o">^&lt;/span>&lt;span class="mi">15&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="n">nsteps&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">dx&lt;/span>&lt;span class="o">:&lt;/span>&lt;span class="n">dx&lt;/span>&lt;span class="ss">:nsteps&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">dx&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">σ&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">10.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">p&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">5.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ψ&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">exp&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="o">.^&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">σ&lt;/span>&lt;span class="o">^&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="nb">im&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">sqrt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sqrt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">π&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">σ&lt;/span>&lt;span class="p">))&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;/p>
&lt;figure class="ma0w-75" id="figure-wave-function-in-position-space">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Wave function in position space" srcset="
/media/computational-sciences/pos_space_wf_hu_6935a8ea92cbe4f9.webp 400w,
/media/computational-sciences/pos_space_wf_hu_39e987df721cb40.webp 760w,
/media/computational-sciences/pos_space_wf_hu_156beef75a94f1df.webp 1200w"
src="https://bose-research-group.github.io/media/computational-sciences/pos_space_wf_hu_6935a8ea92cbe4f9.webp"
width="760"
height="535"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Wave function in position space
&lt;/figcaption>&lt;/figure>
&lt;p>We write a function to get the Fourier transform from the FFT, keeping in mind that in almost all uses of quantum mechanics the factor of $2\pi$ in the Fourier transform kernel is absent,
The inverse Fourier transform can also be implemented using FFT in a similar manner:
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-julia" data-lang="julia">&lt;span class="line">&lt;span class="cl">&lt;span class="k">function&lt;/span> &lt;span class="n">inverse_fourier_transform&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">unitary&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="kt">Bool&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">true&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dk&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">k&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">F&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dk&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">bfft&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ifftshift&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">f&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">.*&lt;/span> &lt;span class="n">exp&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="nb">im&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">ifftshift&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">unitary&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">F&lt;/span> &lt;span class="o">./&lt;/span> &lt;span class="n">sqrt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="nb">π&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">F&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">end&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;/p>
&lt;p>We use this function to obtain the momentum space wave function as follows:
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-julia" data-lang="julia">&lt;span class="line">&lt;span class="cl">&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ψtilde&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">fourier_transform&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ψ&lt;/span>&lt;span class="p">)&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
to obtain the following wave function
&lt;figure class="ma0w-75" id="figure-wave-function-in-momentum-space">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Wave function in momentum space" srcset="
/media/computational-sciences/mom_space_wf_hu_2270dcec797a394f.webp 400w,
/media/computational-sciences/mom_space_wf_hu_a6ff07d3a0ffa5bf.webp 760w,
/media/computational-sciences/mom_space_wf_hu_244c51ef95b7fa81.webp 1200w"
src="https://bose-research-group.github.io/media/computational-sciences/mom_space_wf_hu_2270dcec797a394f.webp"
width="760"
height="557"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Wave function in momentum space
&lt;/figcaption>&lt;/figure>
&lt;/p></description></item></channel></rss>