sandbox/Antoonvh/gradient-sharpening.c
Gradient sharpening by a dipolar vortex
A dipolar vortex propages itself through a modest scalar gradient. hereby the scalar gradients sharply increase at the edge of the dipole’s atmosphere.
The results are presented and discussed in a publication:
A note on scalar-gradient sharpening in the stable atmospheric boundary layer
https://doi.org/10.1007/s10546-020-00516-x
Set-up
We solve the Navier-stokes equations and a tracer advection-diffusion equation.
#include "navier-stokes/centered.h"
#include "tracer.h"
#include "diffusion.h"
#include "view.h"
scalar s[], *tracers = {s};
double Re = 800;
double Pr = 1.;
int maxlevel = 99; //Unlimited
FILE * fp;
double se = 0.02, ue = 0.02;
The equations of motion are solved in the frame of reference that is co-moving with the initialized dipolar vortex. As such, in and outflow conditions are set at the left and right wall, respectively.
u.n[left] = neumann (0.);
p[left] = neumann (0.);
pf[left] = neumann (0.);
u.n[right] = dirichlet (-1.);
p[right] = dirichlet (0.);
pf[right] = dirichlet (0.);
s[right] = dirichlet (tanh((x - 5. + t)/2.));
int main () {
L0 = 25;
X0 = Y0 = -L0/2;
N = 512;
TOLERANCE = 1e-5;
NITERMIN = 2;
foreach_dimension()
u.x.refine = refine_linear;
Uncomment the following line for a sweep op Re values and the other two for a convergence study. Here we only run Re = 800 and se
= ue
= 0.02.
//for (Re = 50; Re <= 3200; Re *= 2)
//for (ue = 0.03; ue >= 0.01; ue -= 0.01)
//for (se = 0.03; se >= 0.01; se /= 0.01)
run();
}
Initialization
We initalize the Lamb-Chaplygin dipolar vortex and the initally modest scalar front.
double xo = -0.01, yo = 0.1;
#define RAD (sqrt(sq(x - xo) + sq(y - yo)))
#define ST ((yo - y)/RAD)
event init (t = 0) {
char fname[99];
sprintf (fname, "datac%g,%g%g", Re, se, ue);
fp = fopen (fname, "w");
scalar psi[];
psi[left] = dirichlet ((1/RAD - RAD)*ST);
psi[right] = dirichlet ((1/RAD - RAD)*ST);
psi[top] = dirichlet ((1/RAD - RAD)*ST);
psi[bottom] = dirichlet ((1/RAD - RAD)*ST);
const face vector nu[] = {1./Re, 1./Re};
mu = nu;
double k = 3.83170597;
refine (RAD < 2. && level < 10);
refine (RAD < 1.1 && level < 11);
foreach()
psi[] = ((RAD > 1)*(1/RAD - RAD)*ST +
(RAD <= 1)*(-2*j1(k*RAD)*ST/(k*j0(k))));
boundary ({psi});
foreach() {
u.x[] = -((psi[0, 1] - psi[0, -1])/(2*Delta));
u.y[] = (psi[1, 0] - psi[-1, 0])/(2*Delta);
s[] = tanh((x - 5)/2);
}
boundary ({s, u});
}
The tracer field is subject to diffusion.
event tracer_diffusion (i++) {
const face vector kappa[] = {1./(Pr*Re), 1./(Pr*Re)};
diffusion (s, dt, kappa);
}
We use an adaptive grid:
event adapt (i++) {
int minlevel = 6;
adapt_wavelet ({s, u}, (double[]){se, ue, ue}, 99, minlevel);
unrefine (x > X0 + 14*L0/15 && level > minlevel - 1);
}
event output (t += 0.1) {
scalar lev[], gr[], omega[];
face vector grf[];
vertex scalar sv[];
double maxgr = 0;
boundary({s});
foreach_face() {
if (fabs(x - X0) < Delta/2. || fabs(x - X0 - L0) < Delta/2. ||
fabs(y - Y0) < Delta/2. || fabs(y - Y0 - L0) < Delta/2.)
grf.x[] = 0;
else
grf.x[] = (15.*(s[] - s[-1]) - (s[1] - s[-2]))/(12.*Delta);
}
boundary ((scalar*){grf});
foreach_vertex()
sv[] = (s[] + s[-1] + s[0,-1] + s[-1,-1])/4.;
foreach() {
lev[] = level;
gr[] = 0;
foreach_dimension()
// gr[] += sq((s[1] - s[-1])/(2.*Delta)); //sconder order diagnosis
gr[] += sq((grf.x[] + grf.x[1])/2.);
if (gr[] > sq(maxgr))
maxgr = sqrt(gr[]);
}
vorticity (u, omega);
boundary ({gr, omega, sv});
fprintf (fp, "%g %d %g %g %d %ld %g \n",
t, i, maxgr, statsf(gr).sum, grid->maxdepth, grid->n, perf.t);
fflush (fp);
printf ("%g %d %d %d %g %g %d\n",
t, i, mgp.i, mgpf.i, maxgr, statsf(gr).sum, depth());
For Re = 800, a movie is generated.
if (Re == 800) {
view (fov = 25, width = 1200, height = 700);
translate (x = t - 5) {
squares ("omega", linear = true, map = cool_warm, min = -8, max = 8);
for (double sval = -0.8 ; sval <= 0.8; sval += 0.4)
isoline ("sv", sval, lw = 2);
//cells();
save ("Re800-overview.mp4");
}
view (fov = 4, width = 1200, height = 700);
squares ("gr", linear = true, min = 0, max = 40, map = cool_warm);
cells();
save ("Re800-grid.mp4");
}
}
event stop (t = 15) {
char dname[99];
sprintf (dname, "dump%g", Re);
dump (dname);
fclose (fp);
}