\input{../tex/headerfile}
\input{../tex/mathdefs}
\setcounter{MaxMatrixCols}{20}
\usepackage{enumerate}
\usepackage{Sweave}
\begin{document}
\input{basic-matrix-math-concordance}

\chapter{Basic matrix math in R}
\label{chap:basicmat}
\chaptermark{Matrix math}

This chapter reviews the basic matrix math operations that you will need to understand the course material and how to do these operations in R.

\section{Creating matrices in R}
Create a $3 \times 4$ matrix, meaning 3 row and 4 columns, that is all 1s:
\begin{Schunk}
\begin{Sinput}
 matrix(1, 3, 4)
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3] [,4]
[1,]    1    1    1    1
[2,]    1    1    1    1
[3,]    1    1    1    1
\end{Soutput}
\end{Schunk}
Create a $3 \times 4$ matrix filled in with the numbers 1 to 12 by column (default) and by row:
\begin{Schunk}
\begin{Sinput}
 matrix(1:12, 3, 4)
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   10
[2,]    2    5    8   11
[3,]    3    6    9   12
\end{Soutput}
\begin{Sinput}
 matrix(1:12, 3, 4, byrow=TRUE)
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    5    6    7    8
[3,]    9   10   11   12
\end{Soutput}
\end{Schunk}
Create a matrix with one column:
\begin{Schunk}
\begin{Sinput}
 matrix(1:4, ncol=1)
\end{Sinput}
\begin{Soutput}
     [,1]
[1,]    1
[2,]    2
[3,]    3
[4,]    4
\end{Soutput}
\end{Schunk}
Create a matrix with one row:
\begin{Schunk}
\begin{Sinput}
 matrix(1:4, nrow=1)
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
\end{Soutput}
\end{Schunk}
Check the dimensions of a matrix
\begin{Schunk}
\begin{Sinput}
 A=matrix(1:6, 2,3)
 A
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
\end{Soutput}
\begin{Sinput}
 dim(A)
\end{Sinput}
\begin{Soutput}
[1] 2 3
\end{Soutput}
\end{Schunk}
Get the number of rows in a matrix:
\begin{Schunk}
\begin{Sinput}
 dim(A)[1]
\end{Sinput}
\begin{Soutput}
[1] 2
\end{Soutput}
\begin{Sinput}
 nrow(A)
\end{Sinput}
\begin{Soutput}
[1] 2
\end{Soutput}
\end{Schunk}
Create a 3D matrix (called array):
\begin{Schunk}
\begin{Sinput}
 A=array(1:6, dim=c(2,3,2))
 A
\end{Sinput}
\begin{Soutput}
, , 1

     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6

, , 2

     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
\end{Soutput}
\begin{Sinput}
 dim(A)
\end{Sinput}
\begin{Soutput}
[1] 2 3 2
\end{Soutput}
\end{Schunk}
Check if an object is a matrix.  A dataframe is not a matrix.  A vector is not a matrix.
\begin{Schunk}
\begin{Sinput}
 A=matrix(1:4, 1, 4)
 A
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
\end{Soutput}
\begin{Sinput}
 class(A)
\end{Sinput}
\begin{Soutput}
[1] "matrix"
\end{Soutput}
\begin{Sinput}
 B=data.frame(A)
 B
\end{Sinput}
\begin{Soutput}
  X1 X2 X3 X4
1  1  2  3  4
\end{Soutput}
\begin{Sinput}
 class(B)
\end{Sinput}
\begin{Soutput}
[1] "data.frame"
\end{Soutput}
\begin{Sinput}
 C=1:4
 C
\end{Sinput}
\begin{Soutput}
[1] 1 2 3 4
\end{Soutput}
\begin{Sinput}
 class(C)
\end{Sinput}
\begin{Soutput}
[1] "integer"
\end{Soutput}
\end{Schunk}

\section{Matrix multiplication, addition and transpose}
You will need to be very solid in matrix multiplication for the course.  If you haven't done it in awhile, google `matrix multiplication youtube' and you find lots of 5min videos to remind you.

In R, you use the \verb@%*%@ operation to do matrix multiplication.  When you do matrix multiplication, the columns of the matrix on the left must equal the rows of the matrix on the right.  The result is a matrix that has the number of rows of the matrix on the left and number of columns of the matrix on the right.
$$(n \times m)(m \times p) = (n \times p)$$
\begin{Schunk}
\begin{Sinput}
 A=matrix(1:6, 2, 3) #2 rows, 3 columns
 B=matrix(1:6, 3, 2) #3 rows, 2 columns
 A%*%B #this works
\end{Sinput}
\begin{Soutput}
     [,1] [,2]
[1,]   22   49
[2,]   28   64
\end{Soutput}
\begin{Sinput}
 B%*%A #this works
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3]
[1,]    9   19   29
[2,]   12   26   40
[3,]   15   33   51
\end{Soutput}
\begin{Sinput}
 try(B%*%B) #this doesn't
\end{Sinput}
\end{Schunk}
To add two matrices use \verb@+@. The matrices have to have the same dimensions.
\begin{Schunk}
\begin{Sinput}
 A+A #works
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3]
[1,]    2    6   10
[2,]    4    8   12
\end{Soutput}
\begin{Sinput}
 A+t(B) #works
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3]
[1,]    2    5    8
[2,]    6    9   12
\end{Soutput}
\begin{Sinput}
 try(A+B) #does not work since A has 2 rows and B has 3
\end{Sinput}
\end{Schunk}
The transpose of a matrix is denoted $\AA^\top$ or $\AA^\prime$.  To transpose a matrix in R, you use \verb@t()@.
\begin{Schunk}
\begin{Sinput}
 A=matrix(1:6, 2, 3) #2 rows, 3 columns
 t(A) #is the transpose of A
\end{Sinput}
\begin{Soutput}
     [,1] [,2]
[1,]    1    2
[2,]    3    4
[3,]    5    6
\end{Soutput}
\begin{Sinput}
 try(A%*%A) #this won't work
 A%*%t(A) #this will
\end{Sinput}
\begin{Soutput}
     [,1] [,2]
[1,]   35   44
[2,]   44   56
\end{Soutput}
\end{Schunk}

\section{Subsetting a matrix}
To subset a matrix, we use \verb@[ ]@:
\begin{Schunk}
\begin{Sinput}
 A=matrix(1:9, 3, 3) #3 rows, 3 columns
 #get the first and second rows of A
 #it's a 2x3 matrix
 A[1:2,]
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
\end{Soutput}
\begin{Sinput}
 #get the top 2 rows and left 2 columns
 A[1:2,1:2]
\end{Sinput}
\begin{Soutput}
     [,1] [,2]
[1,]    1    4
[2,]    2    5
\end{Soutput}
\begin{Sinput}
 #What does this do?
 A[c(1,3),c(1,3)]
\end{Sinput}
\begin{Soutput}
     [,1] [,2]
[1,]    1    7
[2,]    3    9
\end{Soutput}
\begin{Sinput}
 #This?
 A[c(1,2,1),c(2,3)]
\end{Sinput}
\begin{Soutput}
     [,1] [,2]
