0

I'm trying to create my own CFD in C++. I have watched some videos on youtube about the Lattice Boltzmann method, but I cant get my simulations to look like the simulations performed in the videos with lattice Boltzmann implemented in Python.

I use SDL2 to create an image on my screen. I am not trying to create anything fast. Just something that will make pretty simulations on the CPU.

Here is my class for each 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;

    }



};

Please note that im am using a vector for my cells instead of a 2d array. I am using a index function to go from x,y to 1d cordinate.

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

}

Variables:

//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 };

My main function:

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;
}

I do realize my code might be a bit messy and not easy to understand at first. And it is definitely not optimal.

If anyone has any experience in programming their own LBM in c++ i would like to hear your input.

It seams like my simulations is working but i do not get those bueatiful animations like in, https://youtu.be/ZUXmO4hu-20?t=3394

Thanks for any help.

Edit:

I have edited my script to reset, density, velocity X Y and Momentum X Y

Simulation visualised by density, pink is higher, loops if density exceeds color range of 255

Simulation visualised by density

Simulation visualised by density

Christian
  • 1
  • 2
  • 1
    The first step in diagnosing any problem with a program is to isolate the part that's not working. Then, work backwards from there to verify the correctness of the code _and_ the input data. Almost always, one or the other is not what you expected, if not both. You can independently test and confirm as working each individual component of your system, to ensure correctness of output. There's no point writing an entire program, determining it "doesn't work" and then posting it on Stack Overflow. – paddy Dec 19 '22 at 01:31
  • 1
    Of further note, you have not even asked a question here. You just vaguely indicated that something is wrong, without even showing what your program produces, and then asked for "input". – paddy Dec 19 '22 at 01:33
  • 2
    `4 / 9` is `0`... You might want `4.f / 9`. – Jarod42 Dec 19 '22 at 01:34
  • If the error is what has been pointed out by @Jarod42, this is the reason why printing out intermediate values would have spotted the error. If you broke up those calculations into easily digestible pieces instead of one long calculation, you would have realized that `4 / 9` wasn't "acting correctly". A little "divide and conquer" debugging would have spotted the error. – PaulMcKenzie Dec 19 '22 at 03:07
  • Thanks for the comments, @paddy, I do realize that my question isn't that simple. I admit I don't fully understand the math behind the lattice Boltzmann method, and I'm simply asking If anybody with knowledge on the matter could help me along. – Christian Dec 19 '22 at 22:56
  • @Jarod42 , Thanks! this was a oversight on my end. I do still however have issues with my results – Christian Dec 19 '22 at 22:57
  • @PaulMcKenzie , I will note that for the future – Christian Dec 19 '22 at 22:58
  • 1
    It's not about your question being "simple". It's that your question isn't really a question at all. The process of diagnosing and fixing a fault in your own code begins with testing every part of it to verify it performs as expected. It might not even be the math. Who knows? Even after your responses here, the best you can say is that the program has "issues". You can do better than that. Drill in, experiment, and isolate the problem. Then, and only then, ask a question about that. To support that question, provide actual output from your program and show how it differs from what you expect. – paddy Dec 19 '22 at 23:47
  • @paddy that sounds like a good idea, I will return when I've hopefully got an idea about what the issue might be. I will try to include a video of my output too. – Christian Dec 20 '22 at 00:10

0 Answers0