% Created: Enze Chen, June 2017
% Last edited: Enze Chen, December 2017
%
% Chapter 5 of the MSE 142 coursereader. This chapter discusses the Kronig-Penney model for periodic potential barriers. It doesn't delve too deep into the math behind Bloch wave functions, but just applies the result to calculate allowed energies. This is a good model for electron transport through a solid and we will apply to result to look at electronic band structure.

% Uncomment the following three lines and last line to individually compile this chapter
%\documentclass[12pt, english]{book}
%\usepackage{142crstyle}
%\begin{document}

\chapter{Periodic Potentials} \label{ch:period}
%{ \doublespacing
In the last chapter, we looked at quantum tunneling through a finite potential barrier, and we argued that the wave function and its first derivative must remain continuous even at discontinuities in the potential. What happens then, if the potential barrier at the discontinuity becomes infinitely tall yet infinitely narrow, like a huge spike? We will see in this chapter how this changes our continuity condition and how quantum tunneling allows us to use this new model to understand the transport properties of materials.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Electron behavior}
We will start by providing a little more context around the problem at hand. In chemistry class, you might have learned that in metals, the electrons are spread out in a ``sea of electrons'' and move around freely, which give metals good thermal and electrical conductivities. This effect, however, is in fact quite surprising. After all, there is a scattering center (atomic nucleus) every few angstroms in a solid---how do the electrons sneak by? We'll see how tunneling provides a simple answer that allows us to better understand electron transport and the band structure of materials. \par

\begin{figure}[!h]
	\centering
	\includegraphics[width=0.5\linewidth]{comb}
	\caption{A schematic of the Kronig-Penney model that consists of an infinite periodic array of delta functions. The potential is zero everywhere except at the delta functions, where it has a strength $g$.}
	\label{fig:comb}
\end{figure}