[1,]    4    7
[2,]    5    8
[3,]    4    7
\end{Soutput}
\end{Schunk}
If you have used matlab, you know you can say something like \verb@A[1,end]@ to denote the element of a matrix in row 1 and the last column.  R does not have `end'.  To do, the same in R you do something like:
\begin{Schunk}
\begin{Sinput}
 A=matrix(1:9, 3, 3)
 A[1,ncol(A)]
\end{Sinput}
\begin{Soutput}
[1] 7
\end{Soutput}
\begin{Sinput}
 #or
 A[1,dim(A)[2]]
\end{Sinput}
\begin{Soutput}
[1] 7
\end{Soutput}
\end{Schunk}

\textbf{Warning R will create vectors from subsetting matrices!}

One of the really bad things that R does with matrices is create a vector if you happen to subset a matrix to create a matrix with 1 row or 1 column.  Look at this:
\begin{Schunk}
\begin{Sinput}
 A=matrix(1:9, 3, 3)
 #take the first 2 rows
 B=A[1:2,]
 #everything is ok
 dim(B)
\end{Sinput}
\begin{Soutput}
[1] 2 3
\end{Soutput}
\begin{Sinput}
 class(B)
\end{Sinput}
\begin{Soutput}
[1] "matrix"
\end{Soutput}
\begin{Sinput}
 #take the first row
 B=A[1,]
 #oh no! It should be a 1x3 matrix but it is not.
 dim(B)
\end{Sinput}
\begin{Soutput}
NULL
\end{Soutput}
\begin{Sinput}
 #It is not even a matrix any more
 class(B)
\end{Sinput}
\begin{Soutput}
[1] "integer"
\end{Soutput}
\begin{Sinput}
 #and what happens if we take the transpose?
 #Oh no, it's a 1x3 matrix not a 3x1 (transpose of 1x3)
 t(B)
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3]
[1,]    1    4    7
\end{Soutput}
\begin{Sinput}
 #A%*%B should fail because A is (3x3) and B is (1x3)
 A%*%B
\end{Sinput}
\begin{Soutput}
     [,1]
[1,]   66
[2,]   78
[3,]   90
\end{Soutput}
\begin{Sinput}
 #It works? That is horrible!
\end{Sinput}
\end{Schunk}
This will create hard to find bugs in your code because you will look at \verb@B=A[1,]@ and everything looks fine.  Why is R saying it is not a matrix!  To stop R from doing this use \verb@drop=FALSE@.
\begin{Schunk}
\begin{Sinput}
 B=A[1,,drop=FALSE]
 #Now it is a matrix as it should be
 dim(B)
\end{Sinput}
\begin{Soutput}
[1] 1 3
\end{Soutput}
\begin{Sinput}
 class(B)
\end{Sinput}
\begin{Soutput}
[1] "matrix"
\end{Soutput}
\begin{Sinput}
 #this fails as it should (alerting you to a problem!)
 try(A%*%B)
\end{Sinput}
\end{Schunk}

\section{Replacing elements in a matrix}
Replace 1 element.
\begin{Schunk}
\begin{Sinput}
 A=matrix(1, 3, 3)
 A[1,1]=2
 A
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3]
[1,]    2    1    1
[2,]    1    1    1
[3,]    1    1    1
\end{Soutput}
\end{Schunk}
Replace a row with all 1s or a string of values
\begin{Schunk}
\begin{Sinput}
 A=matrix(1, 3, 3)
 A[1,]=2
 A
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3]
[1,]    2    2    2
[2,]    1    1    1
[3,]    1    1    1
\end{Soutput}
\begin{Sinput}
 A[1,]=1:3
 A
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    1    1    1
[3,]    1    1    1
\end{Soutput}
\end{Schunk}
Replace group of elements.  This often does not work as one expects so be sure look at your matrix after trying something like this.  Here I want to replace elements (1,3) and (3,1) with 2, but it didn't work as I wanted.
\begin{Schunk}
\begin{Sinput}
 A=matrix(1, 3, 3)
 A[c(1,3),c(3,1)]=2
 A
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3]
[1,]    2    1    2
[2,]    1    1    1
[3,]    2    1    2
\end{Soutput}
\end{Schunk}
How do I replace elements (1,1) and (3,3) with 2 then?  It's tedious.  If you have a lot of elements to replace, you might want to use a for loop.
\begin{Schunk}
\begin{Sinput}
 A=matrix(1, 3, 3)
 A[1,3]=2
 A[3,1]=2
 A
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3]
[1,]    1    1    2
[2,]    1    1    1
[3,]    2    1    1
\end{Soutput}
\end{Schunk}

\section{Diagonal matrices and identity matrices}
A diagonal matrix is one that is square, meaning number of rows equals number of columns, and it has 0s on the off-diagonal and non-zeros on the diagonal.  In R, you form a diagonal matrix with the \verb@diag()@ function:
\begin{Schunk}
\begin{Sinput}
 diag(1,3) #put 1 on diagonal of 3x3 matrix
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3]
[1,]    1    0    0
[2,]    0    1    0
[3,]    0    0    1
\end{Soutput}
\begin{Sinput}
 diag(2, 3) #put 2 on diagonal of 3x3 matrix
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3]
[1,]    2    0    0
[2,]    0    2    0
[3,]    0    0    2
\end{Soutput}
\begin{Sinput}
 diag(1:4) #put 1 to 4 on diagonal of 4x4 matrix
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3] [,4]
[1,]    1    0    0    0
[2,]    0    2    0    0
[3,]    0    0    3    0
[4,]    0    0    0    4
\end{Soutput}
\end{Schunk}
The \verb@diag()@ function can also be used to replace elements on the diagonal of a matrix:
\begin{Schunk}
\begin{Sinput}
 A=matrix(3, 3, 3)
 diag(A)=1
 A
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3]
[1,]    1    3    3
[2,]    3    1    3
[3,]    3    3    1
\end{Soutput}
\begin{Sinput}
 A=matrix(3, 3, 3)
 diag(A)=1:3
 A
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3]
[1,]    1    3    3
[2,]    3    2    3
[3,]    3    3    3
\end{Soutput}
\begin{Sinput}
 A=matrix(3, 3, 4)
 diag(A[1:3,2:4])=1
 A
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3] [,4]
[1,]    3    1    3    3
[2,]    3    3    1    3
[3,]    3    3    3    1
\end{Soutput}
\end{Schunk}
The \verb@diag@ function is also used to get the diagonal of a matrix.
\begin{Schunk}
\begin{Sinput}
 A=matrix(1:9, 3, 3)
 diag(A)
\end{Sinput}
\begin{Soutput}
[1] 1 5 9
\end{Soutput}
\end{Schunk}
The identity matrix is a special kind of diagonal matrix with 1s on the diagonal.  It is denoted $\II$.  $\II_3$ would mean a $3 \times 3$ diagonal matrix.  A identity matrix has the property that $\AA\II=\AA$ and $\II\AA=\AA$ so it is like a 1.
\begin{Schunk}
\begin{Sinput}
 A=matrix(1:9, 3, 3)
 I=diag(3) #shortcut for 3x3 identity matrix
 A%*%I
\end{Sinput}
\begin{Soutput}
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9
\end{Soutput}
\end{Schunk}

\section{Taking the inverse of a square matrix}
The inverse of a matrix is denoted $\AA^{-1}$.  You can think of the inverse of a matrix like $1/a$.  $1/a \times a = 1$. $\AA^{-1}\AA = \AA\AA^{-1} = \II$.  The inverse of a matrix does not always exist; for one it has to be square.  We'll be using inverses for variance-covariance matrices and by definition (of a variance-covariance matrix), the inverse of those exist.  In R, there are a couple way common ways to take the inverse of a variance-covariance matrix (or something with the same properties).  \verb@solve@ is the most common probably:
\begin{Schunk}
\begin{Sinput}
 A=diag(3,3)+matrix(1,3,3)
 invA=solve(A)
 invA%*%A
\end{Sinput}
\begin{Soutput}
             [,1]          [,2] [,3]
[1,] 1.000000e+00 -6.938894e-18    0
[2,] 2.081668e-17  1.000000e+00    0
[3,] 0.000000e+00  0.000000e+00    1
\end{Soutput}
\begin{Sinput}
 A%*%invA
\end{Sinput}
\begin{Soutput}
             [,1]          [,2] [,3]
[1,] 1.000000e+00 -6.938894e-18    0
[2,] 2.081668e-17  1.000000e+00    0
[3,] 0.000000e+00  0.000000e+00    1
\end{Soutput}
\end{Schunk}
Another option is to use \verb@chol2inv@ which uses a Cholesky decomposition\footnote{The Cholesky decomposition is a handy way to keep your variance-covariance matrices valid when doing a parameter search.  Don't search over the raw variance-covariance matrix.  Search over a matrix where the lower triangle is 0, that is what a Cholesky decomposition looks like.  Let's call it \texttt{B}. Your variance-covariance matrix is \texttt{t(B)\%*\%B}.}:
\begin{Schunk}
\begin{Sinput}
 A=diag(3,3)+matrix(1,3,3)
 invA=chol2inv(chol(A))
 invA%*%A
\end{Sinput}
\begin{Soutput}
              [,1]         [,2]          [,3]
[1,]  1.000000e+00 6.938894e-17  0.000000e+00
[2,]  2.081668e-17 1.000000e+00 -2.775558e-17
[3,] -5.551115e-17 0.000000e+00  1.000000e+00
\end{Soutput}
\begin{Sinput}
 A%*%invA
\end{Sinput}
\begin{Soutput}
             [,1]          [,2]          [,3]
[1,] 1.000000e+00  2.081668e-17 -5.551115e-17
[2,] 6.938894e-17  1.000000e+00  0.000000e+00
[3,] 0.000000e+00 -2.775558e-17  1.000000e+00
\end{Soutput}
\end{Schunk}
For the purpose of this course, \verb@solve@ is fine.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\clearpage
\renewcommand{\rightmark}{}
\section*{Problems}
\addcontentsline{toc}{section}{Problems}

\begin{hwenumerate}
\item Build a $4 \times 3$ matrix with the numbers 1 through 4 in each row.
\item Extract the elements in the 1st and 2nd rows and 1st and 2nd columns (you'll have a $2 \times 2$ matrix). Show the R code that will do this.
\item Build a $4 \times 3$ matrix with the numbers 1 through 12 by row (meaning the first row will have the numbers 1 through 4 in it).
\item Extract the 3rd row of the above.  Show R code to do this where you end up with a vector and how to do this where you end up with a $1 \times 3$ matrix.
\item Build a $4 \times 3$ matrix that is all 1s except a 2 in the (2,3) element (2nd row, 3rd column).
\item Take the transpose of the above.
\item Build a $4 \times 4$ diagonal matrix with 1 through 4 on the diagonal.
\item Build a $5 \times 5$ identity matrix.
\item Replace the diagonal in the above matrix with 2 (the number 2).
\item Build a matrix with 2 on the diagonal and 1s on the offdiagonals.
\item Take the inverse of the above.
\item Build a $3 \times 3$ matrix with the first 9 letters of the alphabet.  First column should be ``a'', ``b'', ``c''.  \verb@letters[1:9]@ gives you these letters.
\item Replace the diagonal of this matrix with the word ``cat''.
\item Build a $4 \times 3$ matrix with all 1s. Multiply by a $3 \times 4$ matrix with all 2s.
\item If $\AA$ is a $4 \times 3$ matrix, is $\AA \AA$ possible? Is $\AA  \AA^\top$ possible?  Show how to write $\AA\AA^\top$ in R.
\item In the equation, $\AA \BB = \CC$, let $\AA=\left[ \begin{smallmatrix}1&4&7\\2&5&8\\3&6&9\end{smallmatrix}\right]$.  Build a $\BB$ matrix with only 1s and 0s such that the values on the diagonal of $\CC$ are 1, 8, 6 (in that order).  Show your R code for $\AA$, $\BB$ and $\AA \BB$.
\item Same $\AA$ matrix as above and same equation $\AA \BB = \CC$.  Build a $3 \times 3$ $\BB$ matrix such that $\CC=2\AA$.  So $\CC=\left[ \begin{smallmatrix}2&8&14\\ 4&10&16\\ 6&12&18\end{smallmatrix}\right]$. Hint, $\BB$ is diagonal.
\item Same $\AA$ and $\AA \BB=\CC$ equation.  Build a $\BB$ matrix to compute the row sums of $\AA$.  So the first `row sum' would be $1+4+7$, the sum of all elements in row 1 of $\AA$.  $\CC$ will be $\left[ \begin{smallmatrix}12\\ 15\\ 18\end{smallmatrix}\right]$, the row sums of $\AA$. Hint, $\BB$ is a column matrix (1 column).
\item Same $\AA$ matrix as above but now equation $\BB \AA  = \CC$.  Build a $\BB$ matrix to compute the column sums of $\AA$.  So the first `column sum' would be $1+2+3$.  $\CC$ will be a $1 \times 3$ matrix.
\item Let $\AA \BB=\CC$ equation but $\AA=\left[ \begin{smallmatrix}2&1&1\\1&2&1\\1&1&2\end{smallmatrix}\right]$ (so A=\verb@diag(3)+1@).  Build a $\BB$ matrix such that $\CC=\left[ \begin{smallmatrix}3\\ 3\\ 3\end{smallmatrix}\right]$. Hint, you need to use the inverse of $\AA$.

\end{hwenumerate}

\bibliography{../tex/Fish507}

\end{document}

docs/Labs/Week 0 basic matrix/basic-matrix-math.tex


\subsubsection{The Spectral Theorem}

With the introduction in previous section of the gramian matrix
$\trans{A}A$, it is time for the heavy machinery that will allow us to
prove the SVD \cref{thm:SVD}; we are talking of course, about
the Spectral Theorem. We will not only present the theorem, but also
include one of the many possible proofs. The one we chose was published
by Wilf in \cite{wilf81}, and we did so because of its brevity and
elegance. It actually makes an interesting connection between the
Linear Algebra world where have been moving so far, and the  world of
Topology; the link is created by using the properties of compact
sets. But before defining what a compact set is, let us
motivate this interesting usage. \\

A common problem that many people are familiar with, specially if they
took single-variable calculus courses at college; is that of finding the
minima or maxima of a given function $f: \R{} \fromto \R{}$. There is a
mechanical part about how to calculate those critical points, but a
crucial part is to verify on the first place, if they actually
exist. A common requirement is for the function $f$ to be continuous,
but further requirements are also needed on its domain. The reader may
recall the famous Extreme Value Theorem, which establishes what are those
conditions on the domain for single-variable functions: \\

\begin{theorem}
\label{thm:xtrem}
Let $f: \R{} \fromto \R{}$ be a continuous function over the closed
(and bounded interval) $[a,b]$, then $f$ reaches its maximum and its
minimum over the same interval.
\end{theorem}
\hfill

The \cref{thm:xtrem} tells us what the required condition is on
the domain of a continuous function $f$, in order to guarantee that its
critical points (minimum/maximum) actually exist. The
condition is simply to have a closed interval, which though not
evident, has the following two properties: \\

\begin{enumerate}
\item Closed: It contains its limit points \footnote{The intuitive
  idea for limit points, is that a ``limit'' process can approximate
  them by using points inside the set.} (like $0$ and $1$).
\item Bounded: There are real numbers which serve as lower and upper
  bounds for all the elements of the interval \footnote{In the case of a closed
  interval in \R{}, these bounds happen to be the limit points and are
  inside the interval; but for more general spaces, that may not be
  the case.}.
\end{enumerate}
\hfill

A set which has these properties of being closed and bounded, is said
to be compact. Being compact, is  a generalization of the closed intervals
on the real line. Why do we need such generalization? Well, simply
because we may be interested in calculating minima and maxima for
functions defined over more complex sets than \R{}; for example,
vector spaces or matrix spaces. Another important property of
compact sets, is that continuous functions preserve its
``compactness''; that is, if $S$ is a compact set and $f$ a continuous
function, then $\func{f}(S)$ is also a compact set. \\

Armed with this brief, but hopefully enough understanding of what
compact sets are; let us proceed with the proof.
The first required artifact is a function called \func{Od}, which
intuitively measures how close is an square matrix of $n \times n$,
from having a diagonal form:

\[
\func{Od}(A) = {\sum\sum}_{i \ne i} A_{ij}^2
\]
\hfill

The next artifact we need is the set of all orthogonal matrices
(denoted \bigO{n} \footnote{Not to be confused with the big-O
  notation for algorithms complexity.}). Using product multiplication, this set has the
algebraic structure of a group (though we do not really need such
property here). \\

The next tool is the following theorem, about Jacobi's method for
finding eigenvalues, which tells us that it is always possible to
perform rigid transformations (change of basis), that take one
non-diagonal matrix into a new one that is closer to a diagonal form
(per the metric defined by function $\func{Od}$). \\

\begin{theorem}
\label{thm:jacobi}
If $A$ is a real non-diagonal matrix, $\implies$ there is an orthogonal
matrix $J$ such that $\func{Od}(\trans{J} A J) < \func{Od}(A)$.
\end{theorem}
\hfill

An informal proof is given in \cite{wilf81}, and a more detailed
discussion is found in \cite{golub13}. This is the last tool we needed
for presenting the proof of the Spectral Theorem from \cite{wilf81},
which follows below: \\

\begin{theorem}
\label{thm:spec}
If $A$ is a symmetric real matrix, $\implies$ there is a real orthogonal
matrix $Q$ such that $\trans{Q}AQ$ is diagonal.
\end{theorem}
\hfill

\begin{proof}
Let $f$ be the function that, given the fixed matrix $A$, maps every
orthogonal matrix $P$ into the product $\trans{P}AP$. This function is
continuous over the compact set \bigO{n}; hence, $\func{f}(\bigO{n})$ is also
compact. The set $\func{f}(\bigO{n})$ contains all the possible products of
fixed matrix $A$ with orthogonal matrices, that may or may not give a diagonal
 as result. Then, we basically use brute force: search for the best
candidate in that set of options. And we do that, by using the metric
we define specifically for that purpose: the function
$\func{Od}$. Thus, we want to search for the product of the form
$\trans{P}AP$ (an element of $\func{f}(\bigO{n})$ which give us the
minimum value of function $\func{Od}$. Here is where the compactness
property comes into play; if the domain $\func{f}(\bigO{n})$ was not compact, we could
not even talk about the minimum of the (continuous) function
$\func{Od}$. \\

Knowing that, the existence of the minimum of function \func{Od} in the
set $\func{f}(\bigO{n})$ is granted, the next thing to realize is that
such minimum must be zero. This is easily seen by using reduction to
the absurd: let us suppose that the minimum reached at matrix
$D = \trans{Q}AQ$, is not zero. That would mean the matrix $D$ is not
diagonal yet and then, by \cref{thm:jacobi} we know that there
must exist another matrix $D^{*} = \trans{Q}DQ$, such that
$\func{Od}(D^{*}) < \func{Od}(D)$. But that contradicts the assumption
that the minimum was reached at $D$. Therefore, the minimum of
\func{Od} must be zero. \\

If the minimum of \func{Od} is zero, it means that is reached on a
matrix which is diagonal (the square of all its
off-diagonal\footnote{The off-diagonal elements of a matrix, are those
which do not lie on the diagonal.} elements is zero, which means they
are all zero).  The existence of such diagonal matrix of the form
$\trans{Q}AQ$ proves the theorem. \\
\end{proof}
\hfill

There are a couple of useful corollaries that derive from the Spectral
Theorem just proved: \\

\begin{itemize}
\item In the search of the minimum, there was an implicit iterative
  process of applying multiplications, where the matrix at step $i+1$,
  was obtained from the previous matrix at step $i$, in the following
  way: $D_{i+1} = \trans{J}D_iJ$ (the matrices $J$ are obtained by the
  Jacobi's method of rotations \footnote{This algorithmic perspective,
  is actually the main inspiration of this proof, which is taken from
  \cite{wilf81}}). If we think in the series of
  transformations done by this iteration, from the original matrix
  $A$, we would realize that all we did was to apply rigid
  transformations; therefore, the resulting entries in the diagonal
  must be real (there is no way that applying a rotation to real
  matrix, produces another matrix with complex entries). \\

\item The second observation is that the result $D = \trans{Q}AQ$,
  where $D$ is a diagonal matrix; implies that $AQ = QD$, which in
  turn can be broken into individual equations of the form $A\vec{q_i}
  = d_i\vec{q_i}$. This tells us that the columns of the orthogonal
  matrix $Q$ are the eigenvectors of $A$, and that the diagonal of $D$
  contains its eigenvalues. We started the other way around, but in
  practice, the usual motivation for diagonalizing a symmetric matrix
  (or for applying the Jacobi's method), is to actually find the
  eigenvalues and eigenvectors.
\end{itemize}
\hfill

These two corollaries will be useful in the final proof to come, that
of the SVD \cref{thm:SVD}.


\section{Planar Approximation}
It is time to deal with the pole situation. The north and south poles that is, not the lovely people over in Poland. We run into problems because the latitude longitude grid cells become to small
near the poles. Therefore, the magnitudes no longer fit into one cell and overflow into other cells which makes everything kind of funky. So we need to fix that, and we do that by a planar
approximation.

\subsection{The Initial Theory}
As said earlier, the grid cells on the latitude longitude grid get closer together the closer you get to the poles which poses problems. To fix this, we will be using a planar approximation of
the poles. What this means is that we will map the 3D grid near the poles onto a 2D plane parallel to the poles, as if we put a giant flat plane in the exact center of the poles and draw lines
from the grid directly upwards to the plane. For a visual representation, please consult the stream with timestamp 1:38:25 \cite{polarPlane}, which includes some explanation. In the streamm we
use $r$ to indicate the radius of the planet (which we assume is a sphere), $\theta$ for the longitude and $\lambda$ for the latitude. So we have spherical coordinates, which we need to transform
into $x$ and $y$ coordinates on the plane. We also need the distance between the center point (the point where the plane touches the planet which is the center of the pole) and the projected
point on the plane from the grid (the location on the plane where a line from the gird upwards to the plane hits it). This distance is denoted by $a$ (Simon chose this one, not me). We then get
the following equations as shown in \autoref{eq:polar distance}, \autoref{eq:polar x} and \autoref{eq:polar y}.

\begin{subequations}
    \begin{equation}
        \label{eq:polar distance}
        a = r \cos(\theta)
    \end{equation}
    \begin{equation}
        \label{eq:polar x}
        x = a \sin(\lambda)
    \end{equation}
    \begin{equation}
        \label{eq:polar y}
        y = a \cos(\lambda)
    \end{equation}
\end{subequations}

But what if we know $x$ and $y$ and want to know $\theta$ and $\lambda$? Pythagoras' Theorem then comes into play \cite{pythagoras}. We know that (due to Pythagoras) \autoref{eq:pythagoras} must
always be true. Then if we substitue $a$ by $\sqrt{x^2 + y^2}$ in \autoref{eq:polar distance} we get \autoref{eq:polar theta1}. Then we transform that equation such that we only have $\theta$ on
one side and the rest on the other side (since we want to know $\theta$) and we get \autoref{eq:polar theta3}.
\begin{equation}
    \label{eq:pythagoras}
    x^2 + y^2 = a^2
\end{equation}

\begin{subequations}
    \begin{equation}
        \label{eq:polar theta1}
        \sqrt{x^2 + y^2} = r\cos(\theta)
    \end{equation}
    \begin{equation}
        \label{eq:polar theta2}
        \frac{\sqrt{x^2 + y^2}}{r} = \cos(\theta)
    \end{equation}
    \begin{equation}
        \label{eq:polar theta3}
        \arccos(\frac{\sqrt{x^2 + y^2}}{r}) = \theta
    \end{equation}
\end{subequations}

For $\lambda$ we need another trigonometric function which is the tangent ($\tan$). The tangent is defined in \autoref{eq:tan}. If we then take a look at \autoref{eq:polar x} and
\autoref{eq:polar y}, we see that $\lambda$ is present in both equations. So we need to use both to get $\lambda$ \footnote{Yes you could only use one but since we both know $x$ and $y$ it is a
bit easier to use both than to only use one as you need to know $\theta$ at that point as well which may or may not be the case.}. So let's combine \autoref{eq:polar x} and \autoref{eq:polar y}
in \autoref{eq:polar lambda1}, transform it such that we end up with only $\lambda$ on one side and the rest on the other side and we end up with \autoref{eq:polar lambda3}.

\begin{equation}
    \label{eq:tan}
    \tan(\alpha) = \frac{\sin(\alpha)}{\cos(\alpha)}
\end{equation}

\begin{subequations}
    \begin{equation}
        \label{eq:polar lambda1}
        \frac{x}{y} = \frac{a\sin(\lambda)}{a\cos(\lambda)} = \frac{\sin(\lambda)}{\cos(\lambda)}
    \end{equation}
    \begin{equation}
        \label{eq:polar lambda2}
        \frac{x}{y} = \tan(\lambda)
    \end{equation}
    \begin{equation}
        \label{eq:polar lambda3}
        \lambda = \arctan(\frac{x}{y})
    \end{equation}
\end{subequations}

\subsection{The Grid Code}
To start the planar approximation, we first need to create a grid. One for the north pole, and one for the south pole. Now since the project is made in Python, Simon uses a function to generate
a grid from two coordinate vectors (lists with a coordinate as elements). Since the documentation tries to not be language specific, I instead opt to use words instead of function calls. What
that comes down to is use your favourite language and import the libraries that do this for you, or start coding your own after finding out how to do that (your mileage may vary). To implement
the grid function in the exact same way as the numpy packages does, please refer to the following two references \cite{meshgridDoc} \cite{meshgridGFG}. Anyway, the code for the grid can be found
in \autoref{alg:polar grid south}. To convert $x, y$ coordinates into $lat, lon$ coordinates, we make use of \autoref{eq:polar theta3} and \autoref{eq:polar lambda3}. Keep in mind that the
equations themselves assume that the angles are in radians, whereas the model uses the angles in degrees so they need to be converted. To convert from $lat, lon$ back into $x, y$ we need to
combine \autoref{eq:polar distance}, \autoref{eq:polar x} and \autoref{eq:polar y}. $gridPad$ refers to how many cells for padding we add to the grid. We add padding so that the calculations
later on all go smoothly and don't require complex and specific code to deal with them. The more general an algorithm is, the better, as you can reuse it for other things while not adjusting
the algorithm for that particular problem. That way, it is easier and better to adjust the input then to alter the algorithm.

\begin{algorithm}[htb]
    \caption{Generating the grid for polar approximation of the south pole}
    \label{alg:polar grid south}
    \SetKwComment{Comment}{//}{}
    $poleLowIndexS \leftarrow $ find first index where $lat > poleLowerLatLimit$ \;
    $poleHighIndexS \leftarrow $ find first index where $lat > poleHigherLatLimit$ \;
    $polarGridResolution \leftarrow dx[poleLowIndexS] $ \Comment*[l]{Will be reused for the north pole}
    $gridSize \leftarrow r \cos(lat[poleLowIndexS + gridPad] \frac{\pi}{180})$ \Comment*[l]{Will be reused for the north pole}
    \BlankLine

    $gridXAxisS \leftarrow $ array going from $-gridSize$ to $gridSize$ with steps of $polarGridResolution$ \;
    $gridYAxisS \leftarrow $ array going from $-gridSize$ to $gridSize$ with steps of $polarGridResolution$ \;
    $gridXValuesS, gridYValuesS \leftarrow $ generate the grid from the two axis vectors $gridXAxissS$ and $gridYAxissS$ \;
    $gridSideLength \leftarrow gridXValuesS.length $ \Comment*[l]{Is globally available\dots}
    \BlankLine

    $gridLatCoordsS \leftarrow $ empty list \;
    $gridLonCoordsS \leftarrow $ empty list \;
    \For{$i \leftarrow 0$ \KwTo $gridXValuesS.length$}{
        \For{$j \leftarrow 0$ \KwTo $gridXValuesS[i].length$}{
            $x \leftarrow gridXValuesS[i, j]$ \;
            $y \leftarrow gridYValuesS[i, j]$ \;
            $latPoint \leftarrow -\arccos(\frac{\sqrt{x^2 + y^2}}{r})\frac{180}{\pi}$ \;
            $lonPoint \leftarrow 180 - \arctan(\frac{x}{y})\frac{180}{\pi}$ \;
            $gridLatCoordsS.append(latPoint)$ \;
            $gridLonCoordsS.append(lonPoint)$ \;
        }
    }

    \BlankLine
    $polarXCoordsS \leftarrow$ empty list \;
    $polarYCoordsS \leftarrow$ empty list \;
    \For{$i \leftarrow 0$ \KwTo $poleLowIndexS$}{
        \For{$j \leftarrow 0$ \KwTo $nlon$}{
            $polarXCoordsS.append(r \cos(lat[i] \frac{\pi}{180}) \sin(lon[j]\frac{\pi}{180}))$ \;
            $polarYCoordsS.append(-r \cos(lat[i] \frac{\pi}{180}) \cos(lon[j]\frac{\pi}{180}))$ \;
        }
    }
\end{algorithm}

To make the process of generating the grid faster, we can vectorise the first for loop as shown in \autoref{alg:polar grid south vectorised}. Here instead of going over each value one by one
(and because Python is an interpreter based language, the interpreter cannot optimise it out as it does not know what is coming next) we treat everything as a vector or a scalar. By treating the
arrays as a vector, Python can efficiently (and most likely in parallel) perform the same calculations as it would do by using the classic for loop. We include the \texttt{flatten()} method as
it forces everything to be a one dimensional array (vector).

\begin{algorithm}[htb]
    \caption{Snippet for generating the grid for polar approximation of the south pole}
    \label{alg:polar grid south vectorised}
    $gridLatCoordsS \leftarrow (-\arccos(\frac{\sqrt{gridXValuesS^2 + gridYValuesS^2}}{r})\frac{180}{\pi}).$\texttt{flatten()} \;
    $gridLonCoordsS \leftarrow (180 - \arctan(\frac{gridXValuesS}{gridYValuesS})\frac{180}{\pi}).$\texttt{flatten()} \;
\end{algorithm}

We need to do a similar thing for the north pole and insert a few changes to some of the equations to correct for different angles and similar things. The code can be found in
\autoref{alg:polar grid north}. Again, see the references at the south pole explanation on how to generate the grid itself.

\begin{algorithm}[htb]
    \caption{Generating the grid for polar approximation of the north pole}
    \label{alg:polar grid north}
    \SetKwComment{Comment}{//}{}
    $poleLowIndexN \leftarrow $ find last index where $lat < -poleLowerLatLimit$ \;
    $poleHighIndexN \leftarrow $ find last index where $lat < -poleHigherLatLimit$ \;
    \BlankLine

    $gridXAxisN \leftarrow $ array going from $-gridSize$ to $gridSize$ with steps of $polarGridResolution$ \;
    $gridYAxisN \leftarrow $ array going from $-gridSize$ to $gridSize$ with steps of $polarGridResolution$ \;
    $gridXValuesN, gridYValuesN \leftarrow $ generate the grid from the two axis vectors $gridXAxisN$ and $gridYAxisN$ \;
    \BlankLine

    $gridLatCoordsN \leftarrow $ empty list \;
    $gridLonCoordsN \leftarrow $ empty list \;
    \For{$i \leftarrow 0$ \KwTo $gridXValuesN.length$}{
        \For{$j \leftarrow 0$ \KwTo $gridXValuesN[i].length$}{
            $x \leftarrow gridXValuesN[i, j]$ \;
            $y \leftarrow gridYValuesN[i, j]$ \;
            $latPoint \leftarrow \arccos(\frac{\sqrt{x^2 + y^2}}{r})\frac{180}{\pi}$ \;
            $lonPoint \leftarrow 180 - \arctan(\frac{x}{y})\frac{180}{\pi}$ \;
            $gridLatCoordsN.append(latPoint)$ \;
            $gridLonCoordsN.append(lonPoint)$ \;
        }
    }

    \BlankLine
    $polarXCoordsN \leftarrow$ empty list \;
    $polarYCoordsN \leftarrow$ empty list \;
    \For{$i \leftarrow 0$ \KwTo $poleLowIndexN$}{
        \For{$j \leftarrow 0$ \KwTo $nlon$}{
            $polarXCoordsN.append(r \cos(lat[i] \frac{\pi}{180}) \sin(lon[j]\frac{\pi}{180}))$ \;
            $polarYCoordsN.append(-r \cos(lat[i] \frac{\pi}{180}) \cos(lon[j]\frac{\pi}{180}))$ \;
        }
    }
\end{algorithm}

As was the case with the south pole, we can optimise the first for loop by vectorising it. A similar snippet to \autoref{alg:polar grid south vectorised} is the result, though there are small
changes. These changes can be found in \autoref{alg:polar grid north vectorised}.

\begin{algorithm}[htb]
    \caption{Snippet for generating the grid for polar approximation of the north pole}
    \label{alg:polar grid north vectorised}
    $gridLatCoordsS \leftarrow (\arccos(\frac{\sqrt{gridXValuesN^2 + gridYValuesN^2}}{r})\frac{180}{\pi}).$\texttt{flatten()} \;
    $gridLonCoordsS \leftarrow (180 - \arctan(\frac{gridXValuesN}{gridYValuesN})\frac{180}{\pi}).$\texttt{flatten()} \;
\end{algorithm}

In both algorithms it is important to make a distinction between $gridLatCoords$ and $polarXCoords$ and their respective variants. $gridLatCoords$ are the latitudinal coordinates on the
$lat, lon$ grid corresponding to the $x$ and $y$ coordinates on the polar grid. Whereas $polarXCoords$ are the $x$ coordinates on the polar grid corresponding to the latitude and longitude on
the $lat, lon$ grid. Those are different to the $gridXValues$ as they represent the values on the $x$ axis as integers which may or may not directly correspond to the $polarXCoords$. So we need
a way of mapping the $polarXCoords$ to $gridXValues$ and their respective values and vice versa. This is done in \autoref{sec:polar switch}.

\subsection{Switching between grids} \label{sec:polar switch}
Now that we have defined the polar plane grid, we need code to convert the values from the $lat, lon$ grid to the polar plane grid and vice versa. Let's start with converting to the polar grid.
We need 2 versions of the algorithm for that. One that converts in 2 dimensions, and one that converts in 3 dimensions. The code for the 2 dimensional case is shown in \autoref{alg:beam up 2d}.
Here we use bivariate spline interpolation \cite{bivariatespline} which is a different form of linear interpolation than discussed in \autoref{sec:interpolation} though the same principle
applies.

\begin{algorithm}[htb]
    \caption{Converting from $lat, lon$ grid to polar plane grid in 2 dimensions}
    \label{alg:beam up 2d}
    \SetKwInOut{Input}{Input}
    \SetKwInOut{Output}{Output}
    \Input{Latitude coordinates $lat$, Longitude coordinates $lon$, Values of the $lat, lon$ grid $data$, Length of one axis of the polar grid? $gridSize$, Latitude coordinates on the polar grid
        $gridLatCoords$, Longitude coordinates on the polar grid $gridLonCoords$}
    \Output{Double array representing the values of the $lat, lon$ grid on the polar grid}
    \SetKwComment{Comment}{//}{}
    $f \leftarrow $ \texttt{BivariateSpline}($lat, lon, data$) \Comment*[l]{Do the interpolation}
    $polarPlane \leftarrow f(gridLatCoords, gridLonCoords).$\texttt{reshape}(($gridSize$, $gridSize$)) \Comment*[l]{Check the values of the interpolation at the specified coordinates and force
    them to align to the polar grid}
    \Return{$polarPlane$}
\end{algorithm}

The 3 dimensional algorithm is quite similar to the 2 dimensional algorithm, which can be found in \autoref{alg:beam up 3d}

\begin{algorithm}[htb]
    \caption{Converting from $lat, lon$ grid to polar plane grid in 3 dimensions}
    \label{alg:beam up 3d}
    \SetKwInOut{Input}{Input}
    \SetKwInOut{Output}{Output}
    \Input{Latitude coordinates $lat$, Longitude coordinates $lon$, Values of the $lat, lon$ grid $data$, Length of one axis of the polar grid? $gridSize$, Latitude coordinates on the polar grid
        $gridLatCoords$, Longitude coordinates on the polar grid $gridLonCoords$}
    \Output{Triple array representing the values of the $lat, lon, layer$ grid on the polar grid}
    \SetKwComment{Comment}{//}{}
    $polarPlane \leftarrow $ 3 Dimensional array where the $1^{\text{st}}$ and $2^{\text{nd}}$ dimensions have length $gridSize$ and the $3^{\text{rd}}$ dimension has length $data[0][0].length$ \;
    \For{$k \leftarrow 0$ \KwTo $data[0][0].length$}{
        $f \leftarrow $ \texttt{BivariateSpline}($lat, lon, data[:, :, k]$) \Comment*[l]{Do the interpolation on this layer}
        $polarPlane[:, :, k] \leftarrow f(gridLatCoords, gridLonCoords).$\texttt{reshape}(($gridSize$, $gridSize$)) \Comment*[l]{Check the values of the interpolation at the specified
        coordinates and force them to align to the polar grid}
    }
    \Return{$polarPlane$}
\end{algorithm}

Having dealt with converting to the polar grid, we now also need to deal with converting from the polar grid. In contrast to converting to the polar griod, this is only done in 3 dimensions so
we do not need a 2 dimensional algorithm. How we convert from the polar grid can be found in \autoref{alg:beam down}.

\begin{algorithm}[htb]
    \caption{Converting from the polar plane grid to the $lat, lon$ grid in 3 dimensions}
    \label{alg:beam down}
    \SetKwInOut{Input}{Input}
    \SetKwInOut{Output}{Output}
    \Input{Longitude coordinates $lon$, Values of the $lat, lon$ grid $data$, Polar $x$ value indices $gridXValues$, Polar $y$ value indices $gridYValues$, Polar $x$ coordinates $polarXCoords$,
        Polar $y$ coordinates $polarYCoords$}
    \Output{Triple array representing the values of the polar grid on the $lat, lon, layer$ grid}
    \SetKwComment{Comment}{//}{}
    $resample \leftarrow $3 Dimensional array where the $1^{\text{st}}$ dimension has length $\lfloor \frac{polarXCoords}{lon.length} \rfloor$, the $2^{\text{nd}}$ dimension has length
    $lon.length$ and the $3^{\text{rd}}$ dimension has length $data[0][0].length$ \;
    \For{$k \leftarrow 0$ \KwTo $data[0][0].length$}{
        $f \leftarrow $ \texttt{BivariateSpline})($gridXValues, gridYValues, data[:, :, k]$) \Comment*[l]{Do the interpolation on this layer}
        $resample[:, :, k] \leftarrow f(polarXCoords, polarYCoords).$\texttt{reshape}(($\lfloor \frac{polarXCoords}{lon.length} \rfloor, lon.length$)) \Comment*[l]{Check the values of the
        interpolation at the specified coordinates and force them to align to the polar grid}
    }
    \Return{$resample$}
\end{algorithm}

\subsection{Creating the Other Required Vectors and Matrices (Planes)}
So now that we have the grids, we need some more vectors and matrices. We need the coriolis plane (the coriolis force on the polar plane) and the velocity vectors. We need these in order for the
velocity calculations to go correctly. We also need these at this level and not locally as both velocity and advection need the velocity vectors and it is easier to adjust the coriolis plane for
different planets on the highest level than when it is embedded into the calculation algorithms. How we create the plane and the velocity vectors is shown in \autoref{alg:polar grid coriolis}.

\begin{algorithm}[htb]
    \caption{Generating the coriolis planes and the velocity vectors}
    \label{alg:polar grid coriolis}
    $data \leftarrow $ matrix with dimensions $nlat - poleLowIndexN + gridPad \times nlon$ \;
    \For{$i \leftarrow poleLowIndexN - gridPad$ \KwTo $nlat - 1$}{
        $data[i - poleLowIndexN, :] \leftarrow coriolis[i]$ \;
    }
    $coriolisPlaneN \leftarrow $ \texttt{BeamMeUp2D}$(lat[(poleLowIndexN - gridPad):], lon, data, gridSideLength, gridLatCoordsN, gridLonCoordsN)$ \;

    $data \leftarrow $ matrix with dimensions $poleLowIndexS + gridPad \times nlon$ \;
    \For{$i \leftarrow 0$ \KwTo $poleLowIndexS + gridPad - 1$}{
        $data[i, :] \leftarrow coriolis[i]$ \;
    }
    $coriolisPlaneS \leftarrow $ \texttt{BeamMeUp2D}$(lat[:(poleLowIndexS + gridPad)], lon, data, gridSideLength, gridLatCoordsS, gridLonCoordsS)$ \;
\end{algorithm}

\subsection{Gradually Changing Grids}
Now that we can convert between grids we also need a way to do so gradually. Otherwise we would move the hard border we had previously around the poles further down the $lat, lon$ grid. Instead
we have to do some interpolation between the two grids in order to ensure a smooth transition in the final output, so that there are no hard borders. This interpolation is done in
\autoref{alg:polar interpolation}, using the linear interpolation technique as discussed in \autoref{sec:interpolation}.

\begin{algorithm}[htb]
    \caption{Gradually transition from the $lat, lon$ grid to the polar grid}
    \label{alg:polar interpolation}
    \SetKwInOut{Input}{Input}
    \SetKwInOut{Output}{Output}
    \Input{Index when to start using the polar grid $poleLowIndex$, Index when to only use the polar grid $poleHighIndex$, Polar data $polarData$, $lat, lon$ data $sphericalData$}
    \Output{3 Dimensional array representing the values on the polar grid with the part that gradually transitions to the $lat, lon$ grid}
    \SetKwComment{Comment}{//}{}
    $output \leftarrow$ 3 Dimensional array with the exact same structure as $polarData$ \;
    $overlap \leftarrow $ $|poleLowIndex - poleHighIndex|$ \;

    \BlankLine
    \uIf(\Comment*[h]{Determine whether we are talking about the north or south pole}){$lat[poleLowIndex] < 0$}{
        \DontPrintSemicolon
        \Comment*[l]{South pole}
        \PrintSemicolon
        \For{$k \leftarrow 0$ \KwTo $output[0][0].length$}{
            \For{$i \leftarrow 0$ \KwTo $poleLowIndex$}{
                \uIf{$i < poleHighIndex$}{
                    $\lambda \leftarrow 0$ \;
                } \uElse{
                    $\lambda \leftarrow \frac{i - poleHighIndex}{overlap}$ \;
                }
                $output[i, :, k] \leftarrow (1 - \lambda) sphericalData[i, :, k] + \lambda polarData[i, :, k]$ \;
            }
        }
    } \uElse{
        \DontPrintSemicolon
        \Comment*[l]{North pole}
        \PrintSemicolon
        \For{$k \leftarrow 0$ \KwTo $output[0][0].length$}{
            \For{$i \leftarrow 0$ \KwTo $nlat - poleLowIndex$}{
                \uIf{$i + poleLowIndex + 1 > poleHighIndex$}{
                    $\lambda \leftarrow 0$ \;
                } \uElse{
                    $\lambda \leftarrow \frac{i}{overlap}$ \;
                }
                $output[i, :, k] \leftarrow (1 - \lambda) sphericalData[i, :, k] + \lambda polarData[i, :, k]$ \;
            }
        }
    }

    \BlankLine
    \Return{$output$}
\end{algorithm}

\subsection{Gradients on the Grid}
With our new found ability to convert to and from the polar grid, while also gradually transitioning, we now get to the part we are doing it all for. Calculations on the polar grid. In order for
that to work, we need some utility functions specifically for the polar grid first. We will need gradients in all 3 dimensions, those being the $x$ dimension, the $y$ dimension and the $p$
dimension (pressure). All of the gradients will be quite similar to \autoref{alg:gradient x}, \autoref{alg:gradient y} and \autoref{alg:gradient z} though some small tweaks are required as we
are not differentiating over a spehere but over a plane. These changes are reflected in \autoref{alg:polar gradient x}, \autoref{alg:polar gradient y} and \autoref{alg:polar gradient p}.

\begin{algorithm}[htb]
    \caption{Gradient in the $x$ dimension on the polar grid}
    \label{alg:polar gradient x}
    \SetKwInOut{Input}{Input}
    \SetKwInOut{Output}{Output}
    \Input{Triple array of data $data$, first index $i$, second index $j$ and third index $k$, resolution of the polar grid $polarGridResolution$}
    \Output{Gradient in the $x$ dimension for the value of the grid point at the specified coordinates}
    \uIf{$i = 0$}{
        $value \leftarrow \frac{data[i, j + 1, k] - data[i, j, k]}{polarGridResolution}$ \;
    } \uElseIf{$j = gridSideLength - 1$}{
        $value \leftarrow \frac{data[i, j, k] - data[i, j - 1, k]}{polarGridResolution}$ \;
    } \uElse{
        $vale \leftarrow \frac{data[i, j + 1, k] - data[i, j - 1, k]}{2 polarGridResolution}$ \;
    }
    \Return{$value$}
\end{algorithm}

\begin{algorithm}[htb]
    \caption{Gradient in the $y$ dimension on the polar grid}
    \label{alg:polar gradient y}
    \SetKwInOut{Input}{Input}
    \SetKwInOut{Output}{Output}
    \Input{Triple array of data $data$, first index $i$, second index $j$ and third index $k$, resolution of the polar grid $polarGridResolution$}
    \Output{Gradient in the $y$ dimension for the value of the grid point at the specified coordinates}
    \uIf{$i = 0$}{
        $value \leftarrow \frac{data[i + 1, j, k] - data[i, j, k]}{polarGridResolution}$ \;
    } \uElseIf{$i = gridSideLength - 1$}{
        $value \leftarrow \frac{data[i, j, k] - data[i - 1, j, k]}{polarGridResolution}$ \;
    } \uElse{
        $vale \leftarrow \frac{data[i + 1, j, k] - data[i - 1, j, k]}{2 polarGridResolution}$ \;
    }
    \Return{$value$}
\end{algorithm}

\begin{algorithm}[htb]
    \caption{Gradient in the $p$ dimension on the polar grid}
    \label{alg:polar gradient p}
    \SetKwInOut{Input}{Input}
    \SetKwInOut{Output}{Output}
    \Input{Triple array of data $data$, first index $i$, second index $j$ and third index $k$, pressure levels $pressureLevels$}
    \Output{Gradient in the $p$ dimension for the value of the grid point at the specified coordinates}
    \uIf{$i = 0$}{
        $value \leftarrow \frac{data[i, j, k + 1] - data[i, j, k]}{pressureLevels[k + 1] - pressureLevels[k]}$ \;
    } \uElseIf{$k = nlevels - 1$}{
        $value \leftarrow \frac{data[i, j, k] - data[i, j, k - 1]}{pressureLevels[k] - pressureLevels[k - 1]}$ \;
    } \uElse{
        $vale \leftarrow \frac{data[i, j, k + 1] - data[i, j, k - 1]}{pressureLevels[k + 1] - pressureLevels[k - 1]}$ \;
    }
    \Return{$value$}
\end{algorithm}

Now that we have seen the normal versions, let us vectorise them for optimal performance. The vectorised versions do exactly the same, however instead of returning a single value (and the method
needing to be called for each and every element) we return a matrix of gradients. By using a matrix, we can apply the gradient to multiple elements at once and efficiently. The vectorised
versions can be found in \autoref{alg:polar gradient x vectorised}, \autoref{alg:polar gradient y vectorised} and \autoref{alg:polar gradient p vectorised} respectively.

\begin{algorithm}[htb]
    \caption{Gradient in the $x$ dimension on the polar grid}
    \label{alg:polar gradient x vectorised}
    \SetKwInOut{Input}{Input}
    \SetKwInOut{Output}{Output}
    \Input{Triple array of data $data$, resolution of the polar grid $polarGridResolution$}
    \Output{Triple array containing the gradients for each cell on the polar grid}
    $shiftEast \leftarrow $ shift all $x$ coordinates in $data$ one cell to the east (positive $x$) \;
    $shiftWest \leftarrow $ shift all $x$ coordinates in $data$ one cell to the west (negative $x$) \;
    \Return{$\frac{shiftWest - shiftEast}{2 polarGridResolution}$}
\end{algorithm}

\begin{algorithm}[htb]
    \caption{Gradient in the $y$ dimension on the polar grid}
    \label{alg:polar gradient y vectorised}
    \SetKwInOut{Input}{Input}
    \SetKwInOut{Output}{Output}
    \Input{Triple array of data $data$, resolution of the polar grid $polarGridResolution$}
    \Output{Triple array containing the gradients for each cell on the polar grid}
    $shiftSouth \leftarrow $ shift all $y$ coordinates in $data$ one cell to the south (negative $y$) \;
    $shiftNorth \leftarrow $ shift all $y$ coordinates in $data$ one cell to the north (positive $y$) \;
    \Return{$\frac{shiftNorth - shiftSouth}{2 polarGridResolution}$}
\end{algorithm}

\begin{algorithm}[htb]
    \caption{Gradient in the $p$ dimension on the polar grid}
    \label{alg:polar gradient p vectorised}
    \SetKwInOut{Input}{Input}
    \SetKwInOut{Output}{Output}
    \Input{Triple array of data $data$, pressure levels $pressureLevels$}
    \Output{Triple array containing the gradients for each cell on the polar grid}
    $shiftUp\leftarrow $ shift all $p$ coordinates in $data$ one cell upwards (positive $p$) \;
    $shiftDown \leftarrow $ shift all $p$ coordinates in $data$ one cell downwards (negative $p$) \;
    $shiftPressureUp \leftarrow$ shift the pressure in $pressureLevels$ up by one cell \;
    $shiftPressureDown \leftarrow$ shift the pressure in $pressureLevels$ down by one cell \;
    \Return{$\frac{shiftDown - shiftUp}{shiftPressureDown - shiftPressureUp}$}
\end{algorithm}

\subsection{Calculating Velocities on the Polar Grid}
With all the utility functions out of the way, we now come to the physics of it. Let us start with the velocity calculations on the polar grid. These work very similarly to the ones on the lat,
lon grid, though not exactly. For the explanation of the equations, please refer to \autoref{sec:velocity}. The algorithm is given (in its non-vectorised form) in
\autoref{alg:polar velocity}. An important thing to note is that this algorithm does not calculate the new velocities, but rather what needs to be changed with regards to the velocities.
The \texttt{gridXGradient} refers to \autoref{alg:polar gradient x} and \texttt{gridYGradient} refers to \autoref{alg:polar gradient y}.

\begin{algorithm}[htb]
    \caption{Velocity calculations on the polar plane}
    \label{alg:polar velocity}
    \SetKwInOut{Input}{Input}
    \SetKwInOut{Output}{Output}
    \Input{Polar plane $polarPlane$, Length of one axis of the grid $polarGridLength$, Coriolis force on the plane (with the same size and resolution as the $polarPlane$) $coriolisPlane$,
            East-west velocity vector on the polar plane $\dot{x}$, North-south velocity vector on the polar plane $\dot{y}$, Resolution of the polar grid $polarGridResolution$}
    \Output{Additions to the east-west velocity vector on the polar plane $\dot{x}_{add}$, Additions to the north-south velocity vector on the polar plane $\dot{y}_{add}$}
    \For{$i \leftarrow 0$ \KwTo $polarGridLength$}{
        \For{$j \leftarrow 0$ \KwTo $polarGridLength$}{
            \For{$k \leftarrow 0$ \KwTo $polarPlane[0, 0].length$}{
                \uIf{$k \geq 17$}{
                    $\dot{x}_{add}[i, j, k] \leftarrow - \dot{x}[i, j, k] \texttt{gridXGradient}(\dot{x}, i, j, k) - \dot{y}[i, j, k] \texttt{gridYGradient}(\dot{x}, i, j, k) +$
                    $coriolisPlane[i, j] \dot{y}[i, j, k] - \texttt{gridXGradient}(polarPlane, i, j, k) - \dot{x}[i, j, k] \cdot 10^{-5}$ \;
                    $\dot{y}_{add}[i, j, k] \leftarrow - \dot{x}[i, j, k] \texttt{gridXGradient}(\dot{y}, i, j, k) - \dot{y}[i, j, k] \texttt{gridYGradient}(\dot{y}, i, j, k) -$
                    $coriolisPlane[i, j] \dot{x}[i, j, k] - \texttt{gridXGradient}(polarPlane, i, j, k) - \dot{y}[i, j, k] \cdot 10^{-5}$ \;
                } \uElse{
                    $\dot{x}_{add}[i, j, k] \leftarrow - \dot{x}[i, j, k] \texttt{gridXGradient}(\dot{x}, i, j, k) - \dot{y}[i, j, k] \texttt{gridYGradient}(\dot{x}, i, j, k) -$
                    $\dot{x}[i, j, k] \cdot 10^{-3}$ \;
                    $\dot{y}_{add}[i, j, k] \leftarrow - \dot{x}[i, j, k] \texttt{gridXGradient}(\dot{y}, i, j, k) - \dot{y}[i, j, k] \texttt{gridYGradient}(\dot{y}, i, j, k) -$
                    $\dot{y}[i, j, k] \cdot 10^{-3}$ \;
                }

            }
        }
    }

    \Return{$\dot{x}_{add}, \dot{y}_{add}$}
\end{algorithm}

One velocity calculation is still missing. That one being the vertical velocity, which is described in \autoref{alg:polar velocity vert}.

\begin{algorithm}[htb]
    \caption{Vertical velocity calculations for the polar plane}
    \label{alg:polar velocity vert}
    \SetKwInOut{Input}{Input}
    \SetKwInOut{Output}{Output}
    \Input{East-west velocity vector on the polar plane $\dot{x}$, North-south velocity vector on the polar plane $\dot{y}$, Pressure levels $pressureLevels$, Temperature on the polar plane
            $temp$, Resolution of the polar grid $polarGridResolution$}
    \Output{Vertical velocity on the polar plane}
    $output \leftarrow$ array like $\dot{x}$ \;
    \For{$i \leftarrow 0$ \KwTo $output.length$}{
		\For{$j \leftarrow 0$ \KwTo $output[i].length$}{
			\For{$k \leftarrow 0$ \KwTo $output[i, j].length$}{
                $output[i,j,k] = - \frac{(pressureLevels[k] - pressureLevels[k-1]) * pressureLevels[k] * g * (\texttt{gridXGradient}(\dot{x}, i, j, k) + \texttt{gridYGradient}(\dot{y}, i, j, k))}
                    {287 * temp[i, j, k]}$ \;
            }
        }
    }
    \Return{$output$}
\end{algorithm}

Now it is time to optimise (and thus vectorise)! The new versions of the algorithms can be found in \autoref{alg:polar velocity vectorised} and \autoref{alg:polar velocity vert vectorised}.
Here, \texttt{gridXGradient} refers to \autoref{alg:polar gradient x vectorised} and \texttt{gridYGradient} refers to \autoref{alg:polar gradient y vectorised}.

\begin{algorithm}[htb]
    \caption{Velocity calculations on the polar plane}
    \label{alg:polar velocity vectorised}
    \SetKwInOut{Input}{Input}
    \SetKwInOut{Output}{Output}
    \Input{Polar plane $polarPlane$, Length of one axis of the grid $polarGridLength$, Coriolis force on the plane (with the same size and resolution as the $polarPlane$) $coriolisPlane$,
            East-west velocity vector on the polar plane $\dot{x}$, North-south velocity vector on the polar plane $\dot{y}$, Resolution of the polar grid $polarGridResolution$}
    \Output{Additions to the east-west velocity vector on the polar plane $\dot{x}_{add}$, Additions to the north-south velocity vector on the polar plane $\dot{y}_{add}$}
    $\dot{x}_{add} \leftarrow - \dot{x} \texttt{gridXGradient}(\dot{x}, polarGridResolution) - \dot{y} \texttt{gridYGradient}(\dot{x}, polarGridResolution) + coriolisPlane[:, :, None] \dot{y} -$
        $\texttt{gridXGradient}(polarPlane, polarGridResolution) - \dot{x} \cdot 10^{-5}$ \;
    $\dot{y}_{add} \leftarrow - \dot{x} \texttt{gridXGradient}(\dot{y}, polarGridResolution) - \dot{y} \texttt{gridYGradient}(\dot{y}, polarGridResolution) - coriolisPlane[:, :, None] \dot{x} -$
        $\texttt{gridXGradient}(polarPlane, polarGridResolution) - \dot{y} \cdot 10^{-5}$ \;

    $\dot{x}_{add}[:,:,17:] \leftarrow - \dot{x}[:,:,17:] \texttt{gridXGradient}(\dot{x}, polarGridResolution) - \dot{y}[:,:,17:] \texttt{gridYGradient}(\dot{x}, polarGridResolution) - $
        $\dot{x}[:,:,17:] \cdot 10^{-3}$ \;
    $\dot{y}_{add}[:,:,17:] \leftarrow - \dot{x}[:,:,17:] \texttt{gridXGradient}(\dot{y}, polarGridResolution) - \dot{y}[:,:,17:] \texttt{gridYGradient}(\dot{y}, polarGridResolution) -$
        $\dot{y}[:,:,17:] \cdot 10^{-3}$ \;

    \Return{$\dot{x}_{add}, \dot{y}_{add}$}
\end{algorithm}

\begin{algorithm}[htb]
    \caption{Vertical velocity calculations for the polar plane}
    \label{alg:polar velocity vert vectorised}
    \SetKwInOut{Input}{Input}
    \SetKwInOut{Output}{Output}
    \Input{East-west velocity vector on the polar plane $\dot{x}$, North-south velocity vector on the polar plane $\dot{y}$, Pressure levels $pressureLevels$, Temperature on the polar plane
            $temp$, Resolution of the polar grid $polarGridResolution$}
    \Output{Vertical velocity on the polar plane}
    $shiftUp \leftarrow$ shift all cells in pressureLevels up by one cell (wrap around if needed) \;
    \Return{$-\frac{(pressureLevels - shiftUp) * pressureLevels * g * (\texttt{gridXGradient}(\dot{x}, polarGridResolution) + \texttt{gridYGradient}(\dot{y}, polarGridResolution))}{287 * temp}$}
\end{algorithm}

\subsection{Projecting the Velocities}
Now that we have methods that can calculate the velocities on the polar plane and on the normal grid, we now need to combine methods to convert from the polar plane to the normal grid and vice
versa. Due to the polar grid having different axes than the normal grid, we cannot simply project them down and be done with it. We actually need to correct for the differences in axes. After
projecting the polar plane velocity vectors down as is, we correct for the mismatch in axes by converting everything back to the lat, lon grid. As that grid uses spherical coordinates, we know
that each pointon that grid is uniquely identified by a combination of the $\sin$ and $\cos$ functions. This fact we use in realigning the velocity vectors. The whole process is shown in
\autoref{alg:project velocities north} and \autoref{alg:project velocities south}. \texttt{BeamMeDown} refers to \autoref{alg:beam down}. Again, the north and south methods are quite similar.
Apart from a few different variable names the only real difference is reversing the reprojected vector values along the 2nd dimension for the north polar plane. This has to do with the
difference in axis alignment between the two polar planes. Now you might be wondering what $[\texttt{None}, :, \texttt{None}]$ means when appended to $lon$. It turns the $lon$ 1-dimensional
array into a 3-dimensional array. It does this by creating small arrays that contain all a single element. So $lon[\texttt{None}, :, \texttt{None}]$ will become something like:
$[[[x], [y], \dots]]$ where $x$ and $y$ are elements of the original $lon$.

\begin{algorithm}[htb]
    \caption{Projecting velocities from the northern polar plane down to the normal grid}
    \label{alg:project velocities north}
    \SetKwInOut{Input}{Input}
    \SetKwInOut{Output}{Output}
    \Input{Longitude coordinates $lon$, East-west velocity vector on the polar plane $\dot{x}$, North-south velocity vector on the polar plane $\dot{y}$, Lower limit of northern polar plane
        $poleLowIndexN$, Polar $x$ value indices $gridXValues$, Polar $y$ value indices $gridYValues$, Polar $x$ coordinates $polarXCoords$, Polar $y$ coordinates $polarYCoords$}
    \Output{Reprojected east-west velocity vector on the lat, lon grid $u$, Reprojected north-south velocity vector on the lat, lon grid $v$}
    $repX \leftarrow $ \texttt{BeamMeDown}$(lon, \dot{x}, poleLowIndexN, gridXValues, gridYValues, polarXCoords, polarYCoords)$ \;
    $repY \leftarrow $ \texttt{BeamMeDown}$(lon, \dot{y}, poleLowIndexN, gridXValues, gridYValues, polarXCoords, polarYCoords)$ \;
    $u \leftarrow repX * \sin(lon[\texttt{None}, :, \texttt{None}] * \frac{\pi}{180}) + repY * \cos(lon[\texttt{None}, :, \texttt{None}] * \frac{\pi}{180})$ \;
    $v \leftarrow repX * \cos(lon[\texttt{None}, :, \texttt{None}] * \frac{\pi}{180}) - repY * \sin(lon[\texttt{None}, :, \texttt{None}] * \frac{\pi}{180})$ \;
    $u \leftarrow $ reverse all values of $u$ along the 2nd dimension \;
    $v \leftarrow $ reverse all values of $v$ along the 2nd dimension \;
    \Return{$u, v$}
\end{algorithm}

\begin{algorithm}[htb]
    \caption{Projecting velocities from the southern polar plane down to the normal grid}
    \label{alg:project velocities south}
    \SetKwInOut{Input}{Input}
    \SetKwInOut{Output}{Output}
    \Input{Longitude coordinates $lon$, East-west velocity vector on the polar plane $\dot{x}$, North-south velocity vector on the polar plane $\dot{y}$, Lower limit of southern polar plane
        $poleLowIndexS$, Polar $x$ value indices $gridXValues$, Polar $y$ value indices $gridYValues$, Polar $x$ coordinates $polarXCoords$, Polar $y$ coordinates $polarYCoords$}
    \Output{Reprojected east-west velocity vector on the lat, lon grid $u$, Reprojected north-south velocity vector on the lat, lon grid $v$}
    $repX \leftarrow $ \texttt{BeamMeDown}$(lon, \dot{x}, poleLowIndexS, gridXValues, gridYValues, polarXCoords, polarYCoords)$ \;
    $repY \leftarrow $ \texttt{BeamMeDown}$(lon, \dot{y}, poleLowIndexS, gridXValues, gridYValues, polarXCoords, polarYCoords)$ \;
    $u \leftarrow repX * \sin(lon[\texttt{None}, :, \texttt{None}] * \frac{\pi}{180}) + repY * \cos(lon[\texttt{None}, :, \texttt{None}] * \frac{\pi}{180})$ \;
    $v \leftarrow -repX * \cos(lon[\texttt{None}, :, \texttt{None}] * \frac{\pi}{180}) + repY * \sin(lon[\texttt{None}, :, \texttt{None}] * \frac{\pi}{180})$ \;
    \Return{$u, v$}
\end{algorithm}

The previous algorithms show how to convert from the polar plane to the lat, lon grid. However we also need the other direction. That process is shown in \autoref{alg:project velocities up}. We
use similar information to re-align the velocity vectors to the polar plane grid as we used to re-align the velocity vectors to the lat, lon grid. \texttt{BeamMeUp} corresponds to the
\autoref{alg:beam up 3d}.

\begin{algorithm}[htb]
    \caption{Projecting velocities from the normal grid to the polar plane}
    \label{alg:project velocities up}
    \SetKwInOut{Input}{Input}
    \SetKwInOut{Output}{Output}
    \Input{Latitude coordinates $lat$, Longitude coordinates $lon$, East-west velocity vector $u$, North-south velocity vector $v$, Size of the polar grid $gridSize$, Latitude coordinates
        corresponding to the polar plane grid $gridLatCoords$, Longitude coordinates correpsonding to the polar plane grid $gridLonCoords$}
    \Output{East-west velocity vector on the polar plane $\dot{x}$, North-south velocity vector on the polar planes $\dot{y}$}
    \SetKwComment{Comment}{//}{}
    $gridU \leftarrow $ \texttt{BeamMeUp}$(lat, lon, u, gridSize, gridLatCoords, gridLonCoords)$ \;
    $gridV \leftarrow $ \texttt{BeamMeUp}$(lat, lon, v, gridSize, gridLatCoords, gridLonCoords)$ \;

    $nlevels \leftarrow u[0, 0].length$ \Comment*[r]{Does not replace the global, is only of effect here in this method}

    $\dot{x} \leftarrow$ matrix with shape $gridSize \times gridSize \times nlevels$ \;
    $\dot{y} \leftarrow$ matrix with shape $gridSize \times gridSize \times nlevels$ \;

    $gridLonCoords \leftarrow gridLonCoords.\texttt{reshape}(gridSize, gridSize)$ \;

    \uIf(//Check to see with which pole we are dealing){$lat[0] < 0$}{
        \For{$k \leftarrow 0$ \KwTo $nlevels - 1$}{
            $\dot{x}[:, :, k] \leftarrow gridU[:, :, k] * \sin(gridLonCoords * \frac{\pi}{180}) - gridV[:, :, k] * \cos(gridLonCoords * \frac{\pi}{180})$ \;
            $\dot{y}[:, :, k] \leftarrow gridU[:, :, k] * \cos(gridLonCoords * \frac{\pi}{180}) + gridV[:, :, k] * \sin(gridLonCoords * \frac{\pi}{180})$ \;
        }
    } \uElse {
        \For{$k \leftarrow 0$ \KwTo $nlevels - 1$}{
            $\dot{x}[:, :, k] \leftarrow -gridU[:, :, k] * \sin(gridLonCoords * \frac{\pi}{180}) + gridV[:, :, k] * \cos(gridLonCoords * \frac{\pi}{180})$ \;
            $\dot{y}[:, :, k] \leftarrow -gridU[:, :, k] * \cos(gridLonCoords * \frac{\pi}{180}) - gridV[:, :, k] * \sin(gridLonCoords * \frac{\pi}{180})$ \;
        }
    }
    \Return{$\dot{x}, \dot{y}$}
\end{algorithm}

\subsection{Advection on the Polar Planes}
Like we have done with the velocities, we also need to make a calculation for the advection on the polar planes themselves. We do this in \autoref{alg:polar advection}. For more details about
advection itself, please refer to \autoref{sec:adv}. The interesting bit of magic happens with the $\dot{y}[i, j, :] + |\dot{y}[i, j, :]|$ term. If $\dot{y}[i, j, :]$ is negative, then this
whole term will be $0$ and hence will not be considered, whereas if it is positive it will be considered (that's also why we divide by $2 * polarGridResolution$, to correct for adding
$\dot{y}[i, j, :]$ twice). Doing it this way saves an if statement and allows everything to be calculated faster along the last dimension. We have also added specific assignments for $j = 0$ and
for $j = \dot{x}[i].length$ as these indicate the boundaries of the $\dot{x}$ vector and saves us 2 more if statements.

\begin{algorithm}[htb]
    \caption{Performing the advection calculations on the polar plane}
    \label{alg:polar advection}
    \SetKwInOut{Input}{Input}
    \SetKwInOut{Output}{Output}
    \Input{Data matrix $data$, East-west velocity vector on the polar plane $\dot{x}$, North-south velocity vector on the polar plane $\dot{y}$, Resolution of the polar grid $polarGridResolution$}
    \Output{3-dimensional matrix with the advection data on the polar plane $adv$}
    $adv \leftarrow $ matrix with the same size as $data$ \;
    \For{$i \leftarrow 1$ \KwTo $\dot{x}.length - 1$}{
        $j \leftarrow 0$ \;
        $adv[i, j, :] \leftarrow adv + \frac{(\dot{y}[i, j, :] + |\dot{y}[i, j, :]|) * (data[i, j, :] - data[i - 1, j, :])}{2 * polarGridResolution} +$
        $\frac{(\dot{y}[i, j, :] + |\dot{y}[i, j, :]|) * (data[i + 1, j, :] - data[i, j, :])}{2 * polarGridResolution}$ \;
        $adv[i, j, :] \leftarrow adv + \frac{(\dot{x}[i, j, :] + |\dot{x}[i, j, :]|) * (data[i, j + 1, :] - data[i, j, :])}{2 * polarGridResolution}$ \;

        \For{$j \leftarrow 1$ \KwTo $\dot{x}[i].length - 1$}{
            $adv[i, j, :] \leftarrow adv + \frac{(\dot{y}[i, j, :] + |\dot{y}[i, j, :]|) * (data[i, j, :] - data[i - 1, j, :])}{2 * polarGridResolution} +$
            $\frac{(\dot{y}[i, j, :] + |\dot{y}[i, j, :]|) * (data[i + 1, j, :] - data[i, j, :])}{2 * polarGridResolution}$ \;
            $adv[i, j, :] \leftarrow adv + \frac{(\dot{x}[i, j, :] + |\dot{x}[i, j, :]|) * (data[i, j, :] - data[i, j - 1, :])}{2 * polarGridResolution} + $
            $\frac{(\dot{x}[i, j, :] + |\dot{x}[i, j, :]|) * (data[i, j + 1, :] - data[i, j, :])}{2 * polarGridResolution}$ \;
        }

        $j \leftarrow \dot{x}[i].length - 1$ \;
        $adv[i, j, :] \leftarrow adv + \frac{(\dot{y}[i, j, :] + |\dot{y}[i, j, :]|) * (data[i, j, :] - data[i - 1, j, :])}{2 * polarGridResolution} +$
        $\frac{(\dot{y}[i, j, :] + |\dot{y}[i, j, :]|) * (data[i + 1, j, :] - data[i, j, :])}{2 * polarGridResolution}$ \;
        $adv[i, j, :] \leftarrow adv + \frac{(\dot{x}[i, j, :] + |\dot{x}[i, j, :]|) * (data[i, j, :] - data[i, j - 1, :])}{2 * polarGridResolution}$ \;
    }
    \Return{$adv$}
\end{algorithm}


\section{Canonical Quantization}

Classical $Q$ configuration space.
$q_i$, for $i=1,\ldots,N$
$p_i$, for $i=1,\ldots,N$
Poisson brackets
$\left\{ q_i, p_i \right\}=1$

Quantum $\mathcal{H}$ on $Q$.
$\hat{q}_i$ and $\hat{p}_i$.
Commutator
$\left[ \hat{q}_i, \hat{p}_i \right] = i\hbar \delta_{ij}$.

Hamiltonian is
\begin{align}
    \hat{H} = \mathcal{H}\left( \hat{q}_i, \hat{p}_i \right)
\end{align}

\begin{example}[1D particle]
    $\hat{x}\ket{x} = x\ket{x}$
    and
    \begin{align}
        \ket{\psi} = \int_{-\infty}^{\infty} dx\,
        \psi(x)\ket{x}
    \end{align}
    and hte momentum is
    \begin{align}
        \hat{p}\ket{x} := i\hbar \frac{d}{dx}\ket{x}
    \end{align}
    with
    \begin{align}
        \left[ \hat{x}, \hat{p} \right] = i\hbar
    \end{align}
\end{example}
\begin{proof}
    For a basis state,
    \begin{align}
        \left[ \hat{x}, \hat{p} \right]
        &=
        \hat{x} i\hbar \frac{d}{dx}\ket{x}
        - \hat{p}\hat{x}\ket{x}\\
        &=
        i\hbar
        \frac{(x + dx)\ket{x + dx} - x\ket{x}}{dx}
        - x i\hbar \frac{d}{dx}\ket{x}\\
        &=
        i\hbar\left(
            x \frac{d}{dx} + \frac{dx}{dx}\ket{x}
        \right)
        - i\hbar x \frac{d}{dx}\kket{x}\\
        &= i\hbar \ket{x}
    \end{align}
    Then more generally
    \begin{align}
        \left[ \hat{x}, \hat{p} \right] &=
        \int_{-\infty}^{\infty} dx \left[ \hat{x}, \hat{p} \right]
        \ket{x} \braket{x}{\psi}\\
        &= i\hbar\ket{\psi}
    \end{align}
\end{proof}

\begin{example}[Particle on a sphere]
    The Lagrangian is
    \begin{align}
        L &=
        \frac{m}{2} R^2\left(
            \theta^2 + \sin^2\theta \phi^2
        \right)
    \end{align}
    and the conjugate momenta are
    \begin{align}
        p_\theta &=
        \frac{dL}{d\theta}
        = mR^2\theta\\
        p_\phi &=
        \frac{dL}{d\phi}
        = mR^2 \sin^2\theta \phi
    \end{align}
    which gives the Hamiltonian
    \begin{align}
        H &=
        \frac{m}{2} R^2\left(
            \frac{p_\theta^2}{(mR^2)^2}
            + \frac{p_\phi^2}{(mR^2)^2\sin^2\theta}
        \right)
    \end{align}
    Classically the Poisson bracket is
    \begin{align}
        \left\{ \theta, p_\theta \right\} &=
        \left\{ \phi, p_\phi \right\}
        = 1
    \end{align}
    which upon quantisation leads becomes commutation relations
    \begin{align}
        \left[ \hat{\theta}, \hat{p}_\theta \right] =
        \left[ \hat{\phi}, \hat{p}_\phi \right] =
        i\hbar
    \end{align}
    We can then define the position operators acting on basis states with
    \begin{align}
        \hat{\theta}\ket{\theta,\phi} &=
        \theta\ket{\theta,\phi}\\
        \hat{\phi}\ket{\theta,\phi} &=
        \phi\ket{\theta,\phi}
    \end{align}
    and the momentum operators
    \begin{align}
        \hat{p}_\theta\ket{\theta,\phi}
        &=
        i\hbar \frac{\partial}{\partial\theta}\ket{\theta,\phi}\\
        \hat{p}_\phi\ket{\theta,\phi}
        &=
        i\hbar \frac{\partial}{\partial\phi}\ket{\theta,\phi}
    \end{align}
    A arbitrary state can be written as a superposition
    \begin{align}
        \ket{\psi} &=
        \underbrace{
            \int_{0}^{2\pi} d\theta\sin\theta
            \int_0^{\pi d\phi}
        }_{\displaystyle\int_{\textrm{sphere}} d\Omega}
        \psi(\theta,\phi) \ket{\theta,\phi}
    \end{align}
    However, the momentum operator does not act like how you think it does.
    \begin{align}
        \hat{p}_\theta \psi(x) &\ne
        -i\hbar \frac{\partial}{\partial\theta} \psi(\theta,\phi)
    \end{align}
    If you plug the above into the Hamiltonian,
    you don't get the Laplacian back, so it must be wrong.
    The correct expression is
    \begin{align}
        \hat{p}_\theta \psi(x) &=
        \frac{-i\hbar}{\sqrt{\sin\theta}}
        \frac{\partial}{\partial\theta}\sqrt{\sin\theta}
    \end{align}
    Then you find that
    \begin{align}
        \bra{\psi}\hat{p}\ket{\chi}
        &=
        \int_{0}^{2\pi} d\theta \sqrt{\sin\theta}
        \int_{0}^{\pi}d\phi\,
        \psi^*(\theta,\phi)\cdots
    \end{align}
    Then you find that
    the solutions are spherical harmonics $Y_{l,m}(\theta,\phi)$
    which you can use as basis.
\end{example}

\section{Operator Ording Ambiguities}
Canonical quantization is not a good algorithm for quantisation,
bcecause there is ambigiuity in the ordering of the Hamiltonian.
Suppose you have
\begin{align}
    H &= \frac{p^2}{2m}
\end{align}
and you quantize it into
\begin{align}
    \hat{H} &= \frac{\hat{p}^2}{2m}
\end{align}
However, another Hamiltonian you could have that is classically the same is
\begin{align}
    H &=
    \frac{1}{x^{100}}
    \frac{p x^{100} p}{2m}
\end{align}
which quantizes into
\begin{align}
    \hat{H} &= \frac{1}{2m}
    \frac{1}{\hat{x}^{100}}
    \hat{p} \hat{x}^{100} \hat{p}
\end{align}
which is wildly different!


\documentclass{article}

\usepackage{amsmath}
\usepackage{bm}
\usepackage{natbib}
\usepackage{hyperref}
\usepackage{cleveref}

% Turn off ChkTeX warning about \( \) instead of $ $
% chktex-file 46

\begin{document}

\author{Jonas Lippuner}
\title{Ethon hydrodynamics notes}

\maketitle

Ethon is a free and open source software framework to test and develop hydrodynamics methods
with block-based  adaptive mesh refinement on various parallel computing architectures. It
is available at \url{https://github.com/lanl/Ethon} and described in detail in \cite{lippuner:21}.
These notes are distributed together with the Ethon source code and they describe
the hydrodynamics physics currently implemented in Ethon.

Throughout these notes, we will use index notation for vectors and derivatives. The vector $\vec x$
will be denoted as $x^i$, where $i$ ranges from 1 to 3. Furthermore, we denote time and spacial
derivatives as follows.
\begin{align}
  \frac{\partial}{\partial t} = \partial_t
  \qquad \text{and} \qquad
  \frac{\partial}{\partial x_i} = \partial_i.
\end{align}
Note that we are in flat space-time, hence covariant and contravariant indices are the same.
Repeated indices are summed over. For example, the gradient of a scalar and divergence of a vector
field are written as
\begin{align}
  \label{eq:examples}
  \nabla f = \partial_i f
  \qquad \text{and} \qquad
  \nabla \cdot \vec u = \partial_i u^i.
\end{align}

\section{Conserved and primitive variables}

We define the following \textbf{primitive} variables:
\begin{itemize}
  \item Fluid density $\rho$
  \item Fluid velocity $u^i$
  \item Fluid internal specific energy $e$
  \item Fluid stress tensor $P^{ij}$
\end{itemize}
For now we only consider isotropic stresses and so we write $P^{ij} = p\delta^{ij}$, where $p$ is
the usual fluid pressure and $\delta^{ij}$ is the Kronecker delta.

The \textbf{conserved} variables are the ones that are actually evolved and they are:
\begin{itemize}
  \item Mass density $\rho$
  \item Momentum density $\mu^i = \rho u^i$
  \item Total energy density $\epsilon = \rho e + \frac{1}{2}\rho u_i u^i$
\end{itemize}
Note that the total energy density is the sum of the internal energy density and kinetic energy
density.

\section{Compressible Euler equations}

We write the conservation equations for the conserved variables as follows.
\begin{align}
  \label{eq:mass_cons}
  \partial_t \rho + \partial_j(\rho u^j)  & = 0 \\
  \label{eq:mom_cons}
  \partial_t \mu^i + \partial_j(\rho u^i u^j + P^{ij}) & = \rho g^i \\
  \label{eq:ener_cons}
  \partial_t \epsilon + \partial_j(\epsilon u^j + u_i P^{ij}) & = \rho u_i g^i,
\end{align}
where $g^i$ is the external acceleration due to gravity. Note that we can write the above also in
terms of the time derivatives of the primitive variables.
The mass conservation equation \labelcref{eq:mass_cons} remains the same. The momentum conservation
equation \labelcref{eq:mom_cons} becomes
\begin{align}
  \label{eq:dtu}
  & \partial_t(\rho u^i)
  + \partial_j(\rho u^i u^j + P^{ij})
  = \rho g^i
  \nonumber \\
  \Leftrightarrow\ \
  & u^i\left(\partial_t + \partial_j(\rho u^j)\right)
  + \rho \partial_t u^i
  + \rho u^j \partial_j u^i
  + \partial^j p \delta^{ij}
  = \rho g^i
  \nonumber \\
  \Leftrightarrow\ \
  & \partial_t u^i
  + u^j \partial_j u^i
  + \frac{\partial^i p}{\rho}
  = g^i,
\end{align}
where we used \cref{eq:mass_cons}, $\mu^i = \rho u^i$, and $P^{ij} = p\delta^{ij}$. Finally, for the
energy conservation equation \labelcref{eq:ener_cons} we find
\begin{align}
  & \partial_t\left(\rho e + \frac{1}{2}\rho u_i u^i\right)
  + \partial_j\left(\rho e u^j + \frac{1}{2}\rho u_i u^i u^j + u_i P^{ij}\right)
  = \rho u_i g^i
  \nonumber \\
  \Leftrightarrow\ \
  & e\partial_t\rho + \rho \partial_t e + \frac{1}{2}u_i u^i\partial_t \rho + \rho u_i\partial_t u^i
  \nonumber \\
  & {} + e\partial_j(\rho u^j) + \rho u^j \partial_j e + \frac{1}{2}u_i u^i \partial_j(\rho u^j)
    + \rho u^j u_i\partial_j u^i
  \nonumber \\
  & {} + u_i \partial^i p + p\partial^i u_i
  = \rho u_i g^i
  \nonumber \\
  \Leftrightarrow\ \
  & e\left(\partial_t \rho + \partial_j(\rho u^j)\right)
  \nonumber \\
  & {} + \frac{1}{2}u_i u^i\left(\partial_t \rho + \partial_j(\rho u^j)\right)
  \nonumber \\
  & {} + \rho u_i \left(\partial_t u^i + u^j\partial_j u^i + \frac{\partial^i p}{\rho} - g^i\right)
  \nonumber \\
  & {} + \rho \partial_t e + \rho u^j \partial_j e + p \partial^i u_i = 0
  \nonumber \\
  \Leftrightarrow\ \
  & \partial_t e + u^i\partial_i e + \frac{p}{\rho}\partial^i u_i = 0,
\end{align}
where we used \cref{eq:mass_cons,eq:dtu}, $\epsilon = \rho e + \frac{1}{2}\rho u_i u^i$, and
$P^{ij} = p\delta^{ij}$.

If shocks are present, non-conservative methods do not converge to the correct solution, so one must
use conservative methods in those cases (which do converge to the correct solution, if they converge
at all), see \citet[][\S 5.3]{toro}.

\newcommand{\vc}[1]{\mathrm{\bf #1}}

For notational simplicity, we shall write the conservative form of the compressible Euler equations
\labelcref{eq:mass_cons,eq:mom_cons,eq:ener_cons} as follows
\begin{align}
  \label{eq:euler_vec}
  \partial_t \vc{U} + \partial_j \vc{F}^j(\vc U) = \vc{S}(\vc U),
\end{align}
where the state vector $\vc U$, the flux tensor $\vc F^j(\vc U)$, and the source term
$\vc S(\vc U)$ are given by
\begin{align}
  \label{eq:system_vecs}
  \vc U =
    \begin{bmatrix}
      \rho  \\
      \mu^1 \\
      \mu^2 \\
      \mu^3 \\
      \epsilon
    \end{bmatrix}, \qquad
  \vc F^j(\vc U) =
    \begin{bmatrix}
      \rho u^j \\
      \rho u^1 u^j + P^{1j} \\
      \rho u^2 u^j + P^{2j} \\
      \rho u^3 u^j + P^{3j} \\
      \epsilon u^j + u_i P^{ij}
    \end{bmatrix}, \qquad
  \vc S(\vc U) =
    \begin{bmatrix}
      0 \\
      \rho g^1 \\
      \rho g^2 \\
      \rho g^3 \\
      \rho u_i g^i
    \end{bmatrix}.
\end{align}
Note that to evaluate $\vc F^j(\vc U)$ we need an additional Equation of State (EOS) that allows us
to recover the primitive variables from the conservative ones, which are contained in $\vc U$. Note
that all of the above quantities are functions of time and space.

\section{Finite-volume scheme}

To discretize the non-linear, partial-differential Euler equations \labelcref{eq:mass_cons,%
eq:mom_cons,eq:ener_cons} we introduce a Cartesian mesh. For simplicity, we initially consider a
uniform mesh with cells of size $\Delta x^i$, where the sizes in the three dimensions can vary, in
principle (in practice they are usually the same, though). Furthermore, we consider a cell-centered
method where we have grid points at the centers of the cells and the cell-averaged quantities are
stored at those grid points. Additionally, we initially restrict ourselves to the case without
source terms, i.e.\ $\vc S = \vc 0$ and so we have the system
\begin{align}
  \label{eq:sys}
  \partial_t \vc U + \partial_j \vc F^j(\vc U) = \vc 0.
\end{align}

\newcommand{\dv}{\,\mathrm{d}V}
\newcommand{\ds}{\,\mathrm{d}S}
\newcommand{\dt}{\,\mathrm{d}t}

Now consider a cell with index $\alpha$ and volume
\begin{align}
  V_\alpha = \Delta x^1 \Delta x^2 \Delta x^3.
\end{align}
We define the cell average of the state vector in cell $\alpha$ as
\begin{align}
  \label{eq:cell-average}
  \bar{\vc U}_\alpha(t) = \frac{1}{V_\alpha} \int_{V_\alpha} \vc U(x^i,t) \dv.
\end{align}
Since $\partial_t \vc U = -\partial_j\vc F^j(\vc U)$, we have
\begin{align}
  \vc U(x^i,t_2) = \vc U(x^i, t_1) - \int_{t_1}^{t_2} \partial_j \vc F^j(\vc U(x^i,t)) \dt,
\end{align}
and so
\begin{align}
  \label{eq:avg-update}
  \bar{\vc U}_\alpha(t_2) &= \frac{1}{V_\alpha}\int_{V_\alpha} \left( \vc U(x^i,t_1)
    - \int_{t_1}^{t^2} \partial_j \vc F^j(\vc U(x^i, t))\dt \right)\dv
  \nonumber \\
  &= \bar{\vc U}_\alpha(t_1) - \frac{1}{V_\alpha}\int_{t_1}^{t_2}\int_{\partial V_\alpha}
    n_j \vc F^j(\vc U(x^i, t))\ds\dt,
\end{align}
where we assumed that the flux $\vc F$ is well behaved so that we can change the order of
integration, and
we used the divergence theorem to replace the volume integral of the divergence of $\vc F$ with the
surface integral over the cell $\alpha$, where $n_j$ is the normal vector of the cell surface. Note
that \cref{eq:avg-update} is exact since we have made no approximations yet.

The surface integral in \cref{eq:avg-update} has six components, namely the integral of the flux
across the six faces of the cell. For cell $\alpha$ we define the following quantities
\begin{align}
  \label{eq:cell-def}
  x_\alpha^i &= \text{cell center location}, \nonumber \\
  x_{\alpha,L}^i &= \text{coordinates of the lower cell faces, and} \nonumber \\
  x_{\alpha,U}^i &= \text{coordinates of the upper cell faces.}
\end{align}
Note that
\begin{align}
  x_{\alpha,U}^i - x_{\alpha,L}^i = \Delta x^i \qquad \text{and} \qquad
  x_\alpha^i = \frac{x_{\alpha,L}^i + x_{\alpha,U}^i}{2}.
\end{align}
We can now write \cref{eq:avg-update} as
\begin{align}
  \label{eq:finite-volume}
  \bar{\vc U}_\alpha(t_2) = \bar{\vc U}_\alpha(t_1) + \frac{\Delta t}{\Delta x^i}
          \left(\bar{\vc F}^i_{\alpha,L} - \bar{\vc F}^i_{\alpha,U}\right),
\end{align}
where $\Delta t$ = $t_2 - t_1$, and $\bar{\vc F}^i_{\alpha,L}$ and
$\bar{\vc F}^i_{\alpha,U}$ are the average fluxes through the lower and upper faces in the
$i$-direction. Their exact form is
\begin{align}
  \label{eq:fluxes}
  \bar{\vc F}^i_{\alpha,L} = \frac{\Delta x^i}{\Delta t V_\alpha}\int_{t_1}^{t_2}
      \int_{V_\alpha} \vc F^i(\vc U(x^1, x^2, x^3, t)) \delta(x^i - x^i_L) \dv \dt
      \quad \text{(no sum over $i$)},
\end{align}
where the Dirac-Delta function reduces the integral over the cell volume to an integral over the
lower cell face in direction $i$ with coordinate $x^i_L$. The expression for
$\bar{\vc F}^i_{\alpha,U}$ is analogous, since we have already taken care of the sign of the
normal vector of the lower and upper faces in \cref{eq:finite-volume}.

Obviously, we cannot evaluate \cref{eq:fluxes} directly, because that would require knowledge of the
solution $\vc U$ at all times and all points in space. One of the core ingredients of a finite
volume method is thus to prescribe some numeric approximations for $\bar{\vc F}^i_{\alpha,L}$
and $\bar{\vc F}^i_{\alpha,U}$ that can be readily evaluated.

\subsection{Godunov scheme}

The Godunov scheme is one of the simplest finite volume schemes and it is first-order
accurate. We compute the fluxes by solving the Riemann Problem between the two cells, i.e.
\begin{align}
\bar{\vc{F}}^j_{\alpha,L} = \text{RP}(\bar{\vc U}_{\alpha-1}, \bar{\vc U}_\alpha), \\
\bar{\vc{F}}^j_{\alpha,U} = \text{RP}(\bar{\vc U}_\alpha, \bar{\vc U}_{\alpha+1}),
\end{align}
where $\bar{\vc U}_{\alpha-1}$ and $\bar{\vc U}_{\alpha+1}$ are the average states of the cells
adjacent to cell $\alpha$ in the lower and upper direction in dimension $j$, respectively,
and we use RP to denote the solution to the Riemann Problem. We can use use these fluxes in
\cref{eq:finite-volume} to update the state in cell $\alpha$.

\subsection{MUSCL-Hancock scheme}

The MUSCL-Hancock scheme is a popular finite volume scheme that is second-order accurate in time and
space. MUSCL stands for Monotone Upstream-centred Scheme for Conservation Laws. For example, FLASH
uses MUSCL-Hancock for its dimensionally unsplit hydro solver. See
\cite[\S13.4, \S14.4, \S16.5]{toro} for more details.

The central idea in the MUSCL-Hancock scheme is to replace the constant cell averages by a linearly
varying quantity within the cell. Considering only one dimension for a moment, we define the
conserved quantity $\vc U_\alpha(x)$ in the cell $\alpha$ as
\begin{align}
  \label{eq:ux}
  \vc U_\alpha(x) = \bar{\vc U}_\alpha + \frac{x - x_\alpha}{\Delta x} \vc\Delta_\alpha
  \qquad\text{for } x\in [x_{\alpha,L}, x_{\alpha,U}],
\end{align}
where $\vc\Delta_\alpha$ is a suitably chosen slope vector (of the five conserved quantities)
of the solution inside the cell (see \cref{sec:slope} for details on how to construct the slope
vector).
The above is at a fixed time.
We now evaluate the above at the lower and upper boundaries
to get the extrapolated boundary values of $\vc U$:
\begin{align}
  \label{eq:extrapolated-boundary-values-1d}
  \vc U^L_\alpha = \vc U_\alpha(x_{\alpha,L}) =
    \bar{\vc U}_\alpha - \frac{\vc\Delta_\alpha}{2}
  \quad \text{and} \quad
  \vc U^U_\alpha = \vc U_\alpha(x_{\alpha,U}) =
    \bar{\vc U}_\alpha + \frac{\vc\Delta_\alpha}{2}.
\end{align}
We now evolve the boundary extrapolated conserved quantities for a half timestep $\Delta t/2$
according to \cref{eq:finite-volume} by evaluating $\vc F$ for the boundary extrapolated values
$\vc U^L_\alpha$ and $\vc U^U_\alpha$ and using these as the approximate fluxes. Hence
we get
\begin{align}
  \label{eq:half-time-step-1d}
  \hat{\vc U}^L_\alpha &= \vc U^L_\alpha + \frac{\Delta t}{2\Delta x}
      \left[\vc F(\vc U^L_\alpha) - \vc F(\vc U^U_\alpha)\right], \nonumber \\
  \hat{\vc U}^U_\alpha &= \vc U^U_\alpha + \frac{\Delta t}{2\Delta x}
      \left[\vc F(\vc U^L_\alpha) - \vc F(\vc U^U_\alpha)\right],
\end{align}
where all the right-hand side terms are evaluated at the current time $t_1$. Finally, to obtain the
actual approximate fluxes at the cell boundaries, we solve the one-dimensional local Riemann problem
at the cell boundaries using the evolved boundary extrapolated quantities. A thorough discussion of
the Riemann Problem is beyond the scope of these notes. Simply put, the solution to Riemann Problem
roughly provides the flux across a discontinuity namely a cell face. For more details, see \cite{toro}.
The Riemann Problem
requires left and right initial states $\vc U_L$ and $\vc U_R$ and produces a similarity solution
$\vc U(x/t)$, which we will denote by
\begin{align}
  \label{eq:RP-notation}
  \vc U(x/t) \equiv \text{RP}(\vc U_L, \vc U_R).
\end{align}
At the lower cell boundary of cell $\alpha$, the left initial state for the Riemann problem is
$\hat{\vc U}_{\alpha-1}^U$ and the right initial state is $\hat{\vc U}_\alpha^L$, where $\alpha -1$
denotes the cell to the left of cell $\alpha$ in the $x$-direction. The initial states for the
Riemann Problem at the upper cell boundary of cell $\alpha$ are analogous. Hence we have
\begin{align}
  \label{eq:RPs-1d}
  \vc U_\alpha^L(x/t) &= \text{RP}(\hat{\vc U}_{\alpha-1}^U, \hat{\vc U}_\alpha^L), \nonumber \\
  \vc U_\alpha^U(x/t) &= \text{RP}(\hat{\vc U}_\alpha^U, \hat{\vc U}_{\alpha+1}^L),
\end{align}
where $\alpha+1$ is the cell to the right of cell $\alpha$ in the $x$-direction. We now use the
Riemann similarity solutions evaluated at $x/t = 0$ to get the final approximate fluxes for
\cref{eq:finite-volume}, thus we have
\begin{align}
  \label{eq:fluxes-1d}
  \bar{\vc F}_{\alpha,L} = \vc F(\vc U_\alpha^L(0)) \qquad \text{and} \qquad
  \bar{\vc F}_{\alpha,U} = \vc F(\vc U_\alpha^U(0)).
\end{align}
Note that in principle, we could solve the Generalized Riemann Problem where the left and right
states are not constant. We could use a linear form similar to \cref{eq:ux} to describe the left and
right states for the Riemann Problems at the boundaries. However, the Generalized Riemann Problem is
exceedingly difficult and not typically employed \cite[\S13.4.1]{toro}.

Generalizing the above to three dimensions is straight forward. We still solve one-dimensional,
piece-wise constant Riemann Problems at the cell boundaries (now there are six instead of two), but
for the time evolution in \cref{eq:half-time-step-1d} we incorporate the fluxes from all six faces.
We now have a different slope vector (see \cref{sec:slope}) in each dimension and we'll denote the
component in dimension $i$ by $\vc \Delta_\alpha^i$. We have six boundary extrapolated values,
namely
\begin{align}
  \label{eq:boundary-values-3d}
  \vc U_\alpha^{L,i} = \bar{\vc U}_\alpha - \frac{\vc \Delta_\alpha^i}{2}
  \qquad \text{and} \qquad
  \vc U_\alpha^{U,i} = \bar{\vc U}_\alpha + \frac{\vc \Delta_\alpha^i}{2},
\end{align}
which are evolved forward in time by $\Delta t/2$ to yield
\begin{align}
  \label{eq:evolved-boundary-values-3d}
  \hat{\vc U}_\alpha^{[L|U],i} = \vc U_\alpha^{[L|U],i} + \frac{\Delta t}{2\Delta x^j}
      \left[\vc F^j(\vc U_\alpha^{L,j}) - \vc F^j(\vc U_\alpha^{U,j})\right].
\end{align}
Now we solve the Riemann Problem at all six faces using one evolved boundary extrapolated value from
this cell and one from the adjacent cell, just like in \cref{eq:RPs-1d}. This yields a similarity
solution at each face, which we plug into the flux function $\vc F$ to get the approximate flux
$\bar{\vc F}^i_{\alpha,[L|U]}$
through that face. The cell averaged conserved quantity $\bar{\vc U}_\alpha$ is then updated
according to \cref{eq:finite-volume}.

\subsection{Slope construction and limiter methods}\label{sec:slope}

\newcommand{\du}{\vc\Delta_\alpha^\text{up}}
\newcommand{\dd}{\vc\Delta_\alpha^\text{down}}
\newcommand{\dc}{\vc\Delta_\alpha^\text{cent}}
\newcommand{\db}{\bar{\vc\Delta}_\alpha}

We will restrict ourselves again to one dimension in this section, since it drastically simplifies
notation. The components of the slope vector in the different dimensions are all determined
independently from each other, so generalizing this discussion to multiple dimension is trivial.
We use $\alpha+1$ to denote the neighboring cell in the positive direction and $\alpha-1$ the
neighbor in the negative direction. We follow \cite[\S6]{leveque}. A general form of the slope is
\begin{align}
  \label{eq:slope_vector}
  \vc \Delta_\alpha =
      \frac{1}{2}(1+\omega) \left(\bar{\vc U}_{\alpha} - \bar{\vc U}_{\alpha-1}\right)
    + \frac{1}{2}(1-\omega) \left(\bar{\vc U}_{\alpha+1} - \bar{\vc U}_{\alpha}\right),
\end{align}
where $\omega$ is a free parameter in the interval $[-1,1]$. Three common choices for $\omega$ are
\begin{align}
  \label{eq:example_slopes}
  \text{Upwind ($\omega = 1$):} \quad
    & \du = \bar{\vc U}_{\alpha} - \bar{\vc U}_{\alpha-1} &
    & \text{(Beam--Warming).}  \\
  \text{Centered ($\omega = 0$):} \quad
    & \dc = \frac{\bar{\vc U}_{\alpha+1} - \bar{\vc U}_{\alpha-1}}{2} &
    & \text{(Fromm),}  \\
  \text{Downwind ($\omega = -1$):} \quad
    & \dd = \bar{\vc U}_{\alpha+1} - \bar{\vc U}_{\alpha} &
    & \text{(Lax--Wendroff),}
\end{align}

Using any of these slopes leads to a second-order method. Unfortunately, with the increased accuracy
also come spurious oscillations near discontinuities. To avoid these discontinuities, the slope
computed above needs to be limited in a way that ensures that the total variation of the solution
does not increase. The resulting scheme is said to be total variation diminishing (TVD). Let
$\db$ denote the limited slope and define the minmod and maxmod functions as
\begin{align}
  \label{eq:minmod-maxmod}
  \text{minmod}(a,b) = \left\{
    \begin{array}{ll}
      0 & \text{if } ab \leq 0, \\
      a & \text{if } |a| \leq |b| \text{ and } ab > 0, \\
      b & \text{if } |b| \leq |a| \text{ and } ab > 0.
    \end{array}\right. \\[6pt]
    \text{maxmod}(a,b) = \left\{
    \begin{array}{ll}
      0 & \text{if } ab \leq 0, \\
      a & \text{if } |a| \geq |b| \text{ and } ab > 0, \\
      b & \text{if } |b| \geq |a| \text{ and } ab > 0.
    \end{array}\right.
\end{align}

Some popular limiters are the following.
\begin{align}
  \label{eq:slope-limiters}
  \text{minbee:}   \quad & \db = \text{minmod}\left(\du, \dd\right) \\[6pt]
  \text{superbee:} \quad & \db = \text{maxmod}\big[\text{minmod}\left(\du, 2\dd\right), \nonumber \\
      & \hphantom{\db = \text{maxmod}\big[} \text{minmod}\left(2\du,\dd\right)\big] \\[6pt]
  \text{MC:} \quad       & \db = \left\{ \begin{array}{ll}
    \phantom{-}0 & \text{if } \du\dd \leq 0, \\
    \phantom{-}\text{min}(2|\du|, 2|\dd|, |\dc|) & \text{if } \dc > 0, \\
    -\text{min}(2|\du|, 2|\dd|, |\dc|) & \text{if } \dc < 0.
  \end{array} \right. \\[6pt]
  \text{van Leer:} \quad & \db = \left\{ \begin{array}{ll}
    0 & \text{if } \du\dd \leq 0, \\
    \dfrac{2\du\dd}{\du+\dd} & \text{otherwise.}
  \end{array} \right.
\end{align}
Note that the minbee limiter is also called minmod limiter.

\section{$\gamma$-Law Equation of State}

Let $\gamma$ be the adiabatic index (ratio constant-pressure heat capacity to constant-volume heat
capacity). The pressure is given by
\begin{align}
  \label{eq:gamma-Law}
  P = (\gamma-1)\rho e,
\end{align}
where $\rho$ is the mass density and $e$ is the specific internal energy. We have $\gamma = 5/3$ for
monoatomic ideal gases and $\gamma = 7/5$ for diatomic ideal gases. From the ideal gas law we
also have
\begin{align}
  \label{eq:ideal-gas}
  PV = Nk_BT \Rightarrow P = \frac{N}{V}k_BT = nk_BT = \frac{\rho}{m}k_BT,
\end{align}
where $V$ is the volume, $N$ is the number of particles, $n = N/V$ is the number density, and $m$ is
the mass of a particle. Equating the above gives
\begin{align}
  \label{eq:gamma-law_e}
  e = \frac{1}{\gamma-1}\frac{k_BT}{m}.
\end{align}
For an isentropic (constant entropy, i.e.\ adiabatic and reversible) process, one can derive
\begin{align}
  \label{eq:isentropic}
  P = \alpha \rho^\gamma,
\end{align}
for some constant $\gamma$. The sound speed can now be computed as
\begin{align}
  \label{eq:sound-speed}
  c_s^2 = \left.\frac{dP}{d\rho}\right|_S = \gamma \alpha \rho^{\gamma-1} = \gamma\frac{P}{\rho} =
  \gamma(\gamma-1)e.
\end{align}

\section*{Acknowledgements}

The development of Ethon was funded by the Laboratory Directed
Research and Development program of Los Alamos National Laboratory under
project number 20190519ECR. The development used LANL Institutional Computing
Program resources. LANL is operated by Triad National Security, LLC, for the
National Nuclear Security Administration of the U.S.DOE (Contract No.\
89233218CNA000001).

\bibliographystyle{apj}
\bibliography{notes.bib}

\end{document}


\subsection{Matching}

Matching is similar to regression. We assume that effects are constant, and the effect of treatment on \(y_{0i}\) and \(y_{1i}\) are independent of treatment, once controlling for \(X\).

Again, this is biased if this is not the case.

We however do not have to assume a linear form for \(X\).

We assume: \(E[y_{ji}|\mathbf x_{i}, D_i]=E[y_{ji}|\mathbf x_{i}]\)

For each entity, find a near entity which had the opposite treatment.


\subsection{Additionstheoreme}
	$\sin(a \pm b)=\sin(a) \cdot \cos(b) \pm \cos(a) \cdot \sin(b)$\\
	$\cos(a \pm b)=\cos(a) \cdot \cos(b) \mp \sin(a) \cdot \sin(b)$\\
	$\tan(a \pm b)=\dfrac{\tan(a) \pm \tan(b)}{1 \mp \tan(a) \cdot \tan(b)}$