You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Lattice Boltzmann方法的C++ CFD仿真效果异常求助

C++实现LBM仿真效果不佳求助

我尝试用C++实现自主CFD程序,参考YouTube上的Lattice Boltzmann方法视频,但仿真效果达不到视频中Python实现的LBM效果。使用SDL2在CPU端做可视化,不追求速度,只想要美观的仿真动画效果。

代码实现

Cell类代码

//cell class
class cell {

public:
    double Fi[nL] = {0,0,0,0,0,0,0,0,0};
    double density = 0;

    double momentumX = 0;
    double momentumY = 0;

    double velocityX = 0;
    double velocityY = 0;

    double Fieq[nL] = {0,0,0,0,0,0,0,0,0};

    //obstacle
    bool obstacle = false;

    void densityOperator() {
        for (int i = 0; i < nL; i++) {
            density += Fi[i];
        }
    }

    void momentumOperator() {
        for (int i = 0; i < nL; i++) {
            momentumX += Fi[i] * cX[i];
            momentumY += Fi[i] * cY[i];
        }
    }

    void velocityOperator() {
        for (int i = 0; i < nL; i++) {

            if (density == 0) {
                density += 0.001;
            }

            velocityX += momentumX / density; // prolly very slow
            velocityY += momentumY / density;

            //velocityX += cX[i];
            //velocityY += cY[i];

        }
    }

    void FieqOperator() {
        for (int i = 0; i < nL; i++) {
            Fieq[i] = weights[i] * density *
                    (
                    1 +
                    (cX[i] * velocityX + cY[i] * velocityY) / Cs +
                    pow((cX[i] * velocityX + cY[i] * velocityY), 2) / (2 * pow(Cs, 4)) -
                    (velocityX * velocityX + velocityY * velocityY) / (2 * pow(Cs, 2))
                    );
        }
    }

    void FiOperator() {
        for (int i = 0; i < nL; i++) {      
            Fi[i] = Fi[i] - (timestep / tau) * (Fi[i] - Fieq[i]);
        }
    }

    void addRightVelocity() {   
        Fi[0] = 1.f;
        Fi[1] = 1.f;
        Fi[2] = 1.f;
        Fi[3] = 6.f;
        Fi[4] = 1.f;
        Fi[5] = 1.f;
        Fi[6] = 1.f;
        Fi[7] = 1.f;
        Fi[8] = 1.f;

    }


};

索引转换函数

使用vector存储cell而非二维数组,通过以下函数将x,y坐标转换为一维索引:

int index(int x, int y) {
    return x * nY + y;
}

全局变量定义

//box
const int nX = 400;
const int nY = 100;

//viscosity
float tau = 0.5; // 0.53

//time delta time per iteration
float timestep = 1;

//distance between cells
float dist = 1000;

//Speed of sound
float Cs = 1 / sqrt(3) * (dist / timestep);

//viscociti

float v = pow(Cs, 2) * (tau - timestep / 2); // tau will need to be much smaller

//time steps
int nT = 3000;

//lattice speeds and weights
const int nL = 9;

