/**
# Overflow
This test case was designed by [Ilicak et al., 2012](#ilicak2012),
section 4, to investigate the mixing properties of numerical schemes
in the case of "overflow" i.e. a denser fluid flowing down a sill or
continental slope.
Note that the test case is largely qualitative and is in particular
very sensitive to various sources of dissipation, including bottom
boundary conditions etc.
The evolution of the "temperature"/density field is illustrated in the
sequence below. The cool/dense fluid to the left is released at the
top of the slope and flows down. Although no explicit temperature
diffusion is prescribed, numerical diffusion leads to the formation of
a diffused plume in regions of high shear (the "head" of the flow).
![Animation of the temperature field](overflow/movie.mp4)
The figures at $t=3$ and $t=6$ hours below agree closely with Figure
4.k and 4.l of [Petersen et al, 2015](#petersen2015).
![$t=3$ hours](overflow/T-3.png){ width=100% }
|
![$t=6$ hours](overflow/T-6.png){ width=100% }
|
The amount of mixing can be measured by looking at the evolution of
the Reference (or Resting) Potential Energy (RPE) as proposed by
[Ilicak et al, 2012](#ilicak2012). In the ideal case without any
numerically-induced mixing, the RPE should be conserved.
~~~gnuplot Evolution of the normalised reference potential energy
set xlabel 'Time (hours)'
set ylabel '(RPE - RPE(0))/RPE(0) x 10^5'
hour = 3600.
set xrange [0:12]
plot 'log' u ($1/hour):(-$3/$4*1e7) w l t ''
~~~
~~~gnuplot Evolution of the average rate of change of the reference potential energy
set ylabel 'dRPE/dt (Watts/m^2)'
set logscale y
L0 = 256e3
plot 'log' u ($1/hour):(abs($3)/$1/L0) w l t ''
~~~
~~~gnuplot Evolution of the Available Potential Energy (APE = PE - RPE).
set ylabel 'APE (Joules)'
unset logscale y
plot 'log' every 1 u ($1/hour):($5-$3) w l t ''
~~~
~~~gnuplot Evolution of the Kinetic Energy.
set ylabel 'KE (Joules)'
plot 'log' every 1 u ($1/hour):6 w l t ''
~~~
~~~gnuplot Evolution of the Total Energy KE + APE.
set ylabel 'Total Energy (Joules)'
unset logscale
plot 'log' every 10 u 1:($5-$3+$6) w l t ''
~~~
## Non-diffusive interface
This is the same setup but using a vertical remapping which preserves
the sharp temperature/density interface (i.e. the interface is treated
in a Lagrangian manner while the other layers are "Eulerian"). Note
that this is different from the two-layers isopycnal run of [Petersen
et al, 2015](#petersen2015) since here 20 layers are used (10 in each
"phase"), and so the vertical velocity profile is resolved.
![Animation of the temperature field](overflow-isopycnal/movie.mp4)
![$t=3$ hours](overflow-isopycnal/T-3.png){ width=100% }
|
![$t=6$ hours](overflow-isopycnal/T-6.png){ width=100% }
|
In the absence of spurious numerical diffusion, the evolution is much
faster and the front propagates much further.
As expected the resting potential energy is conserved to within
machine accuracy.
~~~gnuplot Evolution of the normalised reference potential energy
set xlabel 'Time (hours)'
set ylabel '(RPE - RPE(0))/RPE(0) x 10^5'
hour = 3600.
set xrange [0:12]
plot '../overflow-isopycnal/log' u ($1/hour):(-$3/$4*1e7) w l t ''
~~~
## References
~~~bib
@article{ilicak2012,
title = {Spurious dianeutral mixing and the role of momentum closure},
journal = {Ocean Modelling},
volume = {45-46},
pages = {37-58},
year = {2012},
issn = {1463-5003},
doi = {https://doi.org/10.1016/j.ocemod.2011.10.003},
url = {https://www.sciencedirect.com/science/article/pii/S1463500311001685},
author = {Mehmet Ilicak and Alistair J. Adcroft and Stephen M. Griffies and
Robert W. Hallberg}
}
@article{petersen2015,
title = {Evaluation of the arbitrary {L}agrangian–{E}ulerian vertical coordinate
method in the {MPAS}-Ocean model},
journal = {Ocean Modelling},
volume = {86},
pages = {93-113},
year = {2015},
issn = {1463-5003},
doi = {https://doi.org/10.1016/j.ocemod.2014.12.004},
url = {https://www.sciencedirect.com/science/article/pii/S1463500314001796},
author = {Mark R. Petersen and Douglas W. Jacobsen and Todd D. Ringler and
Matthew W. Hecht and Mathew E. Maltrud},
}
~~~
## Code
We use the 1D (hydrostatic) multilayer solver with a time-implicit
discretisation of the (barotropic) free-surface evolution. */
#include "grid/multigrid1D.h"
#include "layered/hydro.h"
#include "layered/implicit.h"
/**
We include the Boussineq buoyancy term with a linear "equation of
state" linking the temperature $T$ with the relative density variation
$\Delta\rho(T)/\rho_0$. */
#define rho0 1000.
#define drho(T) (- (0.2*(T - 5.))/rho0)
#include "layered/dr.h"
/**
The vertical remapping is either uniform (i.e. $\sigma$-coordinate) or
"half-$\sigma$" in the "isopycnal" case. */
#if ISOPYCNAL
# define HALF 1
#endif
#include "layered/remap.h"
/**
This module contains function to compute the (non-trivial) "Resting
Potential Energy". */
#include "layered/rpe.h"
/**
We add safety checks on the implicit integration of the free-surface
and performance statistics. */
#include "layered/check_eta.h"
#include "layered/perfs.h"
/**
The horizontal viscosity is set to the corresponding value in
[Petersen et al, 2015](#petersen2015), Figure 4.k,l. Note however that
this has much less influence than in this paper, since most of the
effective viscosity comes from the upwind-biased momentum advection
scheme. */
double nu_H = 1000.; // 1e-2;
int main()
{
size (256e3 [1]);
N = 256;
/**
In the "isopycnal" case, we increase the vertical viscosity to try
to slow down the gravity current. */
#if ISOPYCNAL
nl = 20;
nu = 1e-1;
#else
nl = 100;
nu = 1e-4;
#endif
G = 9.81;
DT = 15. [0,1]; // Ilicak et al, 2012 use 10 sec
/**
Vertical remapping uses a monotonic limiter to avoid creating new
extrema in the temperature field. */
cell_lim = mono_limit;
system ("rm -f plot-*.png"); // fixme: should not be necessary
run();
}
event init (i = 0)
{
foreach() {
double d1 = 500, d2 = 2000, x0 = 40e3, sigma = 7e3;
zb[] = - (d1 + (d2 - d1)/2.*(1. + tanh((x - x0)/sigma)));
foreach_layer() {
#if ISOPYCNAL
T[] = point.l < nl/2 ? 10 : 20;
if (x < 20e3)
h[] = point.l < nl/2 ? - zb[]/(nl/2) : 1e-2;
else
h[] = point.l >= nl/2 ? - zb[]/(nl/2) : 1e-2;
#else
h[] = - zb[]/nl;
T[] = x < 20e3 ? 10 : 20;
#endif
}
}
}
/**
### Quadratic bottom friction
The bottom boundary slip length corresponding to quadratic bottom
friction is given by
$$
\lambda_b = \nu\frac{h_0}{C_f|\mathbf{u}|}
$$
with $C_f$ the (dimensionless) quadratic bottom friction coefficient. */
vector lambda_q[];
event viscous_term (i++)
{
// Quadratic bottom friction,
// see also: gerris-snapshot/doc/figures/diffusion.tm
double Cf = 1e-2; // fixme: this has the dimensions of a length...
lambda_b = lambda_q;
foreach() {
double au = norm(u);
lambda_q.x[] = au < 1e-6 ? HUGE : nu*h[]/(Cf*au);
}
}
/**
### Horizontal viscosity
This is a somewhat naive implementation of horizontal viscosity. Note
that we do not use the
[horizontal_diffusion()](/src/layered/diffusion.h#horizontal_diffusion)
function since it does not behave well for zero layer thickness. */
event viscous_term (i++)
{
scalar d2u[];
foreach_layer() {
foreach()
d2u[] = (u.x[1] + u.x[-1] - 2.*u.x[])/sq(Delta);
foreach()
u.x[] += dt*nu_H*d2u[];
}
}
/**
### Outputs */
event logfile (i += 10)
{
static double rpe0 = 0., rpen = 0., tn = 0.;
double rpe = rho0*RPE();
double PE, KE;
energy (&PE, &KE);
if (i == 0)
rpe0 = rpe;
fprintf (stderr, "%g %g %.12g %.12g %.12g %.12g %.12g %d\n", t, dt,
rpe - rpe0, rpe0, rho0*PE, rho0*KE,
t > tn ? (rpe - rpen)/(t - tn)/L0 : 0.,
#if NH
mgp.i
#else
mgH.i
#endif
);
rpen = rpe, tn = t;
}
void setup (FILE * fp)
{
fprintf (fp,
#if ISOPYCNAL
"set pm3d map corners2color c2\n"
#else
"set pm3d map\n"
#endif
"# jet colormap\n"
"set palette defined ( 0 0 0 0.5647, 0.125 0 0.05882 1, 0.25"
" 0 0.5647 1, 0.375 0.05882 1 0.9333, 0.5 0.5647 1 0.4392, 0.625"
" 1 0.9333 0, 0.75 1 0.4392 0, 0.875 0.9333 0 0, 1 0.498 0 0 )\n"
"unset key\n"
// "set cbrange [10:20]\n"
"set xlabel 'x (km)'\n"
"set ylabel 'depth (m)'\n"
"set xrange [0:200]\n"
"set yrange [-2000:10]\n"
);
}
#define hour 3600.
void plot (FILE * fp)
{
fprintf (fp,
"set title 't = %.2f hours'\n"
"sp '-' u ($1/1e3):2:4\n",
t/hour);
foreach (serial) {
double z = zb[];
fprintf (fp, "%g %g %g %g\n", x, z, u.x[], T[]);
foreach_layer() {
z += h[];
fprintf (fp, "%g %g %g %g\n", x, z, u.x[], T[]);
}
fprintf (fp, "\n");
}
fprintf (fp, "e\n\n");
// fprintf (fp, "pause 1\n");
fflush (fp);
}
event gnuplot (t += 600)
{
static FILE * fp = popen ("gnuplot 2> /dev/null", "w");
if (i == 0)
setup (fp);
if (getenv ("DISPLAY")) {
fprintf (fp, "set term x11\n");
plot (fp);
}
fprintf (fp,
"set term pngcairo font \",10\" size 800,500\n"
"set xrange [0:200]\n"
"set output 'plot-%04d.png'\n", i);
plot (fp);
}
event figures (t <= 12*hour; t += 3.*hour)
{
FILE * fp = popen ("gnuplot 2> /dev/null", "w");
setup (fp);
fprintf (fp,
"set term pngcairo font \",10\" size 800,500\n"
"set xrange [0:85]\n"
"set output 'T-%g.png'\n", t/hour);
plot (fp);
}
event moviemaker (t = end)
{
system ("for f in plot-*.png; do convert $f ppm:- && rm -f $f; done | "
"ppm2mp4 movie.mp4");
}
/**
This optionally displays the diagnostic corresponding to `check_eta.h`
above. */
#if 0
#include "deta.h"
#endif