Jeroen WoutersPersonal website of Jeroen Wouters.
http://www.diasporist.org/jeroen/
New PNAS paper on climatic rare event simulation<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<p>Extreme heat waves can have devastating impacts. For the 2003 and 2010 European heat waves, estimates of additional deaths are 70 000 and 50 000, respectively. Additionaly, such heat waves cause significant economic and ecological damage. Such events are rare and have no precedent, so we cannot use observations to estimate the expected time between two such events. We have to use complex state-of-the-art climate models.</p>
<p>Unfortunately, such climate model require a very large amount of computer power. Assume that we are interested in very rare heat waves that only occur about once in a thousand years. To get a decent sample of such heat waves, we would need perhaps 100 samples. That means we would have to run our climate model for a hundred thousand years. Such long simulations are currently not possible.</p>
<p>Luckily, there exist algorithms that can speed things up and make the impossible possible. Such algorithms are know as <a href="https://en.wikipedia.org/wiki/Rare_Event_Sampling">rare event simulation algorithms</a>, see the research section for <a href="/jeroen/research/rare events/#rare-event-simulation">more details</a>. Successfully applying such algorithms to climatic rare events could make a huge impact on how we prepare for possibly catastrophic events.</p>
<p>Together with Francesco Ragone and Freddy Bouchet, we have applied such an algorithm for the first time to a realistic climate model. The results have been published in the Proceedings of the National Academy of Sciences (PNAS).</p>
<p>Using the output of this algorithm, we are able to study extreme heat waves with unprecedented accuracy. It allows for example to determine the global atmospheric conditions during a European heat wave, demonstrating a new teleconnection pattern, as shown below.</p>
<p><img src="/jeroen/images/Extreme_Teleconnection.png" alt="D2Q9 lbm" /></p>
<p>For more details, see <a href="http://www.pnas.org/content/114/49/12864.abstract">here</a> for the published paper, or <a href="https://arxiv.org/abs/1709.03757">here</a> for the pre-print version.</p>
Wed, 20 Dec 2017 00:00:00 +0100
http://www.diasporist.org/jeroen/math/climate/rare-events/2017/12/20/pnas-paper/
http://www.diasporist.org/jeroen/math/climate/rare-events/2017/12/20/pnas-paper/A demo of rare event simulation<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<p>The probability of a rare event is difficult to estimate in a numerical model. The rarer the event, the longer it takes to obtain a sample of the event we are interested in. Think for example of simulating heat waves in a climate model. We could be interested in very rare heat waves that only occur about once in a thousand years. To get a decent sample of such heat waves, we would need perhaps 100 samples. That means we would have to run our climate model for a hundred thousand years. Such long simulations are currently not possible.</p>
<p>Luckily, there exist algorithms that can speed things up and make the impossible possible. Such algorithms are know as <a href="https://en.wikipedia.org/wiki/Rare_Event_Sampling">rare event simulation algorithms</a>, see the research section for <a href="/jeroen/research/rare events/#rare-event-simulation">more details</a>. Successfully applying such algorithms to climatic rare events could make a huge impact on how we prepare for possibly catastrophic events.</p>
<p>Today I’d like to share some code with you that demonstrates the use of rare event simulation techniques on a simple Ornstein-Uhlenbeck system. With <a href="/jeroen/assets/rare-event-simulation-demo.zip">the code</a> (some Python scripts and a Jupyter notebook), you can see how rare event simulation can accurately estimate very small probabilities.</p>
<p><img src="/jeroen/images/OUdemo.png" alt="D2Q9 lbm" /></p>
<p>For an in-depth discussion of these techniques, see my <a href="https://dx.doi.org/10.1088/1751-8113/49/37/374002">publication</a> with Freddy Bouchet in J Phys A (<a href="https://arxiv.org/abs/1511.02703">preprint</a>).</p>
Thu, 20 Oct 2016 00:00:00 +0200
http://www.diasporist.org/jeroen/math/code/julia/2016/10/20/rare-event-simulation-demo/
http://www.diasporist.org/jeroen/math/code/julia/2016/10/20/rare-event-simulation-demo/Entering Unicode math symbols in GNOME<p>Many mathematicians and physicists are so used to using <a href="https://en.wikipedia.org/wiki/LaTeX">LaTeX</a> that you find LaTeX code in emails and source code comments that scientists then “render” in their head. LaTeX code is not always very readable though and I find it quickly gets distracting as the argument you’re writing down becomes more complex.</p>
<p>Enter <a href="https://en.wikipedia.org/wiki/Unicode">Unicode</a> math symbols. Just as you can represent the letters from almost all alphabets on Earth in Unicode, it also supports tons of <a href="https://en.wikipedia.org/wiki/Unicode#Standardized_subsets">mathematical operators, arrows, symbols etc.</a>. If you insert one of these characters into your favorite Unicode-aware editor, you’ll see the corresponding symbol immediately, without having to compile, as you would need to do with a LaTeX document.</p>
<p>Obviously, there’s no room on your keyboard for all of these symbols. That’s where the <a href="https://en.wikipedia.org/wiki/Intelligent_Input_Bus">ibus</a> input method really comes in handy. Motivated by the need to input characters from complex alphabets using a finite size keyboard, this method can also be used to insert math symbols into regular text documents. This software is installed by default in a standard Fedora installation and you can configure the input methods you want to use in the <a href="https://help.gnome.org/users/gnome-help/unstable/keyboard-layouts.html.en">“Region and Language”</a> section of the System Settings. There’s one math input method that is installed by default in Fedora, called “math-latex”. After you add it to your list of Input Sources, you can switch to this source using the Super+Space keyboard shortcut (the Super key is also known as the “Windows key”). Once it is selected, type on your keyboard “int”, et voila, the symbol “∫” will appear. Since this feature is not really documented, you’ll have to look into the file “/usr/share/m17n/math-latex.mim” to see what commands are supported and which key sequence corresponds to which symbol. Not so convenient.</p>
<p>Next up is the “mathwriter” input source, which improves upon the previous source. It is not installed by default, but can be added by installing the “ibus-table-mathwriter” package. You may need to restart (or execute “ibus restart”) after this in order for the newly installed source to appear in the settings. With mathwriter you can start typing LaTeX commands and it will show you a list of matching symbols as you type. Select the one you want with the cursors and hit the space bar.</p>
<p>Where can you make use of these features? You can use it in XeTeX to make your tex code more readable with the <a href="https://github.com/wspr/unicode-math">unicode-math</a> package, or use it in the excellent <a href="http://rednotebook.sourceforge.net/">rednotebook</a> journal to improve your scientific notes.</p>
Mon, 15 Feb 2016 00:00:00 +0100
http://www.diasporist.org/jeroen/math/gnome/2016/02/15/unicode-math-in-gnome/
http://www.diasporist.org/jeroen/math/gnome/2016/02/15/unicode-math-in-gnome/Lattice Boltzmann Method in Julia<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<p><a href="https://en.wikipedia.org/wiki/Lattice_Boltzmann_methods">Lattice Boltzmann methods</a> form a very popular class of algorithms to numerically integrate approximations to the <a href="https://en.wikipedia.org/wiki/Boltzmann_equation">Boltzmann equations</a> which describes the evolution of the probability density function $f(r,p,t)$. This probability density $f$ tells us how likely it is to find a particle with a given position $r$ and momentum $p$ at time $t$. By the <a href="https://en.wikipedia.org/wiki/Chapman%E2%80%93Enskog_theory">Chapman-Enskog expansion</a>, the famous <a href="https://en.wikipedia.org/wiki/Navier%E2%80%93Stokes_equations">Navier-Stokes equations</a> of fluid dynamics can be derived from these Boltzmann equations.</p>
<p>The evolution of the Boltzmann equation is given by a partial differential equation, which is in principle infinite dimensional and therefore impossible to simulate exactly. A possible way of approximating the equations is to restrict possible positions to a grid and the possible velocities to a finite number of vectors.</p>
<p>Below is a code to perform LBM on a 2 dimensional grid with 9 possible velocities (it is called D2Q9 for this reason). The code was adapted to Julia from a <a href="http://www.exolete.com/lbm/">Matlab code</a> to wich I have also added some extra comments.</p>
<p>The algorithm is performed on a grid of size $(nx, ny)$. The array $F$ holds the probability density function. Its first two indices refer to the position of the node on the grid, while the third index refers one of the 9 possible velocity vectors $e_i$, with counterclockwise counting from the vector $(1,0)$, so $e_1$ is pointing to the right, $e_2$ points to $(1,1)$, $e_3$ points up, etc.</p>
<div class="highlighter-rouge"><pre class="highlight"><code>#*
# configuration
#*
omega = 1.0;
density = 1.0;
fraction = 0.1 # average fraction of occupied nodes
radius = 5.
nx = 64;
ny = 32;
deltaU=1e-7;
#*
# setup of variables
#*
avu=1; prevavu=1;
ts=0;
avus = zeros(Float64, 40000)
# single-particle distribution function
# particle densities conditioned on one of the 9 possible velocities
F = repeat([density/9], outer= [nx, ny, 9]);
FEQ = F;
msize = nx*ny;
CI = [0:msize:msize*7]; # offsets of different directions e_a in the F matrix
function setboundary()
#BOUND = rand(nx,ny) .> 1 - fraction; # random domain
center = [nx/2, ny/2]
global BOUND = [norm([i, j]-center) < radius for i=1:nx, j=1:ny]
global ON = find(BOUND); # matrix offset of each Occupied Node
global numactivenodes=sum(sum(1-BOUND));
# linear indices in F of occupied nodes
global TO_REFLECT=[ON+CI[1] ON+CI[2] ON+CI[3] ON+CI[4] ON+CI[5] ON+CI[6] ON+CI[7] ON+CI[8]];
# Right <-> Left: 1 <-> 5; Up <-> Down: 3 <-> 7
#(1,1) <-> (-1,-1): 2 <-> 6; (1,-1) <-> (-1,1): 4 <-> 8
global REFLECTED= [ON+CI[5] ON+CI[6] ON+CI[7] ON+CI[8] ON+CI[1] ON+CI[2] ON+CI[3] ON+CI[4]];
end
setboundary()
#*
# constants
#*
t1 = 4/9;
t2 = 1/9;
t3 = 1/36;
c_squ = 1/3;
#*
# main loop
#*
tic()
while ((ts<4000) & (1e-10 < abs((prevavu-avu)/avu))) | (ts<100)
#*
# Streaming
#*
# particles at (x,y)=[2,1] were at [1, 1] before: 1 points right (1,0)
F[:,:,1] = F[[nx, 1:nx-1],:,1];
# particles at [1,2] were at [1, 1] before: 3 points up (0,1)
F[:,:,3] = F[:,[ny, 1:ny-1],3];
# particles at [1,1] were at [2, 1] before: 5 points left (-1,0)
F[:,:,5] = F[[2:nx, 1],:,5];
# particles at [1,1] were at [1, 2] before: 7 points down (0,-1)
F[:,:,7] = F[:,[2:ny, 1],7];
# particles at [2,2] were at [1, 1] before: 2 points to (1,1)
F[:,:,2] = F[[nx, 1:nx-1],[ny, 1:ny-1],2];
# particles at [1,2] were at [2, 1] before: 4 points to (-1, 1)
F[:,:,4] = F[[2:nx, 1],[ny, 1:ny-1],4];
# particles at [1,1] were at [2, 2] before: 6 points to (-1, -1)
F[:,:,6] = F[[2:nx, 1],[2:ny, 1],6];
# particles at [2,1] were at [1, 2] before: 8 points down (1,-1)
F[:,:,8] = F[[nx, 1:nx-1],[2:ny, 1],8];
DENSITY = sum(F,3);
# 1,2,8 are moving to the right, 4,5,6 to the left
# 3, 7 and 9 don't move in the x direction
global UX = (sum(F[:,:,[1, 2, 8]],3)-sum(F[:,:,[4, 5, 6]],3))./DENSITY;
# 2,3,4 are moving up, 6,7,8 down
# 1, 5 and 9 don't move in the y direction
global UY = (sum(F[:,:,[2, 3, 4]],3)-sum(F[:,:,[6, 7, 8]],3))./DENSITY;
UX[1,1:ny] = UX[1,1:ny] + deltaU; #Increase inlet pressure
UX[ON] = 0; UY[ON] = 0; DENSITY[ON] = 0;
U_SQU = UX.^2+UY.^2;
U_C2 = UX+UY;
U_C4 = -UX+UY;
U_C6 = -U_C2;
U_C8 = -U_C4;
# Calculate equilibrium distribution: stationary (a = 0)
FEQ[:,:,9] = t1*DENSITY.*(1-U_SQU/(2*c_squ));
# nearest-neighbours
FEQ[:,:,1] = t2*DENSITY.*(1+UX/c_squ+0.5*(UX/c_squ).^2-U_SQU/(2*c_squ));
FEQ[:,:,3] = t2*DENSITY.*(1+UY/c_squ+0.5*(UY/c_squ).^2-U_SQU/(2*c_squ));
FEQ[:,:,5] = t2*DENSITY.*(1-UX/c_squ+0.5*(UX/c_squ).^2-U_SQU/(2*c_squ));
FEQ[:,:,7] = t2*DENSITY.*(1-UY/c_squ+0.5*(UY/c_squ).^2-U_SQU/(2*c_squ));
# next-nearest neighbours
FEQ[:,:,2] = t3*DENSITY.*(1+U_C2/c_squ+0.5*(U_C2/c_squ).^2-U_SQU/(2*c_squ));
FEQ[:,:,4] = t3*DENSITY.*(1+U_C4/c_squ+0.5*(U_C4/c_squ).^2-U_SQU/(2*c_squ));
FEQ[:,:,6] = t3*DENSITY.*(1+U_C6/c_squ+0.5*(U_C6/c_squ).^2-U_SQU/(2*c_squ));
FEQ[:,:,8] = t3*DENSITY.*(1+U_C8/c_squ+0.5*(U_C8/c_squ).^2-U_SQU/(2*c_squ));
BOUNCEDBACK = F[TO_REFLECT]; #Densities bouncing back at next timestep
F = omega*FEQ + (1-omega)*F;
F[REFLECTED] = BOUNCEDBACK;
prevavu = avu;
avu = sum(sum(UX))/numactivenodes;
avus[ts+1] = avu;
ts = ts+1;
end
toc()
</code></pre>
</div>
<p>The result can then be plotted</p>
<div class="highlighter-rouge"><pre class="highlight"><code>using PyPlot
figure();
imshow(1-BOUND', cmap="hot", interpolation="None", vmin=0., vmax=1., origin="lower");
quiver(1:nx-1, 0:ny-1, UX[2:nx,:]', UY[2:nx,:]');
title(string("Flow field after \$ ", string(ts), " \\delta t\$"));
xlabel("x");
ylabel("y");
</code></pre>
</div>
<p><img src="/jeroen/images/d2q9 lbm.png" alt="D2Q9 lbm" /></p>
<p><a href="/jeroen/assets/D2Q9 LBM.ipynb">Download IPython notebook</a></p>
Fri, 17 Jul 2015 00:00:00 +0200
http://www.diasporist.org/jeroen/physics/math/code/julia/2015/07/17/lbm-in-julia/
http://www.diasporist.org/jeroen/physics/math/code/julia/2015/07/17/lbm-in-julia/