As with every chapter, we start by considering a simple model, which in this case consists of an infinite series of periodic \textbf{delta functions} spaced a distance $d$ apart (Figure~\ref{fig:comb}). The question is how to solve for the wave function of an electron of total energy $E$ consistent with our requirement that the probability density function remains finite. This problem was first solved by Ralph Kronig and William Penney in 1931,\footnote{See R. Kronig and W. G. Penney, \href{http://rspa.royalsocietypublishing.org/content/130/814/499}{\emph{Proc. Roy. Soc. A}} \textbf{130} (1931). Their original formulation consisted of periodic rectangular blocks, while we jump straight to the typical approximation of height $\rightarrow\infty$ and width $\rightarrow0$.} so it is also known as the \textbf{Kronig-Penney model}.

The Kronig-Penney model is a good approximation for a crystal lattice, where the nuclei are periodic sites of infinite potential\footnote{OK, technically these should approach $-\infty$ to model attraction, but this way the math is simpler.} and we assume zero potential everywhere else inside the lattice. To put this in mathematical terms, we can assign a periodicity to the potential such that \begin{equation*}
	V(x) = V(x+d)
\end{equation*}

In fact, we can go one step further and say that, given a potential strength of $g$, the series of potentials can be expressed as an infinite summation:
\begin{tcolorbox}[title = Kronig-Penney model potential] \vspace{-2ex}
	\begin{equation}
	V(x) = g \sum_{n=-\infty}^{\infty} \delta(x - nd) \label{eq:kp-pot}
	\end{equation}
\end{tcolorbox}

where $\delta(x)$ is the \textbf{Dirac delta function} given by
\begin{equation*}
	\boxed{\delta(x) = \begin{cases}
		+\infty & x=0 \\ 0 & x \neq 0
	\end{cases} \quad \text{ and } \quad
	\int_{-\infty}^{\infty} \delta(x) \dd{x} = 1}
\end{equation*}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Bloch waves}
Now, since the electron behaves like a free particle between the delta functions, we know that its wave functions look like $\psi_n(x) = Ae^{ik_nx}$. This means that the electron density for a regular free particle, which is proportional to $\abs{\psi(x)}^2$, is a constant value. However, a constant isn't quite the correct solution here because then the translational invariance of the probability density function would be broken by the infinite potentials. To resolve this issue, we will instead argue that due to the periodicity of the lattice, it must be the case that the probability density function is also periodic, i.e.

\begin{equation}
	\boxed{\abs{\psi(x)}^2 = \abs{\psi(x+d)}^2} \label{kp-period}
\end{equation}

In other words, if we know the probability density at one point $x$, since the potential is infinitely long and periodic (assume we are in the bulk solid and away from surfaces and grain boundaries), this means we also know the probability density at $x+d$, $x+2d$, and so on. Now, what does this imply about the wave function itself? We can guess that the wave function is also periodic, at least up to a phase factor $e^{iqx}$ (this complex number will disappear when you take the modulus squared). This fact was formally proved in 1928 by Felix Bloch to describe the wave function of electrons in a crystalline lattice,\footnote{His \href{https://link.springer.com/article/10.1007\%2FBF01339455}{original paper} is in German, but \href{https://en.wikipedia.org/wiki/Bloch_wave}{Wikipedia} also gives a good explanation and even presents a proof.} and \textbf{Bloch's theorem} allows us to write the wave function as
\begin{tcolorbox}[title = Bloch wave equation] \vspace{-2ex}
	\begin{equation}
		\psi(x) = u(x)e^{iqx} \label{eq:bloch}
	\end{equation}
\end{tcolorbox}

where the function $u(x)$ is periodic in $d$, i.e. $u(x) = u(x+d)$. To verify that this is a valid solution for the wave function, we can check to see if it satisfies Equation~\ref{kp-period}.
\begin{align*}
	\psi(x+d) &= u(x+d)e^{iq(x+d)} \\
	\psi(x+d) &= u(x)e^{iqx}e^{iqd} \\
	\psi(x+d) &= \psi(x)e^{iqd} \numberthis \label{eq:bloch2}  \\
	\abs{\psi(x+d)}^2 &= \abs{\psi(x)}^2
\end{align*}

which is what we desired. The steps above are the key to the whole problem. Instead of trying to solve for the wave functions for all $x$, we only need to solve the \Sch\ equation in one period (from $x=0$ to $x=d$, for example). Once we know the wave function there, we know it everywhere else by Bloch's theorem. What we claim is that the wave function for an electron in a periodic potential differs only from the wave function for a free particle by a periodic modulation, the function $u(x)$. This is quite remarkable! In the following sections we'll see how the variable $q$ really acts like a quantum number just as the integer $n$ did in the case of the particle in a box, where only certain ranges of $q$ will ultimately correspond to wave-like solutions.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Continuity condition}
We will start by designating the region $x \in (-d,0)$ in Figure~\ref{fig:comb} as $L$ and the region $x \in (0,d)$ as $R$. Each of these regions has zero potential, so the electron behaves as a free particle in these regions. We can then say that for $x \in (0,d)$, the electron has wave function solutions of the form
\begin{equation}
	\psi_R(x) = A\sin(kx) + B\cos(kx) \label{eq:kpr}
\end{equation}
where $k = \sqrt{2mE/\hbar^2}$. \par

What about region $L$? In our derivation above, we observed in Equation~\ref{eq:bloch2} that the wave function in adjacent regions differed only by a phase factor. We can rearrange that equation to obtain
\begin{equation}
	\psi(x) = e^{-iqd}\psi(x+d) \label{eq:bloch3}
\end{equation}

Aha! It might not be obvious at first, but Equation~\ref{eq:bloch3} allows us to express the wave function in region $L$ using the expression for the wave function in region $R$. Otherwise, we would have to use extra coefficients like $C$ and $D$ when writing down the wave function, which would complicate the math. Instead, we can say that for $x \in (-d,0)$,
\begin{equation}
	\psi_L(x) = e^{-iqd}\left[A\sin(k(x+d)) + B\cos(k(x+d))\right] \label{eq:kpl}
\end{equation}

We need one more step to finish setting up our calculations, and that is the behavior of the wave function at $x=0$ where the potential is discontinuous. We derived a continuity condition in the last chapter, but that was only under the assumption that the potential did not go to infinity, which is unfortunately not the case here. Instead, we will assume that the time-independent \Sch\ equation at the delta function takes the form
\begin{equation*}
	-\frac{\hbar^2}{2m} \psi''(x) + g\delta(x) \psi(x) = E\psi(x)
\end{equation*}

Same as before, we will now integrate this equation over an infinitesimal region $(-\epsilon,\epsilon)$ to obtain:
\begin{align*}
	\int_{-\epsilon}^{\epsilon} -\frac{\hbar^2}{2m}  \psi''(x) \dd{x} + \int_{-\epsilon}^{\epsilon} g\delta(x) \psi(x) \dd{x} &= \int_{-\epsilon}^{\epsilon} E\psi(x) \dd{x} \\
	-\frac{\hbar^2}{2m} \int_{-\epsilon}^{\epsilon} \psi''(x) \dd{x} + g \int_{-\epsilon}^{\epsilon} \delta(x) \psi(x) \dd{x} &= E \int_{-\epsilon}^{\epsilon} \psi(x) \dd{x} \\
	-\frac{\hbar^2}{2m} \left[ \psi'|_{\epsilon} - \psi'_{-\epsilon} \right] + g \psi(0) &= 0 \\
	-\frac{\hbar^2}{2m} \left[ \psi'|_{\epsilon} - \psi'_{-\epsilon} \right] &= -g \psi(0)
\end{align*}

\begin{tcolorbox}[title = Continuity across the delta function potential] \vspace{-2ex}
	\begin{equation}
	\dv{\Psi}{x} \bigg|_{\epsilon} - \dv{\Psi}{x} \bigg|_{-\epsilon} = \frac{2mg}{\hbar^2}\psi(0) \label{eq:kp-cont}
	\end{equation}
\end{tcolorbox}

We see there is now a \textbf{discontinuity} in the \emph{first derivative} of the wave function at $x=0$, which came as a result of integrating the delta function.\footnote{To do this, we applied the result $\int\delta(x-a)f(x) \dd{x} = f(a)$, which is known as the ``selection property'' of the delta function. Since $\delta(x-a)$ is only defined at $x=a$, it picks out the value of $f(a)$ (in this case, $\psi(0)$).} It is important to realize that the wave function itself is still continuous at the boundary just like it always was (again, probability argument works well here), even if its first derivative isn't. \par

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Forbidden energies}
Now we have all the pieces assembled for the calculations, so it's time to roll up our sleeves and get to work. We will start by using the continuity conditions to get expressions for $A$ and $B$ from Equation~\ref{eq:kpr} and~\ref{eq:kpl}, and then proceed to derive an expression for $q$, which is what we ultimately want. At $x=0$, we have by the continuity of the wave function that
\begin{align*}
	\psi_R(0) &= \psi_L(0) \\
	A\sin(0) + B\cos(0) &= e^{-iqd}\left[A\sin(kd) + B\cos(kd)\right] \\
	Ae^{-iqd}\sin(kd) + B\left(e^{-iqd}\cos(kd) - 1\right) &= 0 \numberthis \label{eq:kpc1}
\end{align*}

Now for the first derivatives, we have
\begin{align*}
	\psi_R'(0) &= Ak\cos(kx) - Bk\sin(kx) = Ak \\
	\psi_L'(0) &= e^{-iqd}\left[Ak\cos(kd) - Bk\sin(kd)\right]
\end{align*}
which we can plug into Equation~\ref{eq:kp-cont} to obtain
\begin{align*}
	\psi_R'(0) - \psi_L'(0) &= \frac{2mg}{\hbar^2}\psi(0) \\
	Ak - Ae^{-iqd}k\cos(kd) + Be^{-iqd}k\sin(kd) &= \frac{2mg}{\hbar^2}B \\
	A \left(k - e^{-iqd}k\cos(kd)\right) + B\left(e^{-iqd}k\sin(kd) - \frac{2mg}{\hbar^2} \right) &= 0 \numberthis \label{eq:kpc2}
\end{align*}

Equation~\ref{eq:kpc1} and~\ref{eq:kpc2} give us two equations and two variables ($A$ and $B$), which we know how to solve! Of course, these equations look extremely ugly to solve by the substitution method, so we will take a more clever approach that can directly solve for $q$. \par

You have probably learned in your math classes that one way to solve linear systems of equations is by constructing a matrix. We will do that here in the following manner:
\begin{align*}
	Ae^{-iqd}\sin(kd) + B\left(e^{-iqd}\cos(kd) - 1\right) &= 0 \\
	A \left(k - e^{-iqd}k\cos(kd)\right) + B\left(e^{-iqd}k\sin(kd) - \frac{2mg}{\hbar^2} \right) &= 0 \\
	\Downarrow \qquad \qquad \qquad \qquad & \\
	\underset{Q}{\underbrace{\begin{bmatrix}
		e^{-iqd}\sin(kd) & e^{-iqd}\cos(kd) - 1 \\ k\left(1 - e^{-iqd}\cos(kd)\right) & e^{-iqd}k\sin(kd) - \frac{2mg}{\hbar^2}
	\end{bmatrix}}} \begin{bmatrix}
	A \\ B
	\end{bmatrix} &= 0 \numberthis \label{eq:kpmat}
\end{align*}
where we have a complicated coefficient matrix $Q$ multiplying our variables matrix. We can see right away that a trivial solution to this equation is $A=B=0$, which can't be the correct solution because it would lead to a degenerate wave function. Instead, we note that allowable solutions (of which there are infinitely many) to Equation~\ref{eq:kpmat} are obtained when the determinant of $Q$ is zero.\footnote{This is discussed briefly on \href{https://en.wikipedia.org/wiki/System\_of\_linear\_equations\#Solution\_set\_2}{Wikipedia}.} Calculating the determinant\footnote{For a $2\times2$ matrix $Q=\begin{pmatrix} a & b \\ c & d	\end{pmatrix}$, the determinant is given by $\det(Q)=ad-bc$.} and setting it equal to zero gives us an equation for $q$ that we can then solve. Proceeding, we find
\begin{align*}
	\det(Q) &= 0 \\
	e^{-iqd}\sin(kd) \left( e^{-iqd}k\sin(kd) - \frac{2mg}{\hbar^2} \right) &= \left( e^{-iqd}\cos(kd) - 1 \right) \left( k\left(1 - e^{-iqd}\cos(kd)\right) \right) \\
	ke^{-2iqd} \sin^2(kd) - \frac{2mg}{\hbar^2}e^{-iqd}\sin(kd) &= k\left[ e^{-iqd}\cos(kd) - e^{-2iqd}\cos^2(kd) - 1 + e^{-iqd}\cos(kd) \right]
\end{align*}

Now we multiply both sides by $e^{iqd}$.
\begin{align*}
	ke^{-iqd}\sin^2(kd) - \frac{2mg}{\hbar^2}\sin(kd) &= k\left[ \cos(kd) - e^{-iqd}\cos^2(kd) - e^{iqd} + \cos(kd) \right] \\
	ke^{-iqd}\sin^2(kd) + ke^{-iqd}\cos^2(kd) - \frac{2mg}{\hbar^2}\sin(kd) &= 2k\cos(kd) - ke^{iqd} \\
	ke^{-iqd} + ke^{iqd} - \frac{2mg}{\hbar^2}\sin(kd) &= 2k\cos(kd) \\
	2k\cos(qd) &= 2k\cos(kd) + \frac{2mg}{\hbar^2}\sin(kd)
\end{align*}

We finish this off by dividing by $2k$ and multiplying the second term on the right hand side (RHS) by $\frac{d}{d}$ to create another $\frac{\sin(x)}{x}$ term. This gives us
\begin{tcolorbox}[title = Kronig-Penney model allowed solutions] \vspace{-2ex}
	\begin{equation}
		\cos(qd) = \cos(kd) + P\frac{\sin(kd)}{kd} \label{eq:kp}
	\end{equation}
\end{tcolorbox}
where $P = \dfrac{mgd}{\hbar^2}$. \par

To see what we can glean from this equation, the RHS of Equation~\ref{eq:kp} is plotted as a function of $kd$ in Figure~\ref{fig:kp}.

\begin{figure}[!h]
	\centering
	\includegraphics[width=0.55\linewidth]{kp-rhs}
	\caption{A plot of the right hand side of Equation~\ref{eq:kp} is shown in blue. The hatched areas are forbidden values for $k$ (and hence, the energy) because they lie outside the range of cosine, and thus can never be equal to $\cos(qd)$ on the left hand side. This leaves a series of energy bands of allowed electron states (orange).}
	\label{fig:kp}
\end{figure}

One observes immediately that there are ranges of $k$ and therefore ranges of $E$ (since $k=\sqrt{2mE/\hbar^2})$ for which no value of $k$ in that range satisfies Equation~\ref{eq:kp}, as the curve oscillates outside the region between $-1$ and $1$. In particular, at low energies, there is a region for which there is no solution. This might be expected: For very small $E$ compared to the potential barrier, the electrons can't propagate through the periodic potential because the barriers are too high. At higher $E$, the curve enters the region between $\pm 1$ corresponding to well-defined solutions. These look like wave-like solutions of the form given by the Bloch wave equation (Equation~\ref{eq:bloch}) and with $q$ specified by Equation~\ref{eq:kp}. The lowest energy ground state is non-zero, consistent with the notion that the ground state energy always has value greater than the minimum value of the potential (we saw this similarly for the solution to the particle in a box). At higher energies, the curve again exits the region of allowed solutions, corresponding to a region for which propagating solutions do not exist. Remarkably, this corresponds to the existence of a band gap in the material, which we will show in the following section.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Application: Band structure}
Recall that our original motivation for the Kronig-Penney model was to model the behavior of electrons inside a material. Due to the presence of periodically-spaced atomic nuclei that act as scattering centers, such as in a crystal lattice, the wave-like electrons cannot have arbitrary energies. Instead, they are confined to \textbf{bands} of energy and forbidden from other regions; together, these bands and regions constitute the \textbf{band structure} of a material and are fundamental to the optical and electronic properties of a material. \par

In order to calculate the band structure, we look to Equation~\ref{eq:kp}. To better see the relationship between the LHS and RHS, we have plotted a close-up of the first energy band in Figure~\ref{fig:kp-zoom}. At point $A$, the RHS equals 1, which leads to
\begin{equation*}
	\cos(qd) = 1 \implies q = 0
\end{equation*}

\begin{figure}[!h]
	\centering
	\includegraphics[width=0.55\linewidth]{kp-rhs-zoom}
	\caption{A close-up of the first energy band shown in Figure~\ref{fig:kp}. The labeled points demonstrate clear correspondences between $q$ and $k$.}
	\label{fig:kp-zoom}
\end{figure}

We can do the same with the other three points, and we consolidate the results in Table~\ref{tab:qvk}.

\begin{table}[!h]
	\centering
	\begin{tabular}{crlc}
		Point & RHS & Equation & $q$ \\ \toprule
		$A$ & 1 & $\cos(qd) = 1$ & 0 \\
		$B$ & 0 & $\cos(qd) = 0$ & $\pi/2d$ \\
		$C$ & $-1$ & $\cos(qd) = -1$ & $\pi/d$ \\
		$D$ & $-1$ & $\cos(qd) = -1$ & $\pi/d$
	\end{tabular}
	\caption{Four correspondence points near the first energy band that show the relationship between $q$ and $k$.}
	\label{tab:qvk}
\end{table}

Note that at point $A$, $q=0$ corresponds to a non-zero value of $k$ and hence a non-zero value for the energy, which we have previously discussed. Also, even though $q=\pi/d$ at both $C$ and $D$, those points are at different energy levels. This means if we construct a plot of $E$ vs. $q$, as we have done in Figure~\ref{fig:Evq}, we will see a jump discontinuity at $q=\pi/d$---and thus the band gap emerges! This pattern continues at every multiple of $\pi/d$, and the width of each successive energy band increases while the gap in between them slowly decreases. Instead of having discrete energy levels like in the particle in a box model, here the energies have spread out into wider bands due to quantum interactions between neighboring wave functions across the potential barrier.

\begin{figure}[!h]
	\centering
	\subfloat[]{\includegraphics[width=0.45\linewidth]{evq1} \label{fig:Evq1}}
	\subfloat[]{\includegraphics[width=0.45\linewidth]{evq2} \label{fig:Evq2}}
	\caption{A plot of $E$ vs. $q$ in \protect\subref{fig:Evq1} expanded form and \protect\subref{fig:Evq2} reduced form, where we have translated the energy bands to fit within the first Brillouin zone.}
	\label{fig:Evq}
\end{figure}

Now, in a class like ENGR 50 or MATSCI 143, you have used a unit cell to characterize many of the properties of the bulk crystal. It turns out there's a direct analogy here thanks to the Bloch wave description we saw earlier. Instead of drawing out the energy bands in an expanded form like we did in Figure~\ref{fig:Evq1}, we will first translate each band by a multiple of $2\pi/d$ until it lies within the interval from $[-\pi/d, \pi/d]$. We then take that image and reflect it across the $y$-axis to produce the symmetric image shown in Figure~\ref{fig:Evq2}. This region from $[-\pi/d, \pi/d]$ is called the \textbf{first Brillouin zone} (pronounced ``Bree-luwan'') and it is sufficient to characterize all of the wave vectors of the electron moving through a periodic potential. You can think of it as the unit cell equivalent in momentum space, or what's more commonly known as \textbf{reciprocal space}. These fascinating topics are unfortunately outside the scope of this course, but I encourage you to do some research on your own as they build beautifully on top of what we've seen so far. \par

OK, now that we've shown the existence of the band gap within a material's band structure, why should we \emph{care}? Well, we've already stated that inside the band gap, no electronic states can exist. This means that electrons must exist in the band right below it, known as the \textbf{valence band}, or acquire enough energy to be promoted to the upper energy band, known as the \textbf{conduction band}. It turns out that only electrons in the conduction band are free to move within the crystal lattice and conduct electric current, so right away we can see how the band gap determines whether a material is a metal, semiconductor, or insulator (Figure~\ref{fig:bgs}).

\begin{figure}[!h]
	\centering
	\includegraphics[width=0.7\linewidth]{bandgaps}
	\caption{Schematic of the different band structures in metals, semiconductors, and insulators.}
	\label{fig:bgs}
\end{figure}

Typically, the two energy bands in a metal overlap, which give metals good conductivity since there is no band gap to overcome! On the other hand, the bands are so far apart in insulators that it becomes impossible for electrons to gain enough energy to overcome the band gap and conduct electricity. Semiconductors are a hot topic of research precisely due to their small band gap that can be tuned to modulate the amount of energy it takes for electrons to cross the barrier. Band gap engineering typically involves changing a material's chemical composition, layer thickness, and/or morphological patterning to control the positions of the energy bands, which has led to huge advancements in solar cells,\footnote{Featuring Michael McGehee, a former Stanford MSE professor. See Hoke et al. \href{http://pubs.rsc.org/-/content/articlehtml/2015/sc/c4sc03141e}{\emph{Chem. Sci.}} \textbf{6} (2015) and Eperon et al. \href{http://science.sciencemag.org/content/354/6314/861.full}{\emph{Science}} \textbf{354}, 6314 (2016).} optoelectronics,\footnote{Featuring Mark Brongersma from our MSE department. See Sukhdeo et al. \href{https://www.osapublishing.org/oe/abstract.cfm?uri=oe-23-13-16740}{\emph{Optics Express}} \textbf{23}, 13 (2015).} and photonics.\footnote{Featuring Shanhui Fan from Stanford's EE department. See Joannopoulos et al. \href{https://www.nature.com/nature/journal/v386/n6621/pdf/386143a0.pdf}{\emph{Nature}} \textbf{386} (1997). This article, albeit a little dated, gives a thorough introduction into the analogous \emph{photonic} band gap.}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Summary}
To recap, this chapter exposed us to the idea of a periodic potential modeled as a series of delta functions in the Kronig-Penney model. We applied Bloch's theorem to describe the periodicity in an electron's wave function and derive a new continuity condition across the potential barriers. This allowed us to derive an equation for the relationship between the phase shift wave number $q$ and the electron's energy $E$. We discovered that the result was a good model for the band structure of a material, and that there were certain regions of energy that were forbidden for the electron, thus demonstrating the existence of a material's band gap. The Kronig-Penney model's simplistic nature and uncanny ability to elucidate the band gap make it a powerful model for periodic quantum mechanical systems. \par

So far, all of the potentials we've encountered have been rectangular, although this need not be the case. Coming up next, we will explore the behavior of particles in a parabolic potential, which describes simple harmonic motion in a quantum mechanical system. Get ready to work with some of the nifty mathematical tools contained within quantum theory!

%} % for doublespacing
%\end{document}


\section{The heat equation with an explicit Euler}
  \label{section:applications:heat-equation}

\chapterDescription
  {
    60 minutes.
  }
  {
    Chapter \ref{chapter:quickstart}.
  }

In this section, we sketch how to realise a heat equation solver for
\[
  \partial _t u - \nabla (\epsilon \nabla) u = 0
\]
that is based
upon an explicit Euler.
It uses the spacetree as computational grid.

\subsection{Preparation}

We create an empty project with the PDT (\texttt{--create-project myproject
myproject}) and first adopt our cell and vertex data structure such that each
cell holds an $\epsilon$ value and each vertex holds the current and previous
solution.

\begin{code}
Packed-Type: short int;
class myproject::records::Vertex {
  parallelise persistent double  u;
  discard                double  oldU;
};
\end{code}

\begin{code}
Packed-Type: short int;
class myproject::records::Cell {
  persistent double epsilon;
};
\end{code}

\noindent
Furthermore, we make the code's state hold the solver's time step size. We will
write the code such that it works in 2d and 3d. All the pictures are done for a
3d setup. To run with other dimensions, you have to adopt your makefile
accordingly.

\begin{code}
Packed-Type: short int;
class myproject::records::State {
  persistent parallelise double dt;
};
\end{code}

\noindent
We do not use any sophisticated plotting routines and thus rely in some plotters
that are available out-of-the-box for Peano.
We also require only two mappings: one for the setup, one for the time stepping.
Depending on our personal choices, we combine them with plotting features or
not\footnote{There is a known issue with the coding standards in Peano/PDT
which can be avoided a priori if all read and write attributes start with an
uppercase---even though they might be defined with lowercase in the def file.}.

\begin{code}
omponent: ExplicitEulerForHeatEquation
namespace: ::myproject
vertex:
  dastgen-file: Vertex.def
  read scalar(double): U
  read scalar(double): OldU
  write scalar(double): U
cell:
  dastgen-file: Cell.def
state:
  dastgen-file: State.def
event-mapping:
  name: CreateGrid
event-mapping:
  name: TimeStep
adapter:
  name: CreateGrid
  merge-with-user-defined-mapping: CreateGrid
adapter:
  name: TimeStep
  merge-with-user-defined-mapping: TimeStep
adapter:
  name: CreateGridAndPlot
  merge-with-user-defined-mapping: CreateGrid
  merge-with-predefined-mapping: VTKPlotCellValue(epsilon,getEpsilon,eps)
  merge-with-predefined-mapping: VTKPlotVertexValue(initialSetup,getU,u)
adapter:
  name: TimeStepAndPlot
  merge-with-user-defined-mapping: TimeStep
  merge-with-predefined-mapping: VTKPlotVertexValue(result,getU,u)
\end{code}

\noindent
To translate this file, you need the corresponding predefined mappings that are
held in the repository or on the webpage.
To find out what the arguments of the predefined mappings mean, please have a
look into the corresponding template header files.
We note that we write out epsilon only throughout the setup phase.
It does not make sense to plot each each iteration, as this material parameter
does not change in time.
We furthermore note that we add some \texttt{read} and \texttt{write}
statements.
They make the PDT generate helper methods that allow us within each cell to
access all $u$ values of a cell as one vector.

\subsection{Making the plotter work}

This code so far does not compile. It complains with

\begin{code}
> make -f myproject/makefile
--- This is Peano 3 ---
g++ -DDim3 [...] -c myproject/adapters/CreateGridAndPlot2VTKPlotCellValue_0.cpp -o \
myproject/adapters/CreateGridAndPlot2VTKPlotCellValue_0.o
[...]  In member function void [...]::CreateGridAndPlot2VTKPlotCellValue_0::enterCell([...]):
[...] error: class myproject::Cell has no member named getEpsilon
     _cellValueWriter->plotCell(cellIndex,fineGridCell.getEpsilon() );
                                                       ^
make: *** [myproject/adapters/CreateGridAndPlot2VTKPlotCellValue_0.o] Error 1
\end{code}

\noindent
This is correct.
We have told the predefined mapping that there would be an opteration
\texttt{getEpsilon} to print cell data, but we have not provided one yet.
A similar reasoning holds for the plotting of the actual solution.
Therefore, we add

\begin{code}
void myproject::Cell::init() {
  _cellData.setEpsilon( 1.0 + static_cast<double>(rand() % 100)/100.0 );
}

double myproject::Cell::getEpsilon() const {
  return _cellData.getEpsilon();
}
\end{code}

\noindent
This snippet also allows us to initialise a cell with a random value from
$(1,2)$.

\begin{remark}
An initialisation of the cell's $\epsilon$ in the default constructor does not
work because of the flyweight pattern (see next remark). Instead, we have to
provide an explicit initialisation routine, and we have to call this routine
within the mapping's \texttt{createCell} event.
\end{remark}

\noindent
We reiterate our code extension for the vertex,

\begin{code}
double myproject::Vertex::getU() const {
  return _vertexData.getU();
}
\end{code}

\noindent
Finally, we plug into \texttt{CreateGrid}'s \texttt{createInnerVertex} and
\texttt{createBoundaryVertex} and add some refinement statements:

\begin{code}
void myproject::mappings::CreateGrid::createInnerVertex(...) {
 if (coarseGridVerticesEnumerator.getLevel()<3) {
  fineGridVertex.refine();
 }
}

void myproject::mappings::CreateGrid::createBoundaryVertex(...) {
 if (coarseGridVerticesEnumerator.getLevel()<3) {
  fineGridVertex.refine();
 }
}

void myproject::mappings::CreateGrid::createCell(...) {
 logTraceInWith4Arguments( "createCell(...)", fineGridCell, ... );

 fineGridCell.init();

 logTraceOutWith1Argument( "createCell(...)", fineGridCell );
}

\end{code}

As soon as this first plot is available, as add a time stepping loop in the
\texttt{runners::Runner}:

\begin{code}
int myproject::runners::Runner::runAsMaster(myproject::repositories::Repository& repository) {
  peano::utils::UserInterface::writeHeader();

  repository.switchToCreateGridAndPlot();
  repository.iterate();

  repository.getState().setTimeStepSize( 0.5e-7 );
  for (int i=0; i<10000; i++) {
    if (i%100==0) {
      repository.switchToTimeStepAndPlot();
    }
    else {
     repository.switchToTimeStep();
    }
    repository.iterate();
  }

  repository.logIterationStatistics(true);
  repository.terminate();

  return 0;
}
\end{code}

\noindent
The implementation of the \texttt{State}'s \texttt{void setTimeStepSize(double
dt)} operation is left to the reader.
Please add the corresponding \texttt{double getTimeStepSize() const}, too, we we
will need it later.

