使用C++实现格子玻尔兹曼方法(LBM)模拟Couette流动的完整代码,包含周期边界条件和曲线边界条件处理。
1. 基本LBM框架
cpp
#include <iostream>
#include <fstream>
#include <cmath>
#include <vector>
#include <array>
using namespace std;
// 常数定义
const int NX = 100; // x方向格子数
const int NY = 50; // y方向格子数
const int Q = 9; // D2Q9模型
const double tau = 0.8; // 松弛时间
const double rho0 = 1.0; // 初始密度
const double u0 = 0.1; // 顶板速度
// D2Q9模型的离散速度
const array<int, Q> cx = {0, 1, 0, -1, 0, 1, -1, -1, 1};
const array<int, Q> cy = {0, 0, 1, 0, -1, 1, 1, -1, -1};
// 权重系数
const array<double, Q> w = {
4.0/9.0, 1.0/9.0, 1.0/9.0, 1.0/9.0, 1.0/9.0,
1.0/36.0, 1.0/36.0, 1.0/36.0, 1.0/36.0
};
// 分布函数
vector<vector<array<double, Q>>> f(NX, vector<array<double, Q>>(NY));
vector<vector<array<double, Q>>> f_eq(NX, vector<array<double, Q>>(NY));
vector<vector<array<double, Q>>> f_new(NX, vector<array<double, Q>>(NY));
// 宏观量
vector<vector<double>> rho(NX, vector<double>(NY, rho0));
vector<vector<double>> ux(NX, vector<double>(NY, 0.0));
vector<vector<double>> uy(NX, vector<double>(NY, 0.0));
// 边界条件标志 (0=流体, 1=上壁面, 2=下壁面, 3=曲线边界)
vector<vector<int>> boundary(NX, vector<int>(NY, 0));
// 初始化函数
void initialize() {
// 设置边界条件
for (int i = 0; i < NX; ++i) {
boundary[i][0] = 2; // 下壁面 (静止)
boundary[i][NY-1] = 1; // 上壁面 (移动)
}
// 初始化分布函数
for (int i = 0; i < NX; ++i) {
for (int j = 0; j < NY; ++j) {
for (int k = 0; k < Q; ++k) {
f[i][j][k] = w[k] * rho[i][j];
}
}
}
}
// 计算平衡分布函数
void calculate_eq() {
for (int i = 0; i < NX; ++i) {
for (int j = 0; j < NY; ++j) {
double u2 = ux[i][j] * ux[i][j] + uy[i][j] * uy[i][j];
for (int k = 0; k < Q; ++k) {
double cu = cx[k] * ux[i][j] + cy[k] * uy[i][j];
f_eq[i][j][k] = w[k] * rho[i][j] * (1.0 + 3.0 * cu + 4.5 * cu * cu - 1.5 * u2);
}
}
}
}
// 碰撞步骤
void collision() {
for (int i = 0; i < NX; ++i) {
for (int j = 0; j < NY; ++j) {
if (boundary[i][j] == 0) { // 仅处理流体节点
for (int k = 0; k < Q; ++k) {
f_new[i][j][k] = f[i][j][k] - (f[i][j][k] - f_eq[i][j][k]) / tau;
}
}
}
}
}
2. 边界条件处理
cpp
// 周期边界条件处理
void apply_periodic_boundary() {
// 左边界 (i=0)
for (int j = 0; j < NY; ++j) {
if (boundary[0][j] == 0) { // 流体节点
for (int k = 0; k < Q; ++k) {
if (cx[k] == -1) { // 向左移动的粒子
f_new[NX-1][j][k] = f_new[0][j][k];
}
}
}
}
// 右边界 (i=NX-1)
for (int j = 0; j < NY; ++j) {
if (boundary[NX-1][j] == 0) { // 流体节点
for (int k = 0; k < Q; ++k) {
if (cx[k] == 1) { // 向右移动的粒子
f_new[0][j][k] = f_new[NX-1][j][k];
}
}
}
}
}
// 曲线边界条件处理 (反弹格式)
void apply_curved_boundary() {
for (int i = 0; i < NX; ++i) {
for (int j = 0; j < NY; ++j) {
if (boundary[i][j] == 3) { // 曲线边界节点
// 找到最近的流体节点
int i_fluid = i, j_fluid = j;
if (i > 0 && boundary[i-1][j] == 0) i_fluid = i-1;
else if (i < NX-1 && boundary[i+1][j] == 0) i_fluid = i+1;
if (j > 0 && boundary[i][j-1] == 0) j_fluid = j-1;
else if (j < NY-1 && boundary[i][j+1] == 0) j_fluid = j+1;
// 反弹格式
for (int k = 0; k < Q; ++k) {
int k_opp = (k + Q/2) % Q; // 相反方向
f_new[i][j][k] = f_new[i_fluid][j_fluid][k_opp];
}
}
}
}
}
// 移动壁面边界条件 (Couette流上壁面)
void apply_moving_wall() {
for (int i = 0; i < NX; ++i) {
// 上壁面 (j=NY-1)
if (boundary[i][NY-1] == 1) {
ux[i][NY-1] = u0; // 设置壁面速度
uy[i][NY-1] = 0.0;
// 计算壁面处的平衡分布
double u2 = ux[i][NY-1] * ux[i][NY-1] + uy[i][NY-1] * uy[i][NY-1];
for (int k = 0; k < Q; ++k) {
double cu = cx[k] * ux[i][NY-1] + cy[k] * uy[i][NY-1];
f_new[i][NY-1][k] = w[k] * rho[i][NY-1] * (1.0 + 3.0 * cu + 4.5 * cu * cu - 1.5 * u2);
}
}
// 下壁面 (j=0)
if (boundary[i][0] == 2) {
ux[i][0] = 0.0; // 静止壁面
uy[i][0] = 0.0;
// 计算壁面处的平衡分布
double u2 = ux[i][0] * ux[i][0] + uy[i][0] * uy[i][0];
for (int k = 0; k < Q; ++k) {
double cu = cx[k] * ux[i][0] + cy[k] * uy[i][0];
f_new[i][0][k] = w[k] * rho[i][0] * (1.0 + 3.0 * cu + 4.5 * cu * cu - 1.5 * u2);
}
}
}
}
3. 流动步骤和宏观量计算
cpp
// 流动步骤
void streaming() {
for (int i = 0; i < NX; ++i) {
for (int j = 0; j < NY; ++j) {
if (boundary[i][j] == 0) { // 仅处理流体节点
for (int k = 0; k < Q; ++k) {
int i_next = (i + cx[k] + NX) % NX; // 周期边界处理
int j_next = j + cy[k];
if (j_next >= 0 && j_next < NY) {
if (boundary[i_next][j_next] == 0) { // 流向流体节点
f[i_next][j_next][k] = f_new[i][j][k];
}
}
}
}
}
}
}
// 计算宏观量
void calculate_macro() {
for (int i = 0; i < NX; ++i) {
for (int j = 0; j < NY; ++j) {
if (boundary[i][j] == 0) { // 仅处理流体节点
double rho_temp = 0.0;
double ux_temp = 0.0;
double uy_temp = 0.0;
for (int k = 0; k < Q; ++k) {
rho_temp += f[i][j][k];
ux_temp += f[i][j][k] * cx[k];
uy_temp += f[i][j][k] * cy[k];
}
rho[i][j] = rho_temp;
ux[i][j] = ux_temp / rho_temp;
uy[i][j] = uy_temp / rho_temp;
}
}
}
}
4. 主程序和输出
cpp
// 添加曲线边界 (示例: 圆形障碍物)
void add_curved_boundary() {
int center_x = NX/2;
int center_y = NY/2;
int radius = NY/4;
for (int i = 0; i < NX; ++i) {
for (int j = 0; j < NY; ++j) {
int dx = i - center_x;
int dy = j - center_y;
if (dx*dx + dy*dy <= radius*radius) {
boundary[i][j] = 3; // 曲线边界
}
}
}
}
// 输出结果到文件
void output(int step) {
ofstream file("velocity_" + to_string(step) + ".dat");
file << "VARIABLES = \"X\", \"Y\", \"U\", \"V\", \"Rho\"\n";
file << "ZONE I=" << NX << ", J=" << NY << ", F=POINT\n";
for (int j = 0; j < NY; ++j) {
for (int i = 0; i < NX; ++i) {
file << i << " " << j << " " << ux[i][j] << " " << uy[i][j] << " " << rho[i][j] << "\n";
}
}
file.close();
}
int main() {
// 初始化
initialize();
add_curved_boundary(); // 添加曲线边界
// 主循环
int max_step = 10000;
int output_interval = 1000;
for (int step = 0; step < max_step; ++step) {
calculate_eq(); // 计算平衡分布
collision(); // 碰撞步骤
apply_periodic_boundary(); // 应用周期边界
apply_curved_boundary(); // 应用曲线边界
apply_moving_wall(); // 应用移动壁面边界
streaming(); // 流动步骤
calculate_macro(); // 计算宏观量
// 输出结果
if (step % output_interval == 0) {
output(step);
cout << "Step: " << step << endl;
}
}
return 0;
}
5. 代码说明和参数调整
5.1 关键参数说明
- NX, NY: 计算域大小
- tau : 松弛时间,影响流体粘性 (
ν = (τ-0.5)/3) - u0: 上壁面移动速度,决定剪切率
- w: D2Q9模型的权重系数
- cx, cy: D2Q9模型的离散速度方向
5.2 边界条件实现
- 周期边界: 在x方向实现周期性流动
- 曲线边界: 使用反弹格式处理复杂边界
- 移动壁面: 上壁面以速度u0移动,下壁面静止
5.3 扩展功能
- 要模拟不同几何形状,修改
add_curved_boundary()函数 - 要改变流动条件,调整壁面速度或初始条件
- 要输出更多物理量,扩展
output()函数
5.4 编译和运行
使用C++编译器编译并运行:
bash
g++ lbm_couette.cpp -o lbm_couette -O3
./lbm_couette
输出文件可以使用Tecplot、Paraview等软件可视化。
参考代码 用C++模拟LBM的couette流源代码 www.youwenfan.com/contentcsl/56505.html
这个实现提供了Couette流动的完整LBM模拟框架,包含周期边界和曲线边界处理,可以作为更复杂LBM模拟的基础。