├── ReadMe.txt ├── lbm2d steady flow ├── lbm2dSteady_v4.cpp ├── lbm2dSteady_v5.cpp ├── lbm2dSteadyFlow.cpp ├── class lbm2dSteadyFlow2d │ ├── lbSteadyFlow.h │ └── main.cpp ├── lbm2dtest_v.cpp └── lbm2dtest_v2.cpp ├── README.md └── lbSteadyFlowD3Q19 ├── main.cpp ├── lbSteadyFlowD3Q19.h └── lbSteadyFlowD3Q19.cpp /ReadMe.txt: -------------------------------------------------------------------------------- 1 | input file is *.sgn format, we can modify the code to adapt for different description. -------------------------------------------------------------------------------- /lbm2d steady flow/lbm2dSteady_v4.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/higginsjia/LBM/HEAD/lbm2d steady flow/lbm2dSteady_v4.cpp -------------------------------------------------------------------------------- /lbm2d steady flow/lbm2dSteady_v5.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/higginsjia/LBM/HEAD/lbm2d steady flow/lbm2dSteady_v5.cpp -------------------------------------------------------------------------------- /lbm2d steady flow/lbm2dSteadyFlow.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/higginsjia/LBM/HEAD/lbm2d steady flow/lbm2dSteadyFlow.cpp -------------------------------------------------------------------------------- /lbm2d steady flow/class lbm2dSteadyFlow2d/lbSteadyFlow.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/higginsjia/LBM/HEAD/lbm2d steady flow/class lbm2dSteadyFlow2d/lbSteadyFlow.h -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lattice Boltzmann Method 2 | Lattice Boltzmann Method (LBM) to simulate CFD problem coupled with mass and heat transfer. 3 | ## Focus On 4 | - Steady flow 2D 5 | - Steady flow 3D 6 | - Free surface flow 7 | ## Current Model 8 | - LES model 9 | - Volume of fluid(VOF) 10 | - Level set 11 | ## Future Work 12 | - GPU based method 13 | - Multi-grid or AMR 14 | - Other useful approach for optimization 15 | -------------------------------------------------------------------------------- /lbm2d steady flow/class lbm2dSteadyFlow2d/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "stdafx.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | #include "lbSteadyFlow.h" 14 | using namespace std; 15 | 16 | int _tmain(int argc, _TCHAR* argv[]) 17 | { 18 | lbSteadyFlow2d A; 19 | 20 | int Nx = 50; 21 | int Ny = 100; 22 | 23 | int in_x1 = 10; 24 | int in_x2 = 20; 25 | 26 | int out_x1 = 35; 27 | int out_x2 = 47; 28 | 29 | double dx = 0.01; 30 | double Uin[2] = { 0.0, -5.0 }; 31 | double visc = 1.0e-6; 32 | double CS = 0.13; 33 | 34 | A.setPhysicalParam(Nx, Ny, in_x1, in_x2, out_x1, out_x2, dx, visc, Uin, CS); 35 | 36 | double* Ucur = (double*)malloc(sizeof(double)*Nx*Ny); 37 | double* Unex = (double*)malloc(sizeof(double)*Nx*Ny); 38 | 39 | A.setMem(); 40 | 41 | A.init(); 42 | 43 | int MaxIter = 100000; 44 | int logIter = 1000; 45 | double velocityAccuracy = 1.0e-6; 46 | 47 | for (int iter = 1; iter <= MaxIter; ++iter) 48 | { 49 | 50 | A.getVelocityField(Ucur); 51 | 52 | A.streamDFs(); 53 | 54 | A.calMarcoVar(); 55 | 56 | A.collideDFs(); 57 | 58 | A.treatDFsBoundary(); 59 | 60 | A.getVelocityField(Unex); 61 | 62 | double u_err = 0.0; 63 | double u_sum = 0.0; 64 | 65 | for (int i = 0; i < Nx*Ny; ++i) 66 | { 67 | u_err += fabs(Ucur[i] - Unex[i]); 68 | u_sum += Ucur[i]; 69 | } 70 | 71 | u_err /= u_sum; 72 | 73 | if (iter % logIter == 0) 74 | { 75 | 76 | printf("iter=%6d err=%e\n", iter,u_err); 77 | } 78 | 79 | if (u_errlogIter) 80 | { 81 | printf("iter=%6d err=%e\n", iter, u_err); 82 | break; 83 | } 84 | 85 | } 86 | 87 | A.Out_file(666); 88 | 89 | A.resetMem(); 90 | 91 | 92 | return 0; 93 | } 94 | 95 | -------------------------------------------------------------------------------- /lbSteadyFlowD3Q19/main.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "lbSteadyFlowD3Q19.h" 3 | 4 | int _tmain(int argc, _TCHAR* argv[]) 5 | { 6 | lbSteadyFlowD3Q19 A; 7 | 8 | //char* sgnFileName = "castingWithRiser.sgn"; 9 | char* sgnFileName = "d3mm.sgn"; 10 | 11 | char* outputFileName = "D:\\output\\results.plt"; 12 | 13 | A.preReadSgn(sgnFileName); 14 | 15 | A.setSgnMem(); 16 | 17 | A.readSgn(sgnFileName); 18 | 19 | A.setMem(); 20 | 21 | A.initSimuParam(); 22 | 23 | A.initSimuVarValue(); 24 | 25 | A.initDfsValue(); 26 | 27 | const int gridSize = A.getSize(); 28 | double* curU = new double[gridSize]; 29 | double* nexU = new double[gridSize]; 30 | 31 | int MaxIter=100; 32 | const int logIter = 5; 33 | const int writeIter = 50; 34 | 35 | cout << "input max iter num:\n"; 36 | cin >> MaxIter; 37 | 38 | double velocityAccuracy = 1.0e-4; 39 | cout << "input velocity accuracy:\n"; 40 | cin >> velocityAccuracy; 41 | 42 | double t_start = omp_get_wtime(); 43 | 44 | for (int iter = 0; iter <= MaxIter; ++iter) 45 | { 46 | A.getVelocityField(curU); 47 | 48 | A.streamDfs(); 49 | 50 | A.calMarcoVar(); 51 | 52 | A.collideDfs(); 53 | 54 | A.treatDfsBoundary(); 55 | 56 | A.getVelocityField(nexU); 57 | 58 | double u_err = 0.0; 59 | double u_sum = 0.0; 60 | for (int i = 0; i < gridSize; ++i) 61 | { 62 | u_err += fabs(curU[i] - nexU[i]); 63 | u_sum += curU[i]; 64 | } 65 | 66 | u_err /= u_sum; 67 | if (u_sum == 0.0) 68 | u_err= 1.0; 69 | 70 | if (iter%logIter == 0) 71 | { 72 | printf("iter=%7d U err=%e\n", iter,u_err); 73 | } 74 | 75 | if (iter % writeIter == 0) 76 | { 77 | char chNameU[600] = "D:\\output\\steadyFlow"; 78 | char chTailerU[255] = ".plt"; 79 | char str_tmpU[255]; 80 | sprintf(str_tmpU, "%d", 10000+iter/writeIter); 81 | strcat(chNameU, str_tmpU); 82 | strcat(chNameU, chTailerU); 83 | 84 | A.writeData(chNameU); 85 | } 86 | 87 | if (u_err < velocityAccuracy) 88 | { 89 | printf("calculation finished:\niter=%7d U err=%e\n", iter, u_err); 90 | break; 91 | } 92 | } 93 | 94 | double t_end = omp_get_wtime(); 95 | 96 | printf("solver time used: %6.2f s\n", t_end - t_start); 97 | 98 | A.writeData(outputFileName); 99 | 100 | A.resetMem(); 101 | 102 | return 0; 103 | } -------------------------------------------------------------------------------- /lbSteadyFlowD3Q19/lbSteadyFlowD3Q19.h: -------------------------------------------------------------------------------- 1 | #ifndef _LBSTEADYFLOWD3Q19_H_ 2 | #define _LBSTEADYFLOWD3Q19_H_ 3 | 4 | #include "assert.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "omp.h" 13 | using namespace std; 14 | 15 | //not show warning C4996, as we use fopen() function in writeData() 16 | #pragma warning(disable:4996) 17 | 18 | /* 19 | 1. preReadSgn: get Nx, Ny, Nz 20 | 2. setSgnMem: new mem for sgn 21 | 3. readSgn: get info to sgn 22 | 4. 23 | 24 | */ 25 | 26 | 27 | class lbSteadyFlowD3Q19 28 | { 29 | public: 30 | lbSteadyFlowD3Q19(); 31 | ~lbSteadyFlowD3Q19(); 32 | 33 | //pre-processing 34 | void preReadSgn(char* filename); 35 | void setSgnMem(); 36 | void readSgn(char* filename); 37 | void setMem(); 38 | 39 | //init 40 | void initSimuParam(); 41 | void initSimuVarValue(); 42 | void initDfsValue(); 43 | 44 | //solver 45 | void streamDfs(); 46 | 47 | void calMarcoVar(); 48 | 49 | void collideDfs(); 50 | 51 | void treatDfsBoundary(); 52 | 53 | void getVelocityField(double* velocityField); 54 | int getSize(); 55 | 56 | double calFeq(double density, double velocity[3],int i); 57 | double computeLocalRelaxationTime(double tau_, double stressTensorNorm, double smagConstant); 58 | 59 | void resetMem(); 60 | 61 | 62 | 63 | FILE *fp; 64 | //post-processing 65 | void writeData(const char* filename); 66 | 67 | void Writechar(char t) 68 | { 69 | fwrite(&t, sizeof(char), 1, fp); 70 | }; 71 | 72 | void Writeint(int t) 73 | { 74 | fwrite(&t, sizeof(int), 1, fp); 75 | }; 76 | 77 | void Writeshort(short t) 78 | { 79 | fwrite(&t, sizeof(short), 1, fp); 80 | }; 81 | 82 | void Writefloat(float t) 83 | { 84 | fwrite(&t, sizeof(float), 1, fp); 85 | }; 86 | 87 | void Writedouble(double t) 88 | { 89 | fwrite(&t, sizeof(double), 1, fp); 90 | }; 91 | 92 | void WriteNchar(char* chars, int length) 93 | { 94 | fwrite(chars, sizeof(char), length, fp); 95 | }; 96 | 97 | void WriteString(char* str) 98 | { 99 | int t = 0; 100 | do 101 | { 102 | t = (*str); 103 | Writeint(t); 104 | str++; 105 | } while (t != 0); 106 | }; 107 | 108 | 109 | private: 110 | 111 | double gridLength; 112 | double timeStep; 113 | double velocityScale; 114 | 115 | int Nx; 116 | int Ny; 117 | int Nz; 118 | 119 | double fluidViscosity; 120 | double phyInletVelocity[3];//unit: m/s 121 | double latticeInletVelocity[3];//unit: lb 122 | 123 | double relaxationTime; 124 | double smagorinskyConstant; 125 | 126 | int FLUID; 127 | int INLET; 128 | int OUTLET; 129 | int NO_SLIP; 130 | 131 | double* collideField; 132 | double* streamField; 133 | 134 | int* flag; 135 | double* latticeUZ; 136 | double* latticeUY; 137 | double* latticeUX; 138 | double* latticeDensity; 139 | 140 | short* sgn; 141 | 142 | const int latticeDim = 19; 143 | static const double latticeWeight[19]; 144 | static const int latticeVelocity[19][3]; 145 | 146 | //assist function for index 147 | 148 | int cellIndex(int x, int y, int z); 149 | int funcIndex(int x, int y, int z, int i); 150 | }; 151 | 152 | 153 | #endif -------------------------------------------------------------------------------- /lbm2d steady flow/lbm2dtest_v.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 修改边界条件或平衡分布函数等 3 | */ 4 | #include "stdafx.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "omp.h" 13 | using namespace std; 14 | 15 | 16 | 17 | /* 18 | #pragma omp parallel for 19 | 20 | */ 21 | #define Nx 40 22 | #define Ny 40 23 | 24 | #define IN_X1 8 25 | #define IN_X2 18 26 | #define OUT_X1 25 27 | #define OUT_X2 36 28 | 29 | #define MaxIter 100000 30 | #define LogStep 1000 31 | const double w[9] = { 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 }; 32 | const double cx[9] = { 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, -1.0, -1.0, 1.0 }; 33 | const double cy[9] = { 0.0, 0.0, 1.0, 0.0, -1.0, 1.0, 1.0, -1.0, -1.0 }; 34 | const int inv[9] = { 0, 3, 4, 1, 2, 7, 8, 5, 6 }; 35 | 36 | const double tau = 0.501; 37 | const double omega = 1.0 / tau; 38 | const double Uin = 0.05; 39 | 40 | const int boundary = 1; 41 | const int inlet = 3; 42 | const int fluid = 0; 43 | const int outlet = 4; 44 | 45 | double f_old[Nx][Ny][9], f_new[Nx][Ny][9]; 46 | double u[Nx][Ny], v[Nx][Ny], rho[Nx][Ny]; 47 | int flag[Nx][Ny]; 48 | 49 | void init(); 50 | double feq(double rho_, double u_, double v_, int k); 51 | void evolute(); 52 | void Out_file(int m); 53 | double computeLocalRelaxationTime(double tau_, double stressTensorNorm, double smagConstant) 54 | { 55 | const double viscosity = (tau_ - 0.5) / 3.0; 56 | const double smagSqr = smagConstant * smagConstant; 57 | const double stress = 58 | (std::sqrt(viscosity * viscosity + 18.0 * smagSqr * stressTensorNorm) - viscosity) / 59 | (6.0 * smagSqr); 60 | 61 | return 3.0 * (viscosity + smagSqr * stress) + 0.5; 62 | } 63 | void calMeanVelocity(); 64 | int _tmain(int argc, _TCHAR* argv[]) 65 | { 66 | init(); 67 | 68 | for (int i = 0; i<=MaxIter; i++) 69 | { 70 | evolute(); 71 | if (i%LogStep == 0) 72 | { 73 | printf("iter=%6d ", i); 74 | calMeanVelocity(); 75 | } 76 | 77 | } 78 | 79 | Out_file(999); 80 | 81 | return 0; 82 | } 83 | 84 | 85 | void init() 86 | { 87 | int i, j, k; 88 | //set flag 89 | 90 | for (i = 0; i= IN_X1 && (i <= IN_X2)) && j == Ny - 2) 96 | flag[i][j] = inlet; 97 | else if ((i >= OUT_X1) && (i <= OUT_X2) && (j == 1)) 98 | flag[i][j] = outlet; 99 | else 100 | flag[i][j] = fluid; 101 | }//for 102 | // 103 | //set initial value 104 | printf("init flag\n"); 105 | 106 | #pragma omp parallel for 107 | for (i = 0; i= 0 && i < Nx&&j >= 0 && j < Ny) 274 | { 275 | if (flag[i + (int)cx[k]][j + (int)cy[k]] == fluid) 276 | f_old[i][j][k] = feq(rho[i + (int)cx[k]][j + (int)cy[k]], 0.0, 0.0, k)+ 277 | f_old[i + (int)cx[k]][j + (int)cy[k]][k] - 278 | feq(rho[i + (int)cx[k]][j + (int)cy[k]], 279 | u[i + (int)cx[k]][j + (int)cy[k]], 280 | v[i + (int)cx[k]][j + (int)cy[k]], 281 | k); 282 | 283 | } 284 | } 285 | 286 | 287 | } 288 | 289 | 290 | 291 | 292 | // 293 | 294 | 295 | } 296 | 297 | void Out_file(int m) 298 | { 299 | ostringstream name; 300 | name << "D:\\output\\cavityA_" << setfill('0') << setw(8) << m << ".plt"; 301 | ofstream out(name.str().c_str()); 302 | out << "Title=\"LBM Lid Driven Flow\"\n" 303 | << "VARIABLES=X,Y,U,V,UV,Bound,Rho\n" 304 | << "ZONE T= \"BOX\", I= " 305 | << Nx << ", J=" << Ny << ", F=POINT" << endl; 306 | int i, j; 307 | for (j = 0; j 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "omp.h" 13 | using namespace std; 14 | 15 | 16 | 17 | /* 18 | #pragma omp parallel for 19 | 20 | */ 21 | #define Nx 40 22 | #define Ny 40 23 | 24 | #define IN_X1 15 25 | #define IN_X2 21 26 | #define OUT_X1 2 27 | #define OUT_X2 38 28 | 29 | #define MaxIter 50000 30 | #define LogStep 1000 31 | const double w[9] = { 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 }; 32 | const double cx[9] = { 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, -1.0, -1.0, 1.0 }; 33 | const double cy[9] = { 0.0, 0.0, 1.0, 0.0, -1.0, 1.0, 1.0, -1.0, -1.0 }; 34 | const int inv[9] = { 0, 3, 4, 1, 2, 7, 8, 5, 6 }; 35 | 36 | const double tau = 0.501; 37 | const double omega = 1.0 / tau; 38 | const double Uin = 0.05; 39 | 40 | const int boundary = 1; 41 | const int inlet = 3; 42 | const int fluid = 0; 43 | const int outlet = 4; 44 | 45 | double f_old[Nx][Ny][9], f_new[Nx][Ny][9]; 46 | double u[Nx][Ny], v[Nx][Ny], rho[Nx][Ny]; 47 | int flag[Nx][Ny]; 48 | 49 | void init(); 50 | double feq(double rho_, double u_, double v_, int k); 51 | void evolute(); 52 | void Out_file(int m); 53 | double computeLocalRelaxationTime(double tau_, double stressTensorNorm, double smagConstant) 54 | { 55 | const double viscosity = (tau_ - 0.5) / 3.0; 56 | const double smagSqr = smagConstant * smagConstant; 57 | const double stress = 58 | (std::sqrt(viscosity * viscosity + 18.0 * smagSqr * stressTensorNorm) - viscosity) / 59 | (6.0 * smagSqr); 60 | 61 | return 3.0 * (viscosity + smagSqr * stress) + 0.5; 62 | } 63 | void calMeanVelocity(); 64 | int _tmain(int argc, _TCHAR* argv[]) 65 | { 66 | init(); 67 | 68 | for (int i = 0; i<=MaxIter; i++) 69 | { 70 | evolute(); 71 | if (i%LogStep == 0) 72 | { 73 | printf("iter=%6d ", i); 74 | calMeanVelocity(); 75 | } 76 | 77 | } 78 | 79 | Out_file(999); 80 | 81 | return 0; 82 | } 83 | 84 | 85 | void init() 86 | { 87 | int i, j, k; 88 | //set flag 89 | 90 | for (i = 0; i= IN_X1 && (i <= IN_X2)) && j == Ny - 2) 96 | flag[i][j] = inlet; 97 | else if ((i >= OUT_X1) && (i <= OUT_X2) && (j == 0)) 98 | flag[i][j] = outlet; 99 | else 100 | flag[i][j] = fluid; 101 | }//for 102 | // 103 | //set initial value 104 | printf("init flag\n"); 105 | 106 | #pragma omp parallel for 107 | for (i = 0; i= 0 && i < Nx&&j >= 0 && j < Ny) 274 | { 275 | if (flag[i + (int)cx[k]][j + (int)cy[k]] == fluid) 276 | f_old[i][j][k] = feq(rho[i + (int)cx[k]][j + (int)cy[k]], 0.0, 0.0, k) + 277 | f_old[i + (int)cx[k]][j + (int)cy[k]][k] - 278 | feq(rho[i + (int)cx[k]][j + (int)cy[k]], 279 | u[i + (int)cx[k]][j + (int)cy[k]], 280 | v[i + (int)cx[k]][j + (int)cy[k]], 281 | k); 282 | } 283 | } 284 | 285 | 286 | } 287 | 288 | 289 | 290 | 291 | // 292 | 293 | 294 | } 295 | 296 | void Out_file(int m) 297 | { 298 | ostringstream name; 299 | name << "D:\\output\\cavityA_" << setfill('0') << setw(8) << m << ".plt"; 300 | ofstream out(name.str().c_str()); 301 | out << "Title=\"LBM Lid Driven Flow\"\n" 302 | << "VARIABLES=X,Y,U,V,UV,Bound,Rho\n" 303 | << "ZONE T= \"BOX\", I= " 304 | << Nx - 2 << ", J=" << Ny - 2 << ", F=POINT" << endl; 305 | int i, j; 306 | for (j = 1; j = 0 && x < Nx); 7 | assert(y >= 0 && y < Ny); 8 | assert(z >= 0 && z < Nz); 9 | 10 | //check index according to the max index equal N-1 11 | return z + y*Nz + x*Ny*Nz; 12 | } 13 | 14 | int lbSteadyFlowD3Q19::funcIndex(int x, int y, int z, int i) 15 | { 16 | assert(x >= 0 && x < Nx); 17 | assert(y >= 0 && y < Ny); 18 | assert(z >= 0 && z < Nz); 19 | assert(i >= 0 && i < latticeDim); 20 | 21 | //check index carefully 22 | return (z + y*Nz + x*Ny*Nz)*latticeDim + i; 23 | } 24 | 25 | void lbSteadyFlowD3Q19::preReadSgn(char* filename) 26 | { 27 | //empty 28 | } 29 | 30 | void lbSteadyFlowD3Q19::setSgnMem() 31 | { 32 | const int cellNum = Nx*Ny*Nz; 33 | sgn = new short[cellNum]; 34 | memset(sgn, 0, sizeof(short)*cellNum); 35 | } 36 | 37 | void lbSteadyFlowD3Q19::readSgn(char* filename) 38 | { 39 | //empty 40 | } 41 | 42 | void lbSteadyFlowD3Q19::setMem() 43 | { 44 | const int cellNum = Nx*Ny*Nz; 45 | const int DfNum = cellNum*latticeDim; 46 | 47 | collideField = new double[DfNum]; 48 | streamField = new double[DfNum]; 49 | 50 | flag = new int[cellNum]; 51 | latticeUX = new double[cellNum]; 52 | latticeUY = new double[cellNum]; 53 | latticeUZ = new double[cellNum]; 54 | latticeDensity = new double[cellNum]; 55 | 56 | memset(collideField, 0, sizeof(double)*DfNum); 57 | memset(streamField, 0, sizeof(double)*DfNum); 58 | 59 | memset(flag, 0, sizeof(int)*cellNum); 60 | memset(latticeUX, 0, sizeof(double)*cellNum); 61 | memset(latticeUY, 0, sizeof(double)*cellNum); 62 | memset(latticeUZ, 0, sizeof(double)*cellNum); 63 | memset(latticeDensity, 0, sizeof(double)*cellNum); 64 | 65 | } 66 | 67 | void lbSteadyFlowD3Q19::resetMem() 68 | { 69 | delete[] collideField; 70 | delete[] streamField; 71 | 72 | delete[] flag; 73 | delete[] latticeUX; 74 | delete[] latticeUY; 75 | delete[] latticeUZ; 76 | delete[] latticeDensity; 77 | 78 | delete[] sgn; 79 | } 80 | 81 | void lbSteadyFlowD3Q19::initSimuParam() 82 | { 83 | velocityScale = 100.0; 84 | timeStep = gridLength / velocityScale; 85 | 86 | 87 | //we should set phyInletU 88 | for (int i = 0; i < 3; ++i) 89 | latticeInletVelocity[i] = phyInletVelocity[i] / velocityScale; 90 | 91 | relaxationTime = 3.0*fluidViscosity*timeStep / gridLength / gridLength + 0.5; 92 | 93 | 94 | printf("inlet velocity physical=(%6.4f,%6.4f,%6.4f)m/s\n", 95 | phyInletVelocity[0], phyInletVelocity[1], phyInletVelocity[2]); 96 | 97 | printf("inlet velocity LB=(%6.4f,%6.4f,%6.4f)\n\n", 98 | latticeInletVelocity[0], latticeInletVelocity[1], latticeInletVelocity[2]); 99 | 100 | printf("grid size=%6.4f m\ntime step=%e s\n\n", 101 | gridLength, timeStep); 102 | 103 | printf("fluid viscosity=%e m2/s\ntau=%e\nLES constant=%4.3f\n\n", 104 | fluidViscosity, relaxationTime, smagorinskyConstant); 105 | 106 | 107 | 108 | 109 | } 110 | 111 | void lbSteadyFlowD3Q19::initSimuVarValue() 112 | { 113 | //first we set cell type 114 | const int cellNum = Nx*Ny*Nz; 115 | int inletNumFirst = 0;//log inlet node num, sometimes no inlet cell is set in sgn grid 116 | for (int i = 0; i < cellNum; ++i) 117 | { 118 | const int curSgn = sgn[i]; 119 | if (curSgn % 100 == 0 && curSgn != 100) 120 | flag[i] = FLUID; 121 | else if (curSgn == 100) 122 | { 123 | flag[i] = INLET; 124 | inletNumFirst++; 125 | } 126 | else 127 | flag[i] = NO_SLIP; 128 | } 129 | 130 | if (inletNumFirst == 0) 131 | { 132 | printf("no inlet cell is set!\n"); 133 | 134 | //now we find inlet as top fluid cell 135 | int findInlet = false; 136 | int inletPosZ; 137 | for (int z = Nz - 1; z >= 0 && !findInlet; z--) 138 | for (int x = 0; x < Nx&&!findInlet; ++x) 139 | for (int y = 0; y < Ny&&!findInlet; ++y) 140 | { 141 | const int idx = cellIndex(x, y, z); 142 | if (sgn[idx] % 100 == 0) 143 | { 144 | inletPosZ = z; 145 | findInlet = true; 146 | } 147 | } 148 | //now we set inlet cell on top fluid cell 149 | for (int x = 0; x < Nx; ++x) 150 | for (int y = 0; y < Ny; ++y) 151 | { 152 | const int z = inletPosZ; 153 | const int idx = cellIndex(x, y, z); 154 | if (sgn[idx] % 100 == 0) 155 | flag[idx] = INLET; 156 | } 157 | } 158 | 159 | //now the riser is set as fluid, we set outlet according to sgn 160 | 161 | int findTopRiser = false; 162 | int topRiserZ; 163 | for (int z = Nz - 1; z >= 0 && !findTopRiser; z--) 164 | for (int x = 0; x < Nx&&!findTopRiser; ++x) 165 | for (int y = 0; y < Ny&&!findTopRiser; ++y) 166 | { 167 | const int idx = cellIndex(x, y, z); 168 | 169 | if (sgn[idx] == 4000) 170 | { 171 | topRiserZ = z; 172 | findTopRiser = true; 173 | } 174 | } 175 | 176 | printf("riser top z index=%d\n", topRiserZ); 177 | 178 | int outletNum = 0; 179 | for (int x = 0; x < Nx; ++x) 180 | for (int y = 0; y < Ny; ++y) 181 | { 182 | int z = topRiserZ; 183 | const int idx = cellIndex(x, y, z); 184 | if (sgn[idx] == 4000) 185 | { 186 | flag[idx] = OUTLET; 187 | outletNum++; 188 | } 189 | } 190 | 191 | printf("outlet node num is %d\n", outletNum); 192 | 193 | //now we cal inlet z index and count total num of diff type cell 194 | int inletIndexZ; 195 | int inletNumber = 0; 196 | int outletNumber = 0; 197 | int fluidNumber = 0; 198 | int noSlipNumber = 0; 199 | 200 | for (int x = 0; x < Nx; ++x) 201 | for (int y = 0; y < Ny; ++y) 202 | for (int z = 0; z < Nz; ++z) 203 | { 204 | const int idx = cellIndex(x, y, z); 205 | const int curFlag = flag[idx]; 206 | if (curFlag == FLUID) 207 | fluidNumber++; 208 | else if (curFlag == INLET) 209 | { 210 | inletNumber++; 211 | inletIndexZ = z; 212 | } 213 | else if (curFlag == OUTLET) 214 | outletNumber++; 215 | else if (curFlag == NO_SLIP) 216 | noSlipNumber++; 217 | } 218 | int totalNum = inletNumber + outletNumber + noSlipNumber + fluidNumber; 219 | printf("cell type count:\n"); 220 | printf("inlet=%d\noutlet=%d\nnoSlip=%d\nfluid=%d\ncell sum=%d\n", 221 | inletNumber, outletNumber, noSlipNumber, fluidNumber, totalNum); 222 | printf("inlet Z index=%d\n", inletIndexZ); 223 | 224 | if (totalNum == Nx*Ny*Nz) 225 | printf("cell type sum right.\n"); 226 | else 227 | printf("cell type sum WRONG!\n"); 228 | } 229 | 230 | void lbSteadyFlowD3Q19::writeData(const char* filename) 231 | { 232 | int varnum = 10; 233 | fp = fopen(filename, "wb"); 234 | assert(fp != NULL); 235 | WriteNchar("#!TDV102", 8); 236 | Writeint(1); 237 | WriteString("");//The TITLE. 238 | 239 | Writeint(varnum);//Number of variables (NumVar) in the datafile. 240 | 241 | WriteString("I"); 242 | WriteString("J"); 243 | WriteString("K"); 244 | 245 | WriteString("U"); 246 | WriteString("V"); 247 | WriteString("W"); 248 | 249 | WriteString("Velovity"); 250 | WriteString("VOF"); 251 | WriteString("Pressure"); 252 | WriteString("CellType"); 253 | 254 | //WriteString("mat"); 255 | 256 | Writefloat(299.0); 257 | WriteString("ZONE 001");//Zone name. 258 | Writeint(-1); 259 | Writeint(0);//Zone type: ordered 260 | Writedouble(0.0); 261 | Writefloat(0.0); 262 | 263 | Writeint(Nx); 264 | Writeint(Ny); 265 | Writeint(Nz); 266 | 267 | Writeint(0); 268 | Writefloat(357.0); 269 | Writefloat(299.0); 270 | for (int it = 0; it= 0 && Xci < Nx&&Yci >= 0 && Yci < Ny&&Zci >= 0 && Zci < Nz) 618 | { 619 | const int nearIdx = cellIndex(Xci, Yci, Zci); 620 | double curU[3] = { 0.0, 0.0, 0.0 }; 621 | double nearU[3] = { latticeUX[nearIdx], latticeUY[nearIdx], latticeUZ[nearIdx] }; 622 | 623 | if (flag[nearIdx] == FLUID) 624 | { 625 | collideField[funcIndex(x, y, z, i)] = 626 | calFeq(latticeDensity[nearIdx], curU, i) + 627 | collideField[funcIndex(Xci, Yci, Zci, i)] - calFeq(latticeDensity[nearIdx], nearU, i); 628 | } 629 | } 630 | }//for i=0-Q 631 | } 632 | 633 | } 634 | 635 | } 636 | 637 | double lbSteadyFlowD3Q19::calFeq(double density, double velocity[3], int i) 638 | { 639 | double cu = 640 | latticeVelocity[i][0] * velocity[0] + 641 | latticeVelocity[i][1] * velocity[1] + 642 | latticeVelocity[i][2] * velocity[2]; 643 | 644 | double uu = 645 | velocity[0] * velocity[0] + 646 | velocity[1] * velocity[1] + 647 | velocity[2] * velocity[2]; 648 | 649 | double feq = latticeWeight[i] * (density + 3.0*cu + 4.5*cu*cu - 1.5*uu); 650 | 651 | return feq; 652 | } 653 | 654 | double lbSteadyFlowD3Q19::computeLocalRelaxationTime(double tau_, double stressTensorNorm, double smagConstant) 655 | { 656 | const double viscosity = (tau_ - 0.5) / 3.0; 657 | const double smagSqr = smagConstant * smagConstant; 658 | const double stress = 659 | (std::sqrt(viscosity * viscosity + 18.0 * smagSqr * stressTensorNorm) - viscosity) / 660 | (6.0 * smagSqr); 661 | 662 | return 3.0 * (viscosity + smagSqr * stress) + 0.5; 663 | } 664 | 665 | void lbSteadyFlowD3Q19::getVelocityField(double* velocityField) 666 | { 667 | #pragma omp parallel for 668 | for (int i = 0; i < Nx*Ny*Nz; ++i) 669 | { 670 | velocityField[i] = sqrt( 671 | latticeUX[i] * latticeUX[i] + 672 | latticeUY[i] * latticeUY[i] + 673 | latticeUZ[i] * latticeUZ[i]); 674 | } 675 | 676 | } 677 | 678 | int lbSteadyFlowD3Q19::getSize() 679 | { 680 | return Nx*Ny*Nz; 681 | } 682 | 683 | lbSteadyFlowD3Q19::lbSteadyFlowD3Q19() 684 | { 685 | phyInletVelocity[0] = 0.0; 686 | phyInletVelocity[1] = 0.0; 687 | phyInletVelocity[2] = -5.0; 688 | 689 | smagorinskyConstant = 0.12; 690 | fluidViscosity = 1.0e-6; 691 | gridLength = 0.01; 692 | 693 | FLUID = 0; 694 | INLET = 1; 695 | OUTLET = 2; 696 | NO_SLIP = 3; 697 | 698 | //fp = NULL; 699 | } 700 | 701 | lbSteadyFlowD3Q19::~lbSteadyFlowD3Q19() 702 | { 703 | } 704 | 705 | const double lbSteadyFlowD3Q19::latticeWeight[19] = 706 | { (1. / 36), (1. / 36), (2. / 36), (1. / 36), (1. / 36), 707 | (1. / 36), (2. / 36), (1. / 36), (2. / 36), (12. / 36), 708 | (2. / 36), (1. / 36), (2. / 36), (1. / 36), (1. / 36), 709 | (1. / 36), (2. / 36), (1. / 36), (1. / 36) }; 710 | 711 | const int lbSteadyFlowD3Q19::latticeVelocity[19][3] = { 712 | { 0, -1, -1 }, { -1, 0, -1 }, { 0, 0, -1 }, { 1, 0, -1 }, { 0, 1, -1 }, 713 | { -1, -1, 0 }, { 0, -1, 0 }, { 1, -1, 0 }, { -1, 0, 0 }, { 0, 0, 0 }, 714 | { 1, 0, 0 }, { -1, 1, 0 }, { 0, 1, 0 }, { 1, 1, 0 }, { 0, -1, 1 }, 715 | { -1, 0, 1 }, { 0, 0, 1 }, { 1, 0, 1 }, { 0, 1, 1 } }; 716 | --------------------------------------------------------------------------------