sandbox/Antoonvh/lid.c
The Lid-Driven Cavity in 2D
We study the flow in a lid-driven square cavity at different Reynolds numbers. The set-up consists of a square (L \times L) no-slip box with a top lid that forces a flow by moving in the positive x-direction with velocity U. Given a fluid viscosity (\nu), we can define a Reynolds number:
Re=\frac{UL}{\nu}.
Expressed in advection time scales we run the simulation until t_{end}=20 \times L/U.
in particular we are interested in how the computational costs scale with increasing Reynolds number. In the case set-up we use a normalized lengthscale L and lid velocity U.
#include "navier-stokes/centered.h"
scalar omg[],lev[],U[];
int maxlevel,m;
double vis,e,ens,vit,vir,vil,vib;
int main(){
=1.;
L0=Y0=0.; X0
We run the simulation 5 times (only 4 in the sandbox) with an increasing Reynolds number and maximum grid resolution.
for (m=0;m<4;m++){
run();
}
}
The boundary conditions are chosen to be a no-slip box with a top lid that drives the flow.
.t[top]=dirichlet(1.);
u.t[bottom]=dirichlet(0.);
u.n[left]=dirichlet(0.);
u.n[right]=dirichlet(0.);
u.t[left]=dirichlet(0.);
u.t[right]=dirichlet(0.);
u.n[top]=dirichlet(0.);
u.n[bottom]=dirichlet(0.);
u
event init(t=0){
The Reynolds number is directly controlled by the viscosity of the fluid \nu. The Reynolds number and maximum grid resolution are doubled each run iteration, starting with Re=125 and an effective resolution of 64\times64 grid points.
=1./(125.*pow(2.,(double)m));
vis=6+m; maxlevel
The grid is initialized consistent with the adaptation algorithm.
(1<<3);
init_gridconst face vector muc[]={vis,vis};
=muc;
mufprintf(ferr,"Re = %g and max res = %d X %d\n",1/vis,(int)pow(2,maxlevel),(int)pow(2,maxlevel));
int j = 0;
int g = 0;
=adapt_wavelet((scalar *){u},(double []){0.005,0.005},maxlevel,3).nf;
gboundary(all);
while(g>1){
foreach()
.x[]=0.;
uboundary(all);
++;
jfprintf(ferr,"j=%d and g=%d\n",j,g);
=adapt_wavelet((scalar *){u},(double []){0.005,0.005},maxlevel,3).nf;
g}
=0.01;
DT}
For Re=500 we output an animation of the vorticity and the grid resolution.
event movie(t+=0.1){
if (m==2){
fprintf(ferr,"%g\n",t);
foreach(){
[]=((u.x[0,1]-u.x[0,-1]) - (u.y[1,0]-u.y[-1,0]))/(2*Delta);
omg[]=level;
lev}
boundary({omg}); //For interpolation purposes
static FILE * fp3 = popen ("ppm2gif > omg.gif", "w");
output_ppm(omg,fp3, n=512,linear=true, min=-10., max=10.);
static FILE * fp2 = popen ("ppm2gif > lev.gif", "w");
output_ppm(lev,fp2, n=512, min=3, max=maxlevel);
}
}
event adapt(i++){
((scalar *){u},(double []){0.005,0.005},maxlevel,3);
adapt_wavelet}
At t=20L/U the simulation is stopped and some output statistics are calculated.
event stop(t+=1.;t<25.){
if (t>=20.){
=0;
ens=0;
vit=0;
vir=0;
eforeach(reduction(+:ens) reduction(+:e)){
[]=((u.x[0,1]-u.x[0,-1]) - (u.y[1,0]-u.y[-1,0]))/(2*Delta);
omg+=sq(omg[])*sq(Delta);
ens[]=level;
lev[]=sqrt(sq(u.x[])+sq(u.y[]));
U+=sq(U[])*sq(Delta);
e}
boundary({omg});
foreach_boundary(top)
+=Delta*omg[];
vitforeach_boundary(right)
+=Delta*omg[];
virforeach_boundary(left)
+=Delta*omg[];
vilforeach_boundary(bottom)
+=Delta*omg[];
vibfprintf(ferr,"%d\t%g\t%g\t%g\t%g\t%g\t%g\t%g\n",i,t,e,ens,vit,vir,vir,vib);
return 1;
}
}
Results
First we look at the evolution of the voricity field for Re=500 and the level of refinement within the domain.


It appears that the costs of the simulations scale with Re^{1.9}. See the Appendix of Van Hooft et al. (2018) for a more elaborate narrative.