sandbox/yonghui/vortex/exit_traingle.c
The flow towards a cone
It’s a simple test of a uniform inflow from a channel towards a triangle, we want to check the flow dynamics with different shape of exit shape and triangle position.
#include "embed.h"
#include "navier-stokes/centered.h"
#include "tracer.h"
#include "view.h"
We defind some MACRO here.
The origin (0,0) is set to the lower conner of the exit, with channel height diameter, its length (from left border to exit) aa1 and the minimum exit wall thickness at bottom bb1 (used for L_0 = 1).
The distance of traingle’s left conner towards exit conepx, with a possible height differece eta between the triangle’s lower interface and the one of channel.
#define L_p 1 // domain size L0 = L_p^2
#define LVM 8 + L_p
#define aa1 0.3
#define bb1 0.4
#define diameter 0.15
#define eta 0.02
#define conepx 0.1
the NORMALIZED (with L_0 = 1) constante viscosity mu = 1/Re in the simulation.
#define mucst 1./2000
#define tend 10.0
#define ADAPT 1
// DO NOT SET 2 SWITCH OPEN AT SAME TIME,round will override chamber
#define round_conner 0
#if !round_conner
#define chamfer_conner 0
#endif
we set a tracer for fun.
scalar f[];
scalar * tracers = {f};
face vector muv[];
main
int main() {
(pow(2,L_p));
size(64);
init_grid ( -aa1, -bb1-(L0-1.)/2. );
origin= muv;
mu = 1e-3;
TOLERANCE run();
}
event properties (i++)
{
foreach_face()
.x[] = fm.x[]*mucst;
muv}
The fluid is injected on the left boundary with a unit velocity.
.n[left] = dirichlet(1.*cs[]);
u[left] = neumann(0.);
p[left] = neumann(0.);
pf[left] = dirichlet( y < eta || (y < eta+diameter/2. && y > diameter/2.) );
f
.n[right] = neumann(0.);
u[right] = dirichlet(0.);
p[right] = dirichlet(0.); pf
Free outflow condition at other three boundaries. Comment the follow for using free slip conditions.
.n[top] = neumann(0.);
u[top] = dirichlet(0.);
p[top] = dirichlet(0.);
pf
.n[bottom] = neumann(0.);
u[bottom] = dirichlet(0.);
p[bottom] = dirichlet(0.); pf
ALL the solid surfaces are no-slip.
init event
We use the function proposed in Basilisk
#define intersection(a,b) min(a,b)
#define union(a,b) max(a,b)
#define difference(a,b) min(a,-(b))
phi[] > 0 means the fluid domain.
with fraction field cs, fluids : cs[]=1 and solid : cs[]=0.
event init (t = 0)
{
refine (( x<1.-aa1 && x > -aa1 && y < 1.-bb1 && y > -bb1 ) && level < LVM ) ;
vertex scalar phi[];
vertex scalar rec1[];
vertex scalar rec2[];
vertex scalar cone[];
A rounded conner shape exit.
We use “simply” two rect and one circle!!
#if round_conner
double rr1 = 0.1; //the bottom
vertex scalar rec11[];
vertex scalar rec12[];
vertex scalar rec1t[];
double rr2 = 0.1; //the top
vertex scalar rec21[];
vertex scalar rec22[];
vertex scalar rec2t[];
vertex scalar cir2[];
foreach_vertex() {
[] = union (x, y+rr1);
rec11[] = union (x+rr1, y);
rec12[] = intersection (rec11[], rec12[]);
rec1t//left lower rectangle <0, rest >0
[] = intersection (rec1t[], sq(x+rr1) + sq(y+rr1)-sq(rr1));
rec1
[] = union (x+rr2, diameter - y);
rec21[] = union (x, diameter + rr2 - y);
rec22[] = intersection (rec21[], rec22[]);
rec2t//left upper rectangle <0, rest >0
[] = intersection (rec2t[], sq(x+rr2) + sq(y-rr2-diameter)-sq(rr2));
rec2}
A chamfer conner shape exit.
We use “simply” two trapezoids at angle 45 degree!!
#elif chamfer_conner
double tt1 = 0.1; //the bottom
vertex scalar trap11[];
vertex scalar trap12[];
double tt2 = 0.1; //the top
vertex scalar trap21[];
vertex scalar trap22[];
foreach_vertex() {
[] = union (x, y+x+tt1);
trap11[] = union (y, y+tt1+x);
trap12//left lower rectangle <0, rest >0
[] = union (trap11[], trap12[]);
rec1
[] = union (x, diameter + tt2 + x- y);
trap21[] = union (diameter-y, diameter + x + tt2 - y );
trap22//left upper rectangle <0, rest >0
[] = union (trap21[], trap22[]);
rec2}
A normal rectangle shape exit.
#else
foreach_vertex() {
//left lower rectangle <0, rest >0
[] = union (x, y);
rec1//left upper rectangle <0, rest >0
[] = union (x, diameter - y);
rec2}
#endif
With the choosen exit shape, now we define the traingle shape and remove the 2 solid exit domain form the domain.
foreach_vertex() {
//right cone <0, rest >0,assume slope = 0.3
[] = union ( (y - 0.3*( x - conepx )) ,eta-y);
cone// remove rec1 from cone
[] = intersection (cone[],rec1[]);
phi// remove rec1 from phi
[] = intersection (phi[], rec2[]);
phi}
boundary ({phi});
fractions (phi, cs, fs);
//foreach()
// u.x[] = cs[] ? 1. : 0.;
// ============ whole domain view=================
char legend[1000];
sprintf(legend, " mu=%g, D=%g, eta=%g, t=%0.2g", mucst, diameter, eta, t);
view (fov = 24., tx = aa1/L0 - 0.5, ty = (bb1-0.5)/L0, bg = {1,1,1}, width = 1024, height = 1024, samples = 1);
clear();
box();
cells();
draw_string(legend, 1, size = 50.,lw = 3.);
draw_vof ("cs", filled = -1, fc = {1,1,1});
squares("cs",max=1.,min=0.);
#if round_conner
save ("round.png");
#elif chamfer_conner
save ("chamber.png");
#else
save ("rectangle.png");
#endif
// ============ local view=================
view (fov = 24./L0, tx = (aa1-0.5)/L0, ty = (bb1-0.5)/L0, bg = {1,1,1}, width = 1024, height = 1024, samples = 1);
clear();
cells();
draw_string(legend, 1, size = 50.,lw = 3.);
draw_vof ("cs", filled = -1, fc = {1,1,1});
squares("cs",max=1.,min=0.);
save ("test.png");
//exit(0);
}
We check the number of iterations of the Poisson and viscous problems.
We output some videos. we neglect the “converged regime” before t = 1
event movies (t += tend/300. ; t <= tend)
{
if (t > 1.) {
scalar omega[];
vorticity (u, omega);
char legend[2000]; //time
sprintf(legend, " mu=%g, D=%g, eta=%g, t=%0.2g", mucst, diameter, eta, t);
view (fov = 24./L0, tx = (aa1-0.5)/L0, ty = (bb1-0.5)/L0, bg = {1,1,1}, width = 1024, height = 1024, samples = 1);
clear();
box();
draw_vof ("cs", filled = -1, fc = {1,1,1});
draw_string(legend, 1, size = 50.,lw = 3.);
squares("omega");
#if round_conner
save ("omega_round.mp4");
#elif chamfer_conner
save ("omega_chamber.mp4");
#else
save ("omega_rectangle.mp4");
#endif
view (fov = 24., tx = aa1/L0 - 0.5, ty = (bb1-0.5)/L0, bg = {1,1,1}, width = 1024, height = 1024, samples = 1);
clear();
cells();
draw_vof ("cs", filled = -1, fc = {1,1,1});
draw_string(legend, 1, size = 50.,lw = 3.);
squares("f",linear = false, min = 0, max = 1,);
#if round_conner
save ("f_round.mp4");
#elif chamfer_conner
save ("f_chamber.mp4");
#else
save ("f_rectangle.mp4");
#endif
}
}
We adapt according to the error on the embedded geometry, velocity and tracer fields.
#if ADAPT
event adapt (i++) {
({cs,u,f}, (double[]){1e-2,3e-2,3e-2,3e-2}, LVM, 4);
adapt_wavelet }
#endif