src/test/wind-driven-stvt.c
Wind-driven lake
This is a simple test case of a wind-driven lake where we can compare results with an analytical solution. For the bottom of the domain we impose a no-slip condition (that is the default), for the top we impose a Neumann condition (see viscous friction between layers for details).
We run the test case for three different solvers: multilayer Saint-Venant, layered hydrostatic, layered non-hydrostatic.
#include "grid/multigrid1D.h"
#if !ML
# include "saint-venant.h"
#else
# include "layered/hydro.h"
# if NH
# include "layered/nh.h"
# else
# include "layered/implicit.h"
# endif
# include "layered/remap.h"
#endif
There are five parameters L, h, g, \dot{u}, \nu. Only three are independent e.g. a = \frac{L}{h}, \text{Re} = \frac{\dot{u} h^2}{\nu} = s \frac{gh^3}{\nu^2}, s = \frac{\dot{u} \nu}{gh} = \frac{\dot{u}^2 h}{\text{Re} g} where a is the aspect ratio, Re the Reynolds number and s the slope of the free-surface. A characteristic time scale is t_{\nu} = \frac{h^2}{\nu} We choose a small Reynolds number and a small slope.
double Re = 10.;
double s = 1./1000.;
double h0 = 1.;
double du0;
#if !ML
scalar duv[];
#else
vector duv[];
#endif
int main()
{
= 10. [1];
L0 = -L0/2.;
X0 = 9.81;
G = 64;
N = sqrt(s*G*cube(h0)/Re);
nu = sqrt(s*G*Re/h0);
du0 = duv; dut
We vary the number of layers.
#if ML
= 8.;
CFL_H = 1.; // to damp short waves faster
theta_H #endif
for (nl = 4; nl <= 32; nl *= 2)
run();
}
We set the initial water level to 1 and set the surface stress.
event init (i = 0) {
foreach() {
#if !ML
[] = h0;
h[] = du0*(1. - pow(2.*x/L0,10));
duv#else
()
foreach_layer[] = h0/nl;
h.x[] = du0*(1. - pow(2.*x/L0,10));
duv#endif
}
}
We compute the error between the numerical solution and the analytical solution.
#define uan(z) (du0*(z)/4.*(3.*(z) - 2.))
double t0 = 10;
event error (t = t0/nu)
{
int i = 0;
foreach() {
if (i++ == N/2) {
double z = zb[], emax = 0.;
#if !ML
int l = 0;
for (vector u in ul) {
double e = fabs(u.x[] - uan (z + h[]*layer[l]/2.));
if (e > emax)
= e;
emax += h[]*layer[l++];
z }
#else
() {
foreach_layerdouble e = fabs(u.x[] - uan (z + h[]/2.));
if (e > emax)
= e;
emax += h[];
z }
#endif
fprintf (stderr, "%d %g\n", nl, emax);
}
}
}
Uncomment this part if you want on-the-fly animation.
#if 0
#include "plot_layers.h"
#endif
For the hydrostatic case, we compute a diagnostic vertical velocity
field w
. Note that this needs to be done within this event
because it relies on the fluxes hu
and face heights
hf
, which are only defined temporarily in the multilayer solver.
#if !NH && ML
scalar w = {-1};
event update_eta (i++)
{
if (w.i < 0)
= new scalar[nl];
w vertical_velocity (w, hu, hf);
The layer interface values are averaged at the center of each layer.
foreach() {
double wm = 0.;
() {
foreach_layerdouble w1 = w[];
[] = (w1 + wm)/2.;
w= w1;
wm }
}
}
#endif // !NH && ML
We save the horizontal velocity profile at the center of the domain and the two components of the velocity field for the case with 32 layers.
event output (t = end) {
char name[80];
sprintf (name, "uprof-%d", nl);
FILE * fp = fopen (name, "w");
int i = 0;
foreach() {
if (i++ == N/2) {
#if !ML
int l = 0;
double z = zb[] + h[]*layer[l]/2.;
for (vector u in ul)
fprintf (fp, "%g %g\n", z, u.x[]), z += h[]*layer[l++];
#else
double z = zb[];
()
foreach_layerfprintf (fp, "%g %g\n", z + h[]/2., u.x[]), z += h[];
#endif
}
if (nl == 32) {
double z = zb[];
#if !ML
int l = 0;
scalar w;
vector u;
for (w,u in wl,ul) {
printf ("%g %g %g %g\n", x, z + h[]*layer[l]/2., u.x[], w[]);
+= layer[l++]*h[];
z }
#else
()
foreach_layerprintf ("%g %g %g %g\n", x, z + h[]/2., u.x[], w[]), z += h[];
#endif
printf ("\n");
}
}
fclose (fp);
}
Results
set xr [0:1]
set xl 'z'
set yl 'u'
set key left top
G = 9.81
s = 1./1000.
Re = 10.
du0 = sqrt(s*Re*G)
plot [0:1]du0*x/4.*(3.*x-2.) t 'analytical', \
'uprof-4' pt 5 t '4 layers', \
'uprof-8' pt 6 t '8 layers', \
'uprof-16' pt 9 t '16 layers', \
'uprof-32' pt 10 t '32 layers'
reset
set cbrange [1:2]
set logscale
set xlabel 'Number of layers'
set ylabel 'max|e|'
set xtics 4,2,32
set grid
fit a*x+b 'log' u (log($1)):(log($2)) via a,b
plot [3:36]'log' u 1:2 pt 7 t '', \
(b)*x**a t sprintf("%.2f/N^{%4.2f}", exp(b), -a) lt 1 exp
reset
unset key
set xlabel 'x'
set ylabel 'z'
scale = 10.
plot [-5:5][0:1]'out' u 1:2:($3*scale):($4*scale) w vectors