//Ci vector direction, discrete velocity 
int cX[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
int cY[9] = { 0, 1, 1, 0, -1, -1, -1, 0 , 1 };

//weights, based on navier stokes
float weights[9] = { 4 / 9, 1 / 9, 1 / 36, 1 / 9, 1 / 36, 1 / 9, 1 / 36, 1 / 4, 1 / 36 };

//opposite populations
int cO[9] = { 0, 5, 6, 7, 8, 1, 2, 3, 4 };

主函数代码

int main() {

    //init vector cells

    for (int x = 0; x < nX; x++) {
        for (int y = 0; y < nY; y++) {

            cell cellUnit;

            cells.push_back(cellUnit);
            TempCells.push_back(cellUnit);
            
        }
    }


    //SDL
    
    //SDL
    //-------------------------------------------------------------
    SDL_Window* window = nullptr;
    SDL_Renderer* renderer = nullptr;

    SDL_Init(SDL_INIT_VIDEO);
    SDL_CreateWindowAndRenderer(nX* 3, nY * 3, 0, &window, &renderer);
    SDL_RenderSetScale(renderer, 3, 3);

    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);                                      
    //-------------------------------------------------------------//

    //Circle Object Gen
    for (int x = 0; x < nX; x++) {
        for (int y = 0; y < nY; y++) {

            //cicle position
            int circleX = 5;
            int circleY = 50;
            //circle radius
            float radius = 10;

            //distance bewtween cell and circle pos
            float distance = sqrt(pow(circleX - x, 2) + pow(circleY - y, 2));

            if (distance < radius) {
                cells[index(x,y)].obstacle = true;
            }
            else {
                cells[index(x, y)].obstacle = false;
            }
        }
    }
    
    //add velocity

    for (int x = 0; x < nX; x++) {
        for (int y = 0; y < nY; y++) {

            cells[index(x, y)].addRightVelocity();

            //random velocity

            for (int i = 0; i < nL; i++) {

                cells[index(x,y)].Fi[i] += (rand() % 200) / 100;

            }

        }
    }
    

    for (int t = 0; t < nT; t++) {
                        
        //SDL
        //--------------------------------------------------------------
    
        //clear renderer
        
        if (t % 20 == 0) {
            SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
            SDL_RenderClear(renderer);
        }

        //--------------------------------------------------------------


        //streaming:

        //because we will loop over the same populations we do not want to switch the same population twice
                 

        for (int x = 0; x < nX; x++) {
            for (int y = 0; y < nY; y++) {


                if (x == 0) {
                    cells[index(x, y)].Fi[3] += 0.4;
                }

                //for populations
                for (int i = 0; i < nL; i++) {
                    //boundary

                    //checs if cell is object or air
                    if (cells[index(x, y)].obstacle == false) {
                        //air

                        //targetet cell
                        int cellX = x + cX[i];
                        int cellY = y + cY[i];
                                            
                        //out of bounds check + rearange to other side
                        if (cellX < 0) {

                            //left to right
                            cellX = nX;

                        }
                        if (cellX >= nX) {

                            //right to left
                            cellX = 0;
                            continue;

                        }
                        if (cellY < 0) {

                            //top to buttom
                            cellY = nY;


                        }
                        if (cellY >= nY) {

                            //bottom to top
                            cellY = 0;

                        }

                        //if neighborinig cell is object --> collision with object
                        if (cells[index(cellX, cellY)].obstacle == true) {

                            //Boundary handling https://youtu.be/jfk4feD7rFQ?t=2821
                            TempCells[index(x,y)].Fi[cO[i]] = cells[index(x, y)].Fi[i];

                        }

                        //if not then stream to neighbor air cell with oposite population
                        
                        TempCells[index(cellX, cellY)].Fi[cO[i]] = cells[index(x, y)].Fi[i];
                        
                    } 
                    else {
                        //wall

                        //SDL GRAPICHS
                        
                        if (t % 20 == 0) {
                            SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
                            SDL_RenderDrawPoint(renderer, x, y);
                        }                                            
                    }
                }
            }
        }
        
        for (int x = 0; x < nX; x++) {
            for (int y = 0; y < nY; y++) {
                for (int i = 0; i < nL; i++) {
                    cells[index(x, y)].Fi[i] = TempCells[index(x, y)].Fi[cO[i]];
                }
            }
        }

        //collision:
        
        for (int x = 0; x < nX; x++) {
            for (int y = 0; y < nY; y++) {
                
                //density:
                cells[index(x, y)].densityOperator();

                //momentum:
                cells[index(x, y)].momentumOperator();

                //velocity:
                cells[index(x, y)].velocityOperator();
                
                //Fieq + new new Fi:
                for (int i = 0; i < nL; i++) {
                    
                    cells[index(x, y)].FieqOperator();              

                }


                //SDL Graphics

                if (t % 20 == 0) {
                    if (cells[index(x, y)].obstacle == false) {
                        SDL_SetRenderDrawColor(renderer, cells[index(x, y)].density, cells[index(x, y)].density , 255 , 255);
                        SDL_RenderDrawPoint(renderer, x, y); 
                    }
                }
            }
        }

        for (int x = 0; x < nX; x++) {
            for (int y = 0; y < nY; y++) {
                
                cells[index(x, y)].FiOperator();
            }
        }

        //SDL Graphics

        if (t % 20 == 0 ) {
            SDL_RenderPresent(renderer);
        }
    }

    return 0;
}

当前仿真效果

  • 密度可视化(粉色表示高密度,超出255范围循环显示)
  • 密度可视化
  • 密度可视化

求助需求

代码较为杂乱且未优化,希望有C++实现LBM经验的开发者提供建议。仿真能运行,但无法达到目标视频中的美观动画效果。

编辑说明:已重置density、velocityX/Y、momentumX/Y等参数。

内容的提问来源于stack exchange,提问作者Christian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 12:10:23