summaryrefslogtreecommitdiffstats
path: root/hacks/euler2d.tex
diff options
context:
space:
mode:
Diffstat (limited to 'hacks/euler2d.tex')
-rw-r--r--hacks/euler2d.tex337
1 files changed, 337 insertions, 0 deletions
diff --git a/hacks/euler2d.tex b/hacks/euler2d.tex
new file mode 100644
index 0000000..700ad31
--- /dev/null
+++ b/hacks/euler2d.tex
@@ -0,0 +1,337 @@
+\documentclass[12pt]{article}
+
+%\usepackage{fullpage}
+\usepackage{amsmath,amssymb}
+
+\begin{document}
+
+\title{Two Dimensional Euler Simulation}
+
+\author{
+S.J. Montgomery-Smith\\
+Department of Mathematics\\
+University of Missouri\\
+Columbia, MO 65211, U.S.A.\\
+stephen@math.missouri.edu\\
+http://www.math.missouri.edu/\~{}stephen}
+
+\date{September 10, 2000}
+
+\maketitle
+
+This document describes a program I wrote to simulate the
+two dimensional Euler Equation --- a program that is part
+of the {\tt xlock} screensaver as the {\tt euler2d}
+mode. A similar explanation may also be found in the
+book by Chorin \cite{C}.
+
+\section{The Euler Equation}
+
+The Euler Equation describes the motion of an incompressible
+fluid that has no viscosity. If the fluid is contained
+in a domain $\Omega$ with boundary $\partial \Omega$, then
+the equation is in the vector field $u$ (the velocity)
+and the
+scalar field $p$ (the pressure):
+\begin{eqnarray*}
+\frac{\partial}{\partial t} u &=& -u \cdot \nabla u + \nabla p \\
+\nabla \cdot u &=& 0 \\
+u \cdot n &=& 0 \quad \text{on $\partial \Omega$}
+\end{eqnarray*}
+where $n$ is the unit normal to $\partial \Omega$.
+
+\section{Vorticity}
+
+It turns out that it can be easier write these equations
+in terms of the vorticity. In two dimensions the vorticity
+is the scalar $w = \partial u_2/\partial x - \partial u_1/\partial y$.
+The equation for vorticity becomes
+\[ \frac{\partial}{\partial t} w = -u \cdot \nabla w .\]
+A solution to this equation can be written as follows. The velocity
+$u$ causes a flow, that is, a function $\varphi(t,x)$ that tells where
+the particle initially at $x$ ends up at time $t$, that is
+\[
+\frac\partial{\partial t} \varphi(t,x)
+= u(t,\varphi(t,x)) .\]
+Then the equation
+for $w$ tells us that the vorticity is ``pushed'' around by the flow,
+that is, $w(t,\varphi(t,x)) = w(0,x)$.
+
+\section{The Biot-Savart Kernel}
+
+Now, once we have the vorticity, we can recover the velocity $u$ by
+solving the equation
+\begin{eqnarray*}
+\partial u_2/\partial x - \partial u_1/\partial y &=& w \\
+\nabla \cdot u &=& 0 \\
+u \cdot n &=& 0 \quad \text{on $\partial \Omega$}.
+\end{eqnarray*}
+This equation is solved by using a Biot-Savart kernel $K(x,y)$:
+$$ u(x) = \int_\Omega K(x,y) w(y) \, dy .$$
+The function $K$ depends upon the choice of domain. First let us consider
+the case when $\Omega$ is the whole plane (in which case the boundary
+condition $u \cdot n = 0$ is replaced by saying that $u$ decays at infinity).
+Then
+\begin{equation*}
+K(x,y) = K_1(x,y) = c \frac{(x-y)^\perp}{|x-y|^2} .
+\end{equation*}
+Here $x^\perp = (-x_2,x_1)$, and $c$ is a constant, probably something
+like $1/2\pi$. In any case we will set it to be one, which in effect
+is rescaling the time variable, so we don't need to worry about it.
+
+We can use this as a basis to find $K$ on the unit disk
+$\Omega = \Delta = \{x:|x|<1\}$. It turns out to be
+\begin{equation*}
+K_2(x,y) = K_1(x,y) - K_1(x,y^*) ,
+\end{equation*}
+where $y^* = y/|y|^2$ is called the reflection of $y$ about the
+boundary of the unit disk.
+
+Another example is if we have a bijective analytic function
+$p:\Delta \to {\mathbb C}$, and we let $\Omega = p(\Delta)$.
+(Here we think of $\Delta$ as a subset of $\mathbb C$, that is,
+we are identifying the plane with the set of complex numbers.)
+In that case we get
+\[ K_p(p(x),p(y)) = K_2(x,y)/|p'(x)|^2 .\]
+Our simulation considers the last case. Examples of such
+analytic functions include series
+$p(x) = x + \sum_{n=2}^\infty c_n x^n$, where
+$\sum_{n=2}^\infty n |c_n| \le 1$.
+(Thanks to David Ullrich for pointing this out to me.)
+
+\section{The Simulation}
+
+Now let's get to decribing the simulation. We assume a rather
+unusual initial distribution for the vorticity --- that the
+vorticity is a finite sum of dirac delta masses.
+\[ w(0,x) = \sum_{k=1}^N w_k \delta(x-x_k(0)) .\]
+Here $x_k(0)$ is the initial place where the points
+of vorticity are concentrated, with values $w_k$.
+Then at time $t$, the vorticity becomes
+\[ w(t,x) = \sum_{k=1}^N w_k \delta(x-x_k(t)) .\]
+The points of fluid $x_k(t)$ are pushed by the
+flow, that is, $x_k(t) = \varphi(t,x_k(0))$, or
+\[ \frac{\partial}{\partial t} x_k(t) = u(t,x_k(t)) .\]
+Putting this all together, we finally obtain the equations
+\[ \frac{\partial}{\partial t} x_k = \alpha_k \]
+where
+\[ \alpha_k = \sum_{l=1}^N w_l K(x_k,x_l) .\]
+This is the equation that our simulation solves.
+
+In fact, in our case, where the domain is $p(\Delta)$,
+the points are described by points
+$\tilde x_k$, where $x_k = p(\tilde x_k)$. Then
+the equations become
+\begin{eqnarray}
+\label{tildex-p1}
+\frac{\partial}{\partial t} \tilde x_k &=& \tilde\alpha_k \\
+\label{tildex-p2}
+\tilde\alpha_k &=& \frac1{|p'(\tilde x_k)|^2}
+ \sum_{l=1}^N w_l K_2(\tilde x_k,\tilde x_l) .
+\end{eqnarray}
+
+We solve this $2N$ system of equations using standard
+numerical methods, in our case, using the second order midpoint method
+for the first step, and thereafter using the second order Adams-Bashforth
+method. (See for example the book
+by Burden and Faires \cite{BF}).
+
+\section{The Program - Data Structures}
+
+The computer program solves equation (\ref{tildex-p1}), and displays
+the results on the screen, with a boundary. All the information
+for solving the equation and displaying the output is countained
+in the structure {\tt euler2dstruct}. Let us describe some of
+the fields in {\tt euler2dstruct}.
+The points $\tilde x_k$ are contained
+in {\tt double *x}: with the coordinates of
+$\tilde x_k$ being the two numbers
+{\tt x[2*k+0]}, {\tt x[2*k+1]}. The values $w_k$ are contained
+in {\tt double *w}. The total number of points is
+{\tt int N}. (But only the first {\tt int Nvortex} points
+have $w_k \ne 0$.) The coefficients of the analytic function
+(in our case a polynomial) $p$
+are contained in {\tt double p\_coef[2*(deg\_p-1)]} --- here
+{\tt deg\_p} is the degree of $p$, and the real and imaginary
+parts of the coefficient
+$c_n$ is contained in {\tt p\_coef[2*(n-2)+0]} and {\tt p\_coef[2*(n-2)+1]}.
+
+\section{Data Initialization}
+
+The program starts in the function {\tt init\_euler2d}. After allocating
+the memory for the data, and initialising some of the temporary variables
+required for the numerical solving program, it randomly assigns the
+coefficients of $p$, making sure that $\sum_{n=2}^{\tt deg\_p} n |c_n| = 1$.
+Then the program figures out how to draw the boundary, and what rescaling
+of the data is required to draw it on the screen. (This uses the
+function {\tt calc\_p} which calculates $p(x)$.)
+
+Next, it randomly assigns the initial values of $\tilde x_k$. We want
+to do this in such a way so that the points are uniformly spread over the
+domain. Let us first consider the case when the domain is the unit circle
+$\Delta$. In that case the proportion of points that we would expect
+inside the circle of radius $r$ would be proportional to $r^2$. So
+we do it as follows:
+\[ r = \sqrt{R_{0,1}},\quad \theta = R_{-\pi,\pi}, \quad
+ \tilde x_k = r (\cos \theta, \sin \theta) .\]
+Here, and in the rest of this discussion, $R_{a,b}$ is a function
+that returns a random variable uniformly distributed over the interval
+$[a,b]$.
+
+This works fine for $\Delta$, but for $p(\Delta)$, the points
+$p(\tilde x_k)$ are not uniformly distributed over $p(\Delta)$,
+but are distributed with a density proportional to
+$1/|p'(\tilde x_k)|^2$. So to restore the uniform density we need
+to reject this value of $\tilde x_k$ with probability proportional
+to $|p'(\tilde x_k)|^2$. Noticing that the condition
+$\sum_{n=2}^{\tt deg\_p} n |c_n| = 1$ implies that
+$|p'(\tilde x_k)| \le 2$, we
+do this by rejecting if $|p'(\tilde x_k)|^2 < R_{0,4}$.
+(This makes use of the function {\tt calc\_mod\_dp2} which calculates
+$|p'(x)|^2$.)
+
+\section{Solving the Equation}
+
+The main loop of the program is in the function {\tt draw\_euler2d}.
+Most of the drawing operations are contained in this function, and
+the numerical aspects are sent to the function {\tt ode\_solve}.
+But there is an aspect of this that I would like
+to discuss in the next section, and so we will look at a simple method for
+numerically solving differential equations.
+
+The Euler Method
+(nothing to do with the Euler Equation), is as
+follows. Pick a small number $h$ --- the time step (in
+the program call {\tt delta\_t}). Then we approximate
+the solution of the equation:
+\begin{equation}
+\label{method-simple}
+\tilde x_k(t+h) = \tilde x_k(t) + h \tilde\alpha_k(t) .
+\end{equation}
+The more sophisticated methods we use are variations of
+the Euler Method, and so the discussion in the following section
+still applies.
+
+In the program, the quantities $\tilde\alpha_k$, given by
+equations (\ref{tildex-p2}) are calculated by the function
+{\tt derivs}
+(which in turns calls {\tt calc\_all\_mod\_dp2} to
+calculate $|p'(\tilde x_k)|^2$ at all the points).
+
+
+\section{Subtle Perturbation}
+
+Added later: the scheme described here seems to not be that effective,
+so now it is not used.
+
+One problem using a numerical scheme such as the Euler Method occurs
+when the points $\tilde x_k$ get close to the boundary
+of $\Delta$. In that case, it is possible that the new
+points will be pushed outside of the boundary. Even if they
+are not pushed out of the boundary, they may be much closer
+or farther from the boundary than they should be.
+Our system of equations is very sensitive to how close points
+are to the boundary --- points with non-zero vorticity
+(``vortex points'') that are close to the boundary travel
+at great speed alongside the boundary, with speed that is
+inversely proportional to the distance from the boundary.
+
+A way to try to mitigate this problem is something that I call
+``subtle perturbation.''
+We map the points in
+the unit disk to points in the plane using the map
+\begin{equation*}
+F(x) = f(|x|) \frac x{|x|} ,
+\end{equation*}
+where $f:[0,1]\to[0,\infty]$ is an increasing continuous
+bijection. It turns out that a good choice is
+\begin{equation*}
+f(t) = -\log(1-t) .
+\end{equation*}
+(The reason for this is that points close to each other
+that are a distance
+about $r$ from the boundary will be pushed around so that
+their distance from each other is about multiplied by the
+derivative of $\log r$, that is, $1/r$.)
+Note that the inverse of this function is given by
+\begin{equation*}
+F^{-1}(x) = f^{-1}(|x|) \frac x{|x|} ,
+\end{equation*}
+where
+\begin{equation*}
+f^{-1}(t) = 1-e^{-t} .
+\end{equation*}
+
+So what we could do is the following: instead of working with
+the points $\tilde x_k$, we could work instead with the points
+$y_k = F(\tilde x_k)$. In effect this is what we do.
+Instead of performing the computation (\ref{method-simple}),
+we do the calculation
+\begin{equation*}
+y_k = F(\tilde x_k(t)) + h {\cal A}(\tilde x_k) \tilde\alpha_k(t)
+\end{equation*}
+where
+${\cal A}(x)$ is the matrix of partial derivatives of $F$:
+\begin{equation*}
+{\cal A}(x) =
+\frac{f(|x|)}{|x|}
+\left[
+\begin{matrix}
+1 & 0\\
+0 & 1
+\end{matrix}
+\right]
++ \frac1{|x|}
+ \left(\frac{f'(|x|)}{|x|} - \frac{f(|x|)}{|x|^2}\right)
+\left[
+\begin{matrix}
+x_{1}^2 & x_{1} x_{2}\\
+x_{1} x_{2} & x_{2}^2
+\end{matrix}
+\right],
+\end{equation*}
+and then compute
+\begin{equation*}
+\tilde x_k(t+h) = F^{-1}(y_k).
+\end{equation*}
+These calculations are done in the function {\tt perturb}, if
+the quantity {\tt SUBTLE\_PERTURB} is set.
+
+\section{Drawing the Points}
+
+As we stated earlier, most of the drawing functions are contained
+in the function {\tt draw\_euler2d}. If the variable
+{\tt hide\_vortex} is set (and the function {\tt init\_euler2d}
+will set this with probability $3/4$), then we only display
+the points $\tilde x_k$ for ${\tt Nvortex} < k \le N$. If
+{\tt hide\_vortex} is not set, then the ``vortex points''
+$\tilde x_k$ ($1 \le k \le {\tt Nvortex}$) are displayed in white.
+In fact the points $p(\tilde x_k)$ are what are put onto the screen,
+and for this we make use of the function {\tt calc\_all\_p}.
+
+\section{Addition to Program: Changing the Power Law}
+
+A later addition to the program adds an option {\tt eulerpower},
+which allows one to change the power law that describes how
+the vortex points influence other points. In effect, if this
+option is set with the value $m$, then the Biot-Savart Kernel
+is replace by
+$$ K_1(x,y) = \frac{(x-y)^\perp}{|x-y|^{m+1}}, $$
+and
+$$ K_2(x,y) = K_1(x,y) - |y|^{1-m} K_1(x,y) .$$
+So for example, setting $m=2$ corresponds to the
+quasi-geostrophic equation. (I haven't yet figured out
+what $K_p$ should be, so if $m \ne 1$ we use the unit circle
+as the boundary.)
+
+\begin{thebibliography}{9}
+
+\bibitem{BF} Richard L. Burden, J. Douglas Faires, Numerical Analysis,
+sixth edition, Brooks/Cole, 1996.
+
+\bibitem{C} Alexandre J. Chorin, Vorticity and Turbulence,
+Applied Mathematical Sciences, Vol 103, Springer Verlag, 1994.
+
+\end{thebibliography}
+
+\end{document}