sandbox/haouche/Hydrodynamic_instabilities/rayleigh-taylor.c
Rayleigh–Taylor Simulation Code
In this section, I present the code used to simulate the
Rayleigh–Taylor instability.
For a step-by-step explanation, feel free to watch my video tutorial:
[link here].
We start by including the necessary libraries:
#include "navier-stokes/centered.h"
#include "two-phase.h"
#include "tension.h"
#include "output_vtu.h"We define the dimensionless numbers of the problem:
- Bond number Bo = \frac{\rho_l g L^2}{\gamma}, which compares gravitational forces to surface tension forces;
- Ohnesorge number Oh = \frac{\mu_l}{\sqrt{\rho_l \gamma L}}, which quantifies the relative importance of viscous forces compared to inertial and capillary effects;
- Density ratio \rho_r = \frac{\rho_1}{\rho_2};
- Viscosity ratio \mu_r = \frac{\mu_1}{\mu_2}.
We also set the wavenumber k, the initial amplitude a_0, and the reference length L.
#define RHOR 0.1383
#define MUR 1.
#define Oh 0.05
#define Bo 100.
#define kk (2.*pi)
#define a0 0.05
#define L 1.We specify the maximum level of mesh refinement, the size of the domain, and the final simulation time.
int LEVEL = 9;
double SIZE_BOX = 4.;
double FINAL_TIME = 5.;In the main() function, we initialize the domain size (a
square domain of side SIZE_BOX), the initial grid
resolution 2^6 = 64, and the physical
parameters: densities, viscosities, and surface tension.
We then call run() to launch the simulation.
int main() {
size(SIZE_BOX);
init_grid(1 << 6);
rho1 = 1.;
rho2 = RHOR;
mu1 = Oh * sqrt(rho1 * L / Bo);
mu2 = mu1 * MUR;
f.sigma = 1./Bo;
system("mkdir -p dumpfile");
run();
}We now define the initial condition. The interface is initialized according to: \eta\big(x,\,t\big)=a_0\cos\big(kx\big) and placed in the middle of the box: F(x, y, t=0) = y - \bigg(\frac{\mathrm{SIZE\_BOX}}{2} + a_0 \cos(kx)\bigg) We also use a mask to change the geometry: instead of a square, we simulate a rectangular domain.
event init (i = 0) {
mask(x > L ? right : none);
if (!restore (file = "restart")) {
refine (y - (1.5*(SIZE_BOX/2. + a0*cos(kk*(x)))) < 0 && level < LEVEL);
fraction (f, (y) - (SIZE_BOX/2. + a0*cos(kk*(x))));
}
}Gravity is applied using an acceleration event.
Alternatively, you could use #include "reduced.h" to
implicitly include gravity via the pressure gradient.
event acceleration(i++) {
face vector av = a;
foreach_face(y)
av.y[] += -1.;
boundary ((scalar *){av});
}We use adapt_wavelet() to dynamically adapt the mesh
during the simulation.
Here, we define error tolerances for the volume fraction and the
velocity components to improve numerical accuracy.
event adapt(i++) {
double femax = 0.001, uxemax = 0.01, uyemax = 0.01;
adapt_wavelet({f, u}, (double[]){femax, uxemax, uyemax}, LEVEL);
}This event is optional. It simply prints runtime information to track the simulation progress.
Finally, this event handles data output using
output_vtu_bin_foreach(),
which saves the volume fraction f, the
pressure p, and the velocity field
\mathbf{u} in .vtu format,
every 0.01 time units.
int pt = 0;
event interface(t += 0.01; t <= FINAL_TIME) {
char name2[80];
sprintf(name2, "dumpfile/snap-%d.vtu", pt);
FILE *ptr2 = fopen(name2,"w");
output_vtu_bin_foreach((scalar *) {f, p}, (vector *) {u}, ptr2, false);
fclose(ptr2);
pt++;
}