\begin{center}
  \includegraphics[width=0.7\textwidth]{41_heat-equation/epsilon.png}
\end{center}

\noindent
What we might want to do before we continue is to add well-suited initial and
boundary conditions.
To do so, we return to \texttt{createInnerVertex} and
\texttt{createBoundaryVertex} of the \texttt{CreateGrid} mapping and add some
calls there as well as an implementation to the vertex:

\begin{code}
...::createBoundaryVertex(...) {
  ...
  const double myValue = 17.3;
  fineGridVertex.init(myValue); // Might be different for the inner vertices
}

myproject::Vertex::Vertex() {
  _vertexData.setU(0.0);
}

void myproject::Vertex::init(double value) {
  _vertexData.setU(value);
}
\end{code}

\noindent
As mentioned, an initialisation of the $u$ value in the constructor is not
necessary as we use a flyweight pattern.
However, it has proven to be reasonable to set it to a reasonable value, as
garbage data tends on the one hand to make your debugging hard.
On the other hand, it sometimes messes up VTK/Paraview.

\begin{remark}
  It is a `original' decision to model states, vertices and cells as classes
  that actually aggregate their data objects (attribute \texttt{\_stateData},
  \texttt{\_vertexData} or \texttt{\_cellData}, respectively).
  The reason for this is two-fold:
  On the one hand, this allows us to separate user-defined code (the
  aggregating class) from the data model generated by DaStGen. The latter also
  comprises complex technical details such as the MPI data types or bit
  compression. If application-specific code is rewritten, the data model is not
  affected and the other way round. On the other hand, the pattern allows us to
  apply the flyweight pattern. A vertex object is not actually stored and loaded
  from input data. It exists only a few time in total, and in each step its
  change is exchanged underneath by the traversal.
\end{remark}

\subsection{A stencil code}

In this example, we stick to a finite differences formulation and
vertex-centred unknown assignment to do the time stepping.
Our strategy (within the mapping) is simple:
\begin{enumerate}
  \item In \texttt{beginIteration}, we grab the time step size from the state.
  This way, the user might alter the time step size in the outer control loop
  (adaptive time stepping).
  The mapping then always works with the right parameter.
  \item In \texttt{touchVertexFirstTime}, we take the current solution and back
  it up in the vertex's property \texttt{\_oldU}. This property is marked as
  discard, i.e.~the additional helper variable per vertex is not held in-between
  two iterations (actually it is only held for a small number of vertices that
  are still in use).
  \item In \texttt{enterCell}, we element-wisely accumulate the new solution in
  the vertices.
\end{enumerate}

\begin{code}
class myproject::mappings::TimeStep {
 private:
  /**
   * Logging device for the trace macros.
   */
  static tarch::logging::Log  _log;

  double _timeStepSize;
  ...
};

void myproject::mappings::TimeStep::beginIteration(
  myproject::State&  solverState
) {
  logTraceInWith1Argument( "beginIteration(State)", solverState );

  _timeStepSize = solverState.getTimeStepSize();

  logTraceOutWith1Argument( "beginIteration(State)", solverState);
}
\end{code}

\noindent
We reiterate that the state is not available to a mapping by default. If you
need the state (or one of its properties), you explicitly have to grab this data
in \texttt{beginIteration}. As an alternative to the double above, it also would
be possible to copy the whole state. If you want to modify the solver's state,
you have to alter it in \texttt{endIteration}. As Peano requires the user to
explicitly move state data around when required, we ensure that the data remains
consistent in the parallel code variants.

\begin{code}
void myproject::mappings::TimeStep::touchVertexFirstTime(...) {
 ...
 fineGridVertex.copyCurrentSolutionIntoOldSolution();
 ...
}

void myproject::Vertex::copyCurrentSolutionIntoOldSolution() {
  _vertexData.setOldU( _vertexData.getU() );
}
\end{code}

\noindent
The interesting stuff happens in the mapping's \texttt{enterCell},
where we first of all take all $2^d$ vertices and write their old solution into
one double vector.
For this, there's a predefined operation in \texttt{VertexOperations} as we have
asked the PDE that we read the scalar.
This $2^d$ vector then is multiplied with the local assembly matrix subject of
an $\epsilon$ scaling.
The result finally is added to the new value.
Again, we us the generated read and write methods.

\begin{code}
#include "myproject/VertexOperations.h"
#include "tarch/la/Matrix.h"

void myproject::mappings::TimeStep::enterCell(...) {
  logTraceInWith4Arguments( "enterCell(...)", fineGridCell, ... );

  tarch::la::Matrix<TWO_POWER_D,TWO_POWER_D,double> A;

  A =  6.0/8.0, -1.0/4.0, -1.0/4.0,      0.0, -1.0/4.0,      0.0,      0.0,      0.0,
      -1.0/4.0,  6.0/8.0,      0.0, -1.0/4.0,      0.0, -1.0/4.0,      0.0,      0.0,
      -1.0/4.0,      0.0,  6.0/8.0, -1.0/4.0,      0.0,      0.0, -1.0/4.0,      0.0,
           0.0, -1.0/4.0, -1.0/4.0,  6.0/8.0,      0.0,      0.0,      0.0, -1.0/4.0,
      -1.0/4.0,      0.0,      0.0,      0.0,  6.0/8.0, -1.0/4.0, -1.0/4.0,      0.0,
           0.0, -1.0/4.0,      0.0,      0.0, -1.0/4.0,  6.0/8.0,      0.0, -1.0/4.0,
           0.0,      0.0, -1.0/4.0,      0.0, -1.0/4.0,      0.0,  6.0/8.0, -1.0/4.0,
           0.0,      0.0,      0.0, -1.0/4.0,      0.0, -1.0/4.0, -1.0/4.0,  6.0/8.0;

  tarch::la::Vector<TWO_POWER_D,double> uOld =
    VertexOperations::readOldU(fineGridVerticesEnumerator,fineGridVertices);

  const double h = fineGridVerticesEnumerator.getCellSize()(0);

  tarch::la::Vector<TWO_POWER_D,double> uUpdate =
    - _timeStepSize * fineGridCell.getEpsilon() * A * uOld / h / h  ;

  VertexOperations::writeU(
    fineGridVerticesEnumerator,fineGridVertices,
    VertexOperations::readU(fineGridVerticesEnumerator,fineGridVertices) + uUpdate
  );

  logTraceOutWith1Argument( "enterCell(...)", fineGridCell );
}
\end{code}

\noindent
In this example, I wrote down the local assembly matrix for $d=3$ explicitly.
If you want to support other dimensions, you have to adopt this part
accordingly.

We use Peano's linear algebra routines here.
They are held in the \texttt{tarch} component, and provide all basic
functionality we typically need.
Obviously, it might make sense to switch to other linear algebra packages
(BLAS, e.g.) for more demanding setups.

For a better understanding, it might make sense to have a look into
\texttt{readOldU}.
We note that \texttt{fineGridVertices} is a pointer to an array of vertices, but
the layout of the vertices within this array remains open.
Therefore, Peano hands over an enumerator object.
The enumerator object has a functor to allow us to select the right vertices.
\texttt{fineGridVertices[ fineGridVerticesEnumerator(0) ]} for example returns
the bottom left vertex of the cell.
See the enumerator's documentation in the header for detailed information.
The read and write that are generated by the PDT run through the vertices and
collect the \texttt{u} or \texttt{oldU} value, respectively, in one vector.
They are scatter/gather operations.
Some codes might prefer not to rely on the temporary vectors and instead work
with the data associated to the vertices directly.
Both options are fine, both options might have different performance
characteristics.

Obviously, the above code is not very elaborate.
The stiffness matrix is set up multiple times.
The most basic optimisation would be to make the matrix an attribute of the
mapping and to initialise it only once.

\begin{remark}
  On the Peano webpage and in the repository, you find a \texttt{matrixfree}
  toolbox. It contains all kind of primitive helper operations that allow you to
  work with stencil codes. It is not as powerful as a real stencil compiler or
  other matrix-free/PDE toolboxes, but it a small suite to build up at least the
  simpler PDE operators from a finite element/tensor-product formalism and it
  also provides operations fitted to PDT's generated read and write routines.
The toolbox also provides helper functions that decompose stencils in element-wise
assembly matrices as the one above.
\end{remark}

\noindent
Obviously, our code does not do anything as we do not set any nonzero boundary
conditions.
Lets do this upon a vertex's first use.
As we have specified a read, the PDT provides write operations that break up the
object encapsulation.
We make use of this now:

\begin{code}
void myproject::mappings::TimeStep::touchVertexFirstTime(...) {
  ...
  if (fineGridVertex.isBoundary() && fineGridX(0)<1e-8) {
    VertexOperations::writeU( fineGridVertex, 1.0 );
  }
  else if (fineGridVertex.isBoundary()) {
    VertexOperations::writeU( fineGridVertex, 0.0 );
  }
  ...
}
\end{code}

\begin{remark}
In this example, we do not ensure that we do not update boundary vertices.
Indeed, we update them, but in the subsequent traversal we overwrite them again
with the prescribed Dirichlet values (code snippet above). Most codes rather add
an additional if statement checking \texttt{fineGridVertex.isBoundary()}.
\end{remark}

    \begin{remark}
    It is obvious that the Jacobi update scheme may only update inner
    unrefined vertices as well as Neumann boundary points. Peano does not offer
    (boundary) vertex types. It distinguishes only inner, boundary and outer
    vertices as those are tied to the internal data flow.
    If you need more flags than those guys, you have to implement this yourself.
    \end{remark}

\begin{center}
  \includegraphics[width=0.45\textwidth]{41_heat-equation/solution00.png}
  \includegraphics[width=0.45\textwidth]{41_heat-equation/solution01.png}
  \includegraphics[width=0.45\textwidth]{41_heat-equation/solution02.png}
  \includegraphics[width=0.45\textwidth]{41_heat-equation/solution03.png}
\end{center}

All figures cut through the domain in the middle and use an orthogonal slice to
visualise the permeability $\epsilon$.
Top, left: We start from a zero condition where only the face at $x=0$ is set to
$1$.
Top, right: Very slowly, the temperature propagates through the domain. As
$\epsilon $ is fuzzy, the propagation profile does not exhibit symmetry but is
ragged as well.
Bottom: The temperature propagates further into the medium.

\subsection{Multiscale data representation}

We continue the solver development with a technical extension that proofs to be
of great value.
Rather than working on the actual fine grid, i.e.~our compute grid, we inject
the finest solutions to the coarser grids all the time:
whenever a vertex coincides with a vertex on a coarser level, we take its value
and copy it to the coarser grid.
To realise this injection, we typically propose to introduce a new mapping in
the specification, and to realise the injection in this new mapping---it has
nothing to do directly with the solver, so the separation of mappings reflects a
separation of concerns.

\begin{code}
...
event-mapping:
  name: Inject
...
adapter:
  name: TimeStep
  merge-with-user-defined-mapping: TimeStep
  merge-with-user-defined-mapping: Inject
...
adapter:
  name: TimeStepAndPlot
  merge-with-user-defined-mapping: TimeStep
  merge-with-user-defined-mapping: Inject
  merge-with-predefined-mapping: VTKPlotVertexValue(result,getU,u)
\end{code}

\noindent
As a result, we have a multiscale representation of the solution on each
individual grid level.
It is (almost) for free, as Peano's vertices are unique due to their combination
of level and spatial position, i.e.~these coarse vertices do exist anyway.

\begin{code}
void myproject::Vertex::inject(const Vertex& fromVertex) {
  _vertexData.setU( fromVertex._vertexData.getU() );
}

void myproject::mappings::Inject::touchVertexLastTime(...) {
 logTraceInWith6Arguments( "touchVertexLastTime(...)", fineGridVertex, fineGridX, ... );

 if ( peano::grid::SingleLevelEnumerator::isVertexPositionAlsoACoarseVertexPosition(
  fineGridPositionOfVertex) ) {
  const peano::grid::SingleLevelEnumerator::LocalVertexIntegerIndex coarseGridPosition =
   peano::grid::SingleLevelEnumerator::getVertexPositionOnCoarserLevel
   (fineGridPositionOfVertex);

  coarseGridVertices[ coarseGridVerticesEnumerator(coarseGridPosition) ].inject(fineGridVertex);
 }

 logTraceOutWith1Argument( "touchVertexLastTime(...)", fineGridVertex );
}
\end{code}

\noindent
In our implementation, we use helper functions of the enumerator classes.
Alternatively, we could have checked the integer array
\texttt{fineGridPosiitionOfVertex} manually whether all entries are either 0 or
3.

\begin{remark}
Several projects have exploited this multiscale representation for visualisation
and data postprocessing. Whenever data in a reduced accuracy is sufficient (to
create fancy pictures, e.g.), one can directly extract this data from the
corresponding spacetree level rather than using the finest grid representation
and postprocess these data.
\end{remark}

\subsection{Static adaptivity}

An elegant way to realise adaptive solvers is to pick up the concept of FAC/MLAT
from the multigrid community.
The idea is very simple:
\begin{itemize}
  \item We calculate an update of the solution for each and every cell in the
  sapcetree. This includes the refined ones.
  \item We interpolate hanging nodes from the next coarser levels. This can be
  done recursively, i.e.~a 3:1 balancing of the tree is not required. Rippling
  does not happen.
  \item We inject the solution of a fine grid vertex to the coarser levels and
  thus overwrite the impact of the unknown update there.
\end{itemize}

\begin{center}
 \includegraphics[width=0.34\textwidth]{41_heat-equation/FAC.pdf}
\end{center}

\noindent
One can read such a scheme as an overlapping domain decomposition:
The coarser levels slightly overlap finer levels.
Those coarse grid vertices that fall into a fine grid partition are treated as
Dirichlet values (we may update them, but the update then is overwritten
immediately).
Their value is injected from finer grids---an ingredient we already have
realised.
Fine grid problems are handled as Dirichlet problems as well.
Their boundary points either are real boundary points or hanging nodes.
The value of hanging nodes in turn stems from coarser levels which closes the
coupling of the coarse and fine grid problems.

We propose to introduce---mirroring \texttt{Inject}---a new mapping
\texttt{InterpolateHangingNodes} that solely plugs into the generation of hanging nodes.
This time, we use Peano's $d$-dimensional loops, as well as PDT's generated
write operations that break up the OO encapsulation.

\begin{code}
#include "myproject/VertexOperations.h"
#include "peano/utils/Loop.h"

void myproject::mappings::InterpolateHangingNodes::createHangingVertex(...) {
  logTraceInWith6Arguments( "createHangingVertex(...)", fineGridVertex, fineGridX, ... );

  double interpolatedValue = 0.0;
  dfor2(k)
    double weight = 1.0;
    for (int d=0; d<DIMENSIONS; d++) {
      if (k(d)==0) {
        weight *= 1.0 - (fineGridPositionOfVertex(d))/3.0;
      }
      else {
        weight *= (fineGridPositionOfVertex(d))/3.0;
      }
    }
    interpolatedValue = weight * coarseGridVertices[ coarseGridVerticesEnumerator(k)].getU();
  enddforx

  VertexOperations::writeU( fineGridVertex, interpolatedValue );
  fineGridVertex.copyCurrentSolutionIntoOldSolution();

  logTraceOutWith1Argument( "createHangingVertex(...)", fineGridVertex );
}
\end{code}

\noindent
We reiterate that Peano's \texttt{matrixfree} toolbox provides helpers realising
such typical interpolation tasks.

Finally, we have to setup an adaptive grid. We stick to a static, simple setup
for the time being where the mesh is made very fine along the $x=0$ plane and
reasonably coarse everywhere else.
Please note that you might have to adopt your time step size as well if you
reduce the resolution along the heated up plate.
Furthermore, if you visualise, please note that the default visualiser we used
so far does not know anything about the hanging nodes' interpolation and thus
plots them as zero values.

\begin{code}
void myproject::mappings::CreateGrid::createInnerVertex(...) {
 if (coarseGridVerticesEnumerator.getLevel()<1) {
  fineGridVertex.refine();
 }
}

void myproject::mappings::CreateGrid::createBoundaryVertex(...) {
 if (coarseGridVerticesEnumerator.getLevel()<3 && fineGridX(0)<1e-8) {
  fineGridVertex.refine();
 }
 else if (coarseGridVerticesEnumerator.getLevel()<1) {
  fineGridVertex.refine();
 }
}
\end{code}

\begin{center}
 \includegraphics[width=0.45\textwidth]{41_heat-equation/initial-adaptive-grid.png}
 \includegraphics[width=0.45\textwidth]{41_heat-equation/adaptive-grid-21.png}
\end{center}

\noindent
In the present example, it does not matter that some cells compute stencil
evaluations that are never used:
These are the cells where all adjacent vertices are refined.
Due to the injection, the stencil evalution here is not necessary.
As the stencils are very small and cheap to evaluate, this does not make a
difference.
For more complicated setups, it however might make a difference.

Obviously, it is not possible in the present case to use the cells'
\texttt{isRefined()} operation to determine whether a stencil evaluation should
be skipped or not.
Refined cells next to an unrefined one have to be taken into account.
Instead, we have to run over all adjacent vertices of a cell and determine their
refinement state.
Peano realises an or-based refinement---if any vertex adjacent to a cell carries
the refinement bit, the cell is refined---so the required check is an or
combination followed by a negation.
In Peano, there's a class \texttt{peano::grid::aspects::VertexStateAnalysis}.
It is worth to study this class; it offers most of such analysis routines
already and makes the programming of multiscale algorithms more convenient.

\subsection{Dynamic adaptivity}

Given a statically adaptive grid, dynamic adaptivity is (technically) a minor
improvement.
We realise it in two steps:
\begin{enumerate}
  \item We write the refinement criterion, and
  \item we ensure that the a posteriori refinement initialises the correct data.
\end{enumerate}

The first step is strongly application dependent.
A simple criterion that seems to work sufficiently is to assign each vertex a
new (non-persistent) value that holds the average value of the surrounding
vertices.
If this value differs significantly from the computed value in the point (which
is kind of a smoothness analysis), we refine.
For this, we change the vertex definition
\begin{code}
Packed-Type: short int;

class myproject::records::Vertex {
  parallelise persistent double  u;
  discard    double  oldU;
  discard    double  averagedU;
};
\end{code}

\noindent
and we also add additional read statements to the specification.
The specification remains more or less unchanged, but we keep all the dynamic
refinement in an additional refinement mapping.

\begin{code}
vertex:
  dastgen-file: Vertex.def
  read scalar(double): U
  read scalar(double): OldU
  read scalar(double): AveragedU
  write scalar(double): U
  write scalar(double): AveragedU

...

event-mapping:
  name: RefineDynamically

...

adapter:
  name: TimeStep
  merge-with-user-defined-mapping: TimeStep
  merge-with-user-defined-mapping: Inject
  merge-with-user-defined-mapping: InterpolateHangingNodes
  merge-with-user-defined-mapping: RefineDynamically
\end{code}

\noindent
Before we implement this additional mapping, we create a slightly more appealing
problem setup in create grid:
\begin{code}
void myproject::mappings::CreateGrid::createCell(...) {
  logTraceInWith4Arguments( "createCell(...)", fineGridCell, ... );

  fineGridCell.init( fineGridVerticesEnumerator.getCellCenter() );

  logTraceOutWith1Argument( "createCell(...)", fineGridCell );
}

void myproject::Cell::init(const tarch::la::Vector<DIMENSIONS,double>&  x) {
  _cellData.setEpsilon( x(1) * x(2) + static_cast<double>(rand() % 100)/100.0 );
}
\end{code}

\noindent
Furthermore, we make the start grid one level coarser along the $x=0$ axis
compared to the previous setup.

Our refinement criterion materialises in a very simple mapping relying on the
simple stencil (here given for two dimensions)
\[
\left[ \begin{array}{ccc}
  0 & 1 & 0 \\
  -1 & 0 & 1 \\
  0 & -1 & 0
\end{array}  \right]
\]
that we apply on the solution.
This stencil determines the derivative in a point.
For a first try, it often yields very reasonable refinement patterns---we
refine where we observe a steep gradient.

\begin{code}
void myproject::mappings::AdaptiveRefinementCriterion::touchVertexFirstTime(...) {
  logTraceInWith6Arguments( "touchVertexFirstTime(...)", fineGridVertex, ... );

  VertexOperations::writeAveragedU( fineGridVertex, 0.0 );

  logTraceOutWith1Argument( "touchVertexFirstTime(...)", fineGridVertex );
}

void myproject::mappings::AdaptiveRefinementCriterion::enterCell(...) {
  logTraceInWith4Arguments( "enterCell(...)", fineGridCell, ... );

  tarch::la::Matrix<TWO_POWER_D,TWO_POWER_D,double> A;

  A =  0.0,  1.0/4.0,  1.0/4.0,  0.0,  1.0/4.0,  0.0,  0.0,  0.0,
      -1.0/4.0,  0.0,  0.0,  1.0/4.0,  0.0,  1.0/4.0,  0.0,  0.0,
      -1.0/4.0,  0.0,  0.0,  1.0/4.0,  0.0,  0.0,  1.0/4.0,  0.0,
       0.0, -1.0/4.0, -1.0/4.0,  0.0,  0.0,  0.0,  0.0,  1.0/4.0,
      -1.0/4.0,  0.0,  0.0,  0.0,  0.0,  1.0/4.0,  1.0/4.0,  0.0,
       0.0, -1.0/4.0,  0.0,  0.0, -1.0/4.0,  0.0,  0.0,  1.0/4.0,
       0.0,  0.0, -1.0/4.0,  0.0, -1.0/4.0,  0.0,  0.0,  1.0/4.0,
       0.0,  0.0,  0.0, -1.0/4.0,  0.0, -1.0/4.0, -1.0/4.0,  0.0;

  tarch::la::Vector<TWO_POWER_D,double> uOld =
    VertexOperations::readOldU(fineGridVerticesEnumerator,fineGridVertices);

  const double h       = fineGridVerticesEnumerator.getCellSize()(0);
  const double scaling = 1.0/h;
  tarch::la::Vector<TWO_POWER_D,double> averageUpdate = scaling * A * uOld;

  VertexOperations::writeAveragedU(
    fineGridVerticesEnumerator,fineGridVertices,
    VertexOperations::readAveragedU(fineGridVerticesEnumerator,fineGridVertices)
    + averageUpdate
  );

  logTraceOutWith1Argument( "enterCell(...)", fineGridCell );
}

void myproject::mappings::AdaptiveRefinementCriterion::touchVertexLastTime(...) {
  logTraceInWith6Arguments( "touchVertexLastTime(...)", fineGridVertex, fineGridX, ... );

  if (coarseGridVerticesEnumerator.getLevel()<6) {
    fineGridVertex.evaluateRefinementCiterion();
  }

  logTraceOutWith1Argument( "touchVertexLastTime(...)", fineGridVertex );
}

\end{code}

\noindent
The magic final operation is kept very simple in this guide book:

\begin{code}
void myproject::Vertex::evaluateRefinementCiterion() {
 if (
  getRefinementControl()==Records::Unrefined
  &&
  std::abs( _vertexData.getAveragedU() )>1.0
 ) {
   refine();
 }
}
\end{code}

\begin{remark}
Almost all sophisticated refinement criteria are based upon a marker concept
such that only a given ratio of the cells are refined per step.
Such markers are non-trivial to implement as they require global sorting.
It is thus convenient to use some binning approach.
The \texttt{matrixfree} toolbox of Peano has a reference implementation that
also works in an MPI environment.
\end{remark}

For the second step, we have to ensure that all newly created cells and vertices
are intialised correctly.
For the cells, we might simply merge the \texttt{CreateGrid} mapping into our
time stepping adapter.
For the vertices, we have to plug into \texttt{createInnerVertex} where we
initialse the vertex with the interpolated value of its coarse grid parents.
Again, Peano offers toolboxes with routines that do so.
However, you may also simply reprogram it using the dimension-specific for-loops
of \texttt{Loop.h}.
The routines are then very similar to the interpolation for hanging nodes.
In this example, we do not reuse \texttt{CreateGrid}, but implement everything
within the adaptivity criterion's mapping.

\begin{code}
void myproject::mappings::AdaptiveRefinementCriterion::createCell( ... ) {
  logTraceInWith4Arguments( "createCell(...)", fineGridCell, ... );

  fineGridCell.init( fineGridVerticesEnumerator.getCellCenter() );

  logTraceOutWith1Argument( "createCell(...)", fineGridCell );
}

void myproject::mappings::AdaptiveRefinementCriterion::createInnerVertex( ... ) {
  logTraceInWith6Arguments( "createInnerVertex(...)", fineGridVertex, fineGridX, fineGridH, ... );

  double interpolatedValue = 0.0;
  dfor2(k)
    double weight = 1.0;
    for (int d=0; d<DIMENSIONS; d++) {
      if (k(d)==0) {
        weight *= 1.0 - (fineGridPositionOfVertex(d))/3.0;
      }
      else {
        weight *= (fineGridPositionOfVertex(d))/3.0;
      }
    }
    interpolatedValue = weight * coarseGridVertices[ coarseGridVerticesEnumerator(k)].getU();
  enddforx

  VertexOperations::writeU( fineGridVertex, interpolatedValue );
  fineGridVertex.copyCurrentSolutionIntoOldSolution();

  logTraceOutWith1Argument( "createInnerVertex(...)", fineGridVertex );
}
\end{code}

\noindent
We finally modifiy our runner in two ways:
\begin{enumerate}
  \item We make the runner also plot if the grid changes in a particular time
  step, and
  \item we ensure that the time step size adopts to the grid structure, i.e.~we
  implement adaptive time stepping.
\end{enumerate}

\begin{code}
int myproject::runners::Runner::runAsMaster(myproject::repositories::Repository& repository) {
  peano::utils::UserInterface::writeHeader();

 repository.switchToCreateGridAndPlot();
 repository.iterate();

 const double initialDt = 1e-4;
 repository.getState().setTimeStepSize( initialDt );
 for (int i=0; i<10000; i++) {
   if (i%100==0 || !repository.getState().isGridStationary()) {
     repository.switchToTimeStepAndPlot();
   }
   else {
    repository.switchToTimeStep();
   }
   repository.iterate();
   double dt = initialDt * repository.getState().getMinimumMeshWidth()
             * repository.getState().getMinimumMeshWidth();
   repository.getState().setTimeStepSize( dt );
   logInfo(
    "runAsMaster(...)",
    "time step " << i << ": dt=" << dt << ", h_min=" <<
    repository.getState().getMinimumMeshWidth() );
 }

 repository.logIterationStatistics(true);
 repository.terminate();

 return 0;
}
\end{code}

\noindent
The screenshots below illustrate how the grid evolves in the first four time
steps of the simulation:
\begin{center}
  \includegraphics[width=0.4\textwidth]{41_heat-equation/dynamic00.png}
  \includegraphics[width=0.4\textwidth]{41_heat-equation/dynamic01.png}
  \includegraphics[width=0.4\textwidth]{41_heat-equation/dynamic02.png}
  \includegraphics[width=0.4\textwidth]{41_heat-equation/dynamic03.png}
\end{center}

\subsection{Global data}

For most solvers, some kind of global information is required.
Such data could be
\begin{itemize}
  \item a global time step size,
  \item a residual norm,
  \item a counter for file plots,
  \item and so forth.
\end{itemize}

\noindent
We could hold such information as static/global data in our code or as an
attribute in a mapping.
Both options are not particular appealing.
Global variables contradict our notion of nice decomposed programming.
Furthermore, I have to anticipate that Peano automatically replicates mappings
on a multithreaded system.
So we have to be very carefully if we access global data within the mapping's
routines to avoid race conditions.
Attributes of mappings suffer from the same issues.
Furthermore, if mappings are replicated, they are replicated as well:
instead of data races we have to ensure that data is correctly replicated and
then fused again.
Finally, if we run on a distributed memory machine, multiple instances of our
application will execute because of MPI's SPMD paradigm, and we have to somehow
manually ensure that global data is kept consistent among all the ranks.

Peano's concept is to model all global data within the \texttt{State.def} file.
Again, we can here also anticipate which data later on is to be distributed
between different ranks. We have discussed this issue before.
We also have clarified that the standard pattern is to set global data in the
runner through the State object and then to use this data alter on.

\begin{code}
Packed-Type: short int;

class myproject::records::State {
  persistent parallelise double dt;
};

\end{code}

To use a state, I recommend to make each mapping extract all required data from
the state in \texttt{beginIteration()}.
The idea is as follows (for parallel runs later on): a global algorithm control
routing sets global data in the state.
This state is distributed among all ranks.
All ranks run a particular set of mappings through one adapter.
Each mapping get the required data in \texttt{beginIteration()}.
Later on, we will can tune exactly when the state data is exchanged.

As copying attributes from the \texttt{State} object is laborious, a standard
pattern is to make each mapping hold a copy of the whole state:

\begin{code}
class myproject::mappings::TimeStep {
  private:
    /**
     * Logging device for the trace macros.
     */
    static tarch::logging::Log  _log;

    State _localState;
    ...
};
\end{code}

\noindent
It is important that this state is a local one and is overwritten in each run,
as the runner outside might have changed it.

\begin{code}
void myproject::mappings::TimeStep::beginIteration(
  myproject::State&  solverState
) {
  logTraceInWith1Argument( "beginIteration(State)", solverState );

  _localState  = solverState;
  _localState._clearAttributes(); // see remark below

  assertion2( _timeStepSize>0.0, _timeStepSize, solverState.toString() );

  logTraceOutWith1Argument( "beginIteration(State)", solverState);
}
\end{code}

\noindent
Once you need data from the state, you can extract this data within the mapping
via \linebreak \texttt{solverState.getTimeStepSize()} in the present example.

We finally have to clarify how to collect global data, i.e.~how to realise the
data flow the other way round.
For this, we also use the copy of the state (this is only one implementation
pattern and again we could fill back data manually attribute-by-attribute. It
is just more convenient this way).
Usually, we first introduce an operation \texttt{State::clearAttributes()} that
resets all data, and we offer operations alike
\texttt{State::updateResidual(double myParam)} that allow us to collect
information within a \texttt{State} instance.

Within the mapping, we then use this operation to collect the data from all grid
entities:
\begin{code}
  ...
  _localState.updateResidual(myValue);
  ...
\end{code}

\noindent
Obviously, the solution so far is not worth a penny, as the mappings work with
their own local copy of state.
The solution now is to introduce a new operation
\begin{code}
void State::merge( const State& otherState ) {
  _stateData.setMyLocalAttribute(
    _stateData.getMyLocalAttribute() +
    otherState._stateData.getMyLocalAttribute()
  );
}
\end{code}

\noindent
We call this operation in \texttt{endIteration()} to basically backplay the data
from the local copy into the global state:
\begin{code}
void myproject::mappings::TimeStep::endIteration(
  myproject::State&  solverState
) {
  solverState.merge( _localState );
}
\end{code}

\noindent
Finally, we can read the state in the global runner and plot some data to the
terminal, e.g.:
\begin{code}
int myproject::runners::Runner::runAsMaster(myproject::repositories::Repository& repository) {
  ...

  const double initialDt = 1e-4;
  repository.getState().setTimeStepSize( initialDt );
  for (int i=0; i<10000; i++) {
    if (i%100==0 || !repository.getState().isGridStationary()) {
      repository.switchToTimeStepAndPlot();
    }
    else {
     repository.switchToTimeStep();
    }
    repository.getState()._clearAttributes();
    repository.iterate();
    logInfo( "runAsMaster(...)", "my fancy global attribute=" <<
    repository.getState().getMyFancyGloalAttribute() );

    ...
  }

  ...
}
\end{code}

\noindent
Please note that you might have to clear also the global state from time to
time, which is done in the snippet above right before we call \texttt{iterate}.

\begin{remark}
  The whole process seems to be a little bit of overengineering just to get a
  few global variables right. The elegance of the solution becomes obvious when
  we use multiple MPI ranks and multiple threads. There, we rely on exactly the
  same \texttt{merge} operation to distribute a global state first to all ranks
  and threads before we fuse all distributed states together again into one
  object.
\end{remark}

\subsection*{Further reading}

\begin{itemize}
  \item   Muntean, Ioan Lucian, Mehl, Miriam, Neckel, Tobias and Weinzierl,
  Tobias (2008). {\em Concepts for Efficient Flow Solvers Based on Adaptive
  Cartesian Grids}. In High Performance Computing in Science and Engineering,
  Garching 2007. Wagner, Siegfried, Steinmetz, Matthias, Bode, Arndt and Brehm,
  Matthias Berlin Heidelberg New York: Springer.
  \item Weinzierl, Tobias and K\"oppl, Tobias (2012). {\em A Geometric
  Space-time Multigrid Algorithm for the Heat Equation}. Numerical Mathematics:
  Theory, Methods and Applications 5(1): 110-130.
  \item Mehl, Miriam, Weinzierl, Tobias and Zenger, Christoph (2006). {\em A
  cache-oblivious self-adaptive full multigrid method}. Numerical Linear Algebra
  with Applications 13(2-3): 275-291.
\end{itemize}


\section{Privacy Preserving Histograms}\label{s:histograms}
Despite the challenges presented in sections \ref{s:challenges} and \ref{s:simple-algorithms}, the majority of algorithms can be transformed to their privacy preserving equivalent.
However, this is not a straightforward translation , as we examined in section \ref{s:simple-algorithms}, and in most cases it adds a complexity overhead to every algorithm that depends its control flow decisions in private data.

Histograms is a practical and notable example of algorithms that are widely used and the complexity of their privacy preserving version remains in computationally feasible levels, comparing to the textbook algorithm.
But first of all, what is a histogram?

As stated in \cite{ioannidis2003history}, histograms initially conceived as a visual aid to statistical approximations.
Webster’s defines a histogram as ``a bar graph of a frequency distribution in which the widths of the bars are proportional to the classes into which the variable has been divided and the heights of the bars are proportional to the class frequencies".
A histogram is generally a form of classifying and representing data in some categories of a specific range; the range is an individual ``base" element associated with each column.

More specifically, a histogram on some attributes $\{A, B, \dots, Z\}$ is constructed by partitioning the data distribution of those attributes into some ranges which are mutually disjoint subsets called buckets and approximating the frequencies and values in each bucket.
For the sake of simplicity let us suppose that the number of ranges ($\beta$) of all attributes are equal ($\beta \geq 1$).

In figures \ref{f:simple-1d-hist} and \ref{f:simple-2d-hist} we present two histograms, the first one\hyp dimensional over the attribute ``Patient Age" and the second is a two\hyp dimensional over the attributes ``Patient Age" and ``Heart rate".
In both histograms $\beta = 4$, since the range of values for each attribute has been partitioned in four mutually disjoint subsets.
In the 1\hyp dimensional histogram \ref{f:simple-1d-hist} the $y-axis$ corresponds to the total number of occurrences of values that belong to each bucket.
In the 2\hyp dimensional histogram \ref{f:simple-2d-hist} since $y-axis$ corresponds to the ranges for the buckets for the second attribute, the occurrences are depicted with different colors.

\begin{figure}[t]
\centering
\begin{minipage}{.5\textwidth}
  \centering
  \includegraphics[width=\columnwidth]{figures/1d-simple-hist.png}
  \captionof{figure}{An one-dimensional histogram with $\beta = 4$}
  \label{f:simple-1d-hist}
\end{minipage}%
\begin{minipage}{.5\textwidth}
  \centering
  \includegraphics[width=\columnwidth]{figures/2d-simple-hist.png}
  \captionof{figure}{A two-dimensional histogram\myslash heatmap with $\beta = 4$}
  \label{f:simple-2d-hist}
\end{minipage}
\end{figure}

\begin{figure}[t]
\centering
\begin{minipage}{.5\textwidth}
  \centering
  \includegraphics[width=\columnwidth]{figures/AgeGroups.png}
  \captionof{figure}{One-dimensional histogram displaying Age Groups}
  \label{f:simple-1d-categorical-hist}
\end{minipage}%
\begin{minipage}{.5\textwidth}
  \centering
  \includegraphics[width=\columnwidth]{figures/AgeGroups_PopulationGroups.png}
  \captionof{figure}{A two-dimensional histogram displaying Age Groups with Continental Population Groups}
  \label{f:simple-2d-categorical-hist}
\end{minipage}
\end{figure}

Similarly, in figures \ref{f:simple-1d-categorical-hist} and \ref{f:simple-2d-categorical-hist} we present two more histograms, but with categorical values.
The attribute ``Age Groups" in \ref{f:simple-1d-categorical-hist} is separated in four disjoint categories; ``Infant", ``Adolescent", ``Child" and ``Adult".
In \ref{f:simple-2d-categorical-hist} we present demographic information (attribute ``Continental Population Groups") in relation with ``Age Groups".

\subsection{Algorithms for Privacy Preserving Histograms}\label{ss:histogram-algos}
Histograms are one of the simplest ways to visualize and easily understand data; rendering them very useful in many data analysis applications.
As we already mentioned, histograms consist of bars that are mutually disjoint and their heights are proportional to the counts of values in the corresponding ranges.

\textbf{Challenges with Privacy-Preserving Histograms}: The textbook algorithm splits the dataset to buckets and consecutively for each item it increments the corresponding ``bucket-counter".
Implementing this algorithm with respect to the privacy of the dataset introduces the problem that for each value it is not trivial to find the bucket that this specific value should be placed.

For instance, let us suppose that we are constructing the histogram in figure \ref{f:simple-1d-categorical-hist}.
In this case $\beta = 4$, thus the algorithm should obliviously split the values into four disjoint buckets.
The range of each bucket is computed considering the $\beta$ parameter, as well as the minimum and maximum age in the dataset.
In this specific example, the minimum age is $18$, while the maximum is $83$.
Having $\beta = 4$ results to bucket-range $(83 - 18) / 4 = 16.25$.
Therefore, the ranges for attribute ``Patient Age" are formed as follows: $[18, 34.25),$ $[34.25, 50.50),$ $[50.50, 66.75),$ $[66.75, 83]$.
Consecutively, for each patient in the dataset the algorithm calculates the number of bucket that the patient belongs by dividing his\myslash her value with the bucket-range; however, this index is encrypted.
Finally, the algorithm iterates through all $\beta$ buckets and obliviously adding $\enc{1}$ if the bucket is the correct one, or $\enc{0}$ otherwise.

The aforementioned algorithm works for numerical values; however, the one for categorical values is very similar.
Bucket-range is fixed to one, and $\beta$ equals to all different possible values in the dataset.
Also, there is no notion of terms minimum and maximum in categorical values.

\subsubsection{Privacy Preserving Histogram Computation: A Naive Approach}\label{sss:histogram-simple}
As we mentioned in section \ref{s:two-types-of-data}, we have separated our algorithms in two major categories, for categorical and for numerical data.
The procedure described in \ref{ss:histogram-algos} is shown in algorithms \ref{a:1d-simple-histogram-categorical} and \ref{a:1d-simple-histogram-numerical}.
These algorithms iterate through all $N$ items and check all possible cells for that item.
When the correct cell is found, they increment the corresponding counter.
The former is tailored to categorical datasets, while the latter is tailored to numerical\myslash continuous values.

\import{./}{algorithms/hist_simple_categorical.tex}

\import{./}{algorithms/hist_simple_numerical.tex}

Both algorithms are straightforward and simple to understand, however, not very efficient.
In the following subsections we delve into details for the privacy preserving algorithms that are based in the same idea, but leverage \texttt{SIMD} operations.

\subsubsection{Privacy Preserving Histograms for Categorical Values}\label{sss:histogram-categorical}
\textbf{One-Dimensional Histograms}: In algorithm \ref{a:1d-histogram-categorical} we present the privacy preserving algorithm of an one-dimensional (1D) histogram for categorical values.
In simple words, categorical data means that the values are discrete.
Hence, the second parameter in the algorithm (dubbed $P$) is the number of possible choices that exist in $array[N]$.
The input data is given in the form of a private array\myslash vector.

The algorithm creates a boolean array of equal size as the input data, and then for each possible encrypted value of the dataset checks (line 3) and counts (line 4) its occurrences.
Method {\fontfamily{lmss} $\textsc{Sum}$} is the same as in algorithm \ref{a:sum}.
Finally, the counts are gathered into a vector and returned -- still encrypted -- to the user.

\import{./}{algorithms/1d_hist_categorical.tex}

\textbf{Multi-Dimensional Histograms}: In algorithm \ref{a:multidim-histogram-categorical} we present the privacy preserving algorithm of multi-dimensional histograms for categorical values.
As in algorithm \ref{a:1d-histogram-categorical}, here, the third parameter ($Ps$) is the number of possible choices that exist in $array$.
However, since here the input data is a private array with multiple dimensions $array[N][M]$, the possible values should express the possible values for each dimension.
Thus, $Ps$ is an array of $A$ slots, where $A$ is the number of attributes.

The algorithm that computes a private multi-dimensional histogram is similar to the one regarding one-dimensional histograms but also addresses the issue of having a histogram of arbitrarily many dimensions.
In case we had a fixed (\textit{i.e.} known \textit{a-priori}) number of dimensions the simplest solution would be to use nested loops, as many as the histogram dimensions.
Since the number of dimensions is not known, we have to think of something else.
We represent the multi-dimensional histogram as a serialized version with an one-dimensional array (a vector) instead of using a multi-dimensional array (a matrix).
For example a 2-dimensional $3 \times 4$ histogram will be represented as a vector whose length is $ 12 $ ($= 3 \cdot 4$), and a $3 \times 4 \times 5$ 3-dimensional histogram wit a vector of length $ 60 $ ($= 3 \cdot 4 \cdot 5$)

When it comes to indexing if we wish to access the 2-dimensional $N \times M$ histogram represented as an one-dimensional at row $ i $ and column $ j $, instead of using $h[i][j]$ we use $h[i \cdot M + j]$.
Similarly, for the 3-dimensional $L \times N \times M$ histogram, $h[i][j][k]$ becomes $h[i \cdot N \cdot M + j \cdot M + k]$. So there needs to be a computation of a single index based on the multiple dimension indexes. In algorithm \ref{a:multidim-histogram-categorical}, the $positions$ vector holds this index for each record of the provided array, as can be seen in lines $ 6 $ and $ 7 $

Similarly to the 1D algorithm, the multi-dimensional one creates a boolean array ($eq$) for each possible histogram cell, which counts the occurrences of that cell in the $positions$ vector, as can be seen in lines $12$ and $13$ of algorithm \ref{a:multidim-histogram-categorical}.
\import{./}{algorithms/multdim_hist_categorical.tex}

\subsubsection{Privacy Preserving Histograms for Numerical Values}\label{sss:histogram-numerical}

\textbf{One-Dimensional Histograms}: In algorithm \ref{a:1d-histogram-numerical} we present the privacy preserving algorithm of one-dimensional (1D) histograms for numerical values.
In contrast with the categorical data, numerical data are not discrete, which means that the buckets in which the histogram will separate the dataset should be fixed (the $\beta$ parameter, as mentioned in section \ref{s:histograms})

First and foremost, the input data is given in the form of a private array\myslash vector of $N$ positions.
The second parameter is open (since the final results will eventually disclose it), and is the number of buckets\myslash cells that the algorithm will create, namely the $\beta$ factor.
The two last parameters are also encrypted and are the minimum and maximum values found in the dataset\myslash array (first parameter of the algorithm).
Those two parameters are necessary in order to determine for each element in the array in which cell should be placed.

This algorithm is very similar and in accord with algorithm \ref{a:1d-histogram-categorical}, however does some extra steps.
In lines 2 and 3, it first determines the width for each cell and then creates an array of $N$ elements that each one indicates the bucket that the element in the corresponding position of $array$ should be placed.
Consecutively, the algorithm creates another boolean array of equal size as the input data, and then for each possible encrypted value of the $cellMap$ checks (line 5) and counts (line 6) its occurrences.
Finally, the counts are gathered into a vector and returned -- still encrypted -- to the user.
Line 5 of algorithm \ref{a:1d-histogram-numerical} is more complex than line 3 of algorithm \ref{a:1d-histogram-categorical}, since the former has to check some corner cases of data that belong to the last bucket.

\import{./}{algorithms/1d_hist_numerical.tex}

\textbf{Multi-Dimensional Histograms}:
The algorithm that implements multi\hyp dimensional histograms for numerical, \textit{i.e.} continuous data is a straightforward generalization of algorithms \ref{a:multidim-histogram-categorical} and \ref{a:1d-histogram-numerical}.
Similarly, for each specified attribute we compute the corresponding cell width (as in the 1\hyp dimensional for numerical values -- alg. \ref{a:1d-histogram-numerical}), that depends on the minimum and maximum values and the specified cell number of that attribute.
Consecutively, we compute the $positions$ vector containing the histogram cell for each one of the $N$ rows of $array$.
Like in algorithm \ref{a:multidim-histogram-categorical}, the $positions$ array contains single indexes that correspond to multiple indexes according to the procedure described above in section \ref{sss:histogram-categorical}.

% \import{./}{algorithms/multdim_hist_numerical.tex}

\subsubsection{Filters in Privacy Preserving Histograms}\label{sss:histogram-filters}
Although histograms are one of the simplest ways to visualize and easily understand data, they also come with some limitations.
For instance, it is difficult to visualize in one image more than three different attributes.
Even though we can compute histograms of arbitrarily many dimensions, even a 3D representation can sometimes  be very obscure and difficult to understand.

Oftentimes, one needs to take into consideration multiple attributes in order to get meaningful results back.
However, adding more attributes to the computed histogram is not always an option as for the reasons described above, the output could be obscure or even useless whatsoever.

For all those reasons, we have implemented a \textit{filtering} technique in order to take more attributes into consideration for the secure computation.
With filtering, the user is able to select a histogram computation over some attributes, and also specify some extra constraints over the same or different attributes.
Each tuple from the dataset has to meet the specified criteria\myslash filters in ordered to be counted in the resulting histogram.

The specified filters are represented as a list of constraints that should be met.
Each constraint is defined by the corresponding attribute, an operator ( one of $\{<, >, =\}$ for continuous attributes, and just $=$ for categorical ones) and a value.
Also a boolean operator (\textit{e.g.} \texttt{AND, OR, XOR}) that will be applied between the different constraints is specified.

For example, one could want to see the correlation of age and height but only for a subset of the dataset.
Let us suppose two examples, in the first we want the subset that include all patients of age above $45$, while in the second subset we want to include all patients of age above $45$ and that in the same time weigh less than $90$ kg.
This can be achieved with two requests of two\hyp dimensional histograms on the attributes \textit{Patient Age} and \textit{Height (cm)} that also includes the filters \textit{Patient Age} $ > 45$, and the second additionally have the limitation that \textit{Weight (kg)} $ < 90$, and also the boolean operator \texttt{AND} between them.
These will result to two 2\hyp dimensional histograms (heatmap) with axes the \textit{Patient Age} and \textit{Height (cm)} attributes, but at the same time the results will be restricted by the selection of these filters.
The described example from above, is depicted in figures \ref{f:2d_no_filter}, \ref{f:2d_1_filter} and \ref{f:2d_filter}, in which the impact of the filters is obvious.

\begin{figure}[t]
  \centering
  \includegraphics[width=0.8\linewidth]{figures/2d_no_filter.png}
  \caption{Histogram on \textit{Patient Age} and \textit{Height (cm)} with no filters}
  \label{f:2d_no_filter}
\end{figure}

\begin{figure}[th]
\centering
\begin{minipage}{.5\textwidth}
  \centering
  \includegraphics[width=\columnwidth]{figures/2d_1_filter.png}
  \captionof{figure}{Histogram on \textit{Patient Age} and \textit{Height (cm)} with filters on \textit{Patient Age}}
  \label{f:2d_1_filter}
\end{minipage}%
\begin{minipage}{.5\textwidth}
  \centering
  \includegraphics[width=\columnwidth]{figures/2d_filter.png}
  \captionof{figure}{Histogram on \textit{Patient Age} and \textit{Height (cm)} with filters on \textit{Patient Age} and \textit{Weight (kg)}}
  \label{f:2d_filter}
\end{minipage}
\end{figure}

Another example can be an one\hyp dimensional histogram on Body mass Index (BMI) on the subset of patients that weigh more than $90$ kg or are less than $170$ cm in height.
This can be achieved withl a request of an one\hyp dimensional histogram on the attribute \textit{BMI (kg/msq)} that also includes the filters \textit{Weight (kg)} $ > 90$, \textit{Height (cm)} $ < 170$, and also the boolean operator \texttt{OR} between them.
The effect of this example can be found in figures \ref{f:1d_no_filter} and \ref{f:1d_filter}.

\begin{figure}
\centering
\begin{minipage}{.5\textwidth}
  \centering
  \includegraphics[width=\columnwidth]{figures/1d_no_filter.png}
  \captionof{figure}{Histogram on \textit{BMI (kg/msq)} with no filters}
  \label{f:1d_no_filter}
\end{minipage}%
\begin{minipage}{.5\textwidth}
  \centering
  \includegraphics[width=\columnwidth]{figures/1d_filter.png}
  \captionof{figure}{Histogram on \textit{BMI (kg/msq)} with filters on \textit{Height (cm)} and \textit{Weight (kg)}}
  \label{f:1d_filter}
\end{minipage}
\end{figure}

\import{./}{algorithms/filters.tex}

The way that \textit{filters} have been implemented is by constructing a vector of size $N$ (\textit{i.e.} as long as the number of tuples in the dataset), that works as a boolean mask corresponding to the specified constraints.
Each position of that vector corresponds to a data tuple from the dataset.
If that tuple satisfies all the specified constraints, then the vector should have the (encrypted) value \texttt{True} in that position, or (encrypted) \texttt{False} otherwise.
This vector then is taken into consideration when we build the histogram.
Only tuples which have ``scored'' \texttt{True} are counted into the histogram.

In algorithm \ref{a:filters-constraint-mask}, the aforementioned vector is called $constraintMask$.
In lines 14-20 we build this boolean mask for each constraint into the $eq$ vector, and in lines 21-27 we combine these vectors to build the total one, according to the specified boolean operator applied between them.

The algorithm for computing histograms for either categorical or numerical attributes utilizes this $constraintMask$ vector.
After having computed the constraints, in order to join them with the data computed by the algorithms, a private multiplication with the $N$-size vector $constraintMask$ is needed.
This multiplication can be done with SIMD operation, which saves a lot of communication overhead between the computing nodes.

As the multi\hyp dimensional histogram computation algorithms for numerical and categorical data, constraint mask can be used for as many dimensions as requested.
Since the constraint\hyp mask is dependent to the number of tuples in the dataset, the dimensions of the requested histogram can be as many as the user requests.

% \import{./}{algorithms/filters2.tex}


% vim: ft=tex iskeyword=@,48-57,_,-,192-255,\: dictionary=bibkeys.lst,labels.lst:
\chapter{The Rotating Wave Approximation}
\label{AppendixRWA}

In many cases, we can simplify the Hamiltonian and make it analytically
tractable by transforming it from the \emph{lab frame}
to the \emph{rotating frame}
oscillating at the laser frequency $\omega_L$. The rotating frame is defined by
a time-dependent unitary transformation $\Op{U}(t)$. Every state $\ket{\Psi}$ in
the lab frame is transformed to the corresponding state in the rotating frame as
\begin{equation}
  \ket{\tilde{\Psi}(t)} = \Op{U}(t) \ket{\Psi(t)}
\end{equation}
In order to derive the Hamiltonian in the rotating frame, we demand the
Schrödinger equation to be fulfilled,
\begin{equation}
  \ii \hbar \partdifquo{t} \ket{\tilde{\Psi}} = \tildeOp{H}
  \ket{\tilde{\Psi}}\,,
\end{equation}
which leads to
\begin{equation}
\begin{split}
  \ii \hbar \partdifquo{t} \ket{\tilde{\Psi}}
    & = \ii \hbar \dotOp{U} \ket{\Psi}
        + \op{U} \ii \hbar \partdifquo{t} \ket{\Psi} \\
    & = \ii \hbar \dotOp{U} \ket{\Psi}
        + \op{U}\op{H}\ket{\Psi} \\
    & = \ii \hbar \dotOp{U} \op{U}\daggered \ket{\tilde{\Psi}}
           + \op{U}\op{H}\op{U}\daggered\ket{\tilde{\Psi}} \\
    & = \left( \ii \hbar \dotOp{U}\op{U}\daggered
        + \op{U}\op{H}\op{U}\daggered \right)\ket{\tilde{\Psi}}.
\end{split}
\end{equation}
So, the transformed Hamiltonian is
\begin{equation} \label{eq:ham_tilde}
  \tildeOp{H} = \ii \hbar \dotOp{U} \op{U}\daggered
                   + \op{U}\op{H}\op{U}\daggered.
\end{equation}

For a system of two dipole-coupled levels separated by energy $\hbar \omega_1$,
driven by a pulse $\epsilon(t)$, the Hamiltonian reads
\begin{equation}
  \Op{H} = \begin{pmatrix}
    0               & \mu \epsilon(t) \\
    \mu \epsilon(t) & \hbar \omega_1
  \end{pmatrix}\,,
\end{equation}
where $\mu$ is the dipole strength. We consider the pulse
\begin{equation}
  \epsilon(t)
  = S(t) \cos(\omega_L t)
  = \frac{S(t)}{2} \left( \ee^{\ii \omega_L t} + \ee^{-\ii \omega_L t } \right)\,,
\end{equation}
with frequency $\omega_L$ and a slowly varying shape $S(t)$.
The rotating frame for this pulse is defined by
\begin{equation}
  \Op{U}(t) = \begin{pmatrix}
    1 & 0                   \\
    0 & \ee^{i \omega_L t}
  \end{pmatrix}\,.
\end{equation}
Applying Eq.~\eqref{eq:ham_tilde} yields
\begin{equation}
  \tildeOp{H} = \begin{pmatrix}
    0                                      & \mu \epsilon(t) \ee^{-\ii \omega_L t }   \\
    \mu \epsilon(t) \ee^{+\ii \omega_L t } & \hbar(\omega_1 - \omega_L)
  \end{pmatrix}\,.
\end{equation}
The energy level has been shifted down by $\omega_L$, resulting from the term
$\ii \hbar \dotOp{U}\Op{U}\daggered$, and the couplings obtain a time-dependent
phase-factor, due to the term $\op{U}\op{H}\op{U}\daggered$. Up to this point,
the transformation is exact. For the off-diagonal terms, we now find
\begin{equation}
  \mu \epsilon(t) \ee^{\pm \ii \omega_L t }
  = \frac{\mu}{2} \epsilon(t) \left( 1 + \ee^{\pm 2 \ii \omega_L t} \right)
  \approx
    \frac{\mu}{2} S(t) \equiv \Omega(t)\,.
\end{equation}
The approximation is valid for $\omega_L \gg 1$, where the fast oscillations at
twice the laser frequency average out, leaving only the slowly varying pulse
shape. With the detuning $\Delta \equiv \hbar(\omega_1 - \omega_L)$, the
RWA-Hamiltonian is therefore
\begin{equation}
  \Op{H}_{\text{RWA}} = \begin{pmatrix}
    0         & \Omega(t) \\
    \Omega(t) & \Delta
  \end{pmatrix}\,.
\end{equation}

In chapter~\ref{chap:robust}, a cesium atom was considered where the ground
state $\ket{0}$ is excited to the Rydberg state \ket{r} by a two-photon
transition via the intermediary level \ket{i}, see
Fig.~\ref{fig:RydRobust_1q_levels}. In the lab frame, the
Hamiltonian reads
\begin{equation}
  \Op{H} = \begin{pmatrix}
    0                   & \mu_B \epsilon_B(t) & 0                  \\
    \mu_B \epsilon_B(t) & \hbar \omega_i      & \mu_R \epsilon_R(t) \\
    0                   & \mu_R \epsilon_R(t) & \hbar \omega_r
  \end{pmatrix}\,,
\end{equation}
with the red and blue laser field
\begin{equation}
  \epsilon_{R,B}(t) = S_{R,B}(t) \cos(\omega_{R,B} t).
\end{equation}
The appropriate two-color RWA is defined by
\begin{equation}
  \Op{U} = \begin{pmatrix}
    1  & 0                    & 0                                   \\
    0  & \ee^{\ii \omega_B t} & 0                                   \\
    0  & 0                    & \ee^{\ii (\omega_B + \omega_R) t}
  \end{pmatrix}\,.
  \label{eq:U_two_color_rwa}
\end{equation}
The transformed Hamiltonian (with $\mu_{R,B}$ absorbed in $\epsilon_{R,B}$) is
\begin{equation}
\begin{split}
  \tildeOp{H}
  & =
  \begin{pmatrix}
    0                                   & \epsilon_B(t) \ee^{-\ii \omega_B t}                           & 0                                                               \\
    \epsilon_B(t) \ee^{\ii \omega_B t}  & \hbar(\omega_i - \omega_R)                                    & \epsilon_R(t) \ee^{-\ii (\omega_R + \omega_B)t +\ii \omega_B t} \\
    0                                   & \epsilon_R(t) \ee^{\ii (\omega_R + \omega_B)t -\ii \omega_Bt} & \hbar(\omega_r - \omega_R -\omega_B)
  \end{pmatrix} \\
  & \approx
  \begin{pmatrix}
   0           & \Omega_B(t) & 0           \\
   \Omega_B(t) & \Delta_1    & \Omega_R(t) \\
   0           & \Omega_R(t) & \Delta_2
  \end{pmatrix}\,,
\end{split}
\end{equation}
with
\begin{equation}
  \Omega_{R,B}(t) = \frac{1}{2} \mu_{R,B} S_{R,B}(t)
\end{equation}
and the single- and two-photon detuning $\Delta_1$ and $\Delta_2$, respectively.
This corresponds to Eq.~\eqref{eq:Rydberg_H_1q}.

In general, the appropriate RWA-transformation $\Op{U}$ can be
read off from a level diagram; \Op{U} is always diagonal with entries $\ee^{\ii
\omega_i t}$, where $\omega_i$ is the amount by which the $i$'th energy level is
shifted down. The shifts result from shortening each transition by the pulse
frequency that is to be eliminated~\cite{ShoreBook11}.
For example, starting from the diagram in
Fig~\ref{fig:RydRobust_1q_levels}, shortening the blue transition means
that both $\ket{i}$ and $\ket{r}$ are shifted down by $\omega_B$. Then,
shortening the red transition means that $\ket{r}$ is shifted down by an
additional amount $\omega_R$, resulting in~Eq.~\eqref{eq:U_two_color_rwa}.