Rewritten more stuff. Finished up to stream 4 so still 6 streams to go

This commit is contained in:
TechWizzart 2020-09-05 09:37:27 +02:00
parent d631480c2f
commit e17e66b639
No known key found for this signature in database
GPG Key ID: 151E66B6CEF55F2E
9 changed files with 507 additions and 560 deletions

View File

@ -49,12 +49,6 @@ particular stream is missing in the version on the Planet Factory repository, ch
patient, or you can start writing a part of the manual yourself! Don't forget to ping me in the Discord to notify me of any additions (GitHub refuses to send me emails so I have no other way of
knowing).
\input{streams/Stream2.tex}
\input{streams/Stream3.tex}
\input{streams/Stream4.tex}
\input{streams/Stream5.tex}
\input{streams/Stream6.tex}
@ -73,9 +67,11 @@ knowing).
\input{topics/radiation.tex}
%Velocity
\input{topics/velocity.tex}
%Advection
\input{topics/advection.tex}
\input{topics/master.tex}
\newpage
\input{streams/TTNMETAF.tex}

View File

@ -1,231 +0,0 @@
\section{Let's Get the Atmosphere Moving}
In its current state, CLaUDE has a static planet. This means that the planet remains in place and does not move. However we know that planets move in orbit and more importantly, spin around
themselves. But before we start adding layers, let's talk about a term you will hear more often: numerical instability.
Numerical instability occurs when you first run the model. This is due to the nature of the equations. Nearly all equations are continuous, which means that they are always at work. However
when you start the model, the equations were not at work yet. It is as if you suddenly give a random meteor an atmosphere, place it in orbit around a star and don't touch it for a bit. You will
see that the whole system oscilates wildly as it adjusts to the sudden changes and eventually it will stabilise. Another term you might encounter is blow up, this occurs when when the model
suddenly no longer behaves like it should. This is most likely caused by mistakes in the code or incorrect paramter initialisation. Be wary of the existence of both factors, and do not dismiss
a model if it behaves weirdly as it has just started up.
\subsection{Equation of State and the Incompressible Atmosphere}
The equation of state relates one or more variables in a dynamical system (like the atmosphee) to another. The most common equation of state in the atmosphere is the ideal gas equation as
described by \autoref{eq:ideal gas} \cite{idealGas}. The symbols in that equation represent:
\begin{itemize}
\item $p$: The gas pressure ($Pa$).
\item $V$: The volume of the gas ($m^3$).
\item $n$: The amount of moles\footnote{Mole is the amount of particles ($6.02214076 \cdot 10^{23}$) in a substance, where the average weight of one mole of particles in grams is about the
same as the weight of one particle in atomic mass units ($u$)\cite{mole}} in the gas.
\item $R$: The Gas constant, $8.3144621$ ($J(mol)^{-1}K$) \cite{idealGas}.
\item $T$: The temperature opf the gas ($K$).
\end{itemize}
If we divide everything in \autoref{eq:ideal gas} by $V$ and set it to be unit (in this case, set it to be exactly $1 m^3$) we can add in the molar mass in both the top and bottom parts of the
division as show in \autoref{eq:gas unit}. We can then replace $\frac{nm}{V}$ by $\rho$ the density of the gas ($kgm^{-3}$) and $\frac{R}{m}$ by $R_s$ the specific gas constant (gas constant that varies per
gas in $J(mol)^{-1}K$) as shown in \autoref{eq:state gas}. the resulting equation is the equation of state that you get that most atmospheric physicists use when talking about the atmosphere \cite{simon}.
\begin{subequations}
\begin{equation}
pV = nRT
\label{eq:ideal gas}
\end{equation}
\begin{equation}
p = \frac{nR}{V}T = \frac{nmR}{Vm}T
\label{eq:gas unit}
\end{equation}
\begin{equation}
p = \rho R_sT
\label{eq:state gas}
\end{equation}
\end{subequations}
The pressure is quite important, as air moves from a high pressure point to a low pressure point. So if we know the density and the temperature, then we know the pressure and we can work out
where the air will be moving to (i.e. how the wind will blow). In our current model, we know the atmospheric temperature but we do not know the density. For simplicities sake, we will now assume
that the atmosphere is Incompressible, meaning that we have a constant density. Obviously we know that air can be compressed and hence our atmosphere can be compressed too but that is not
important enough to account for yet, especially considering the current complexity of our model.
The code that corresponds to this is quite simple, the only change that we need to make in \autoref{eq:state gas} is that we need to replace $T$ by $T_a$, the temperature of the atmosphere. As
$T_a$ is a matrix (known to programmers as a double array), $p$ will be a matrix as well. Now we only need to fill in some values. $\rho = 1.2$\cite{densityAir}, $R_s = 287$\cite{specificGasConstantAir}.
\subsection{The Primitive Equations and Geostrophy}
The primitive equations (also known as the momentum equations) is what makes the air move. It is actually kind of an injoke between physicists as they are called the primitive equations but
actually look quite complicated (and it says $fu$ at the end! \cite{simon}). The primitive equations are a set of equations dictating the direction in the $u$ and $v$ directions as shown in
\autoref{eq:primitive u} and \autoref{eq:primitive v}. We can make the equations simpler by using and approximation called geostrophy which means that we have no vertical motion, such that the
terms with $\omega$ in \autoref{eq:primitive u} and \autoref{eq:primitive v} become 0. We also assume that we are in a steady state, i.e. there is no acceleration which in turn means that the
whole middle part of the equations are $0$. Hence we are left with \autoref{eq:primitive u final} and \autoref{eq:primitive v final}.
\begin{subequations}
\begin{equation}
\frac{du}{dt} = \frac{\delta u}{\delta t} + u\frac{\delta u}{ \delta x} + v\frac{\delta u}{\delta v} + \omega\frac{\delta u}{\delta p} = -\frac{\delta \Phi}{\delta x} + fv
\label{eq:primitive u}
\end{equation}
\begin{equation}
\frac{dv}{dt} = \frac{\delta v}{\delta t} + u\frac{\delta v}{ \delta x} + v\frac{\delta v}{\delta v} + \omega\frac{\delta v}{\delta p} = -\frac{\delta \Phi}{\delta y} - fu
\label{eq:primitive v}
\end{equation}
\begin{equation}
0 = -\frac{\delta \Phi}{\delta x} + fv
\label{eq:primitive u final}
\end{equation}
\begin{equation}
0 = -\frac{\delta \Phi}{\delta y} - fu
\label{eq:primitive v final}
\end{equation}
\end{subequations}
\autoref{eq:primitive u final} can be split up into to parts, the $\frac{\delta \Phi}{\delta x}$ part (the gradient force) and the $fv$ part (the coriolis force). The same applies to
\autoref{eq:primitive v final}. Effectively we have a balance between the gradient and the coriolis force as shown in \autoref{eq:pu simple} and \autoref{eq:pv simple}. The symbols in both of
these equations are:
\begin{itemize}
\item $\Phi$: The geopotential, potential (more explanation in \autoref{sec:potential}) of the planet's gravity field ($Jkg^{-1}$).
\item $x$: The change in the East direction along the planet surface ($m$).
\item $y$: The change in the North direction along the planet surface ($m$).
\item $f$: The coriolis parameter as described by \autoref{eq:coriolis}, where $\Omega$ is the rotation rate of the planet (for Earth $7.2921 \cdot 10^{-5}$) ($rad \ s^{-1}$) and $\theta$ is the
latitude \cite{coriolis}.
\item $u$: The velocity in the latitude ($ms^{-1}$).
\item $v$: The velocity in the longitude ($ms^{-1}$).
\end{itemize}
\begin{subequations}
\begin{equation}
f = 2\Omega\sin(\theta)
\label{eq:coriolis}
\end{equation}
\begin{equation}
\frac{\delta \Phi}{\delta x} = fv
\label{eq:pu simple}
\end{equation}
\begin{equation}
\frac{\delta \Phi}{\delta y} = -fu
\label{eq:pv simple}
\end{equation}
\begin{equation}
\frac{\delta p}{\rho \delta x} = fv
\label{eq:pu simple final}
\end{equation}
\begin{equation}
\frac{\delta p}{\rho \delta y} = -fu
\label{eq:pv simple final}
\end{equation}
\end{subequations}
Since we want to know how the atmosphere moves, we want to get the v and u components of the velocity vector (since $v$ and $u$ are the veolicites in longitude and latitude, if we combine them in a
vector we get the direction of the overall velocity). So it is time to start coding and calculating! If we look back at \autoref{alg:stream1v2}, we can see that we already have a double for loop.
In computer science, having multiple loops is generally considered a bad coding practice as you usually can just reuse the indices of the already existing loop, so you do not need to create a new
one. However this is a special case, since we are calculating new temperatures in the double for loop. If we then also would start to calculate the velocities then we would use new information
and old information at the same time. Since at index $i - 1$ the new temperature has already been calculated, but at the index $i + 1$ the old one is still there. So in order to fix that we need
a second double for loop to ensure that we always use the new temperatures. We display this specific loop in \autoref{alg:stream2}. Do note that everything in \autoref{alg:stream1v2} is still
defined and can still be used, but since we want to focus on the new code, we leave out the old code to keep it concise and to prevent clutter.
\begin{algorithm}[hbt]
\SetAlgoLined
\While{\texttt{TRUE}}{
\For{$lat \in [-nlat, nlat]$}{
\For{$lon \in [0, nlon]$}{
$u[lat, lon] \leftarrow -\frac{p[lat + 1, lon] - p[lat - 1, lon]}{\delta y} \cdot \frac{1}{f[lat]\rho}$ \;
$v[lat, lon] \leftarrow \frac{p[lat, lon + 1] - p[lat, lon - 1]}{\delta x[lat]} \cdot \frac{1}{f[lat]\rho}$ \;
}
}
}
\caption{The main loop of the velocity of the atmosphere calculations}
\label{alg:stream2}
\end{algorithm}
The gradient calculation is done in \autoref{alg:gradient}. For this to work, we need the circumference of the planet. Herefore we need to assume that the planet is a sphere. While that is not
technically true, it makes little difference in practice and is good enough for our model. The equation for the circumference can be found in \autoref{eq:circumference} \cite{circumference},
where $r$ is the radius of the planet. Here we also use the f-plane approximation, where the coriolis paramter has one value for the northern hemisphere and one value for the southern hemisphere
\cite{fplane}.
\begin{equation}
2 \pi r
\label{eq:circumference}
\end{equation}
\begin{algorithm}
\SetAlgoLined
$C \leftarrow 2\pi R$ \;
$\delta y \leftarrow \frac{C}{nlat}$ \;
\For{$lat \in [-nlat, nlat]$}{
$\delta x[lat] \leftarrow \delta y \cos(lat \cdot \frac{\pi}{180})$ \;
\eIf{$lat < 0$}{
$f[lat] \leftarrow -10^{-4}$ \;
}{
$f[lat] \leftarrow 10^{-4}$ \;
}
}
\caption{Calculating the gradient $\delta x$}
\label{alg:gradient}
\end{algorithm}
Because of the geometry of the planet and the construction of the longitude latitude grid, we run into some problems when calculating the gradient. Since the planet is not flat ("controversial
I know"\cite{simon}) whenever we reach the end of the longitude we need to loop around to get to the right spot to calculate the gradients (as the planet does not stop at the end of the
longitude line but loops around). So to fix that we use the modulus (mod) function which does the looping for us if we exceed the grid's boundaries. We do haveanother problem though, the poles.
As the latitude grows closer to the poles, they are converging on the center point of the pole. Looping around there is much more difficult so to fix it, we just do not consider that center
point in the main loop. The changed algorithm can be found in \autoref{alg:stream2v2}
\begin{algorithm}[hbt]
\SetAlgoLined
\While{\texttt{TRUE}}{
\For{$lat \in [-nlat + 1, nlat - 1]$}{
\For{$lon \in [0, nlon]$}{
$u[lat, lon] \leftarrow -\frac{p[(lat + 1) \text{ mod } nlat, lon] - p[(lat -1) \text{ mod } nlat, lon]}{\delta y} \cdot \frac{1}{f[lat]\rho}$ \;
$v[lat, lon] \leftarrow \frac{p[lat, (lon + 1) \text{ mod } nlon] - p[lat, (lon -1) \text{ mod } nlon]}{\delta x[lat]} \cdot \frac{1}{f[lat]\rho}$ \;
}
}
}
\caption{The main loop of the velocity of the atmosphere calculations}
\label{alg:stream2v2}
\end{algorithm}
Do note that the pressure calculation is done between the temperature calculation in \autoref{alg:stream1v2} and the $u, v$ calculations in \autoref{alg:stream2v2}. At this point our model shows
a symmetric vortex around the sun that moves with the sun. This is not very realistic as you usually have convection and air flowing from warm to cold, but we do not have that complexity yet
(due to our single layer atmosphere).
\subsection{Introducing an Ocean}
Now we want to introduce an ocean, because most of the Earth is covered by oceans it plays quite an important role in atmospheric physics. To do this we need a new concept called albedo. Albedo
is basically the reflectiveness of a material (in our case the planet's surface) \cite{albedo}. The average albedo of the Earth is about 0.3. Now to add an ocean to the grid, we define a few
areas where the albedo differs. Where you do this does not really matter for the current complexity. Defining the oceans is as easy as hardcoding (what we computer scientists refer to when
setting parts of an array to be a specific value, where if you want to change the value you need to change it everywhere instead of doing it in a variable) the albedo value for the specific
regions as we do in \autoref{alg:albedo}. Water also takes longer to warm up, so let us change the specific heat capacity ($C_p$ in \autoref{alg:stream1v2}) from a constant to an array. The new
$C_p$ can also be found in \autoref{alg:albedo}, where we have made the specific heat capacity of water one order of magnitude (i.e. $10$ times) larger.
\begin{algorithm}[hbt]
$a \leftarrow 0.5$ \;
$a[5-55, 9-20] \leftarrow 0.2$ \;
$a[23-50, 45-70] \leftarrow 0.2$ \;
$a[2-30, 85-110] \leftarrow 0.2$ \;
$C_p \leftarrow 10^7$ \;
$C_p[5-55, 9-20] \leftarrow 10^8$ \;
$C_p[23-50, 45-70] \leftarrow 10^8$ \;
$C_p[2-30, 85-110] \leftarrow 10^8$ \;
\caption{Defining the oceans}
\label{alg:albedo}
\end{algorithm}
Now that we have that defined, we need to adjust the main loop of the program (\autoref{alg:stream1v2}). For clarity, all the defined constants have been left out. We need to add albedo into the
equation and change $C_p$ from a constant to an array. The algorithm after these changes can be found in \autoref{alg:stream2v3}. We multiply by $1 - a$ since albedo represents how much energy is
reflected instead of absorbed, where we need the amount that is absorbed which is exactly equal to $1$ minus the amount that is reflected.
\begin{algorithm}[hbt]
\SetAlgoLined
\While{\texttt{TRUE}}{
\For{$lat \in [-nlat, nlat]$}{
\For{$lon \in [0, nlot]$}{
$T_p[lat, lon] \leftarrow T_p[lat, lon] + \frac{\delta t ((1 - a[lat, lon])S + 4\epsilon \sigma (T_a[lat, lon])^4 - 4\sigma (T_p[lat, lon])^4)}{C_p[lat, lon]}$ \;
$T_a[lat, lon] \leftarrow T_a[lat, lon] + \frac{\delta t (\sigma (T_p[lat, lon])^4 - 2\epsilon\sigma (T_a[lat, lon])^4)}{C_a}$ \;
$t \leftarrow t + \delta t$ \;
}
}
}
\caption{The main loop of the temperature calculations}
\label{alg:stream2v3}
\end{algorithm}

View File

@ -1,232 +0,0 @@
\section{Adding Mass to CLAuDE}
\subsection{The Momentum Equations}
The momentum equations are a set of equations that describe the flow of a fluid on the surface of a rotating body. For our model we will use the f-plane approximation. The equations corresponding
to the f-plane approximation are given in \autoref{eq:x momentum} and \autoref{eq:y momentum} \cite{momentumeqs}. Note that we are ignoring vertical moevement, as this does not have a significant
effect on the whole flow. All the symbols in \autoref{eq:x momentum} and \autoref{eq:y momentum} mean:
\begin{itemize}
\item $u$: The east to west velocity ($ms^{-1}$).
\item $t$: The time ($s$).
\item $f$: The coriolis parameter as in \autoref{eq:coriolis}.
\item $v$: The north to south velocity ($ms^{-1}$).
\item $\rho$: The density of the atmosphere ($kgm^{-3}$).
\item $p$: The atmospheric pressure ($Pa$).
\item $x$: The local longitude coordinate ($m$).
\item $y$: The local latitude coordinate ($m$).
\end{itemize}
If we then define a vector $\bar{u}$ as $(u, v, 0)$, we can rewrite both \autoref{eq:x momentum} as \autoref{eq:x momentum laplace}. Here $\nabla u$ is the gradient of
$u$ in both $x$ and $y$ directions. Then if we write out $\nabla u$ we get \autoref{eq:x momentum final}. Similarly, if we want to get $\delta v$ instead of $\delta u$ we rewrite
\autoref{eq:y momentum} to get \autoref{eq:y momentum laplace} and \autoref{eq:y momentum final}.
\begin{subequations}
\begin{equation}
\frac{Du}{Dt} - fv = -\frac{1}{\rho} \frac{\delta p}{\delta x}
\label{eq:x momentum}
\end{equation}
\begin{equation}
\frac{Dv}{Dt} - fu = -\frac{1}{\rho} \frac{\delta p}{\delta y}
\label{eq:y momentum}
\end{equation}
\begin{equation}
\frac{\delta u}{\delta t} + \bar{u} \cdot \nabla u - fv = -\frac{1}{\rho}\frac{\delta p}{\delta x}
\label{eq:x momentum laplace}
\end{equation}
\begin{equation}
\frac{\delta v}{\delta t} + \bar{u} \cdot \nabla v - fu = -\frac{1}{\rho}\frac{\delta p}{\delta y}
\label{eq:y momentum laplace}
\end{equation}
\begin{equation}
\frac{\delta u}{\delta t} + u\frac{\delta u}{\delta x} + v\frac{\delta u}{\delta y} - fv = -\frac{1}{\rho}\frac{\delta p}{\delta x}
\label{eq:x momentum final}
\end{equation}
\begin{equation}
\frac{\delta v}{\delta t} + u\frac{\delta v}{\delta x} + v\frac{\delta v}{\delta y} - fu = -\frac{1}{\rho}\frac{\delta p}{\delta y}
\label{eq:y momentum final}
\end{equation}
\end{subequations}
With the gradient functions defined, we can move on to the main code for the momentum equations. The main loop is shown in \autoref{alg:stream3}. Do note that this loop replaces the one
in \autoref{alg:stream2v2} as these calculate the same thing, but the new algorithm does it better.
\begin{algorithm}
$S_{xu} \leftarrow \texttt{gradient\_x}(u, lan, lon)$ \;
$S_{yu} \leftarrow \texttt{gradient\_y}(u, lan, lon)$ \;
$S_{xv} \leftarrow \texttt{gradient\_x}(v, lan, lon)$ \;
$S_{yv} \leftarrow \texttt{gradient\_y}(v, lan, lon)$ \;
$S_{px} \leftarrow \texttt{gradient\_x}(p, lan, lon)$ \;
$S_{py} \leftarrow \texttt{gradient\_x}(p, lan, lon)$ \;
\While{\texttt{TRUE}}{
\For{$lat \in [1, nlat - 1]$}{
\For{$lon \in [0, nlon]$}{
$u[lan, lon] \leftarrow u[lan, lon] + \delta t \frac{-u[lan, lon]S_{xu} - v[lan, lon]S_{yu} + f[lan]v[lan, lon] - S_{px}}{\rho}$ \;
$v[lan, lon] \leftarrow v[lan, lon] + \delta t\frac{-u[lan, lon]S_{xv} - v[lan, lon]S_{yv} - f[lan]u[lan, lon] - S_{py}}{\rho}$ \;
}
}
}
\caption{Calculating the flow of the atmosphere (wind)}
\label{alg:stream3}
\end{algorithm}
\subsection{Thermal Diffusion}
As of this time, what you notice if you run the model is that the winds only get stronger and stronger (and the model is hence blowing up). This is because there is no link yet between the
velocities of the atmosphere and the temperature. Currently, any air movement does not affect the temperature in the atmosphere of our model while it does in reality. So we need to change some
calculations to account for that. Thermal diffusion helps with spreading out the temperatures and tempering the winds a bit.
The diffusion equation, as written in \autoref{eq:diffusion}, describes how the temperature spreads out over time\cite{diffusion}. The symbols in the equation represent:
\begin{itemize}
\item $u$: A vector consisting out of 4 elements: $x, y, z, t$. $x, y, z$ are the local coordinates and $t$ is time.
\item $\alpha$: The thermal diffusivity constant.
\item $\nabla^2$: The Laplace operator, more information in \autoref{sec:laplace}.
\item $\bar{u}$: The time derivative of $u$, or in symbols $\frac{\delta u}{\delta t}$.
\end{itemize}
\begin{equation}
\bar{u} = \alpha \nabla^2 u
\label{eq:diffusion}
\end{equation}
Now to get this into code we need the following algorithms \autoref{alg:laplacian} and \autoref{alg:diffusion}. \autoref{alg:laplacian} implements the laplacian operator, whereas
\autoref{alg:diffusion} implements the diffusion calculations. $\nabla^2$ in \autoref{alg:diffusion} represents the call to \autoref{alg:laplacian}.
\begin{algorithm}
\SetKwInOut{Input}{Input}
\SetKwInOut{Output}{Output}
\Input{A matrix (double array) a}
\Output{A matrix (double array) with results for the laplacian operator for each element}
\For{$lat \in [1, nlat - 1]$}{
\For{$lon \in [0, nlon]$}{
$output[lat, lon] \leftarrow \frac{\Delta_x(a, lat, (lon + 1) \text{ mod } nlon) - \Delta_x(a, lat, (lon - 1) \text{ mod } nlon)}{\delta x[lat]} + \frac{\Delta_y(a, lat + 1, lon) -
\Delta_y(a, lat - 1, lon)}{\delta y}$\;
}
}
\Return{$ouput$} \;
\caption{Calculate the laplacian operator over a matrix a}
\label{alg:laplacian}
\end{algorithm}
\begin{algorithm}
$\alpha_a \leftarrow 2 \cdot 10^{-5}$ \;
$\alpha_p \leftarrow 1.5 \cdot 10^{-6}$ \;
\While{\texttt{TRUE}}{
$T_a \leftarrow T_a + \delta t \alpha_a \nabla^2(T_a)$ \;
$T_p \leftarrow T_p + \delta t \alpha_p \nabla^2(T_p)$ \;
}
\caption{The main loop for calculating the effects of diffusion}
\label{alg:diffusion}
\end{algorithm}
\subsection{Advection}
With thermal diffusion in place, the temperature will spread out a bit, however air is not transported yet. This means that the winds we simulate are not actually moving any air. Advection is
going to change that. Advection is a fluid flow transporting something with it as it flows. This can be temperature, gas, solids or other fluids. In our case we will be looking at temperature.
The advection equation is shown in \autoref{eq:advection}. The symbols are:
\begin{itemize}
\item $\psi$: What is carried along (in our case temperature, $K$).
\item $t$: The time ($s$).
\item $u$: The fluid velocity vector ($ms^{-1}$).
\item $\nabla$: The divergence operator (as explained in \autoref{sec:laplace}).
\end{itemize}
\begin{equation}
\frac{\delta \psi}{\delta t} + \nabla \cdot (\psi u) = 0
\label{eq:advection}
\end{equation}
\begin{algorithm}
\SetKwInOut{Input}{Input}
\SetKwInOut{Output}{Output}
\Input{A matrix (double array) $a$}
\Output{A matrix (double array) containing the result of the divergence operator taken over that element}
$dim_1 \leftarrow \text{ Length of } a \text{ in the first dimension}$ \;
\For{$i \in [0, dim_1]$}{
$dim_2 \leftarrow \text{ Length of } a \text{ in the second dimension (i.e. the length of the array stored at index } i)$ \;
\For{$j \in [0, dim_2]$}{
$output[i, j] \leftarrow \Delta_x(au, i, j) + \Delta_y(av, i, j)$ \;
}
}
\Return{$output$} \;
\caption{Calculate the result of the divergence operator on a vector}
\label{alg:divergence}
\end{algorithm}
With the divergence functon defined, we now need to adjust \autoref{alg:diffusion} to incorporate this effect. The resulting algorithm can be found in \autoref{alg:advection}. Here $\nabla$
represents the function call to \autoref{alg:divergence}.
\begin{algorithm}
$\alpha_a \leftarrow 2 \cdot 10^{-5}$ \;
$\alpha_p \leftarrow 1.5 \cdot 10^{-6}$ \;
\While{\texttt{TRUE}}{
$T_{add} \leftarrow T_a + \delta t \alpha_a \nabla^2(T_a) + \nabla(T_a)$ \;
$T_a \leftarrow T_a + T_{add}[5:-5, :] \text{ //Only add } T_{add} \text{ to } T_a \text{ for indices in the interval } [-nlat + 5, nlat - 5]$. \;
$T_p \leftarrow T_p + \delta t \alpha_p \nabla^2(T_p)$ \;
}
\caption{The main loop for calculating the effects of advection}
\label{alg:advection}
\end{algorithm}
Now that we have the air moving, we also need to account for the moving of the density. This is because moving air to a certain place will change the air density at that place if the air at that
place does not move away at the same rate. Say we are moving air to $x$ at $y \ ms^{-1}$. If air at $x$ moves at a rate $z \ ms^{-1}$ and $z \neq y$ then the air density at $x$ will change.
The equation we will need for that is the mass continuity equation as shown in \autoref{eq:mass continuity} \cite{masscontinue}.
\begin{equation}
\frac{\delta \rho}{\delta t} + \nabla \cdot (\rho v) = 0
\label{eq:mass continuity}
\end{equation}
Using this equation means that we will no longer assume that the atmosphere is incompressible. Therefore we need to change a few things in the code. First we need to change the $\rho$ in
\autoref{alg:stream3}. Since $\rho$ is no longer constant we need to access the right value of $\rho$ by specifying the indices. So $\rho$ will change to $\rho[lat, lon]$. Furthermore we need
to calculate $\rho$ after the movement of air has taken place, so we need to change \autoref{alg:advection} as well to include the calculations for $\rho$. The new version can be found in
\autoref{alg:advectionv2}. Again the $\nabla$ represents the call to \autoref{alg:divergence}.
\begin{algorithm}
$\alpha_a \leftarrow 2 \cdot 10^{-5}$ \;
$\alpha_p \leftarrow 1.5 \cdot 10^{-6}$ \;
\While{\texttt{TRUE}}{
$T_{add} \leftarrow T_a + \delta t \alpha_a \nabla^2(T_a) + \nabla(T_a)$ \;
$T_a \leftarrow T_a + T_{add}[5:-5, :] \text{ //Only add } T_{add} \text{ to } T_a \text{ for indices in the interval } [-nlat + 5, nlat - 5]$. \;
$\rho \leftarrow \rho + \delta t \nabla \rho$ \;
$T_p \leftarrow T_p + \delta t \alpha_p \nabla^2(T_p)$ \;
}
\caption{The main loop for calculating the effects of advection}
\label{alg:advectionv2}
\end{algorithm}
Now that we have a varying density, we need to account for that in the temperature equations. So let us do that. We need it in the denominator as the density has a direct effect on the
heat capacity of the atmosphere. The changes are reflected in \autoref{alg:temperature with density}.
\begin{algorithm}[hbt]
\SetAlgoLined
\While{\texttt{TRUE}}{
\For{$lat \in [-nlat, nlat]$}{
\For{$lon \in [0, nlot]$}{
$T_p[lat, lon] \leftarrow T_p[lat, lon] + \frac{\delta t ((1 - a[lat, lon])S + 4\epsilon \sigma (T_a[lat, lon])^4 - 4\sigma (T_p[lat, lon])^4)}{\rho[lat, lon]C_p[lat, lon]}$ \;
$T_a[lat, lon] \leftarrow T_a[lat, lon] + \frac{\delta t (\sigma (T_p[lat, lon])^4 - 2\epsilon\sigma (T_a[lat, lon])^4)}{\rho[lat, lon]C_a}$ \;
$t \leftarrow t + \delta t$ \;
}
}
}
\caption{The main loop of the temperature calculations}
\label{alg:temperature with density}
\end{algorithm}
\subsection{Improving the Coriolis Parameter}
Another change introduced is in the coriolis parameter. Up until now it has been a constant, however we know that it varies along the latitude. So let's make it vary over the latitude. Recall
\autoref{eq:coriolis}, where $\Theta$ is the latitude. Coriolis ($f$) is currently defined in \autoref{alg:gradient}, so let's incorporate the changes which are shown in \autoref{alg:coriolis}.
\begin{algorithm}
\SetAlgoLined
$C \leftarrow 2\pi R$ \;
$\delta y \leftarrow \frac{C}{nlat}$ \;
$\Omega \leftarrow 7.2921 \cdot 10^{-5}$ \;
\For{$lat \in [-nlat, nlat]$}{
$\delta x[lat] \leftarrow \delta y \cos(lat \cdot \frac{\pi}{180})$ \;
$f[lat] \leftarrow 2\Omega \sin(lat \frac{\pi}{180})$ \;
}
\caption{Calculating the gradient $\delta x$}
\label{alg:coriolis}
\end{algorithm}

View File

@ -1,83 +0,0 @@
\section{Removing Some Assumptions and Mistakes from CLAuDE}
The first half of this stream was spent looking through the code and fixing some mistakes. To spare you dear reader from making these same mistakes, they have already been incorporated into
the previous sections, hooray! This does not only save you some work, but it also spares you from staring at a model that does not function due to wrongly defined constants or using the wrong
values.
\subsection{Adding a Spin-Up Time}
Instead of having a static start (having the planet start from rest, so no rotations allowed) we will have the model start up for some time before we start simulating the climate extensively.
To accomodate for this, we have to make some changes in the code. First we need to add two booleans (variables that can only take two values, either \texttt{TRUE} or \texttt{FALSE}) that we use
to indicate to the model whether we want to simulate the wind and whether we want to simulate advection. This means that the main loop will have some changes made to it. After performing the
calculations in \autoref{alg:temperature with density} we would calculate the velocities and afterwards we would calculate the advection. Instead let us change it to what is shown in
\autoref{alg:stream4v1}.
\begin{algorithm}
\While{\texttt{TRUE}}{
\autoref{alg:temperature with density} \;
\If{$velocity$}{
\autoref{alg:stream3} \;
\If{$advection$}{
\autoref{alg:advectionv2} \;
}
}
}
\caption{Main loop that can simulate flow and advection conditionally}
\label{alg:stream4v1}
\end{algorithm}
Now to dynamically enable/disable the simulation of flow and advection we need to add the spin-up calculations to the main loop. So in \autoref{alg:stream4v1}, before
\autoref{alg:temperature with density} we add \autoref{alg:spinup}. What it does is it changes the timestep when spinnning up and disables flow simulation, and when a week has passed it reduces
the timestep and enables flow simulation. At this point in time, the advection is not dynamically enabled/disabled but it is done by the programmer. Currently it will break the model, so I
recommend leaving it on \texttt{FALSE} until it is fixed in \autoref{sec:advectionfix}.
\begin{algorithm}
\eIf{$t < 7day$}{
$\delta t \leftarrow 60 \cdot 47$ \;
$velocity \leftarrow \texttt{FALSE}$ \;
}{
$\delta t \leftarrow 60 \cdot 9$ \;
$velocity \leftarrow \texttt{TRUE}$ \;
}
\caption{The spin-up block dynamically enabling or disabling flow simulation}
\label{alg:spinup}
\end{algorithm}
\subsection{Varying the Albedo}
The albdeo (reflectiveness of the planet's surface) is of course not the same over the whole planet. To account for this, we instead vary the albedo slightly for each point in the latitude
longitude grid. The algorithm that does this is shown in \autoref{alg:albedo variance}. The uniform distribution basically says that each allowed value in the interval has an equal chance of
being picked \cite{uniformdist}.
\begin{algorithm}
$V_a \leftarrow 0.02$ \;
\For{$lat \in [-nlat, nlat]$}{
\For{$lon \in [0, nlon]$}{
$R \leftarrow \text{ Pick a random number (from the uniform distribution) in the interval } [-V_a, V_a]$ \;
$a[lat, lon] \leftarrow a[lat, lon] + V_a \cdot R$\;
}
}
\caption{Varying the albedo of the planet}
\label{alg:albedo variance}
\end{algorithm}
\subsection{Fixing the Advection} \label{sec:advectionfix}
Currently the advection does not work like it should. This is probably due to boundary issues, where we get too close to the poles and it starts freaking out there \cite{simon}. So to fix this
we are going to define boundaries and assume that the advection only works within those boundaries. We only let it change by half of the values. The changes are incorporated in
\autoref{alg:advectionfix}. The reason why we mention this seperately, in contrast to the other fixes that we have incorporated throughout the manual already, is the accompanying change with the
boundary.
\begin{algorithm}
$\alpha_a \leftarrow 2 \cdot 10^{-5}$ \;
$\alpha_p \leftarrow 1.5 \cdot 10^{-6}$ \;
$boundary \leftarrow 7$ \;
\While{\texttt{TRUE}}{
$T_{add} \leftarrow T_a + \delta t \alpha_a \nabla^2(T_a) + \nabla(T_a)$ \;
$T_a \leftarrow T_a - 0.5T_{add}[boundary:-boundary, :] \text{ //Only subtract } T_{add} \text{ to } T_a \text{ for indices in the interval } [-nlat + boundary, nlat - boundary]$. \;
$\rho[boundary: -boundary, :] \leftarrow \rho - 0.5(\delta t \nabla \rho) \text{ //Only change the density for indices in the interval } [-nlat + boundary, nlat - boundary]$ \;
$T_p \leftarrow T_p + \delta t \alpha_p \nabla^2(T_p)$ \;
}
\caption{The main loop for calculating the effects of advection}
\label{alg:advectionfix}
\end{algorithm}
\subsection{Adding Friction}
In order to simulate friction, we multiply the speeds $u$ and $v$ by $0.99$. Of course there are equations for friction but that gets complicated very fast, so instead we just assume that we
have a constant friction factor. This multiplication is done directly after \autoref{alg:stream3} in \autoref{alg:stream4v1}.

View File

@ -0,0 +1,114 @@
\section{Advection}
Advection is a fluid flow transporting something with it as it flows. This can be temperature, gas, solids or other fluids. In our case we will be looking at temperature.
\subsection{Thermal Diffusion}
As of this time, what you notice if you run the model is that the winds only get stronger and stronger (and the model is hence blowing up, which means that the numbers increase so dramatically
that it is no longer realistic). This is because there is no link yet between the velocities of the atmosphere and the temperature. Currently, any air movement does not affect the temperature
in the atmosphere of our model while it does in reality. So we need to change some calculations to account for that. Thermal diffusion helps with spreading out the temperatures and tempering
the winds a bit.
The diffusion equation, as written in \autoref{eq:diffusion}, describes how the temperature spreads out over time\cite{diffusion}. The symbols in the equation represent:
\begin{itemize}
\item $u$: A vector consisting out of 4 elements: $x, y, z, t$. $x, y, z$ are the local coordinates and $t$ is time.
\item $\alpha$: The thermal diffusivity constant.
\item $\nabla^2$: The Laplace operator, more information in \autoref{sec:laplace}.
\item $\bar{u}$: The time derivative of $u$, or in symbols $\frac{\delta u}{\delta t}$.
\end{itemize}
\begin{equation}
\bar{u} = \alpha \nabla^2 u
\label{eq:diffusion}
\end{equation}
Now to get this into code we need the following algorithms \autoref{alg:laplacian} and \autoref{alg:diffusion}. \autoref{alg:laplacian} implements the laplacian operator, whereas
\autoref{alg:diffusion} implements the diffusion calculations. $\nabla^2$ in \autoref{alg:diffusion} represents the call to \autoref{alg:laplacian}.
\begin{algorithm}
$\alpha_a \leftarrow 2 \cdot 10^{-5}$ \;
$\alpha_p \leftarrow 1.5 \cdot 10^{-6}$ \;
\While{\texttt{TRUE}}{
$T_a \leftarrow T_a + \delta t \alpha_a \nabla^2(T_a)$ \;
$T_p \leftarrow T_p + \delta t \alpha_p \nabla^2(T_p)$ \;
}
\caption{The main loop for calculating the effects of diffusion}
\label{alg:diffusion}
\end{algorithm}
\subsection{Adding in Advection}
With thermal diffusion in place, the temperature will spread out a bit, however air is not transported yet. This means that the winds we simulate are not actually moving any air. Advection is
going to change that. The advection equation is shown in \autoref{eq:advection}. The symbols are:
\begin{itemize}
\item $\psi$: What is carried along (in our case temperature, $K$).
\item $t$: The time ($s$).
\item $u$: The fluid velocity vector ($ms^{-1}$).
\item $\nabla$: The divergence operator (as explained in \autoref{sec:laplace}).
\end{itemize}
\begin{equation}
\frac{\delta \psi}{\delta t} + \nabla \cdot (\psi u) = 0
\label{eq:advection}
\end{equation}
With the divergence functon defined in \autoref{alg:divergence}, we now need to adjust \autoref{alg:diffusion} to incorporate this effect. The resulting algorithm can be found in
\autoref{alg:advection}. Here $\nabla$ represents the function call to \autoref{alg:divergence}.
\begin{algorithm}
$\alpha_a \leftarrow 2 \cdot 10^{-5}$ \;
$\alpha_p \leftarrow 1.5 \cdot 10^{-6}$ \;
\While{\texttt{TRUE}}{
$T_{add} \leftarrow T_a + \delta t \alpha_a \nabla^2(T_a) + \nabla(T_a)$ \;
$T_a \leftarrow T_a + T_{add}[5:-5, :] \text{ //Only add } T_{add} \text{ to } T_a \text{ for indices in the interval } [-nlat + 5, nlat - 5]$. \;
$T_p \leftarrow T_p + \delta t \alpha_p \nabla^2(T_p)$ \;
}
\caption{The main loop for calculating the effects of advection}
\label{alg:advection}
\end{algorithm}
Now that we have the air moving, we also need to account for the moving of the density. This is because moving air to a certain place will change the air density at that place if the air at that
place does not move away at the same rate. Say we are moving air to $x$ at $y \ ms^{-1}$. If air at $x$ moves at a rate $z \ ms^{-1}$ and $z \neq y$ then the air density at $x$ will change.
The equation we will need for that is the mass continuity equation as shown in \autoref{eq:mass continuity} \cite{masscontinue}.
\begin{equation}
\frac{\delta \rho}{\delta t} + \nabla \cdot (\rho v) = 0
\label{eq:mass continuity}
\end{equation}
Using this equation means that we will no longer assume that the atmosphere is incompressible. Therefore we need to change a few things in the code. First we need to change the $\rho$ in
\autoref{alg:stream3}. Since $\rho$ is no longer constant we need to access the right value of $\rho$ by specifying the indices. So $\rho$ will change to $\rho[lat, lon]$. Furthermore we need
to calculate $\rho$ after the movement of air has taken place, so we need to change \autoref{alg:advection} as well to include the calculations for $\rho$. The new version can be found in
\autoref{alg:advectionv2}. Again the $\nabla$ represents the call to \autoref{alg:divergence}.
\begin{algorithm}
$\alpha_a \leftarrow 2 \cdot 10^{-5}$ \;
$\alpha_p \leftarrow 1.5 \cdot 10^{-6}$ \;
\While{\texttt{TRUE}}{
$T_{add} \leftarrow T_a + \delta t \alpha_a \nabla^2(T_a) + \nabla(T_a)$ \;
$T_a \leftarrow T_a + T_{add}[5:-5, :] \text{ //Only add } T_{add} \text{ to } T_a \text{ for indices in the interval } [-nlat + 5, nlat - 5]$. \;
$\rho \leftarrow \rho + \delta t \nabla \rho$ \;
$T_p \leftarrow T_p + \delta t \alpha_p \nabla^2(T_p)$ \;
}
\caption{The main loop for calculating the effects of advection}
\label{alg:advectionv2}
\end{algorithm}
Currently the advection does not work like it should. This is probably due to boundary issues, where we get too close to the poles and it starts freaking out there \cite{simon}. So to fix this
we are going to define boundaries and assume that the advection only works within those boundaries. We only let it change by half of the values. The changes are incorporated in
\autoref{alg:advectionfix}. The reason why we mention this seperately, in contrast to the other fixes that we have incorporated throughout the manual already, is the accompanying change with the
boundary.
\begin{algorithm}
$\alpha_a \leftarrow 2 \cdot 10^{-5}$ \;
$\alpha_p \leftarrow 1.5 \cdot 10^{-6}$ \;
$boundary \leftarrow 7$ \;
\While{\texttt{TRUE}}{
$T_{add} \leftarrow T_a + \delta t \alpha_a \nabla^2(T_a) + \nabla(T_a)$ \;
$T_a \leftarrow T_a - 0.5T_{add}[boundary:-boundary, :] \text{ //Only subtract } T_{add} \text{ to } T_a \text{ for indices in the interval } [-nlat + boundary, nlat - boundary]$. \;
$\rho[boundary: -boundary, :] \leftarrow \rho - 0.5(\delta t \nabla \rho) \text{ //Only change the density for indices in the interval } [-nlat + boundary, nlat - boundary]$ \;
$T_p \leftarrow T_p + \delta t \alpha_p \nabla^2(T_p)$ \;
}
\caption{The main loop for calculating the effects of advection}
\label{alg:advectionfix}
\end{algorithm}

View File

@ -0,0 +1,43 @@
\section{The Master File}
The master file is the file that controls the model calculation. This file decides what calculations are used and what is done with the calculations (which is not the scope of this manual).
In other words, the master file combines all the calculations and theory from the previous sections and puts it all together to form a model. As mentioned earlier, this structure enables the
user to create their own version of the model. If one has their own calculations, or wants to use an older version of the calculations in this manual, then the user can define it themselves
and call it instead of the calls that we use. The model is meant to be customisable, which this structure enables.
\subsection{Adding a Spin-Up Time}
Instead of having a static start (having the planet start from rest, so no rotations allowed) we will have the model start up for some time before we start simulating the climate extensively.
To accomodate for this, we have to make some changes in the code. First we need to add two booleans (variables that can only take two values, either \texttt{TRUE} or \texttt{FALSE}) that we use
to indicate to the model whether we want to simulate the wind and whether we want to simulate advection. This means that the main loop will have some changes made to it. After performing the
calculations in \autoref{alg:temperature with density} we would calculate the velocities and afterwards we would calculate the advection. Instead let us change it to what is shown in
\autoref{alg:stream4v1}.
\begin{algorithm}
\While{\texttt{TRUE}}{
\autoref{alg:temperature with density} \;
\If{$velocity$}{
\autoref{alg:stream3} \;
\If{$advection$}{
\autoref{alg:advectionfix} \;
}
}
}
\caption{Main loop that can simulate flow and advection conditionally}
\label{alg:stream4v1}
\end{algorithm}
Now to dynamically enable/disable the simulation of flow and advection we need to add the spin-up calculations to the main loop. So in \autoref{alg:stream4v1}, before
\autoref{alg:temperature with density} we add \autoref{alg:spinup}. What it does is it changes the timestep when spinnning up and disables flow simulation, and when a week has passed it reduces
the timestep and enables flow simulation. At this point in time, the advection is not dynamically enabled/disabled but it is done by the programmer. Currently it will break the model, so I
recommend leaving it on \texttt{FALSE} until it is fixed in \autoref{sec:advectionfix}.
\begin{algorithm}
\eIf{$t < 7day$}{
$\delta t \leftarrow 60 \cdot 47$ \;
$velocity \leftarrow \texttt{FALSE}$ \;
}{
$\delta t \leftarrow 60 \cdot 9$ \;
$velocity \leftarrow \texttt{TRUE}$ \;
}
\caption{The spin-up block dynamically enabling or disabling flow simulation}
\label{alg:spinup}
\end{algorithm}

View File

@ -1,9 +1,13 @@
\section{Radiation}
\subsection{The First Law of Thermodynamics and the Stefan-Boltzmann Equation}
The beginning of CLAuDE is based upon one of the most important laws of physics: "Energy is neither created nor destroyed, only changed from one form to another." In otherwords, if energy goes
into an object it must equal the outflowing energy plus the change of internal energy. This is captured in Stefan-Boltzmann's law (\autoref{eq:stefan-boltzmann}) \cite{stefan-boltzmann}.
Radiation is energy waves, some waves are visible like light, others are invisible like radio signals. As is the basis for physics, energy cannot be created nor destroyed, only changed from one
form to another.
\subsection{The First Law of Thermodynamics and the Stefan-Boltzmann Equation}
If energy goes into an object it must equal the outflowing energy plus the change of internal energy. Which is exactly what happens with the atmosphere. Radiation from the sun comes in, and
radiation from the atmosphere goes out. And along the way we heat the atmosphere and the planet which causes less radiation to be emitted than received. At least, that is the idea for Earth which
may not apply to all planets. Let one thing be clear, more radiation cannot be emitted than is inserted, unless the planet and atmosphere are cooling. Anyway, we assume that the planet is a black
body, i.e. it absorbs all radiation on all wavelengths. This is captured in Stefan-Boltzmann's law (\autoref{eq:stefan-boltzmann}) \cite{stefan-boltzmann}.
Here we assume that the planet is a black body, i.e. it absorbs all radiation (energy waves, some waves are visible like light, others are invisible like radio signals) on all wavelengths.
In \autoref{eq:stefan-boltzmann} the symbols are:
\begin{itemize}
@ -202,3 +206,70 @@ that $S$ is defined as the call to \autoref{alg:solar}.
\caption{The main function of the temperature calculations}
\label{alg:stream1v2}
\end{algorithm}
\subsection{Albedo}
Albedo is basically the reflectiveness of a material (in our case the planet's surface) \cite{albedo}. The average albedo of the Earth is about 0.2. Do note that we change $C_p$ from a constant
to an array. We do this to allow adding in oceans or other terrain in the future. Same thing for the albedo, different terrain has different reflectiveness.
\begin{algorithm}[hbt]
$a \leftarrow 0.2$ \;
$C_p \leftarrow 10^7$ \;
\caption{Defining the oceans}
\label{alg:albedo}
\end{algorithm}
Now that we have that defined, we need to adjust the main loop of the program (\autoref{alg:stream1v2}). For clarity, all the defined constants have been left out. We need to add albedo into the
equation and change $C_p$ from a constant to an array. The algorithm after these changes can be found in \autoref{alg:stream2v3}. We multiply by $1 - a$ since albedo represents how much energy is
reflected instead of absorbed, where we need the amount that is absorbed which is exactly equal to $1$ minus the amount that is reflected.
\begin{algorithm}[hbt]
\SetAlgoLined
\SetKwInput{Input}{Input}
\SetKwInOut{Output}{Output}
\Input{time $t$, amount of energy that hits the planet $S$}
\Output{Temperature of the planet $T_p$, temperature of the atmosphere $T_a$}
\For{$lat \in [-nlat, nlat]$}{
\For{$lon \in [0, nlot]$}{
$T_p[lat, lon] \leftarrow T_p[lat, lon] + \frac{\delta t ((1 - a[lat, lon])S + 4\epsilon \sigma (T_a[lat, lon])^4 - 4\sigma (T_p[lat, lon])^4)}{C_p[lat, lon]}$ \;
$T_a[lat, lon] \leftarrow T_a[lat, lon] + \frac{\delta t (\sigma (T_p[lat, lon])^4 - 2\epsilon\sigma (T_a[lat, lon])^4)}{C_a}$ \;
}
}
\caption{The main loop of the temperature calculations}
\label{alg:stream2v3}
\end{algorithm}
\subsection{Temperature with Varying Density}
\begin{algorithm}[hbt]
\SetAlgoLined
\SetKwInput{Input}{Input}
\SetKwInOut{Output}{Output}
\Input{time $t$, amount of energy that hits the planet $S$}
\Output{Temperature of the planet $T_p$, temperature of the atmosphere $T_a$}
\For{$lat \in [-nlat, nlat]$}{
\For{$lon \in [0, nlot]$}{
$T_p[lat, lon] \leftarrow T_p[lat, lon] + \frac{\delta t ((1 - a[lat, lon])S + 4\epsilon \sigma (T_a[lat, lon])^4 - 4\sigma (T_p[lat, lon])^4)}{\rho[lat, lon]C_p[lat, lon]}$ \;
$T_a[lat, lon] \leftarrow T_a[lat, lon] + \frac{\delta t (\sigma (T_p[lat, lon])^4 - 2\epsilon\sigma (T_a[lat, lon])^4)}{\rho[lat, lon]C_a}$ \;
$t \leftarrow t + \delta t$ \;
}
}
\caption{The main loop of the temperature calculations}
\label{alg:temperature with density}
\end{algorithm}
\subsection{Varying the Albedo}
The albdeo (reflectiveness of the planet's surface) is of course not the same over the whole planet. To account for this, we instead vary the albedo slightly for each point in the latitude
longitude grid. The algorithm that does this is shown in \autoref{alg:albedo variance}. The uniform distribution basically says that each allowed value in the interval has an equal chance of
being picked \cite{uniformdist}.
\begin{algorithm}
$V_a \leftarrow 0.02$ \;
\For{$lat \in [-nlat, nlat]$}{
\For{$lon \in [0, nlon]$}{
$R \leftarrow \text{ Pick a random number (from the uniform distribution) in the interval } [-V_a, V_a]$ \;
$a[lat, lon] \leftarrow a[lat, lon] + V_a \cdot R$\;
}
}
\caption{Varying the albedo of the planet}
\label{alg:albedo variance}
\end{algorithm}

View File

@ -123,7 +123,7 @@ the basis vector.
\label{eq:laplacian vector}
\end{equation}
The new code can be found in \autoref{alg:laplacian}. $\Delta_x$ and $\Delta_y$ in \autoref{alg:laplacian} represents the calls to \autoref{alg:gradient x} and \autoref{alg:gradient y}
The code can be found in \autoref{alg:laplacian}. $\Delta_x$ and $\Delta_y$ in \autoref{alg:laplacian} represents the calls to \autoref{alg:gradient x} and \autoref{alg:gradient y}
respectively.
\begin{algorithm}[hbt]
@ -157,7 +157,7 @@ respectively.
\subsection{Divergence}
As we expect to use the divergence operator more often throughout our model, let us define a seperate function for it in \autoref{alg:divergence}. $\Delta_x$ and $\Delta_y$ in
\autoref{alg:divergence} represents the calls to \autoref{alg:gradient x} and \autoref{alg:gradient y} respectively. We do the multiplication with the velocity vectors $u, v$ and $w$ here already,
as we expect that we might use it in combination with the divergence operator more frequently. What those vectors are and represent we will discuss in %insert velocity reference here
as we expect that we might use it in combination with the divergence operator more frequently. What those vectors are and represent we will discuss in \autoref{sec:momentum}.
\begin{algorithm}[!hbt]
\SetKwInOut{Input}{Input}

View File

@ -0,0 +1,269 @@
\section{Air Velocity}
Did you ever feel the wind blow? Most probably. That's what we will be calculating here. How hard the wind will blow. This is noted as velocity, how fast something moves.
\subsection{Equation of State and the Incompressible Atmosphere}
The equation of state relates one or more variables in a dynamical system (like the atmosphere) to another. The most common equation of state in the atmosphere is the ideal gas equation as
described by \autoref{eq:ideal gas} \cite{idealGas}. The symbols in that equation represent:
\begin{itemize}
\item $p$: The gas pressure ($Pa$).
\item $V$: The volume of the gas ($m^3$).
\item $n$: The amount of moles\footnote{Mole is the amount of particles ($6.02214076 \cdot 10^{23}$) in a substance, where the average weight of one mole of particles in grams is about the
same as the weight of one particle in atomic mass units ($u$)\cite{mole}} in the gas.
\item $R$: The Gas constant, $8.3144621$ ($J(mol)^{-1}K$) \cite{idealGas}.
\item $T$: The temperature opf the gas ($K$).
\end{itemize}
If we divide everything in \autoref{eq:ideal gas} by $V$ and set it to be unit (in this case, set it to be exactly $1 m^3$) we can add in the molar mass in both the top and bottom parts of the
division as show in \autoref{eq:gas unit}. We can then replace $\frac{nm}{V}$ by $\rho$ the density of the gas ($kgm^{-3}$) and $\frac{R}{m}$ by $R_s$ the specific gas constant (gas constant that varies per
gas in $J(mol)^{-1}K$) as shown in \autoref{eq:state gas}. the resulting equation is the equation of state that you get that most atmospheric physicists use when talking about the atmosphere \cite{simon}.
\begin{subequations}
\begin{equation}
pV = nRT
\label{eq:ideal gas}
\end{equation}
\begin{equation}
p = \frac{nR}{V}T = \frac{nmR}{Vm}T
\label{eq:gas unit}
\end{equation}
\begin{equation}
p = \rho R_sT
\label{eq:state gas}
\end{equation}
\end{subequations}
The pressure is quite important, as air moves from a high pressure point to a low pressure point. So if we know the density and the temperature, then we know the pressure and we can work out
where the air will be moving to (i.e. how the wind will blow). In our current model, we know the atmospheric temperature but we do not know the density. For simplicities sake, we will now assume
that the atmosphere is Incompressible, meaning that we have a constant density. Obviously we know that air can be compressed and hence our atmosphere can be compressed too but that is not
important enough to account for yet, especially considering the current complexity of our model.
The code that corresponds to this is quite simple, the only change that we need to make in \autoref{eq:state gas} is that we need to replace $T$ by $T_a$, the temperature of the atmosphere. As
$T_a$ is a matrix (known to programmers as a double array), $p$ will be a matrix as well. Now we only need to fill in some values. $\rho = 1.2$\cite{densityAir}, $R_s = 287$\cite{specificGasConstantAir}.
\subsection{The Primitive Equations and Geostrophy}
\textbf{NOTE:} This whole subsection is obsolete. We have replaced these calculations with \autoref{sec:momentum}. The folloing subsection is left in for historical value, and maybe for a simpler
calculation if you want your own model to do less heavy calculations. This is where the previously mentioned master file strucutre comes in. You can create a new file with the following
calculations and replace the call that you would make to \autoref{sec:momentum} with a call to the algorithm listed in this subsection. Your choice, though the model Simon has made opted to use
the more complicated calculations. So here are the original calculations and if you want an up to date overview of the calculations please have a look at \autoref{sec:momentum}.
The primitive equations (also known as the momentum equations) is what makes the air move. It is actually kind of an injoke between physicists as they are called the primitive equations but
actually look quite complicated (and it says $fu$ at the end! \cite{simon}). The primitive equations are a set of equations dictating the direction in the $u$ and $v$ directions as shown in
\autoref{eq:primitive u} and \autoref{eq:primitive v}. We can make the equations simpler by using and approximation called geostrophy which means that we have no vertical motion, such that the
terms with $\omega$ in \autoref{eq:primitive u} and \autoref{eq:primitive v} become 0. We also assume that we are in a steady state, i.e. there is no acceleration which in turn means that the
whole middle part of the equations are $0$. Hence we are left with \autoref{eq:primitive u final} and \autoref{eq:primitive v final}.
\begin{subequations}
\begin{equation}
\frac{du}{dt} = \frac{\delta u}{\delta t} + u\frac{\delta u}{ \delta x} + v\frac{\delta u}{\delta v} + \omega\frac{\delta u}{\delta p} = -\frac{\delta \Phi}{\delta x} + fv
\label{eq:primitive u}
\end{equation}
\begin{equation}
\frac{dv}{dt} = \frac{\delta v}{\delta t} + u\frac{\delta v}{ \delta x} + v\frac{\delta v}{\delta v} + \omega\frac{\delta v}{\delta p} = -\frac{\delta \Phi}{\delta y} - fu
\label{eq:primitive v}
\end{equation}
\begin{equation}
0 = -\frac{\delta \Phi}{\delta x} + fv
\label{eq:primitive u final}
\end{equation}
\begin{equation}
0 = -\frac{\delta \Phi}{\delta y} - fu
\label{eq:primitive v final}
\end{equation}
\end{subequations}
\autoref{eq:primitive u final} can be split up into to parts, the $\frac{\delta \Phi}{\delta x}$ part (the gradient force) and the $fv$ part (the coriolis force). The same applies to
\autoref{eq:primitive v final}. Effectively we have a balance between the gradient and the coriolis force as shown in \autoref{eq:pu simple} and \autoref{eq:pv simple}. The symbols in both of
these equations are:
\begin{itemize}
\item $\Phi$: The geopotential, potential (more explanation in \autoref{sec:potential}) of the planet's gravity field ($Jkg^{-1}$).
\item $x$: The change in the East direction along the planet surface ($m$).
\item $y$: The change in the North direction along the planet surface ($m$).
\item $f$: The coriolis parameter as described by \autoref{eq:coriolis}, where $\Omega$ is the rotation rate of the planet (for Earth $7.2921 \cdot 10^{-5}$) ($rad \ s^{-1}$) and $\theta$ is the
latitude \cite{coriolis}.
\item $u$: The velocity in the latitude ($ms^{-1}$).
\item $v$: The velocity in the longitude ($ms^{-1}$).
\end{itemize}
\begin{subequations}
\begin{equation}
f = 2\Omega\sin(\theta)
\label{eq:coriolis}
\end{equation}
\begin{equation}
\frac{\delta \Phi}{\delta x} = fv
\label{eq:pu simple}
\end{equation}
\begin{equation}
\frac{\delta \Phi}{\delta y} = -fu
\label{eq:pv simple}
\end{equation}
\begin{equation}
\frac{\delta p}{\rho \delta x} = fv
\label{eq:pu simple final}
\end{equation}
\begin{equation}
\frac{\delta p}{\rho \delta y} = -fu
\label{eq:pv simple final}
\end{equation}
\end{subequations}
Since we want to know how the atmosphere moves, we want to get the v and u components of the velocity vector (since $v$ and $u$ are the veolicites in longitude and latitude, if we combine them
in a vector we get the direction of the overall velocity). So it is time to start coding and calculating! If we look back at \autoref{alg:stream1v2}, we can see that we already have a double
for loop. In computer science, having multiple loops is generally considered a bad coding practice as you usually can just reuse the indices of the already existing loop, so you do not need to
create a new one. However this is a special case, since we are calculating new temperatures in the double for loop. If we then also would start to calculate the velocities then we would use new
information and old information at the same time. Since at index $i - 1$ the new temperature has already been calculated, but at the index $i + 1$ the old one is still there. So in order to fix
that we need a second double for loop to ensure that we always use the new temperatures. We display this specific loop in \autoref{alg:stream2}. Do note that everything in \autoref{alg:stream1v2}
is still defined and can still be used, but since we want to focus on the new code, we leave out the old code to keep it concise and to prevent clutter.
\begin{algorithm}[hbt]
\SetAlgoLined
\For{$lat \in [-nlat, nlat]$}{
\For{$lon \in [0, nlon]$}{
$u[lat, lon] \leftarrow -\frac{p[lat + 1, lon] - p[lat - 1, lon]}{\delta y} \cdot \frac{1}{f[lat]\rho}$ \;
$v[lat, lon] \leftarrow \frac{p[lat, lon + 1] - p[lat, lon - 1]}{\delta x[lat]} \cdot \frac{1}{f[lat]\rho}$ \;
}
}
\caption{The main loop of the velocity of the atmosphere calculations}
\label{alg:stream2}
\end{algorithm}
The gradient calculation is done in \autoref{alg:gradient}. For this to work, we need the circumference of the planet. Herefore we need to assume that the planet is a sphere. While that is not
technically true, it makes little difference in practice and is good enough for our model. The equation for the circumference can be found in \autoref{eq:circumference} \cite{circumference},
where $r$ is the radius of the planet. Here we also use the f-plane approximation, where the coriolis paramter has one value for the northern hemisphere and one value for the southern hemisphere
\cite{fplane}.
\begin{equation}
2 \pi r
\label{eq:circumference}
\end{equation}
\begin{algorithm}
\SetAlgoLined
$C \leftarrow 2\pi R$ \;
$\delta y \leftarrow \frac{C}{nlat}$ \;
\For{$lat \in [-nlat, nlat]$}{
$\delta x[lat] \leftarrow \delta y \cos(lat \cdot \frac{\pi}{180})$ \;
\eIf{$lat < 0$}{
$f[lat] \leftarrow -10^{-4}$ \;
}{
$f[lat] \leftarrow 10^{-4}$ \;
}
}
\caption{Calculating the gradient $\delta x$ (note that this algorithm is obsolete)}
\label{alg:gradient}
\end{algorithm}
Because of the geometry of the planet and the construction of the longitude latitude grid, we run into some problems when calculating the gradient. Since the planet is not flat ("controversial
I know"\cite{simon}) whenever we reach the end of the longitude we need to loop around to get to the right spot to calculate the gradients (as the planet does not stop at the end of the
longitude line but loops around). So to fix that we use the modulus (mod) function which does the looping for us if we exceed the grid's boundaries. We do haveanother problem though, the poles.
As the latitude grows closer to the poles, they are converging on the center point of the pole. Looping around there is much more difficult so to fix it, we just do not consider that center
point in the main loop. The changed algorithm can be found in \autoref{alg:stream2v2}
\begin{algorithm}[hbt]
\SetAlgoLined
\For{$lat \in [-nlat + 1, nlat - 1]$}{
\For{$lon \in [0, nlon]$}{
$u[lat, lon] \leftarrow -\frac{p[(lat + 1) \text{ mod } nlat, lon] - p[(lat -1) \text{ mod } nlat, lon]}{\delta y} \cdot \frac{1}{f[lat]\rho}$ \;
$v[lat, lon] \leftarrow \frac{p[lat, (lon + 1) \text{ mod } nlon] - p[lat, (lon -1) \text{ mod } nlon]}{\delta x[lat]} \cdot \frac{1}{f[lat]\rho}$ \;
}
}
\caption{The main loop of the velocity of the atmosphere calculations}
\label{alg:stream2v2}
\end{algorithm}
Do note that the pressure calculation is done between the temperature calculation in \autoref{alg:stream1v2} and the $u, v$ calculations in \autoref{alg:stream2v2}. At this point our model shows
a symmetric vortex around the sun that moves with the sun. This is not very realistic as you usually have convection and air flowing from warm to cold, but we do not have that complexity yet
(due to our single layer atmosphere).
\subsection{The Momentum Equations} \label{sec:momentum}
The momentum equations are a set of equations that describe the flow of a fluid on the surface of a rotating body. For our model we will use the f-plane approximation. The equations corresponding
to the f-plane approximation are given in \autoref{eq:x momentum} and \autoref{eq:y momentum} \cite{momentumeqs}. Note that we are ignoring vertical movement, as this does not have a significant
effect on the whole flow. All the symbols in \autoref{eq:x momentum} and \autoref{eq:y momentum} mean:
\begin{itemize}
\item $u$: The east to west velocity ($ms^{-1}$).
\item $t$: The time ($s$).
\item $f$: The coriolis parameter as in \autoref{eq:coriolis}.
\item $v$: The north to south velocity ($ms^{-1}$).
\item $\rho$: The density of the atmosphere ($kgm^{-3}$).
\item $p$: The atmospheric pressure ($Pa$).
\item $x$: The local longitude coordinate ($m$).
\item $y$: The local latitude coordinate ($m$).
\end{itemize}
If we then define a vector $\bar{u}$ as $(u, v, 0)$, we can rewrite both \autoref{eq:x momentum} as \autoref{eq:x momentum laplace}. Here $\nabla u$ is the gradient of
$u$ in both $x$ and $y$ directions. Then if we write out $\nabla u$ we get \autoref{eq:x momentum final}. Similarly, if we want to get $\delta v$ instead of $\delta u$ we rewrite
\autoref{eq:y momentum} to get \autoref{eq:y momentum laplace} and \autoref{eq:y momentum final}.
\begin{subequations}
\begin{equation}
\frac{Du}{Dt} - fv = -\frac{1}{\rho} \frac{\delta p}{\delta x}
\label{eq:x momentum}
\end{equation}
\begin{equation}
\frac{Dv}{Dt} - fu = -\frac{1}{\rho} \frac{\delta p}{\delta y}
\label{eq:y momentum}
\end{equation}
\begin{equation}
\frac{\delta u}{\delta t} + \bar{u} \cdot \nabla u - fv = -\frac{1}{\rho}\frac{\delta p}{\delta x}
\label{eq:x momentum laplace}
\end{equation}
\begin{equation}
\frac{\delta v}{\delta t} + \bar{u} \cdot \nabla v - fu = -\frac{1}{\rho}\frac{\delta p}{\delta y}
\label{eq:y momentum laplace}
\end{equation}
\begin{equation}
\frac{\delta u}{\delta t} + u\frac{\delta u}{\delta x} + v\frac{\delta u}{\delta y} - fv = -\frac{1}{\rho}\frac{\delta p}{\delta x}
\label{eq:x momentum final}
\end{equation}
\begin{equation}
\frac{\delta v}{\delta t} + u\frac{\delta v}{\delta x} + v\frac{\delta v}{\delta y} - fu = -\frac{1}{\rho}\frac{\delta p}{\delta y}
\label{eq:y momentum final}
\end{equation}
\end{subequations}
With the gradient functions defined in \autoref{alg:gradient x} and \autoref{alg:gradient y}, we can move on to the main code for the momentum equations. The main loop is shown in
\autoref{alg:stream3}. Do note that this loop replaces the one in \autoref{alg:stream2v2} as these calculate the same thing, but the new algorithm does it better.
\begin{algorithm}
$S_{xu} \leftarrow \texttt{gradient\_x}(u, lan, lon)$ \;
$S_{yu} \leftarrow \texttt{gradient\_y}(u, lan, lon)$ \;
$S_{xv} \leftarrow \texttt{gradient\_x}(v, lan, lon)$ \;
$S_{yv} \leftarrow \texttt{gradient\_y}(v, lan, lon)$ \;
$S_{px} \leftarrow \texttt{gradient\_x}(p, lan, lon)$ \;
$S_{py} \leftarrow \texttt{gradient\_x}(p, lan, lon)$ \;
\While{\texttt{TRUE}}{
\For{$lat \in [1, nlat - 1]$}{
\For{$lon \in [0, nlon]$}{
$u[lan, lon] \leftarrow u[lan, lon] + \delta t \frac{-u[lan, lon]S_{xu} - v[lan, lon]S_{yu} + f[lan]v[lan, lon] - S_{px}}{\rho}$ \;
$v[lan, lon] \leftarrow v[lan, lon] + \delta t\frac{-u[lan, lon]S_{xv} - v[lan, lon]S_{yv} - f[lan]u[lan, lon] - S_{py}}{\rho}$ \;
}
}
}
\caption{Calculating the flow of the atmosphere (wind)}
\label{alg:stream3}
\end{algorithm}
\subsection{Improving the Coriolis Parameter}
Another change introduced is in the coriolis parameter. Up until now it has been a constant, however we know that it varies along the latitude. So let's make it vary over the latitude. Recall
\autoref{eq:coriolis}, where $\Theta$ is the latitude. Coriolis ($f$) is currently defined in \autoref{alg:gradient}, so let's replace it with \autoref{alg:coriolis}.
\begin{algorithm}
\SetAlgoLined
$\Omega \leftarrow 7.2921 \cdot 10^{-5}$ \;
\For{$lat \in [-nlat, nlat]$}{
$f[lat] \leftarrow 2\Omega \sin(lat \frac{\pi}{180})$ \;
}
\caption{Calculating the coriolis force}
\label{alg:coriolis}
\end{algorithm}
\subsection{Adding Friction}
In order to simulate friction, we multiply the speeds $u$ and $v$ by $0.99$. Of course there are equations for friction but that gets complicated very fast, so instead we just assume that we
have a constant friction factor. This multiplication is done directly after \autoref{alg:stream3} in \autoref{alg:stream4v1}.