sandbox/tianlong/src/semushin/myviscosity.h
#ifndef _MY_VISCOSITY_H
#define _MY_VISCOSITY_H
#include "mypoisson.h"
The original viscosity.h is modified in the presence of solid boundaries. During the iteration of the viscosity solver, when relaxing a given cell, we check if the stencil is across the fluid-solid interface. When the stencil cell is not located inside the fluid domain, instead of using the wrong value, we accordingly compute the correct value with the boundary condition.
struct Viscosity {
vector u;
face vector mu;
scalar rho;
double dt;
int nrelax;
scalar * res;
};
#if AXI
# define lambda ((coord){1., 1. + dt/rho[]*(mu.x[] + mu.x[1] + \
mu.y[] + mu.y[0,1])/2./sq(y)})
#else // not AXI
# if dimension == 1
# define lambda ((coord){1.})
# elif dimension == 2
# define lambda ((coord){1.,1.})
# elif dimension == 3
# define lambda ((coord){1.,1.,1.})
#endif
#endif
#if USE_MY_SOLID
extern scalar is_solid;
extern face vector is_solid_face;
extern bool IS_SOLID_x;
extern bool IS_SOLID_y;
extern const bool is_slip_x;
extern const bool is_slip_y;
void boundarySolidVelCNoauto (vector v);
static void relaxVelX(Point point, const face vector mu, const scalar rho,
const double dt, const vector r, vector u, vector w)
{
double coef = 0.0;
double dt_rho = dt / rho[];
//contribution from tauxx
double tauxx = 2. * mu.x[1] * u.x[1] + 2. * mu.x[] * u.x[-1];
coef = coef + 2. * mu.x[1] + 2. * mu.x[]; //diagonal terms from tauxx
double dudy = mu.y[0, 1] * u.x[0, 1] + mu.y[] * u.x[0, -1]; //contribution from dudy in tauxy
coef = coef + mu.y[0, 1] + mu.y[]; //diagonal terms from dudy in tauxy
coef = coef * dt / rho[] + sq(Delta)*lambda.x;
double dvdx_yp = (u.y[1, 0] + u.y[1, 1]) / 4. - (u.y[-1, 0] + u.y[-1, 1]) / 4.;
double dvdx_ym = (u.y[1, -1] + u.y[1, 0]) / 4. - (u.y[-1, -1] + u.y[-1, 0]) / 4.;
double tauxy = mu.y[0, 1] * dvdx_yp - mu.y[] * dvdx_ym + dudy; //contribution from d tauxy dy
double res = dt / rho[] * (tauxx + tauxy) + r.x[] * sq(Delta); //the second term is the contribution from advection
w.x[] = res / coef;
}
static void relaxVelY(Point point, const face vector mu, const scalar rho,
const double dt, const vector r, vector u, vector w)
{
double coef = 0.0;
//contribution from tauyy
double tauyy = 2. * mu.y[0, 1] * u.y[0, 1] + 2. * mu.y[] * u.y[0, -1];
coef = coef + 2. * mu.y[0, 1] + 2. * mu.y[]; // diagonal terms from tauyy
double dvdx = mu.x[1] * u.y[1] + mu.x[] * u.y[-1]; //contribution from dvdx in tauxy
coef = coef + mu.x[1] + mu.x[]; //diagonal terms from dvdx in tauxy
coef = coef * dt / rho[] + sq(Delta)*lambda.y;
double dudy_xp = (u.x[0, 1] + u.x[1, 1]) / 4. - (u.x[0, -1] + u.x[1, -1]) / 4.;
double dudy_xm = (u.x[-1, 1] + u.x[0, 1]) / 4. - (u.x[-1, -1] + u.x[0, -1]) / 4.;
double tauxy = mu.x[1] * dudy_xp - mu.x[] * dudy_xm + dvdx; // contribution from d tauxy dx
double res = dt / rho[] * (tauyy + tauxy) + r.y[] * sq(Delta); //the second term is the contribution from advection
w.y[] = res / coef;
}
static void relaxVelXSolid(Point point, const face vector mu, const scalar rho,
const double dt, const vector r, vector u, vector w)
{
if((int) is_solid[] == 1)
{
u.x[] = 0.0;
w.x[] = 0.0;
return;
}
double coordmx = x - Delta;
double m1x = 1.0;
double compx = 0.0; //compensating coef
if(IS_SOLID_x && coordmx <= 0.0)
{
m1x = 0.0;
compx = 2.0 * mu.x[];
}
double coef = 0.0;
//contribution from tauxx
double tauxx = 2. * mu.x[1] * u.x[1] + 2. * mu.x[] * u.x[-1] * m1x;
coef = coef + 2. * mu.x[1] + 2. * mu.x[] + compx; //diagonal terms from tauxx
double coordmy = y - Delta;
double m1y = 1.0;
double compy = 0.0; //compensating coef
if(IS_SOLID_y && coordmy <= 0.0)
{
m1y = 0.0;
compy = is_slip_y ? -mu.y[] : mu.y[];
}
double dudy = mu.y[0, 1] * u.x[0, 1] + mu.y[] * u.x[0, -1]*m1y; //contribution from dudy in tauxy
coef = coef + mu.y[0, 1] + mu.y[] + compy; //diagonal terms from dudy in tauxy
coef = coef * dt / rho[] + sq(Delta)*lambda.x;
double uyxmyp = (u.y[-1, 0] + u.y[-1, 1]) / 4.;
double uyxmym = (u.y[-1, -1] + u.y[-1, 0]) / 4.;
if(IS_SOLID_x && coordmx <= 0.0)
{
uyxmyp = is_slip_x ? (u.y[0, 0] + u.y[0, 1]) / 4. : -(u.y[0, 0] + u.y[0, 1]) / 4.;
uyxmym = is_slip_x ? (u.y[0, -1] + u.y[0, 0]) / 4. : - (u.y[0, -1] + u.y[0, 0]) / 4.;
}
double dvdx_yp = (u.y[1, 0] + u.y[1, 1]) / 4. - uyxmyp;
double dvdx_ym = (u.y[1, -1] + u.y[1, 0]) / 4. - uyxmym;
if(IS_SOLID_y && coordmy <= 0.0)
{
dvdx_ym = 0.0; //the solid-liquid boundary (v = 0)
}
double tauxy = mu.y[0, 1] * dvdx_yp - mu.y[] * dvdx_ym + dudy; //contribution from d tauxy dy
double res = dt / rho[] * (tauxx + tauxy) + r.x[] * sq(Delta); //the second term is the contribution from advection
w.x[] = res / coef;
}
static void relaxVelYSolid(Point point, const face vector mu, const scalar rho,
const double dt, const vector r, vector u, vector w)
{
if((int) is_solid[] == 1)
{
u.y[] = 0.0;
w.y[] = 0.0;
return;
}
double coordmy = y - Delta;
double m1y = 1.0;
double compy = 0.0; //compensating coef
if(IS_SOLID_y && coordmy <= 0.0)
{
m1y = 0.0;
compy = 2.0 * mu.y[];
}
//this part will not be influenced by the existence of the solid
double coef = 0.0;
//contribution from tauyy
double tauyy = 2. * mu.y[0, 1] * u.y[0, 1] + 2. * mu.y[] * u.y[0, -1] * m1y;
coef = coef + 2. * mu.y[0, 1] + 2. * mu.y[] + compy; // diagonal terms from tauyy
double coordmx = x - Delta;
double m1x = 1.0;
double compx = 0.0; //compensating coef
if(IS_SOLID_x && coordmx <= 0.0)
{
m1x = 0.0;
compx = is_slip_x ? -mu.x[] : mu.x[];
}
double dvdx = mu.x[1] * u.y[1] + mu.x[] * u.y[-1] * m1x; //contribution from dvdx in tauxy
coef = coef + mu.x[1] + mu.x[] + compx; //diagonal terms from dvdx in tauxy
coef = coef * dt / rho[] + sq(Delta)*lambda.y;
double uxymxp = (u.x[0, -1] + u.x[1, -1]) / 4.;
double uyymxm = (u.x[-1, -1] + u.x[0, -1]) / 4.;
if (IS_SOLID_y && coordmy <= 0.0)
{
uxymxp = is_slip_y ? (u.x[0, 0] + u.x[1, 0]) / 4. : -(u.x[0, 0] + u.x[1, 0]) / 4.;
uyymxm = is_slip_y ? (u.x[-1, 0] + u.x[0, 0]) / 4. : -(u.x[-1, 0] + u.x[0, 0]) / 4.;
}
double dudy_xp = (u.x[0, 1] + u.x[1, 1]) / 4. - uxymxp;
double dudy_xm = (u.x[-1, 1] + u.x[0, 1]) / 4. - uyymxm;
if(IS_SOLID_x && coordmx <= 0.0)
{
dudy_xm = 0.0; //the solid-liquid boundary (u = 0)
}
double tauxy = mu.x[1] * dudy_xp - mu.x[] * dudy_xm + dvdx; // contribution from d tauxy dx
double res = dt / rho[] * (tauyy + tauxy) + r.y[] * sq(Delta); //the second term is the contribution from advection
w.y[] = res / coef;
}
static void relaxViscousitySolid (scalar * a, scalar * b, int l, void * data)
{
struct Viscosity * p = (struct Viscosity *) data;
(const) face vector mu = p->mu;
(const) scalar rho = p->rho;
double dt = p->dt;
vector u = vector(a[0]), r = vector(b[0]);
#if JACOBI
vector w[];
#else
vector w = u;
#endif
foreach_level_or_leaf(l)
{
relaxVelXSolid(point, mu, rho, dt, r, u, w);
relaxVelYSolid(point, mu, rho, dt, r, u, w);
}
#if JACOBI
foreach_level_or_leaf (l)
foreach_dimension()
u.x[] = (u.x[] + 2.*w.x[])/3.;
#endif
#if TRASH
vector u1[];
foreach_level_or_leaf (l)
foreach_dimension()
u1.x[] = u.x[];
trash ({u});
foreach_level_or_leaf (l)
foreach_dimension()
u.x[] = u1.x[];
#endif
}
#endif
static void relax_viscosity (scalar * a, scalar * b, int l, void * data)
{
struct Viscosity * p = (struct Viscosity *) data;
(const) face vector mu = p->mu;
(const) scalar rho = p->rho;
double dt = p->dt;
vector u = vector(a[0]), r = vector(b[0]);
#if JACOBI
vector w[];
#else
vector w = u;
#endif
foreach_level_or_leaf (l) {
foreach_dimension()
w.x[] = (dt/rho[]*(2.*mu.x[1]*u.x[1] + 2.*mu.x[]*u.x[-1]
#if dimension > 1
+ mu.y[0,1]*(u.x[0,1] +
(u.y[1,0] + u.y[1,1])/4. -
(u.y[-1,0] + u.y[-1,1])/4.)
- mu.y[]*(- u.x[0,-1] +
(u.y[1,-1] + u.y[1,0])/4. -
(u.y[-1,-1] + u.y[-1,0])/4.)
#endif
#if dimension > 2
+ mu.z[0,0,1]*(u.x[0,0,1] +
(u.z[1,0,0] + u.z[1,0,1])/4. -
(u.z[-1,0,0] + u.z[-1,0,1])/4.)
- mu.z[]*(- u.x[0,0,-1] +
(u.z[1,0,-1] + u.z[1,0,0])/4. -
(u.z[-1,0,-1] + u.z[-1,0,0])/4.)
#endif
) + r.x[]*sq(Delta))/
(sq(Delta)*lambda.x + dt/rho[]*(2.*mu.x[1] + 2.*mu.x[]
#if dimension > 1
+ mu.y[0,1] + mu.y[]
#endif
#if dimension > 2
+ mu.z[0,0,1] + mu.z[]
#endif
));
}
#if JACOBI
foreach_level_or_leaf (l)
foreach_dimension()
u.x[] = (u.x[] + 2.*w.x[])/3.;
#endif
#if TRASH
vector u1[];
foreach_level_or_leaf (l)
foreach_dimension()
u1.x[] = u.x[];
trash ({u});
foreach_level_or_leaf (l)
foreach_dimension()
u.x[] = u1.x[];
#endif
}
static double residual_viscosity (scalar * a, scalar * b, scalar * resl,
void * data)
{
struct Viscosity * p = (struct Viscosity *) data;
(const) face vector mu = p->mu;
(const) scalar rho = p->rho;
double dt = p->dt;
vector u = vector(a[0]), r = vector(b[0]), res = vector(resl[0]);
double maxres = 0.;
#if TREE
/* conservative coarse/fine discretisation (2nd order) */
We manually apply boundary conditions, so that all components are treated simultaneously. Otherwise (automatic) BCs would be applied component by component before each foreach_face() loop.
boundary ({u});
#if USE_MY_SOLID
boundarySolidVelCNoauto(u);
#endif
foreach_dimension() {
face vector taux[];
foreach_face(x)
taux.x[] = 2.*mu.x[]*(u.x[] - u.x[-1])/Delta;
#if dimension > 1
foreach_face(y)
taux.y[] = mu.y[]*(u.x[] - u.x[0,-1] +
(u.y[1,-1] + u.y[1,0])/4. -
(u.y[-1,-1] + u.y[-1,0])/4.)/Delta;
#endif
#if dimension > 2
foreach_face(z)
taux.z[] = mu.z[]*(u.x[] - u.x[0,0,-1] +
(u.z[1,0,-1] + u.z[1,0,0])/4. -
(u.z[-1,0,-1] + u.z[-1,0,0])/4.)/Delta;
#endif
foreach (reduction(max:maxres)) {
double d = 0.;
foreach_dimension()
d += taux.x[1] - taux.x[];
res.x[] = r.x[] - lambda.x*u.x[] + dt/rho[]*d/Delta;
#if USE_MY_SOLID
res.x[] *= (1.0 - is_solid[]);
#endif
if (fabs (res.x[]) > maxres)
maxres = fabs (res.x[]);
}
}
#else
#if USE_MY_SOLID
boundarySolidVelCNoauto(u);
#endif
/* "naive" discretisation (only 1st order on trees) */
foreach (reduction(max:maxres))
foreach_dimension() {
res.x[] = r.x[] - lambda.x*u.x[] +
dt/rho[]*(2.*mu.x[1,0]*(u.x[1] - u.x[])
- 2.*mu.x[]*(u.x[] - u.x[-1])
#if dimension > 1
+ mu.y[0,1]*(u.x[0,1] - u.x[] +
(u.y[1,0] + u.y[1,1])/4. -
(u.y[-1,0] + u.y[-1,1])/4.)
- mu.y[]*(u.x[] - u.x[0,-1] +
(u.y[1,-1] + u.y[1,0])/4. -
(u.y[-1,-1] + u.y[-1,0])/4.)
#endif
#if dimension > 2
+ mu.z[0,0,1]*(u.x[0,0,1] - u.x[] +
(u.z[1,0,0] + u.z[1,0,1])/4. -
(u.z[-1,0,0] + u.z[-1,0,1])/4.)
- mu.z[]*(u.x[] - u.x[0,0,-1] +
(u.z[1,0,-1] + u.z[1,0,0])/4. -
(u.z[-1,0,-1] + u.z[-1,0,0])/4.)
#endif
)/sq(Delta);
#if USE_MY_SOLID
res.x[] *= (1.0 - is_solid[]);
#endif
if (fabs (res.x[]) > maxres)
maxres = fabs (res.x[]);
}
#endif
return maxres;
}
#undef lambda
trace
mgstats viscosity (struct Viscosity p)
{
vector u = p.u, r[];
foreach()
foreach_dimension()
r.x[] = u.x[];
face vector mu = p.mu;
scalar rho = p.rho;
restriction ({mu,rho});
#if USE_MY_SOLID
return mg_solve ((scalar *){u}, (scalar *){r},
residual_viscosity, relaxViscousitySolid, &p, p.nrelax, p.res);
#else
return mg_solve ((scalar *){u}, (scalar *){r},
residual_viscosity, relax_viscosity, &p, p.nrelax, p.res);
#endif
}
trace
mgstats viscosity_explicit (struct Viscosity p)
{
vector u = p.u, r[];
mgstats mg = {0};
mg.resb = residual_viscosity ((scalar *){u}, (scalar *){u}, (scalar *){r}, &p);
foreach()
foreach_dimension()
u.x[] += r.x[];
return mg;
}
#endif //_MY_VISCOSITY_H