HCZ模型比上一篇文章中的Shan-Chen模型的一大亮点就是可以自己手动设置接触角,而且相对来说可以模拟的密度比也会大上许多,甚至有文献中可以达到100:1。但是HCZ模型的算法就相对来说要复杂上不少了。
HCZ模型中引入了两个不同的分布函数 f 和 g,具体的算法如下:
其中,a = 12RT, b = 4.
流场宏观量的计算如下:
表面张力的计算如下:
这里的参数在我写的程序中被记为kappa,是一个表面张力控制量,具体的量纲可以在文献 Zhang et al, 2000中找到:[1]. Raoyang Zhang, Xiaoyi He, Shiyi Chen, “Interface and surface tension in incompressible lattice Boltzmann multiphase model”, 2000.
在我写的程序中,设置液体密度为0.251,气体密度为0.024,与文献Lei Wang et al.2013中的参数完全相似。这里贴出来这篇文献:[2]. Lei Wang, Haibo Huang, Xiyun Lu, “Scheme for contact angle and its hysteresis in a multiphase lattice Boltzmann method”, 2013.
基本的算法就是这样,接下来进行接触角的模型描述。
在文献[2]中,引入的接触角计算算法是在2007年由hang ding et al.发展的应用于FVM的接触角测量方法:
图片来源于文献[2].
上式是一个二维情况下的接触角设置方法,这个方法的巧妙之处就在于只需要在ghost area设置以下指标函数的参数就可以了,这也就是为什么在这个系列的第二篇文章中,我提醒了要为ghost area留白。
上式是三维情况下的接触角算法。
算法的介绍就到这里,接下来也是惯例地贴出来代码:如果仍然不是很清楚的话就去看我前面提到的三篇文献。
//A program for lattice Boltzmann in D3Q19 mode.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define NUM_THREADS 4
//定义pi的值
#define pi 3.1415926
#define Q 19
#define D 3
/*前处理模块*/
//GLdouble Lha = 0.000010, Lhb = 0.000010, Lhh = 0.000007;//固体边界参数
//网格边界面:x=0,x=l,y=0,y=m.z=0,z=h,内部点为(l-1)*(m-1)*(h-1)个.
#define l 80
#define m 80
#define h 50
GLdouble DD = 25.0;
GLdouble UU = -0.2;
GLdouble c = 1.0;
GLdouble cs2 = c*c / 3.0;
//GLdouble Lha = 0.000010, Lhb = 0.000010, Lhh = 0.000007;//固体边界参数
GLdouble Real_dx = 0.0005;//长度
GLdouble Real_dt = 0.0005;//时间
GLdouble Real_rho = 800.0;//密度
GLdouble Real_mu = 0.001;//粘度
GLdouble Real_vis = Real_mu / Real_rho;
GLdouble Real_sigma = 0.032;//表面张力[N/m = kg/s2]
GLdouble dx = 1.0, dy = 1.0, dz = 1.0;//长度设定
GLdouble dt = 1.0;//时间设定
GLdouble rho_h = 0.251;//密度~质量设定
GLdouble rho_l = 0.024;
GLdouble rho_w = rho_h;
GLdouble psi_max = 0.251;
GLdouble psi_min = 0.024;
//GLdouble vis = cs2*(tau_f - 0.5);//粘度设定
GLdouble vis = (dx*dx / dt)*Real_vis / (Real_dx*Real_dx / Real_dt);//Re = U*L/vis
GLdouble sigma = Real_sigma*(rho_h*dx*dx*dx / dt / dt) / (Real_rho*Real_dx*Real_dx*Real_dx / Real_dt / Real_dt);//We = rho*U*U*L/sigma
GLdouble tau_f = 0.5 + vis / cs2;
GLdouble tau_g = tau_f;//0.7
char up_boundary = 'B';//上边界为Periodic/Bounceback/Dirichlet? choose P,B,D for your prefer.
char down_boundary = 'B';//下边界为Periodic/Bounceback/Dirichlet? choose P,B,D for your prefer.
char left_boundary = 'P';//左边界为Periodic/Bounceback/Dirichlet? choose P,B,D for your prefer.
char right_boundary = 'P';//右边界为Periodic/Bounceback/Dirichlet? choose P,B,D for your prefer.
char front_boundary = 'P';//前边界为Periodic/Bounceback/Dirichlet? choose P,B,D for your prefer.
char behind_boundary = 'P';//后边界为Periodic/Bounceback/Dirichlet? choose P,B,D for your prefer.
/*前处理模块结束*/
GLdouble winx1 = 0.0, winx2 = l, winy1 = 0.0, winy2 = m;//窗口边界
GLint control = 1;
GLint BUOYANCY = 0;
GLint case_index = 0;
GLdouble w[Q] = { 1.0 / 3.0, //指向原点,a=0
1.0 / 18.0, 1.0 / 18.0, 1.0 / 18.0, 1.0 / 18.0, //指向nx,ny,px,py,a=1,2,3,4
1.0 / 36.0, 1.0 / 36.0, 1.0 / 36.0, 1.0 / 36.0, //指向nxny,pxny,pxpy,nxpy,a=5,6,7,8
1.0 / 18.0, //指向nz,a=9
1.0 / 36.0, 1.0 / 36.0, 1.0 / 36.0, 1.0 / 36.0, //指向nxnz,nynz,,pxnz,pynz,a=10,11,12,13
1.0 / 18.0, //指向pz,a=14
1.0 / 36.0, 1.0 / 36.0, 1.0 / 36.0, 1.0 / 36.0 //指向nxpz,nypz,pxpz,pypz,a=15,16,17,18
};
GLdouble e[Q][D] = { { 0.0, 0.0, 0.0 }, //指向原点,a=0
{ 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { -1.0, 0.0, 0.0 }, { 0.0, -1.0, 0.0 }, //指向nx,ny,px,py,a=1,2,3,4
{ 1.0, 1.0, 0.0 }, { -1.0, 1.0, 0.0 }, { -1.0, -1.0, 0.0 }, { 1.0, -1.0, 0.0 }, //指向nxny,pxny,pxpy,nxpy,a=5,6,7,8
{ 0.0, 0.0, 1.0 }, //指向nz,a=9
{ 1.0, 0.0, 1.0 }, { 0.0, 1.0, 1.0 }, { -1.0, 0.0, 1.0 }, { 0.0, -1.0, 1.0 }, //指向nxnz,nynz,,pxnz,pynz,a=10,11,12,13
{ 0.0, 0.0, -1.0 }, //指向pz,a=14
{ 1.0, 0.0, -1.0 }, { 0.0, 1.0, -1.0 }, { -1.0, 0.0, -1.0 }, { 0.0, -1.0, -1.0 } //指向nxpz,nypz,pxpz,pypz,a=15,16,17,18
};
GLint opp_index[Q] = { 0, 3, 4, 1, 2, 7, 8, 5, 6, 14, 17, 18, 15, 16, 9, 12, 13, 10, 11 };
GLdouble BD = 0.0;
GLint Nwri = 10;
GLdouble p0 = 0.0;
GLdouble thetaAVE = 70.0;
GLdouble thetaR = thetaAVE - 0.0, thetaA = thetaAVE + 0.0;
string filename = "10_20";
GLdouble b = 4.0;
GLdouble a = 12.0*cs2;
GLdouble Ia = 0.014594997025594506;//Term used for calculate surface tensor
GLdouble Kappa = sigma / Ia;
GLdouble t_max = 500000;
GLdouble gforce = 0.0;
GLdouble RT = cs2;
static GLdouble fovy = 50, aspect = 1, zFar = 2.0 + h, zNear = -5.0;//投影
static GLdouble eyex = 1.5*l, eyey = 1.5*m, eyez = 0.5*h, centerx = l / 2, centery = m / 2, centerz = h / 2, upx = 0, upy = 0.0, upz = 1.0;//三维观察
class lattice_node{
public:
GLdouble f[Q];
GLdouble g[Q];
GLdouble fnew[Q];
GLdouble fai;
GLdouble prho;
GLdouble dfai[D];
GLdouble dprho[D];
GLdouble u[D];
GLdouble rho;
GLdouble rh;
GLdouble laplace_rh;
GLdouble p;
GLdouble Force[D];
string status;
lattice_node()
{
fai = 0.0;
prho = 0.0;
rho = rho_l;
rh = psi_min;
laplace_rh = 0.0;
p = 0.0;
status = "L";
}
};
lattice_node Nodes[l + 1][m + 1][h + 1];//边界都是预留给虚网格的位置
//GLdouble psx[l + 1][m + 1][h + 1];
GLdouble velocity_before[l + 1][m + 1][h + 1][D];
void init(void){
glLoadIdentity();
glClearColor(1.0, 1.0, 1.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(winx1, winx2, winy1, winy2);
}
void drawing_liquid(void)
{
GLint i = 0, j = 0, r = 0;
GLint hi = 0, hj = 0;
GLdouble rho_ave = 0.5*(rho_l + rho_h);
glColor3f(0.0, 0.0, 1.0);
glPointSize(0.00001);
glBegin(GL_POINTS);
for (i = 0; i <= l; i++)
{
for (j = 0; j <= m; j++)
{
for (r = 1; r < h; r++)
{
if (Nodes[i][j][r].status == "L")
{
if (Nodes[i][j][r].rho >= rho_ave)
{
glVertex3f(i, j, r);
}
}
}
}
}
glEnd();
glColor3f(0.0, 1.0, 0.0);
//绘制流场外围
glBegin(GL_LINE_STRIP);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(l, 0.0, 0.0);
glVertex3f(l, m, 0.0);
glVertex3f(0.0, m, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glEnd();
glBegin(GL_LINE_STRIP);
glVertex3f(0.0, 0.0, h);
glVertex3f(l, 0.0, h);
glVertex3f(l, m, h);
glVertex3f(0.0, m, h);
glVertex3f(0.0, 0.0, h);
glEnd();
glBegin(GL_LINES);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, h);
glVertex3f(l, 0.0, 0.0);
glVertex3f(l, 0.0, h);
glVertex3f(0.0, m, 0.0);
glVertex3f(0.0, m, h);
glVertex3f(l, m, 0.0);
glVertex3f(l, m, h);
glEnd();
//绘制流场外围结束
return;
}
void Bounceback_Boundary()
{
GLint i = 0, j = 0, r = 0;
if (up_boundary == 'B')
{
#pragma omp parallel for private(i,j)
for (i = 0; i <= l; i++)
{
for (j = 0; j <= m; j++)
{
Nodes[i][j][h - 1].status = "Bup";
}
}
}
if (down_boundary == 'B')
{
#pragma omp parallel for private(i,j)
for (i = 0; i <= l; i++)
{
for (j = 0; j <= m; j++)
{
Nodes[i][j][1].status = "Bdown";
}
}
}
if (front_boundary == 'B')
{
#pragma omp parallel for private(i,r)
for (i = 0; i <= l; i++)
{
for (r = 1; r < h; r++)
{
Nodes[i][1][r].status = "Bfront";
}
}
}
if (behind_boundary == 'B')
{
#pragma omp parallel for private(i,r)
for (i = 0; i <= l; i++)
{
for (r = 1; r < h; r++)
{
Nodes[i][m - 1][r].status = "Bbehind";
}
}
}
if (left_boundary == 'B')
{
#pragma omp parallel for private(j,r)
for (j = 0; j <= m; j++)
{
for (r = 1; r < h; r++)
{
Nodes[0][j][r].status = "Bleft";
}
}
}
if (right_boundary == 'B')
{
#pragma omp parallel for private(j,r)
for (j = 0; j <= m; j++)
{
for (r = 1; r < h; r++)
{
Nodes[l][j][r].status = "Bright";
}
}
}
return;
}
void Dirichlet_Boundary()
{
GLint i = 0, j = 0, r = 0;
if (up_boundary == 'D')
{
#pragma omp parallel for private(i,j)
for (i = 0; i <= l; i++)
{
for (j = 0; j <= m; j++)
{
Nodes[i][j][h - 1].status = "Dup";
}
}
}
if (down_boundary == 'D')
{
#pragma omp parallel for private(i,j)
for (i = 0; i <= l; i++)
{
for (j = 0; j <= m; j++)
{
Nodes[i][j][1].status = "Ddown";
}
}
}
if (front_boundary == 'D')
{
#pragma omp parallel for private(i,r)
for (i = 0; i <= l; i++)
{
for (r = 1; r < h; r++)
{
Nodes[i][1][r].status = "Dfront";
}
}
}
if (behind_boundary == 'D')
{
#pragma omp parallel for private(i,r)
for (i = 0; i <= l; i++)
{
for (r = 1; r < h; r++)
{
Nodes[i][m - 1][r].status = "Dbehind";
}
}
}
if (left_boundary == 'D')
{
#pragma omp parallel for private(j,r)
for (j = 0; j <= m; j++)
{
for (r = 1; r < h; r++)
{
Nodes[0][j][r].status = "Dleft";
}
}
}
if (right_boundary == 'D')
{
#pragma omp parallel for private(j,r)
for (j = 0; j <= m; j++)
{
for (r = 1; r < h; r++)
{
Nodes[l][j][r].status = "Dright";
}
}
}
return;
}
void calculate_feq(GLdouble rh, GLdouble u[D], GLdouble feq_temp[Q])
{
GLdouble eu = 0.0, uv = 0.0;
GLint k = 0, rr = 0;
for (rr = 0; rr < D; rr++)
{
uv += (u[rr] * u[rr]);
}
#pragma omp parallel for private(k,rr,eu)
for (k = 0; k < Q; k++)
{
eu = 0.0;
for (rr = 0; rr < D; rr++)
{
eu += (e[k][rr] * u[rr]);
}
eu *= c;
feq_temp[k] = w[k] * rh*(1.0 + eu / cs2 + 0.5*eu*eu / cs2 / cs2 - 0.5*uv / cs2);
}
return;
}
void calculate_feq_geq(GLdouble rh, GLdouble rho, GLdouble p, GLdouble u[D], GLdouble feq_temp[Q], GLdouble geq_temp[Q])
{
GLdouble eu = 0.0, uv = 0.0;
GLint k = 0, rr = 0;
for (rr = 0; rr < D; rr++)
{
uv += (u[rr] * u[rr]);
}
#pragma omp parallel for private(k,rr,eu)
for (k = 0; k < Q; k++)
{
eu = 0.0;
for (rr = 0; rr < D; rr++)
{
eu += (e[k][rr] * u[rr]);
}
eu *= c;
feq_temp[k] = eu / cs2 + 0.5*eu*eu / cs2 / cs2 - 0.5*uv / cs2;
geq_temp[k] = w[k] * (p + cs2*rho*(feq_temp[k]));
feq_temp[k] = w[k] * rh*(1.0 + feq_temp[k]);
}
return;
}
void calculate_geq(GLdouble rho, GLdouble p, GLdouble u[D], GLdouble geq_temp[Q])
{
GLdouble eu = 0.0, uv = 0.0;
GLint k = 0, rr = 0;
for (rr = 0; rr < D; rr++)
{
uv += (u[rr] * u[rr]);
}
#pragma omp parallel for private(k,rr,eu)
for (k = 0; k < Q; k++)
{
eu = 0.0;
for (rr = 0; rr < D; rr++)
{
eu += (e[k][rr] * u[rr]);
}
eu *= c;
geq_temp[k] = w[k] * (p + cs2*rho*(eu / cs2 + 0.5*eu*eu / cs2 / cs2 - 0.5*uv / cs2));
}
return;
}
GLdouble Cal_error()
{
GLint i = 0, j = 0, r = 0, rr = 0;
GLdouble temp_error = 0.0, final_error = 0.0;
#pragma omp parallel for private(i,j,r,rr,temp_error)
for (i = 0; i <= l; i++)
{
for (j = 0; j <= m; j++)
{
for (r = 1; r < h; r++)
{
if (Nodes[i][j][r].status == "L")
{
temp_error = 0.0;
for (rr = 0; rr < D; rr++)
{
temp_error += (Nodes[i][j][r].u[rr] - velocity_before[i][j][r][rr])*(Nodes[i][j][r].u[rr] - velocity_before[i][j][r][rr]);
}
final_error += sqrt(temp_error);
}
}
}
}
return final_error;
}
void Record_velocity(void)
{
//Record the velocity
GLint i = 0, j = 0, r = 0, rr = 0;
#pragma omp parallel for private(i,j,r,rr)
for (i = 0; i <= l; i++)
{
for (j = 0; j <= m; j++)
{
for (r = 1; r < h; r++)
{
if (Nodes[i][j][r].status == "L")
{
for (rr = 0; rr < D; rr++)
{
velocity_before[i][j][r][rr] = Nodes[i][j][r].u[rr];
}
}
//end if.
}
}
}
//end of 2-D circulation.
return;
}
void initnodes()
{
GLint i = 0, j = 0, r = 0, k = 0, rr = 0;
GLdouble temp_rho = 0.0;
GLdouble feq[Q], geq[Q];
#pragma omp parallel for private(i,j)
for (i = 0; i <= l; i++)
{
for (j = 0; j <= m; j++)
{
Nodes[i][j][0].status = "Virtue";
Nodes[i][j][h].status = "Virtue";
}
}
//end of 2-D circulation.
#pragma omp parallel for private(i,j,r,rr,k,temp_rho,feq,geq)
for (i = 0; i <= l; i++)
{
for (j = 0; j <= m; j++)
{
for (r = 1; r < h; r++)
{
Nodes[i][j][r].rh = psi_min;
Nodes[i][j][r].rho = rho_l;
for (rr = 0; rr < D; rr++)
{
Nodes[i][j][r].u[rr] = 0.0;
Nodes[i][j][r].Force[rr] = 0.0;
Nodes[i][j][r].dfai[rr] = 0.0;
Nodes[i][j][r].dprho[rr] = 0.0;
}
if ((i - l / 2)*(i - l / 2) + (j - m / 2)*(j - m / 2) + (r - DD*0.7)*(r - DD*0.7) <= (DD*DD / 4.0))
{
Nodes[i][j][r].rh = psi_max;
Nodes[i][j][r].rho = rho_h;
Nodes[i][j][r].u[D - 1] = UU;
}
temp_rho = b*Nodes[i][j][r].rho / 4.0;
Nodes[i][j][r].p = Nodes[i][j][r].rho*RT*temp_rho*(4.0 - 2.0*temp_rho) / pow((1 - temp_rho), 3) - a*Nodes[i][j][r].rho*Nodes[i][j][r].rho + Nodes[i][j][r].rho*RT;
calculate_feq_geq(Nodes[i][j][r].rh, Nodes[i][j][r].rho, Nodes[i][j][r].p, Nodes[i][j][r].u, feq, geq);
for (k = 0; k < Q; k++)
{
Nodes[i][j][r].f[k] = feq[k];
Nodes[i][j][r].g[k] = geq[k];
}
//end if.
}
}
}
//the end of 3-D circulation.
return;
}
void rebounce_f()
{
GLint i = 0, j = 0, r = 0;
GLdouble swap_temp = 0.0;
#pragma omp parallel for private(i,j,r,swap_temp)
for (i = 0; i <= l; i++)
{
for (j = 0; j <= m; j++)
{
for (r = 1; r < h; r++)
{
if (Nodes[i][j][r].status[0] == 'B')
{
swap_temp = Nodes[i][j][r].f[1]; Nodes[i][j][r].f[1] = Nodes[i][j][r].f[3]; Nodes[i][j][r].f[3] = swap_temp;
swap_temp = Nodes[i][j][r].f[2]; Nodes[i][j][r].f[2] = Nodes[i][j][r].f[4]; Nodes[i][j][r].f[4] = swap_temp;
swap_temp = Nodes[i][j][r].f[5]; Nodes[i][j][r].f[5] = Nodes[i][j][r].f[7]; Nodes[i][j][r].f[7] = swap_temp;
swap_temp = Nodes[i][j][r].f[6]; Nodes[i][j][r].f[6] = Nodes[i][j][r].f[8]; Nodes[i][j][r].f[8] = swap_temp;
swap_temp = Nodes[i][j][r].f[9]; Nodes[i][j][r].f[9] = Nodes[i][j][r].f[14]; Nodes[i][j][r].f[14] = swap_temp;
swap_temp = Nodes[i][j][r].f[10]; Nodes[i][j][r].f[10] = Nodes[i][j][r].f[17]; Nodes[i][j][r].f[17] = swap_temp;
swap_temp = Nodes[i][j][r].f[11]; Nodes[i][j][r].f[11] = Nodes[i][j][r].f[18]; Nodes[i][j][r].f[18] = swap_temp;
swap_temp = Nodes[i][j][r].f[12]; Nodes[i][j][r].f[12] = Nodes[i][j][r].f[15]; Nodes[i][j][r].f[15] = swap_temp;
swap_temp = Nodes[i][j][r].f[13]; Nodes[i][j][r].f[13] = Nodes[i][j][r].f[16]; Nodes[i][j][r].f[16] = swap_temp;
}
//end if.
}
}
}
//The end of 3-D circulation.
return;
}
void rebounce_g()
{
GLint i = 0, j = 0, r = 0;
GLdouble swap_temp = 0.0;
#pragma omp parallel for private(i,j,r,swap_temp)
for (i = 0; i <= l; i++)
{
for (j = 0; j <= m; j++)
{
for (r = 1; r < h; r++)
{
if (Nodes[i][j][r].status[0] == 'B')
{
swap_temp = Nodes[i][j][r].g[1]; Nodes[i][j][r].g[1] = Nodes[i][j][r].g[3]; Nodes[i][j][r].g[3] = swap_temp;
swap_temp = Nodes[i][j][r].g[2]; Nodes[i][j][r].g[2] = Nodes[i][j][r].g[4]; Nodes[i][j][r].g[4] = swap_temp;
swap_temp = Nodes[i][j][r].g[5]; Nodes[i][j][r].g[5] = Nodes[i][j][r].g[7]; Nodes[i][j][r].g[7] = swap_temp;
swap_temp = Nodes[i][j][r].g[6]; Nodes[i][j][r].g[6] = Nodes[i][j][r].g[8]; Nodes[i][j][r].g[8] = swap_temp;
swap_temp = Nodes[i][j][r].g[9]; Nodes[i][j][r].g[9] = Nodes[i][j][r].g[14]; Nodes[i][j][r].g[14] = swap_temp;
swap_temp = Nodes[i][j][r].g[10]; Nodes[i][j][r].g[10] = Nodes[i][j][r].g[17]; Nodes[i][j][r].g[17] = swap_temp;
swap_temp = Nodes[i][j][r].g[11]; Nodes[i][j][r].g[11] = Nodes[i][j][r].g[18]; Nodes[i][j][r].g[18] = swap_temp;
swap_temp = Nodes[i][j][r].g[12]; Nodes[i][j][r].g[12] = Nodes[i][j][r].g[15]; Nodes[i][j][r].g[15] = swap_temp;
swap_temp = Nodes[i][j][r].g[13]; Nodes[i][j][r].g[13] = Nodes[i][j][r].g[16]; Nodes[i][j][r].g[16] = swap_temp;
}
//end if.
}
}
}
//The end of 3-D circulation.
return;
}
void Streaming()
{
GLint i = 0, j = 0, r = 0, ileft = 0, iright = 0, jfront = 0, jbehind = 0, rup = 0, rdown = 0, k = 0;
//Streaming process::L
#pragma omp parallel for private(i,j,r,ileft,iright,jbehind,jfront,rdown,rup)
for (i = 0; i <= l; i++)
{
ileft = (i > 0) ? (i - 1) : (l);
iright = (i < l) ? (i + 1) : (0);
for (j = 0; j <= m; j++)
{
jfront = (j > 0) ? (j - 1) : (m);
jbehind = (j < m) ? (j + 1) : (0);
for (r = 1; r < h; r++)
{
rdown = (r > 1) ? (r - 1) : (h - 1);
rup = (r < h - 1) ? (r + 1) : (1);
Nodes[iright][j][r].fnew[1] = Nodes[i][j][r].f[1];
Nodes[i][jbehind][r].fnew[2] = Nodes[i][j][r].f[2];
Nodes[ileft][j][r].fnew[3] = Nodes[i][j][r].f[3];
Nodes[i][jfront][r].fnew[4] = Nodes[i][j][r].f[4];
Nodes[iright][jbehind][r].fnew[5] = Nodes[i][j][r].f[5];
Nodes[ileft][jbehind][r].fnew[6] = Nodes[i][j][r].f[6];
Nodes[ileft][jfront][r].fnew[7] = Nodes[i][j][r].f[7];
Nodes[iright][jfront][r].fnew[8] = Nodes[i][j][r].f[8];
Nodes[i][j][rup].fnew[9] = Nodes[i][j][r].f[9];
Nodes[iright][j][rup].fnew[10] = Nodes[i][j][r].f[10];
Nodes[i][jbehind][rup].fnew[11] = Nodes[i][j][r].f[11];
Nodes[ileft][j][rup].fnew[12] = Nodes[i][j][r].f[12];
Nodes[i][jfront][rup].fnew[13] = Nodes[i][j][r].f[13];
Nodes[i][j][rdown].fnew[14] = Nodes[i][j][r].f[14];
Nodes[iright][j][rdown].fnew[15] = Nodes[i][j][r].f[15];
Nodes[i][jbehind][rdown].fnew[16] = Nodes[i][j][r].f[16];
Nodes[ileft][j][rdown].fnew[17] = Nodes[i][j][r].f[17];
Nodes[i][jfront][rdown].fnew[18] = Nodes[i][j][r].f[18];
}
}
}
//the end of 3-D circulation.
#pragma omp parallel for private(i,j,r,k)
for (i = 0; i <= l; i++)
{
for (j = 0; j <= m; j++)
{
for (r = 1; r < h; r++)
{
for (k = 1; k < Q; k++)
{
Nodes[i][j][r].f[k] = Nodes[i][j][r].fnew[k];
}
}
}
}
//the end of 3-D circulation.
//Streaming process::L
#pragma omp parallel for private(i,j,r,ileft,iright,jbehind,jfront,rdown,rup)
for (i = 0; i <= l; i++)
{
ileft = (i > 0) ? (i - 1) : (l);
iright = (i < l) ? (i + 1) : (0);
for (j = 0; j <= m; j++)
{
jfront = (j > 0) ? (j - 1) : (m);
jbehind = (j < m) ? (j + 1) : (0);
for (r = 1; r < h; r++)
{
rdown = (r > 1) ? (r - 1) : (h - 1);
rup = (r < h - 1) ? (r + 1) : (1);
Nodes[iright][j][r].fnew[1] = Nodes[i][j][r].g[1];
Nodes[i][jbehind][r].fnew[2] = Nodes[i][j][r].g[2];
Nodes[ileft][j][r].fnew[3] = Nodes[i][j][r].g[3];
Nodes[i][jfront][r].fnew[4] = Nodes[i][j][r].g[4];
Nodes[iright][jbehind][r].fnew[5] = Nodes[i][j][r].g[5];
Nodes[ileft][jbehind][r].fnew[6] = Nodes[i][j][r].g[6];
Nodes[ileft][jfront][r].fnew[7] = Nodes[i][j][r].g[7];
Nodes[iright][jfront][r].fnew[8] = Nodes[i][j][r].g[8];
Nodes[i][j][rup].fnew[9] = Nodes[i][j][r].g[9];
Nodes[iright][j][rup].fnew[10] = Nodes[i][j][r].g[10];
Nodes[i][jbehind][rup].fnew[11] = Nodes[i][j][r].g[11];
Nodes[ileft][j][rup].fnew[12] = Nodes[i][j][r].g[12];
Nodes[i][jfront][rup].fnew[13] = Nodes[i][j][r].g[13];
Nodes[i][j][rdown].fnew[14] = Nodes[i][j][r].g[14];
Nodes[iright][j][rdown].fnew[15] = Nodes[i][j][r].g[15];
Nodes[i][jbehind][rdown].fnew[16] = Nodes[i][j][r].g[16];
Nodes[ileft][j][rdown].fnew[17] = Nodes[i][j][r].g[17];
Nodes[i][jfront][rdown].fnew[18] = Nodes[i][j][r].g[18];
}
}
}
//the end of 3-D circulation.
#pragma omp parallel for private(i,j,r,k)
for (i = 0; i <= l; i++)
{
for (j = 0; j <= m; j++)
{
for (r = 1; r < h; r++)
{
for (k = 1; k < Q; k++)
{
Nodes[i][j][r].g[k] = Nodes[i][j][r].fnew[k];
}
}
}
}
//the end of 3-D circulation.
return;
}
void macro_process()
{
GLint i = 0, j = 0, r = 0, k = 0, rr = 0;
GLint hi = 0, hj = 0;
GLint ileft = 0, iright = 0, jfront = 0, jbehind = 0, rup = 0, rdown = 0;
GLdouble psi_min0 = psi_min;
GLdouble psi_max0 = psi_max;
GLdouble temp_rh = 0.0;
GLint temp_inter1 = 0, temp_inter2 = 0;
GLdouble temp_angle = 0.0, theta = 0.0;
//macroscopic process
#pragma omp parallel for private(i,j,r,rr,k,temp_rh)
for (i = 0; i <= l; i++)
{
for (j = 0; j <= m; j++)
{
for (r = 1; r < h; r++)
{
//calculation of rh & rho.
if (Nodes[i][j][r].status == "L")//压力边界下的rh变量是固定的,固体壁面的rh应作为插值的容器已经得到。
{
Nodes[i][j][r].rh = 0.0;
for (k = 0; k < Q; k++)
{
Nodes[i][j][r].rh += Nodes[i][j][r].f[k];
}
}
//计算内部流体和固体边界的rho.
Nodes[i][j][r].rho = rho_l + (Nodes[i][j][r].rh - psi_min0) / (psi_max0 - psi_min0)*(rho_h - rho_l);
//calculation of prho & fai.
if (Nodes[i][j][r].status == "L" || Nodes[i][j][r].status[0] == 'D')//压力边界上的场点也算是一种流体
{
temp_rh = b*Nodes[i][j][r].rh / 4.0;
Nodes[i][j][r].prho = Nodes[i][j][r].p - cs2*Nodes[i][j][r].rho;
Nodes[i][j][r].fai = Nodes[i][j][r].rh*RT*(4 * temp_rh - 2 * temp_rh*temp_rh) / pow((1 - temp_rh), 3) - a*Nodes[i][j][r].rh*Nodes[i][j][r].rh;
}
//end if.
}
}
}
//The end of 3-D circulation.
//========================================================================
//== ==
//== 接触角的计算 ==
//== ==
//========================================================================
////接触角:假设认为地面和顶面是固体边界,那么r=0和r=h的区域就应该被认作是一层虚网格,我们把需要的参数铺在这层虚网格上面。
if (down_boundary == 'B' && up_boundary == 'B')
{
#pragma omp parallel for private(i,j,r,ileft,iright,jfront,jbehind,rup,rdown,temp_angle,theta)
for (i = 0; i <= l; i++)//x方向是显然的周期性边界条件
{
ileft = (i > 0) ? (i - 1) : (l);
iright = (i < l) ? (i + 1) : (0);
for (j = 0; j <= m; j++)
{
jfront = (j > 0) ? (j - 1) : (m);
jbehind = (j < m) ? (j + 1) : (0);
//下地面:全部设置为固壁边界条件
temp_angle = sqrt(pow(Nodes[iright][j][2].rh - Nodes[ileft][j][2].rh, 2) + pow(Nodes[i][jbehind][2].rh - Nodes[i][jfront][2].rh, 2));
if (temp_angle == 0 && Nodes[i][j][1].rh >= Nodes[i][j][3].rh)
{
theta = 0;
}
else if (temp_angle == 0 && Nodes[i][j][1].rh < Nodes[i][j][3].rh)
{
theta = 180;
}
else
{
theta = 90 - atan((Nodes[i][j][1].rh - Nodes[i][j][3].rh) / temp_angle) * 180 / pi;
}
if (theta > thetaA)
{
theta = thetaA;
Nodes[i][j][1].rh = Nodes[i][j][3].rh + tan(pi*(90.0 - theta) / 180.0)*temp_angle;
}
else if (theta < thetaR)
{
theta = thetaR;
Nodes[i][j][1].rh = Nodes[i][j][3].rh + tan(pi*(90.0 - theta) / 180.0)*temp_angle;
}
//上地面:全部设置为固壁边界条件
/*
temp_angle = sqrt(pow(Nodes[iright][j][h - 2].rh - Nodes[ileft][j][h - 2].rh, 2) + pow(Nodes[i][jbehind][h - 2].rh - Nodes[i][jfront][h - 2].rh, 2));
if (temp_angle == 0 && Nodes[i][j][h - 1].rh >= Nodes[i][j][h - 3].rh)
{
theta = 0;
}
else if (temp_angle == 0 && Nodes[i][j][h - 1].rh < Nodes[i][j][h - 3].rh)
{
theta = 180;
}
else
{
theta = 90 - atan((Nodes[i][j][h - 1].rh - Nodes[i][j][h - 3].rh) / temp_angle) * 180 / pi;
}
if (theta > thetaA)
{
theta = thetaA;
Nodes[i][j][h - 1].rh = Nodes[i][j][h - 3].rh + tan(pi*(90.0 - theta) / 180.0)*temp_angle;
}
else if (theta < thetaR)
{
theta = thetaR;
Nodes[i][j][h - 1].rh = Nodes[i][j][h - 3].rh + tan(pi*(90.0 - theta) / 180.0)*temp_angle;
}
*/
Nodes[i][j][h - 1].rh = Nodes[i][j][h - 3].rh;
//上下地面的一层虚网格
Nodes[i][j][0].rh = Nodes[i][j][1].rh;
Nodes[i][j][h].rh = Nodes[i][j][h - 1].rh;
//辅助变量prho和fai的上下固壁边界插值计算
Nodes[i][j][h - 1].prho = Nodes[i][j][h - 2].prho;
Nodes[i][j][1].prho = Nodes[i][j][2].prho;
Nodes[i][j][h - 1].fai = Nodes[i][j][h - 2].fai;
Nodes[i][j][1].fai = Nodes[i][j][2].fai;
}
}
}
//计算laplace_rh
#pragma omp parallel for private(i,j,r,ileft,iright,jbehind,jfront,rdown,rup)
for (i = 0; i <= l; i++)
{
ileft = (i > 0) ? (i - 1) : (l);
iright = (i < l) ? (i + 1) : (0);
for (j = 0; j <= m; j++)
{
jfront = (j > 0) ? (j - 1) : (m);
jbehind = (j < m) ? (j + 1) : (0);
for (r = 1; r < h; r++)
{
rdown = r - 1;
rup = r + 1;
Nodes[i][j][r].laplace_rh = (Nodes[ileft][j][r].rh + Nodes[iright][j][r].rh + Nodes[i][jfront][r].rh + Nodes[i][jbehind][r].rh + Nodes[i][j][rup].rh + Nodes[i][j][rdown].rh)*2.0 / 6.0;
Nodes[i][j][r].laplace_rh += (Nodes[ileft][jfront][r].rh + Nodes[iright][jfront][r].rh + Nodes[ileft][jbehind][r].rh + Nodes[iright][jbehind][r].rh) / 6.0;
Nodes[i][j][r].laplace_rh += (Nodes[ileft][j][rdown].rh + Nodes[iright][j][rdown].rh + Nodes[ileft][j][rup].rh + Nodes[iright][j][rup].rh) / 6.0;
Nodes[i][j][r].laplace_rh += (Nodes[i][jfront][rdown].rh + Nodes[i][jbehind][rdown].rh + Nodes[i][jfront][rup].rh + Nodes[i][jbehind][rup].rh) / 6.0;
Nodes[i][j][r].laplace_rh -= 24.0*Nodes[i][j][r].rh / 6.0;
}
}
}
//the end of 3-D circulation.
#pragma omp parallel for private(i,j,r,ileft,iright,jbehind,jfront,rdown,rup)
for (i = 0; i <= l; i++)
{
ileft = (i > 0) ? (i - 1) : (l);
iright = (i < l) ? (i + 1) : (0);
for (j = 0; j <= m; j++)
{
jfront = (j > 0) ? (j - 1) : (m);
jbehind = (j < m) ? (j + 1) : (0);
for (r = 1; r < h; r++)
{
rdown = r - 1;
rup = r + 1;
if (Nodes[i][j][r].status[0] == 'B')
{
continue;
}
Nodes[i][j][r].Force[0] = 2.0*(Nodes[iright][j][r].laplace_rh - Nodes[ileft][j][r].laplace_rh);
Nodes[i][j][r].Force[0] += (Nodes[iright][jbehind][r].laplace_rh - Nodes[ileft][jfront][r].laplace_rh);
Nodes[i][j][r].Force[0] += (Nodes[iright][jfront][r].laplace_rh - Nodes[ileft][jbehind][r].laplace_rh);
Nodes[i][j][r].Force[0] += (Nodes[iright][j][rup].laplace_rh - Nodes[ileft][j][rdown].laplace_rh);
Nodes[i][j][r].Force[0] += (Nodes[iright][j][rdown].laplace_rh - Nodes[ileft][j][rup].laplace_rh);
Nodes[i][j][r].Force[0] *= Kappa*Nodes[i][j][r].rh / 12.0;
Nodes[i][j][r].Force[1] = 2.0*(Nodes[i][jbehind][r].laplace_rh - Nodes[i][jfront][r].laplace_rh);
Nodes[i][j][r].Force[1] += (Nodes[iright][jbehind][r].laplace_rh - Nodes[ileft][jfront][r].laplace_rh);
Nodes[i][j][r].Force[1] += (Nodes[ileft][jbehind][r].laplace_rh - Nodes[iright][jfront][r].laplace_rh);
Nodes[i][j][r].Force[1] += (Nodes[i][jbehind][rup].laplace_rh - Nodes[i][jfront][rdown].laplace_rh);
Nodes[i][j][r].Force[1] += (Nodes[i][jbehind][rdown].laplace_rh - Nodes[i][jfront][rup].laplace_rh);
Nodes[i][j][r].Force[1] *= Kappa*Nodes[i][j][r].rh / 12.0;
Nodes[i][j][r].Force[2] = 2.0*(Nodes[i][j][rup].laplace_rh - Nodes[i][j][rdown].laplace_rh);
Nodes[i][j][r].Force[2] += (Nodes[iright][j][rup].laplace_rh - Nodes[ileft][j][rdown].laplace_rh);
Nodes[i][j][r].Force[2] += (Nodes[ileft][j][rup].laplace_rh - Nodes[iright][j][rdown].laplace_rh);
Nodes[i][j][r].Force[2] += (Nodes[i][jbehind][rup].laplace_rh - Nodes[i][jfront][rdown].laplace_rh);
Nodes[i][j][r].Force[2] += (Nodes[i][jfront][rup].laplace_rh - Nodes[i][jbehind][rdown].laplace_rh);
Nodes[i][j][r].Force[2] *= Kappa*Nodes[i][j][r].rh / 12.0;
if (BUOYANCY == 1)
{
Nodes[i][j][r].Force[2] -= gforce*Nodes[i][j][r].rho;
}
Nodes[i][j][r].dfai[0] = 2.0*(Nodes[iright][j][r].fai - Nodes[ileft][j][r].fai);
Nodes[i][j][r].dfai[0] += (Nodes[iright][jbehind][r].fai - Nodes[ileft][jfront][r].fai);
Nodes[i][j][r].dfai[0] += (Nodes[iright][jfront][r].fai - Nodes[ileft][jbehind][r].fai);
Nodes[i][j][r].dfai[0] += (Nodes[iright][j][rup].fai - Nodes[ileft][j][rdown].fai);
Nodes[i][j][r].dfai[0] += (Nodes[iright][j][rdown].fai - Nodes[ileft][j][rup].fai);
Nodes[i][j][r].dfai[0] /= 12.0;
Nodes[i][j][r].dfai[1] = 2.0*(Nodes[i][jbehind][r].fai - Nodes[i][jfront][r].fai);
Nodes[i][j][r].dfai[1] += (Nodes[iright][jbehind][r].fai - Nodes[ileft][jfront][r].fai);
Nodes[i][j][r].dfai[1] += (Nodes[ileft][jbehind][r].fai - Nodes[iright][jfront][r].fai);
Nodes[i][j][r].dfai[1] += (Nodes[i][jbehind][rup].fai - Nodes[i][jfront][rdown].fai);
Nodes[i][j][r].dfai[1] += (Nodes[i][jbehind][rdown].fai - Nodes[i][jfront][rup].fai);
Nodes[i][j][r].dfai[1] /= 12.0;
Nodes[i][j][r].dfai[2] = 2.0*(Nodes[i][j][rup].fai - Nodes[i][j][rdown].fai);
Nodes[i][j][r].dfai[2] += (Nodes[iright][j][rup].fai - Nodes[ileft][j][rdown].fai);
Nodes[i][j][r].dfai[2] += (Nodes[ileft][j][rup].fai - Nodes[iright][j][rdown].fai);
Nodes[i][j][r].dfai[2] += (Nodes[i][jbehind][rup].fai - Nodes[i][jfront][rdown].fai);
Nodes[i][j][r].dfai[2] += (Nodes[i][jfront][rup].fai - Nodes[i][jbehind][rdown].fai);
Nodes[i][j][r].dfai[2] /= 12.0;
Nodes[i][j][r].dprho[0] = 2.0*(Nodes[iright][j][r].prho - Nodes[ileft][j][r].prho);
Nodes[i][j][r].dprho[0] += (Nodes[iright][jbehind][r].prho - Nodes[ileft][jfront][r].prho);
Nodes[i][j][r].dprho[0] += (Nodes[iright][jfront][r].prho - Nodes[ileft][jbehind][r].prho);
Nodes[i][j][r].dprho[0] += (Nodes[iright][j][rup].prho - Nodes[ileft][j][rdown].prho);
Nodes[i][j][r].dprho[0] += (Nodes[iright][j][rdown].prho - Nodes[ileft][j][rup].prho);
Nodes[i][j][r].dprho[0] /= 12.0;
Nodes[i][j][r].dprho[1] = 2.0*(Nodes[i][jbehind][r].prho - Nodes[i][jfront][r].prho);
Nodes[i][j][r].dprho[1] += (Nodes[iright][jbehind][r].prho - Nodes[ileft][jfront][r].prho);
Nodes[i][j][r].dprho[1] += (Nodes[ileft][jbehind][r].prho - Nodes[iright][jfront][r].prho);
Nodes[i][j][r].dprho[1] += (Nodes[i][jbehind][rup].prho - Nodes[i][jfront][rdown].prho);
Nodes[i][j][r].dprho[1] += (Nodes[i][jbehind][rdown].prho - Nodes[i][jfront][rup].prho);
Nodes[i][j][r].dprho[1] /= 12.0;
Nodes[i][j][r].dprho[2] = 2.0*(Nodes[i][j][rup].prho - Nodes[i][j][rdown].prho);
Nodes[i][j][r].dprho[2] += (Nodes[iright][j][rup].prho - Nodes[ileft][j][rdown].prho);
Nodes[i][j][r].dprho[2] += (Nodes[ileft][j][rup].prho - Nodes[iright][j][rdown].prho);
Nodes[i][j][r].dprho[2] += (Nodes[i][jbehind][rup].prho - Nodes[i][jfront][rdown].prho);
Nodes[i][j][r].dprho[2] += (Nodes[i][jfront][rup].prho - Nodes[i][jbehind][rdown].prho);
Nodes[i][j][r].dprho[2] /= 12.0;
}
}
}
//the end of 3-D circulation.
return;
}
void geten()
{
GLint i = 0, j = 0, r = 0, rr = 0, k = 0;
#pragma omp parallel for private(i,j,r,rr,k)
for (i = 0; i <= l; i++)
{
for (j = 0; j <= m; j++)
{
for (r = 1; r < h; r++)
{
if (Nodes[i][j][r].status == "L")//压力边界点处的速度由插值得到,故不作计算
{
for (rr = 0; rr < D; rr++)
{
Nodes[i][j][r].u[rr] = 0.0;
for (k = 0; k < Q; k++)
{
Nodes[i][j][r].u[rr] += e[k][rr] * Nodes[i][j][r].g[k];
}
Nodes[i][j][r].u[rr] *= c;
Nodes[i][j][r].u[rr] += 0.5*RT*dt*Nodes[i][j][r].Force[rr];
Nodes[i][j][r].u[rr] /= (Nodes[i][j][r].rho*RT);
}
}
//end if.
if (Nodes[i][j][r].status == "L" || Nodes[i][j][r].status[0] == 'D')
{
Nodes[i][j][r].p = 0.0;
for (k = 0; k < Q; k++)
{
Nodes[i][j][r].p += Nodes[i][j][r].g[k];
}
for (rr = 0; rr < D; rr++)
{
Nodes[i][j][r].p += (-0.5)*Nodes[i][j][r].u[rr] * Nodes[i][j][r].dprho[rr] * dt;
}
}
//end if.
}
}
}
return;
}
void Collision()
{
GLint i = 0, j = 0, r = 0, k = 0, rr = 0;
GLdouble temp_f = 0.0, temp_g1 = 0.0, temp_g2 = 0.0;
GLdouble feq[Q], geq[Q];
//Collide process
#pragma omp parallel for private(i,j,r,rr,k,temp_f,temp_g1,temp_g2,feq,geq)
for (i = 0; i <= l; i++)
{
for (j = 0; j <= m; j++)
{
for (r = 1; r < h; r++)
{
if (Nodes[i][j][r].status == "L")// || Nodes[i][j][r].status[0] == 'D')
{
calculate_feq_geq(Nodes[i][j][r].rh, Nodes[i][j][r].rho, Nodes[i][j][r].p, Nodes[i][j][r].u, feq, geq);
for (k = 0; k < Q; k++)
{
Nodes[i][j][r].f[k] = Nodes[i][j][r].f[k] * (1.0 - 1.0 / tau_f) + feq[k] / tau_f;
Nodes[i][j][r].g[k] = Nodes[i][j][r].g[k] * (1.0 - 1.0 / tau_g) + geq[k] / tau_g;
temp_f = 0.0;
temp_g1 = 0.0;
temp_g2 = 0.0;
for (rr = 0; rr < D; rr++)
{
temp_f += (e[k][rr] * c - Nodes[i][j][r].u[rr])*(-Nodes[i][j][r].dfai[rr]) * feq[k];
temp_g1 += (e[k][rr] * c - Nodes[i][j][r].u[rr])*Nodes[i][j][r].Force[rr] * feq[k] / Nodes[i][j][r].rh;
temp_g2 += (e[k][rr] * c - Nodes[i][j][r].u[rr])*(-Nodes[i][j][r].dprho[rr]) * ((feq[k] / Nodes[i][j][r].rh) - w[k]);
}
Nodes[i][j][r].f[k] += dt*(tau_f - 0.5) / tau_f * temp_f / (RT*Nodes[i][j][r].rh);
Nodes[i][j][r].g[k] += dt*(tau_g - 0.5) / tau_g*(temp_g1 + temp_g2);
}
}
//end if.
}
}
}
//the end of 3-D circulation.
return;
}
void output()
{
GLint i = 0, j = 0, r = 0;
GLint Temp_i = 0, Temp_j = 0, Temp_r = 0;
char Temp_str1 = 'c', Temp_str2 = 'c';
FILE *fp;
if (!(fp = fopen((filename + "//data_velocity.dat").c_str(), "w")))
{
printf("写入文件失败!\n");
exit(1);
}
fprintf(fp, "TITLE =\"lattice boltzmann\"\n");
fprintf(fp, "VARIABLES = \"X\" \"Y\" \"Z\" \"U\" \"V\" \"W\"\n");
fprintf(fp, "ZONE I=%d, J=%d, K=%d\n", l + 1, m - 1, h - 1);
fprintf(fp, "F=POINT\n");
for (i = 0; i <= l; i++)
{
for (j = 1; j < m; j++)
{
for (r = 1; r < h; r++)
{
fprintf(fp, "%d %d %d %lf %lf %lf\n", i, j, r, Nodes[i][j][r].u[0], Nodes[i][j][r].u[1], Nodes[i][j][r].u[2]);
}
}
}
fclose(fp);
if (!(fp = fopen((filename + "//data_density.dat").c_str(), "w")))
{
printf("写入文件失败!\n");
exit(1);
}
fprintf(fp, "TITLE =\"lattice boltzmann\"\n");
fprintf(fp, "VARIABLES = \"X\" \"Y\" \"Z\" \"RHO\"\n");
fprintf(fp, "ZONE I=%d, J=%d, K=%d\n", l + 1, m - 1, h - 1);
fprintf(fp, "F=POINT\n");
for (i = 0; i <= l; i++)
{
for (j = 1; j < m; j++)
{
for (r = 1; r < h; r++)
{
fprintf(fp, "%d %d %d %lf\n", i, j, r, Nodes[i][j][r].rho);
}
}
}
fclose(fp);
return;
}
void LBMs()
{
GLdouble final_error = 1.0;
GLint i = 0, r = 0;
omp_set_num_threads(NUM_THREADS);
//标记迪利克雷边界条件
Dirichlet_Boundary();
////因为压力边界一般来说都不会包括上壁沿和下壁沿,所以回弹性边界条件放置在压力边界条件的后面进行标记。
//标记回弹性边界条件
Bounceback_Boundary();
//初始化
initnodes();
drawing_liquid();
glutSwapBuffers();
cout << "Kappa: " << Kappa << endl;
cout << "tau_f: " << tau_f << endl;
system("pause");
for (GLint t = 0; t < t_max; t++)
{
//Record the velocity
Record_velocity();
//Streaming process
Streaming();
//macro process
macro_process();
geten();
//Collision process
rebounce_f();
rebounce_g();
Collision();
//Dirichlet_fg();
if (t%Nwri == 0)
{
std::cout << "=====================" << endl;
final_error = Cal_error();
std::cout << "Step: " << t << "; error: " << final_error << endl;
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
gluPerspective(fovy, aspect, zFar, zNear);
gluLookAt(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz);
drawing_liquid();
glutSwapBuffers();
output();
}
}
}
static void display(void)
{
init();
GLint i = 0, j = 0, r = 0;
GLint Temp_i = 0, Temp_j = 0, Temp_r = 0;
GLdouble scale_velo = 20;
char Temp_str1 = 'c', Temp_str2 = 'c';
FILE *fp;
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
gluPerspective(fovy, aspect, zFar, zNear);
gluLookAt(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz);
glColor3f(0.0, 1.0, 0.0);
//绘制流场外围
glBegin(GL_LINE_STRIP);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(l, 0.0, 0.0);
glVertex3f(l, m, 0.0);
glVertex3f(0.0, m, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glEnd();
glBegin(GL_LINE_STRIP);
glVertex3f(0.0, 0.0, h);
glVertex3f(l, 0.0, h);
glVertex3f(l, m, h);
glVertex3f(0.0, m, h);
glVertex3f(0.0, 0.0, h);
glEnd();
glBegin(GL_LINES);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, h);
glVertex3f(l, 0.0, 0.0);
glVertex3f(l, 0.0, h);
glVertex3f(0.0, m, 0.0);
glVertex3f(0.0, m, h);
glVertex3f(l, m, 0.0);
glVertex3f(l, m, h);
glEnd();
//绘制流场外围结束
if (control == 1)
{
LBMs();
control = -1;
output();
}
if (control == 0)
{
if (!(fp = fopen((filename + "//data_density.dat").c_str(), "r")))
{
printf("读入文件失败!\n");
exit(1);
}
while (true)
{
Temp_str2 = Temp_str1;
fscanf(fp, "%c", &Temp_str1);
if (Temp_str1 == 'T'&&Temp_str2 == 'N')
{
break;
}
}
for (i = 0; i <= l; i++)
{
for (j = 1; j < m; j++)
{
for (r = 1; r < h; r++)
{
fscanf(fp, "%d %d %d %lf\n", &Temp_i, &Temp_j, &Temp_r, &Nodes[i][j][r].rho);
}
}
}
fclose(fp);
}
drawing_liquid();
glutSwapBuffers();
//glFlush();
}
void chooseMode(GLint menuIteemNum)
{
switch (menuIteemNum)
{
case 0:
case_index = 0; break;
case 1:
case_index = 1; break;
case 2:
case_index = 2; break;
default:
case_index = -1; break;
}
glutPostRedisplay();
}
void mouseFunc(GLint button, GLint action, GLint xMouse, GLint yMouse)
{
glutCreateMenu(chooseMode);
glutAddMenuEntry("figure : Re=100 & grid = 40x40 80x80 160x160", 0);
glutAddMenuEntry("figure : Re=400 & grid = 40x40 80x80 160x160", 1);
glutAddMenuEntry("figure : Re=1000 & grid = 40x40 80x80 160x160", 2);
glutAttachMenu(GLUT_RIGHT_BUTTON);
}
int main(int argc, char *argv[])
{
if (l<2 || m<2 || h<2)
{
cout << "There's an error in the defination of the division of mesh." << endl;
exit(-1);
}
glutInit(&argc, argv);
glutInitWindowSize(600, 600);
glutInitWindowPosition(10, 10);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("Poiseuille Flow");
init();
glutDisplayFunc(display);
glutMouseFunc(mouseFunc);
glutMainLoop();
return EXIT_SUCCESS;
}
这个程序跟上一个程序完全类似,仅仅是计算液滴在不同接触角下在壁面上的铺展。这里就懒得再放自己跑出来的结果了,知识展示一下文献[2]中的结果。
LBM的多相流模型到这里就算全部都总结完了,其他的比如自由能模型等,我感觉并不是十分好用,所以也没有去接触过。LBM还缺一个圆柱绕流的浸入边界法没有深入讲解,我估计自己也实在是懒得再去写了。
LBM的总结到这里基本就是完全结束了。后面会再开新的系列,不过就已经不再是CFD领域的东西了。