# Two opposing Gaussian vortex rings

Two Gaussian vortex rings in a triply-periodic domain.

Volumetric rendering of the negative \lambda_2 field (via surfdrive)

#include "grid/octree.h"
#include "nsf4t.h"
scalar * tracers = NULL;
#include "lambda2.h"
#include "view.h"
#include "filaments.h"
#include "bwatch.h"

#define R      (sqrt(sq(x) + sq(y)))
#define radi(zp)   (R <= 0.01 ? major_rt				\
: (sqrt(sq(x - major_rt*(x/R)) +			\
sq(y - major_rt*(y/R)) + sq(z - zp))))

double ue = 5e-3;
int maxlevel = 9;
int segs = 654;
double major_rt = 3.0; // Ring' major radius (minor = 1)
double d1 = 10;    // Initial distance
double muv = 1./3000.;   // Fluid's viscosity

double amp = 0.1;
int ampn = 7;

int main(int argc, char ** argv) {
if (argc > 1)
ue = atof (argv[1]);
if (argc > 2)
maxlevel = atoi (argv[2]);
if (argc > 3)
segs = atoi (argv[3]);
if (argc > 4)
muv = atof (argv[4]);
if (pid() == 0)
printf ("# ue = %g, ilev = %d, segs = %d, Re = %g \n",
ue, maxlevel, segs, 1./muv);
foreach_dimension()
periodic(left);
L0 = 40*major_rt;
origin (-L0/2 + pi, -L0/2 + exp(1), -L0/2 - sqrt(2));
const scalar muc[] = muv;
nu = muc;
run();
}

coord ring1 (double t) {
coord C;
C.x = major_rt*cos(t);
C.y = major_rt*sin(t);
C.z = d1 + amp*cos(ampn*t); ;
return C;
}

coord ring2 (double t) {
coord C;
C.x =  major_rt*cos(t);
C.y = -major_rt*sin(t);
C.z = -d1 + amp*sin(ampn*t);
return C;
}

event init (t = 0) {
refine ((radi(-d1) < 12 || radi(d1) < 12) && level < maxlevel - 2);
refine ((radi(-d1) < 6  || radi(d1) < 6)  && level < maxlevel - 1);
refine ((radi(-d1) < 3  || radi(d1) < 3)  && level < maxlevel);
vector A[], omg[], omg2[];
TOLERANCE = 1e-5;
get_vor_vector (omg,  ring1, 0, 2*pi, segs, Lamb_Oseen);
get_vor_vector (omg2, ring2, 0, 2*pi, segs, Lamb_Oseen);
foreach_dimension()
A.x.prolongation = refine_4th;
foreach() {
foreach_dimension() {
A.x[] = 0.;
omg.x[] += omg2.x[];
}
}
foreach_dimension() {
stats o = statsf (omg.x);
foreach()
omg.x[] -= o.sum/o.volume;
}
boundary ((scalar*){A});
foreach_dimension()
poisson (A.x, omg.x);
vector uc[];
foreach_dimension()
uc.x.prolongation = refine_4th;
foreach() {
foreach_dimension() {
uc.x[] = (8.*(A.z[0,1] - A.z[0,-1]) + A.z[0,-2] - A.z[0,2] -
8.*(A.y[0,0,1] - A.y[0,0,-1]) - A.y[0,0,-2] + A.y[0,0,2])/(12*Delta);
}
}
boundary ((scalar*){uc});
vector_to_face (uc);
project (u, p);
}

event dumping (t = {5, 100, 200, 300, 350, 375, 400, 450, 500}) {
vector uc[];
face_to_vector (uc);
char fname[99];
sprintf (fname, "dump%g", t);
dump (fname, (scalar*){uc});
}

event logger (i += 5) {
double ke2 = 0., vd2 = 0.;
double ke4 = 0., vd4 = 0.;
vector uv[];
scalar dissv[], Ev[];
face_to_vector(uv);
foreach(reduction (+:ke2) reduction (+:vd2)) {
foreach_dimension() {
ke2 += dv()*sq(uv.x[]);
vd2 += dv()*(sq(uv.x[1]     - uv.x[-1]) +
sq(uv.x[0,1]   - uv.x[0,-1]) +
sq(uv.x[0,0,1] - uv.x[0,0,-1]))/sq(2.*Delta);
}
}
foreach_dimension() {
uv.x.prolongation = refine_vert5;
uv.x.restriction = restriction_vert;
}
dissv.prolongation = refine_vert5;
dissv.restriction = restriction_vert;
Ev.prolongation = refine_vert5;
Ev.restriction = restriction_vert;
foreach() {
foreach_dimension()
uv.x[] = FACE_TO_VERTEX_4 (u.x);
}
boundary ((scalar*){uv});
foreach() {
Ev[] = dissv[] = 0;
foreach_dimension() {
Ev[] += sq(u.x[]);
dissv[] += (sq(8*(u.x[1] - u.x[-1]) + u.x[-2] - u.x[2]) +
sq(8*(u.x[0,1] - u.x[0,-1]) + u.x[0,-2] - u.x[0,2]) +
sq(8*(u.x[0,0,1] - u.x[0,0,-1]) + u.x[0,0,-2] - u.x[0,0,2]))/sq(12*Delta);
}
}
boundary ({dissv, Ev});
foreach(reduction (+:ke4) reduction (+:vd4)) {
coord cc = {x, y , z};
foreach_child() {
coord ccc = {0};
foreach_dimension()
ccc.x = cc.x + child.x*Delta/sqrt(3);
ke4 += dv()*interpolate_vertex_4 (Ev,    ccc.x, ccc.y, ccc.z);
vd4 += dv()*interpolate_vertex_4 (dissv, ccc.x, ccc.y, ccc.z);
}
}
ke2 /= 2.;
ke4 /= 2.;
vd2 *= muv;
vd4 *= muv;
fprintf (stderr, "%d %g %d %d %d %d %ld %d %g %g %g %g\n",
i, t, mgp.i, mgp.nrelax, mgp2.i, mgp2.nrelax,
grid->tn, grid->maxdepth, ke2, vd2, ke4, vd4);
}

event mov (i += 5) {
scalar l2[];
vector uc[];
face_to_vector (uc);
lambda2 (uc, l2);
view (fov = 12, phi = 0.5, theta = 0.4);
isosurface ("l2", -0.001);
cells (n = {0,1,0});
char str[99];
sprintf (str,"t = %3.3g", t);
draw_string (str, size = 25, pos = 2);
save ("l2.mp4");
}

#if BWATCH
event movb (t += 1) {
scalar l2[];
vector uc[];
face_to_vector (uc);
lambda2 (uc, l2);
foreach()
l2[] = l2[] > 0 ? 0 : -l2[];
boundary ({l2});
static FILE * fp = popen ("ppm2mp4 l2b.mp4", "w");
watch (O = {30, 30., 100} ,
fov = 55, nx = 900, ny = 900);
volume (l2, cols = true, sc = 0.005, mval = 0.001,
min = -0.1, max = 0.1, shading = 1);
store (fp);
plain();
}
#endif

event stop (t = 1000) {
return 1;
}