├── FluidSim2D ├── FluidSim2D │ ├── FluidSim2D.rc │ ├── FluidSim2D.aps │ ├── frag.glsl │ ├── LoadProgram.h │ ├── vert.glsl │ ├── packages.config │ ├── resource.h │ ├── LoadProgram.cpp │ ├── FluidSim2D.vcxproj.filters │ ├── FluidSim2dMain.cpp │ ├── FluidRenderer2d.h │ ├── init_geom3.txt │ ├── init_geom4.txt │ ├── init_geom5.txt │ ├── initial_geom2.txt │ ├── initial_geometry.txt │ ├── FluidSolver2d.h │ ├── SimUtil.cpp │ ├── SimUtil.h │ ├── FluidSim2D.vcxproj │ ├── FluidRenderer2d.cpp │ └── FluidSolver2d.cpp └── FluidSim2D.sln ├── images └── screenshot_2d_fluid_sim.png ├── .gitignore ├── .gitattributes └── README.md /FluidSim2D/FluidSim2D/FluidSim2D.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davrempe/2d-fluid-sim/HEAD/FluidSim2D/FluidSim2D/FluidSim2D.rc -------------------------------------------------------------------------------- /images/screenshot_2d_fluid_sim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davrempe/2d-fluid-sim/HEAD/images/screenshot_2d_fluid_sim.png -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/FluidSim2D.aps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davrempe/2d-fluid-sim/HEAD/FluidSim2D/FluidSim2D/FluidSim2D.aps -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/frag.glsl: -------------------------------------------------------------------------------- 1 | #version 440 2 | 3 | in vec3 fColor; 4 | 5 | void main() { 6 | gl_FragColor = vec4(fColor, 1.0); 7 | } -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/LoadProgram.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | static char* readShaderSource(const char*); 5 | GLuint LoadProgram(const char*, const char*); -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/vert.glsl: -------------------------------------------------------------------------------- 1 | #version 440 2 | 3 | in vec2 vPos; 4 | in vec3 vColor; 5 | 6 | uniform mat4 MVP; 7 | 8 | out vec3 fColor; 9 | 10 | void main() { 11 | fColor = vColor; 12 | // add MVP 13 | gl_Position = MVP * vec4(vPos.x, vPos.y, 0.0, 1.0); 14 | } -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by FluidSim2D.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.db 2 | *.opendb 3 | FluidSim2D/Debug/* 4 | FluidSim2D/FluidSim2D/Debug/* 5 | FluidSim2D/.vs/* 6 | FluidSim2D/FluidSim2D/particle_data* 7 | FluidSim2D/x64/* 8 | FluidSim2D/FluidSim2D/x64/* 9 | FluidSim2D/Release/* 10 | FluidSim2D/FluidSim2D/Release/* 11 | FluidSim2D/packages/* 12 | 13 | # Compiled Object files 14 | *.slo 15 | *.lo 16 | *.o 17 | *.obj 18 | 19 | # Precompiled Headers 20 | *.gch 21 | *.pch 22 | 23 | # Compiled Dynamic libraries 24 | *.so 25 | *.dylib 26 | *.dll 27 | 28 | # Fortran module files 29 | *.mod 30 | *.smod 31 | 32 | # Compiled Static libraries 33 | *.lai 34 | *.la 35 | *.a 36 | *.lib 37 | 38 | # Executables 39 | *.exe 40 | *.out 41 | *.app 42 | -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25123.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FluidSim2D", "FluidSim2D\FluidSim2D.vcxproj", "{8E9E4E9A-2697-4BFA-A1B6-331C81F99EB3}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {8E9E4E9A-2697-4BFA-A1B6-331C81F99EB3}.Debug|x64.ActiveCfg = Debug|x64 17 | {8E9E4E9A-2697-4BFA-A1B6-331C81F99EB3}.Debug|x64.Build.0 = Debug|x64 18 | {8E9E4E9A-2697-4BFA-A1B6-331C81F99EB3}.Debug|x86.ActiveCfg = Debug|Win32 19 | {8E9E4E9A-2697-4BFA-A1B6-331C81F99EB3}.Debug|x86.Build.0 = Debug|Win32 20 | {8E9E4E9A-2697-4BFA-A1B6-331C81F99EB3}.Release|x64.ActiveCfg = Release|x64 21 | {8E9E4E9A-2697-4BFA-A1B6-331C81F99EB3}.Release|x64.Build.0 = Release|x64 22 | {8E9E4E9A-2697-4BFA-A1B6-331C81F99EB3}.Release|x86.ActiveCfg = Release|Win32 23 | {8E9E4E9A-2697-4BFA-A1B6-331C81F99EB3}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/LoadProgram.cpp: -------------------------------------------------------------------------------- 1 | #include "LoadProgram.h" 2 | #include 3 | #include 4 | #include 5 | 6 | static char* readShaderSource(const char* shaderFile) 7 | { 8 | FILE* fp = fopen(shaderFile, "r"); 9 | 10 | if (fp == NULL) { return NULL; } 11 | 12 | fseek(fp, 0L, SEEK_END); 13 | long size = ftell(fp); 14 | 15 | fseek(fp, 0L, SEEK_SET); 16 | char* buf = new char[size + 1]; 17 | fread(buf, 1, size, fp); 18 | 19 | buf[size] = '\0'; 20 | fclose(fp); 21 | 22 | return buf; 23 | } 24 | 25 | GLuint LoadProgram(const char* vShaderFile, const char* fShaderFile) 26 | { 27 | // read in shader contents 28 | const char* vShader = readShaderSource(vShaderFile); 29 | const char* fShader = readShaderSource(fShaderFile); 30 | 31 | GLuint shader, program; 32 | GLint completed; 33 | 34 | program = glCreateProgram(); 35 | 36 | // load and compile vertex shader 37 | if (vShader != NULL) { 38 | shader = glCreateShader(GL_VERTEX_SHADER); 39 | glShaderSource(shader, 1, &vShader, NULL); 40 | glCompileShader(shader); 41 | glGetShaderiv(shader, GL_COMPILE_STATUS, &completed); 42 | 43 | if (!completed) { 44 | GLint len; 45 | char* msg; 46 | glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len); 47 | msg = (char*)malloc(len); 48 | glGetShaderInfoLog(shader, len, &len, msg); 49 | fprintf(stderr, "Vertex shader compilation failure:\n%s\n", msg); 50 | free(msg); 51 | glDeleteProgram(program); 52 | 53 | exit(EXIT_FAILURE); 54 | } 55 | 56 | glAttachShader(program, shader); 57 | 58 | } 59 | 60 | // load and compile fragment shader 61 | if (fShader != NULL) { 62 | shader = glCreateShader(GL_FRAGMENT_SHADER); 63 | glShaderSource(shader, 1, &fShader, NULL); 64 | glCompileShader(shader); 65 | glGetShaderiv(shader, GL_COMPILE_STATUS, &completed); 66 | 67 | if (!completed) { 68 | GLint len; 69 | char* msg; 70 | glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len); 71 | msg = (char*)malloc(len); 72 | glGetShaderInfoLog(shader, len, &len, msg); 73 | fprintf(stderr, "Fragment shader compilation failure:\n%s\n", msg); 74 | free(msg); 75 | glDeleteProgram(program); 76 | exit(EXIT_FAILURE); 77 | } 78 | 79 | glAttachShader(program, shader); 80 | } 81 | 82 | // link program 83 | glLinkProgram(program); 84 | glGetProgramiv(program, GL_LINK_STATUS, &completed); 85 | 86 | if (!completed) { 87 | GLint len; 88 | char* msg; 89 | glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len); 90 | msg = (char*)malloc(len); 91 | glGetProgramInfoLog(program, len, &len, msg); 92 | fprintf(stderr, "Program link failure:\n%s\n", msg); 93 | free(msg); 94 | glDeleteProgram(program); 95 | exit(EXIT_FAILURE); 96 | } 97 | 98 | return program; 99 | 100 | } -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/FluidSim2D.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {7311a435-677b-45f4-bc47-cc02687166e8} 18 | 19 | 20 | 21 | 22 | 23 | Shaders 24 | 25 | 26 | Shaders 27 | 28 | 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | 64 | 65 | Resource Files 66 | 67 | 68 | Resource Files 69 | 70 | 71 | Resource Files 72 | 73 | 74 | Resource Files 75 | 76 | 77 | 78 | 79 | Resource Files 80 | 81 | 82 | -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/FluidSim2dMain.cpp: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------- 2 | // Title: 2D Fluid Simulation 3 | // Author: Davis Rempe 4 | // 5 | // Implementation based on "Fluid Simulation for Computer Graphics" 6 | // by Robert Bridson. 7 | //---------------------------------------------------------------------- 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "FluidSolver2d.h" 15 | #include "FluidRenderer2d.h" 16 | #include "SimUtil.h" 17 | 18 | //---------------------------------------------------------------------- 19 | // Execution Options 20 | //---------------------------------------------------------------------- 21 | 22 | // whether to run the simulation 23 | const bool RUN_SIM = true; 24 | // whether to run rendering 25 | const bool RUN_RENDERING = true; 26 | 27 | //---------------------------------------------------------------------- 28 | // Simulation Parameters 29 | //---------------------------------------------------------------------- 30 | 31 | // resolution of the grid to use (width, height) 32 | const int GRID_WIDTH = 100; 33 | const int GRID_HEIGHT = 50; 34 | // grid cell width (in meters) 35 | const float GRID_CELL_WIDTH = 0.005f; 36 | // simulation time step (in seconds) 37 | const float TIME_STEP = 0.01f; 38 | 39 | //---------------------------------------------------------------------- 40 | // I/O Parameters 41 | //---------------------------------------------------------------------- 42 | 43 | // input file for initial system state - grid marked solid, fluid, or air 44 | const std::string INITIAL_GEOMETRY_FILE_IN = "initial_geom2.txt"; 45 | // output file for particle data 46 | const std::string PARTICLE_DATA_FILE_OUT = "particle_data.csv"; 47 | // the number of frames to simulate 48 | const int NUM_SIM_FRAMES = 100; 49 | // frame rate for render (fps) 50 | const float FRAME_RATE = 25.0f; 51 | // time step between outputted frames 52 | const float FRAME_TIME_STEP = 1.0f / FRAME_RATE; 53 | 54 | //---------------------------------------------------------------------- 55 | // Global Variables 56 | //---------------------------------------------------------------------- 57 | 58 | 59 | 60 | int main(int argc, char** argv) { 61 | if (RUN_SIM) { 62 | // open and clear output file 63 | std::ofstream *particleOut = new std::ofstream(PARTICLE_DATA_FILE_OUT, std::ofstream::trunc); 64 | 65 | FluidSolver2D solver(GRID_WIDTH, GRID_HEIGHT, GRID_CELL_WIDTH, TIME_STEP); 66 | std::cout << "Simulating Frame 1" << std::endl; 67 | solver.init(INITIAL_GEOMETRY_FILE_IN); 68 | 69 | // run simulation 70 | // save initial frame 71 | solver.saveParticleData(particleOut); 72 | float t = 0.0f; 73 | for (int framesOut = 1; framesOut < NUM_SIM_FRAMES; framesOut++) { 74 | std::cout << "Simulating Frame " << framesOut + 1 << std::endl; 75 | 76 | float subTime = 0.0f; 77 | while (subTime < FRAME_TIME_STEP) { 78 | // perform sim time step 79 | solver.step(); 80 | 81 | subTime += TIME_STEP; 82 | t += TIME_STEP; 83 | } 84 | // render at current time 85 | solver.saveParticleData(particleOut); 86 | } 87 | 88 | // cleanup 89 | particleOut->close(); 90 | delete particleOut; 91 | } 92 | 93 | if (RUN_RENDERING) { 94 | FluidRenderer2D renderer(INITIAL_GEOMETRY_FILE_IN, PARTICLE_DATA_FILE_OUT, FRAME_RATE, GRID_WIDTH, GRID_HEIGHT, GRID_CELL_WIDTH); 95 | renderer.init(argc, argv); 96 | renderer.render(); 97 | } 98 | 99 | 100 | return 0; 101 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 2D Fluid Simulation 2 | This is my first implementation of a full fluid solver. Multiple video demos of the simulation running is available [here](http://cse.unl.edu/~drempe/projects.html). I have initially done it in 2D here, but plan to extend it to 3D soon. The system is split into two components: the solver (`FluidSolver2d.cpp`) and the renderer (`FluidRenderer2d.cpp`). The solver is written from scratch based on Fluid Simulation for Computer Graphics (Second Edition) by Robert Bridson. Free SIGGRAPH course notes that this book is based on are [available on the author's website](https://www.cs.ubc.ca/~rbridson/fluidsimulation/fluids_notes.pdf). The renderer mostly uses OpenGL, GLUT, and GLM in a few places. Right now it is extremely simplistic, pretty much just for debugging the solver, as my final goal is a full 3D implementation. 3 | 4 | ![sim screenshot](https://github.com/davrempe/2d-fluid-sim/blob/master/images/screenshot_2d_fluid_sim.png "Example of simulation running") 5 | 6 | # To Run 7 | * The easiest way is to simply open the Visual Studio solution and run. This uses the nupengl package installed through VS. 8 | * I've done all development and testing on Windows 10 with Visual Studio Community 2015, I haven't tested any other set-ups. 9 | * If you run into issues getting GLM to link properly, see [this Stack Overflow answer](http://stackoverflow.com/a/17912620). 10 | * If you don't have Visual Studio, make sure to have GLUT, GLEW, and GLM properly set up. 11 | 12 | The simulation can be parameterized by setting variables in both `FluidSim2dMain.cpp` and `FluidSolver2d.h`. In `FluidSim2dMain.cpp` this includes MAC grid width and height (100 x 50 by default), grid cell width (0.005 m), time step size (0.01 s), input geometry, number of frames to simulate, and frame rate. In `FluidSolver2d.h` you can set the parameters for main algorithms used in the simulation like number of particles to seed per fluid cell, PIC/FLIP blending weight, CFL condition for advection, gravity, fluid density, PCG tolerance, and PCG max iterations. 13 | 14 | # Details 15 | The simulation is meant to be water, as the density in the solver is set to 1000 kg/m^3 (though this can easily be changed). Therefore, the fluid is treated as inviscid and a PIC/FLIP method with an underlying MAC grid is used (again, based on the above book). At the start of the simulation, 4 particles are seeded randomly in each fluid grid cell. So in each simulation step the (high-level) process is as follows: 16 | * transfer particle velocities to the grid 17 | * extrapolate grid veclocity values out at least 1 cell 18 | * save velocity grids for FLIP update 19 | * apply body forces (gravity) on the grid 20 | * solve for pressure on the grid 21 | * apply pressure force on the grid 22 | * transfer grid values to particles using a PIC/FLIP blend 23 | * advect particles through grid velocity field 24 | 25 | A few notes on the above steps. To transfer particle velocities to the grid, at each grid point a weighted average of nearby particles is used. "Nearby" is determined by the bilinear hat function. Body forces are applied to the grid using simple forward Euler. The pressure system is solved using the preconditioned conjugate gradient (PCG) algorithm with a Modified Incomplete Cholesky level zero, MIC(0), preconditioner. The grid to particle transfer is a mix of PIC and FLIP determined by the given weight parameter. A higher weighted PIC update tends to cause excessive diffusion, but can be used to fake more viscous fluids. Finally the particles are advected using the Runge-Kutta 3 method with adaptive substeps based on the given CFL parameter. For full details see the above mentioned course notes, and I also found [this paper](https://www.cs.ubc.ca/~rbridson/docs/zhu-siggraph05-sandfluid.pdf) very helpful. 26 | -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/FluidRenderer2d.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUID_RENDERER_2D_H_ 2 | #define FLUID_RENDERER_2D_H_ 3 | 4 | #define BUFFER_OFFSET(offset) ((GLvoid*) offset) 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "SimUtil.h" 12 | 13 | class FluidRenderer2D { 14 | 15 | struct VertexData { 16 | GLfloat vPos[2]; 17 | GLfloat vColor[3]; 18 | 19 | VertexData() { 20 | vPos[0] = 0.0; 21 | vPos[1] = 0.0; 22 | vColor[0] = 0.0; 23 | vColor[1] = 0.0; 24 | vColor[2] = 0.0; 25 | } 26 | 27 | VertexData(GLfloat vertPos[2], GLfloat vertColor[3]) { 28 | vPos[0] = vertPos[0]; 29 | vPos[1] = vertPos[1]; 30 | vColor[0] = vertColor[0]; 31 | vColor[1] = vertColor[1]; 32 | vColor[2] = vertColor[2]; 33 | } 34 | }; 35 | 36 | private: 37 | //---------------------------------------------------------------------- 38 | // Rendering Parameters 39 | //---------------------------------------------------------------------- 40 | 41 | // file name of geometry information 42 | std::string m_geomFile; 43 | // file name of particle data from simulation 44 | std::string m_particleFile; 45 | // width of simulation grid 46 | int m_width; 47 | // height of simulation grid 48 | int m_height; 49 | // grid cell dimensions 50 | float m_dx; 51 | 52 | //---------------------------------------------------------------------- 53 | // Rendering-related members 54 | //---------------------------------------------------------------------- 55 | 56 | GLfloat PARTICLE_COLOR[3] = { 0.0f, 0.0f, 1.0f }; 57 | GLfloat SOLID_COLOR[3] = { 1.0f, 1.0f, 1.0f }; 58 | GLfloat BACKGROUND_COLOR[3] = { 0.2f, 0.2f, 0.2f }; 59 | 60 | const int VERTICES_PER_QUAD = 4; 61 | const int INDICES_PER_QUAD = 6; 62 | const int BYTES_PER_FLOAT = sizeof(GLfloat); 63 | 64 | // frame currently being rendered 65 | int m_currentFrame; 66 | // the seconds between each frame for the given frame rate 67 | float m_frameTime; 68 | 69 | // particle position data for every frame 70 | std::vector> m_particlePosData; 71 | // grid of labels representing solid geometry 72 | SimUtil::Mat2Di m_geomGrid; 73 | // transform matrix 74 | glm::mat4 m_transMat; 75 | 76 | // array of VertexData for all particles in current frame 77 | VertexData *m_particleVertData; 78 | // number of particles in current particle VertexData array 79 | int m_numParticlesInFrame; 80 | // array of VertexData for vertices that make up solids 81 | VertexData *m_solidVertData; 82 | // array of indices for how to connect solid vertices 83 | GLushort *m_solidIndData; 84 | // number of solid quads in current vertex/index data arrays 85 | int m_numberSolidCells; 86 | // offset of color attribute in VertexData struct 87 | GLintptr m_vColorOffset; 88 | 89 | // buffer for particle vertices 90 | GLuint m_pvBuffer; 91 | // buffer for solid vertices 92 | GLuint m_svBuffer; 93 | // buffer for solid indices 94 | GLuint m_siBuffer; 95 | 96 | // shader position attribute 97 | GLuint m_vPos; 98 | // shader color attribute 99 | GLuint m_vColor; 100 | // uniform shader projection matrix attribute 101 | GLuint m_MVP; 102 | // shader program 103 | GLuint m_shaderProgram; 104 | 105 | //---------------------------------------------------------------------- 106 | // Functions 107 | //---------------------------------------------------------------------- 108 | 109 | void readInParticleData(); 110 | void strSplit(const std::string&, char, std::vector&); 111 | void updateParticleVertexData(int); 112 | void initSolidVertexData(); 113 | void updateBufferData(int); 114 | void initGL(); 115 | // time function to control frame rate 116 | // TODO 117 | 118 | public: 119 | /* 120 | Creates a new 2D fluid renderer. 121 | Args: 122 | - geomFile - name of the file with geometry data in it. Used to draw solid objects in scene. 123 | - particleFile - name of the file with particle data in it. 124 | - frameRate - the frame rate to render at 125 | - gridWidth - the width of the simulation grid used 126 | - gridHeight - the height of the simulation grid used 127 | - cellWidth - width of a cell in the simulation grid used 128 | */ 129 | FluidRenderer2D(std::string, std::string, float, int, int, float); 130 | ~FluidRenderer2D(); 131 | 132 | /* 133 | Initializes renderer by reading in geometry/particle data and preparing to render. 134 | Args: 135 | argc - unmodified argc from main 136 | argv - unmodified argv from main 137 | */ 138 | void init(int, char**); 139 | 140 | /* 141 | Starts the renderer. 142 | */ 143 | void render(); 144 | 145 | // display function, should not be called from outside the renderer 146 | void display(); 147 | // time function, should not be called from outside the renderer 148 | void timer(int); 149 | }; 150 | 151 | #endif //FLUID_RENDERER_2D_H_ -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/init_geom3.txt: -------------------------------------------------------------------------------- 1 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 2 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 3 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 4 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 5 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 6 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 7 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 8 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 9 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 10 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 11 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 12 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 13 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 14 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 15 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 16 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 17 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 18 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 19 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 20 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 21 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 22 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 23 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 24 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 25 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 26 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 27 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 28 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 29 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 30 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 31 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 32 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 33 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 34 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 35 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 36 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 37 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 38 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 39 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 40 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 41 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 42 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 43 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 44 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 45 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 46 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 47 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 48 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 49 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 50 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 51 | -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/init_geom4.txt: -------------------------------------------------------------------------------- 1 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 2 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 3 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 4 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 5 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 6 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 7 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 8 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 9 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 10 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 11 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 12 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 13 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 14 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 15 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 16 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 17 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 18 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 19 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 20 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 21 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 22 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 23 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 24 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 25 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 26 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 27 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 28 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 29 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 30 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 31 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 32 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 33 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 34 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 35 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 36 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 37 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 38 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 39 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 40 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 41 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 42 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 43 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 44 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 45 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 46 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 47 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 48 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 49 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 50 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 51 | -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/init_geom5.txt: -------------------------------------------------------------------------------- 1 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 2 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 3 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 4 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 5 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 6 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 7 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 8 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 9 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 10 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 11 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 12 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 13 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 14 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 15 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 16 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 17 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 18 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 19 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 20 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 21 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 22 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 23 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 24 | ssssssssssssssssssssssssssssssssssssssssssssssssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 25 | ssssssssssssssssssssssssssssssssssssssssssssssssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 26 | ssssssssssssssssssssssssssssssssssssssssssssssssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 27 | ssssssssssssssssssssssssssssssssssssssssssssssssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 28 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 29 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 30 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaassssssssssssssssssssssssssssssssssssssssssss 31 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaassssssssssssssssssssssssssssssssssssssssssss 32 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaassssssssssssssssssssssssssssssssssssssssssss 33 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaassssssssssssssssssssssssssssssssssssssssssss 34 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 35 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 36 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 37 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 38 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 39 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 40 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 41 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 42 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 43 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 44 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 45 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 46 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 47 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 48 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 49 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 50 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 51 | -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/initial_geom2.txt: -------------------------------------------------------------------------------- 1 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 2 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 3 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 4 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 5 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 6 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaafffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaasssss 7 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaafffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaasssss 8 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaafffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaasssss 9 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaafffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaasssss 10 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaafffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaasssss 11 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaafffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaasssss 12 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaafffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaasssss 13 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaafffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaasssss 14 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaafffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaasssss 15 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaafffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaasssss 16 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaafffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaasssss 17 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaafffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaasssss 18 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaafffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaasssss 19 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaafffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaasssss 20 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaafffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaasssss 21 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaafffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaasssss 22 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaafffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaasssss 23 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaafffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaasssss 24 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssssssssssssssssssssssssssssssssssaaaaaaaaaaaaaaaaaaaaaaaaaasssss 25 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssssssssssssssssssssssssssssssssssaaaaaaaaaaaaaaaaaaaaaaaaaasssss 26 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssssssssssssssssssssssssssssssssssaaaaaaaaaaaaaaaaaaaaaaaaaasssss 27 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssssssssssssssssssssssssssssssssssaaaaaaaaaaaaaaaaaaaaaaaaaasssss 28 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 29 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 30 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 31 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 32 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 33 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 34 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 35 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 36 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 37 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 38 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 39 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 40 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 41 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 42 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 43 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 44 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 45 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 46 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 47 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 48 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 49 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 50 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 51 | -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/initial_geometry.txt: -------------------------------------------------------------------------------- 1 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 2 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 3 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 4 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 5 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 6 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 7 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 8 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 9 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 10 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 11 | sssssaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 12 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 13 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 14 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 15 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 16 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 17 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 18 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 19 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 20 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 21 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 22 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 23 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 24 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 25 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 26 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 27 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 28 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 29 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 30 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 31 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 32 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 33 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 34 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 35 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 36 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 37 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 38 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 39 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 40 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 41 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 42 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 43 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 44 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 45 | sssssfffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasssss 46 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 47 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 48 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 49 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 50 | ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss 51 | -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/FluidSolver2d.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUID_SOLVER_2D_H_ 2 | #define FLUID_SOLVER_2D_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "SimUtil.h" 10 | 11 | 12 | class FluidSolver2D { 13 | 14 | private: 15 | //---------------------------------------------------------------------- 16 | // Grid Attributes 17 | //---------------------------------------------------------------------- 18 | 19 | // nx 20 | int m_gridWidth; 21 | // ny 22 | int m_gridHeight; 23 | // distance between each grid cell 24 | float m_dx; 25 | // grid of cell labels, size (nx, ny) 26 | SimUtil::Mat2Di m_label; 27 | 28 | // pressure and velocity are held in a MAC grid so that 29 | // p(i, j, k) = p_i_j_k 30 | // u(i, j, k) = u_i-1/2_j_k 31 | // v(i, j, k) = v_i_j-1/2_k 32 | 33 | // grid of pressures, size (nx, ny) 34 | SimUtil::Mat2Df m_p; 35 | // grid of vel x component, size (nx+1, ny) 36 | SimUtil::Mat2Df m_u; 37 | // grid of vel y component, size (nx, ny+1) 38 | SimUtil::Mat2Df m_v; 39 | 40 | // TODO grids for solid velocity? 41 | 42 | // saved grid of vel x component for FLIP update, size (nx+1, ny) 43 | SimUtil::Mat2Df m_uSaved; 44 | // saved grid of vel y component for FLIP update, size (nx, ny+1) 45 | SimUtil::Mat2Df m_vSaved; 46 | 47 | //---------------------------------------------------------------------- 48 | // Simulation Attributes 49 | //---------------------------------------------------------------------- 50 | 51 | const int VEL_UNKNOWN = INT_MIN; 52 | // number of particles to seed in each cell at start of sim 53 | const int PARTICLES_PER_CELL = 4; 54 | // the amount of weight to give to PIC in PIC/FLIP update 55 | const float PIC_WEIGHT = 0.02f; 56 | // the maximum number of grid cells a particle should move when advected 57 | const int ADVECT_MAX = 1; 58 | // acceleration due to gravity 59 | const SimUtil::Vec2 GRAVITY = { 0.0f, -9.81f }; 60 | // density of the fluid (kg/m^3) 61 | const float FLUID_DENSITY = 1000.0f; 62 | // error tolerance for PCG 63 | const float PCG_TOL = 0.000001f; 64 | // max iterations for PCG 65 | const int PCG_MAX_ITERS = 200; 66 | 67 | // simulation time step 68 | float m_dt; 69 | 70 | //---------------------------------------------------------------------- 71 | // Particle-related Members 72 | //---------------------------------------------------------------------- 73 | 74 | // list of all particles in the simulation 75 | std::vector *m_particles; 76 | 77 | //---------------------------------------------------------------------- 78 | // Functions 79 | //---------------------------------------------------------------------- 80 | 81 | // solver steps 82 | 83 | void seedParticles(int, std::vector*); 84 | void labelGrid(); 85 | void particlesToGrid(); 86 | void extrapolateGridFluidData(SimUtil::Mat2Df, int, int, int); 87 | void saveVelocityGrids(); 88 | void applyBodyForces(); 89 | void pressureSolve(); 90 | void applyPressure(); 91 | void gridToParticles(float); 92 | void advectParticles(int); 93 | void cleanupParticles(float); 94 | 95 | // helper functions 96 | template void initGridValues(T**, int, int, T); 97 | double trilinearHatKernel(SimUtil::Vec2); 98 | double hatFunction(double); 99 | double quadBSplineKernel(SimUtil::Vec2); 100 | bool isFluid(int, int); 101 | std::vector checkNeighbors(SimUtil::Mat2Di, int[2], int[2], int[][2], int, int); 102 | SimUtil::Vec2 interpVel(SimUtil::Mat2Df, SimUtil::Mat2Df, SimUtil::Vec2); 103 | void RK3(SimUtil::Particle2D*, SimUtil::Vec2, float, SimUtil::Mat2Df, SimUtil::Mat2Df); 104 | void constructRHS(SimUtil::Mat2Dd); 105 | void constructA(SimUtil::Mat2Dd, SimUtil::Mat2Dd, SimUtil::Mat2Dd); 106 | void constructPrecon(SimUtil::Mat2Dd, SimUtil::Mat2Dd, SimUtil::Mat2Dd, SimUtil::Mat2Dd); 107 | void PCG(SimUtil::Mat2Dd, SimUtil::Mat2Dd, SimUtil::Mat2Dd, SimUtil::Mat2Dd, SimUtil::Mat2Dd); 108 | void applyPrecon(SimUtil::Mat2Dd, SimUtil::Mat2Dd, SimUtil::Mat2Dd, SimUtil::Mat2Dd, SimUtil::Mat2Dd, SimUtil::Mat2Dd); 109 | void applyA(SimUtil::Mat2Dd, SimUtil::Mat2Dd, SimUtil::Mat2Dd, SimUtil::Mat2Dd, SimUtil::Mat2Dd); 110 | bool projectParticle(SimUtil::Particle2D *, float); 111 | 112 | public: 113 | /* 114 | Creates a new 2D fluid solver. 115 | Args: 116 | width - width of the grid to use 117 | height - height of the grid to use 118 | dx - the grid cell width 119 | dt - the timestep to use 120 | */ 121 | FluidSolver2D(int, int, float, float); 122 | ~FluidSolver2D(); 123 | 124 | /* 125 | Initializes the solver by reading in and constructing initial 126 | grid based on the given initial geometry file. The solver will save particle 127 | data at each time step to the given output file. 128 | Args: 129 | initialGemoetryFile - name of the .txt file containing initial geometry 130 | */ 131 | void init(std::string); 132 | 133 | /* 134 | Steps the simulation forward dt. 135 | */ 136 | void step(); 137 | 138 | /* 139 | Saves all particles currently in the simulation using the given file stream 140 | Outputs in csv format where each particle position is an entry in the row: 141 | "0.234 0.154, ... , \n" 142 | Args: 143 | particleOut - pointer to file stream to use for output 144 | */ 145 | void saveParticleData(std::ofstream*); 146 | }; 147 | 148 | #endif //FLUID_SOLVER_2D_H_ -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/SimUtil.cpp: -------------------------------------------------------------------------------- 1 | #include "SimUtil.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace SimUtil { 9 | 10 | 11 | template 12 | T** initMat2D(int m, int n) { 13 | T** mat = new T*[m]; 14 | for (int i = 0; i < m; i++) { 15 | mat[i] = new T[n]; 16 | } 17 | 18 | return mat; 19 | } 20 | 21 | template 22 | void deleteMat2D(int m, int n, T ** mat) { 23 | for (int i = 0; i < m; i++) { 24 | delete[] mat[i]; 25 | } 26 | delete[] mat; 27 | } 28 | 29 | template 30 | void printMat2D(int m, int n, T** mat) { 31 | for (int i = 0; i < m; i++) { 32 | std::cout << "["; 33 | for (int j = 0; j < n - 1; j++) { 34 | std::cout << mat[i][j] << ", "; 35 | } 36 | std::cout << mat[i][n - 1] << "]" << std::endl; 37 | } 38 | } 39 | 40 | template 41 | T** initGrid2D(int x, int y) { 42 | return initMat2D(x, y); 43 | } 44 | 45 | template 46 | void deleteGrid2D(int x, int y, T ** grid) { 47 | deleteMat2D(x, y, grid); 48 | } 49 | 50 | template 51 | void printGrid2D(int x, int y, T** grid) { 52 | std::cout << "====================================================================================\n"; 53 | for (int i = y - 1; i >= 0; i--) { 54 | std::cout << "["; 55 | for (int j = 0; j < x - 1; j++) { 56 | std::cout << grid[j][i] << ", "; 57 | } 58 | std::cout << grid[x - 1][i] << "]" << std::endl; 59 | } 60 | std::cout << "====================================================================================\n"; 61 | } 62 | 63 | template 64 | T*** initMat3D(int m, int n, int l) { 65 | T*** mat = new T**[m]; 66 | for (int i = 0; i < m; i++) { 67 | mat[i] = new T*[n]; 68 | for (int j = 0; j < l; j++) { 69 | mat[i][j] = new T[l]; 70 | } 71 | } 72 | 73 | return mat; 74 | } 75 | 76 | template 77 | void deleteMat3D(int m, int n, int l, T *** mat) { 78 | for (int i = 0; i < m; i++) { 79 | for (int j = 0; j < n; j++) { 80 | delete[] mat[i][j]; 81 | } 82 | delete[] mat[i]; 83 | } 84 | delete[] mat; 85 | } 86 | 87 | template 88 | T*** initGrid3D(int x, int y, int z) { 89 | return initMat3D(x, y, z); 90 | } 91 | 92 | template 93 | void deleteGrid3D(int x, int y, int z, T *** grid) { 94 | deleteMat3D(x, y, z, grid); 95 | } 96 | 97 | void readInGeom2D(int x, int y, std::string geomFileName, Mat2Di grid) { 98 | // open the geometry file 99 | std::ifstream geomFile(geomFileName); 100 | if (geomFile.is_open()) { 101 | std::string lineStr; 102 | // parse file based on given dimensions, will error if file does not match these 103 | // fills grid so that [0][0] is at bottom left corner of simulation 104 | for (int i = y - 1; i >= 0; i--) { 105 | std::getline(geomFile, lineStr); 106 | for (int j = 0; j < x; j++) { 107 | switch (lineStr[j]) { 108 | case 'f': 109 | grid[j][i] = SimUtil::FLUID; 110 | break; 111 | case 's': 112 | grid[j][i] = SimUtil::SOLID; 113 | break; 114 | case 'a': 115 | grid[j][i] = SimUtil::AIR; 116 | break; 117 | } 118 | } 119 | } 120 | geomFile.close(); 121 | } 122 | } 123 | 124 | Vec2 getGridCellPosition(float i, float j, float dx) { 125 | return Vec2(i*dx + 0.5f*dx, j*dx + 0.5f*dx); 126 | } 127 | 128 | int* getGridCellIndex(Vec2 pos, float dx) { 129 | int index[2] = { (int)(pos.x / dx), (int)(pos.y / dx) }; 130 | return index; 131 | } 132 | 133 | Vec2 add(Vec2 vec1, Vec2 vec2) { 134 | return Vec2(vec1.x + vec2.x, vec1.y + vec2.y); 135 | } 136 | 137 | Vec3 add(Vec3 vec1, Vec3 vec2) { 138 | return Vec3(vec1.x + vec2.x, vec1.y + vec2.y, vec1.z + vec2.z); 139 | } 140 | 141 | Vec2 sub(Vec2 vec1, Vec2 vec2) { 142 | return Vec2(vec1.x - vec2.x, vec1.y - vec2.y); 143 | } 144 | 145 | Vec3 sub(Vec3 vec1, Vec3 vec2) { 146 | return Vec3(vec1.x - vec2.x, vec1.y - vec2.y, vec1.z - vec2.z); 147 | } 148 | 149 | Vec2 scale(Vec2 vec1, float scalar) { 150 | return Vec2(scalar * vec1.x, scalar * vec1.y); 151 | } 152 | 153 | Vec3 scale(Vec3 vec1, float scalar) { 154 | return Vec3(scalar * vec1.x, scalar * vec1.y, scalar * vec1.z); 155 | } 156 | 157 | float norm(Vec2 vec) { 158 | return sqrt(vec.x * vec.x + vec.y * vec.y); 159 | } 160 | 161 | float norm(Vec3 vec) { 162 | return sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z); 163 | } 164 | 165 | template 166 | double dot(T** grid1, T** grid2, int x, int y) { 167 | double dotProd = 0.0; 168 | for (int i = 0; i < x; i++) { 169 | for (int j = 0; j < y; j++) { 170 | dotProd += grid1[i][j] * grid2[i][j]; 171 | } 172 | } 173 | 174 | return dotProd; 175 | } 176 | 177 | template 178 | T max(T** grid1, int x, int y) { 179 | T maxVal = std::numeric_limits::lowest(); 180 | for (int i = 0; i < x; i++) { 181 | for (int j = 0; j < y; j++) { 182 | if (grid1[i][j] > maxVal) { 183 | maxVal = grid1[i][j]; 184 | } 185 | } 186 | } 187 | 188 | return maxVal; 189 | } 190 | 191 | } 192 | 193 | // explicit instantiation of template functions for compilation 194 | template int** SimUtil::initMat2D(int, int); 195 | template float** SimUtil::initMat2D(int, int); 196 | template double** SimUtil::initMat2D(int, int); 197 | template void SimUtil::deleteMat2D(int, int, int**); 198 | template void SimUtil::deleteMat2D(int, int, float**); 199 | template void SimUtil::deleteMat2D(int, int, double**); 200 | template void SimUtil::printMat2D(int, int, int**); 201 | template void SimUtil::printMat2D(int, int, float**); 202 | template int** SimUtil::initGrid2D(int, int); 203 | template float** SimUtil::initGrid2D(int, int); 204 | template double** SimUtil::initGrid2D(int, int); 205 | template void SimUtil::deleteGrid2D(int, int, int**); 206 | template void SimUtil::deleteGrid2D(int, int, float**); 207 | template void SimUtil::deleteGrid2D(int, int, double**); 208 | template void SimUtil::printGrid2D(int, int, int**); 209 | template void SimUtil::printGrid2D(int, int, float**); 210 | template void SimUtil::printGrid2D(int, int, double**); 211 | template int*** SimUtil::initMat3D(int, int, int); 212 | template float*** SimUtil::initMat3D(int, int, int); 213 | template double*** SimUtil::initMat3D(int, int, int); 214 | template void SimUtil::deleteMat3D(int, int, int, int***); 215 | template void SimUtil::deleteMat3D(int, int, int, float***); 216 | template void SimUtil::deleteMat3D(int, int, int, double***); 217 | template int*** SimUtil::initGrid3D(int, int, int); 218 | template float*** SimUtil::initGrid3D(int, int, int); 219 | template double*** SimUtil::initGrid3D(int, int, int); 220 | template void SimUtil::deleteGrid3D(int, int, int, int***); 221 | template void SimUtil::deleteGrid3D(int, int, int, float***); 222 | template void SimUtil::deleteGrid3D(int, int, int, double***); 223 | 224 | template double SimUtil::dot(int**, int**, int, int); 225 | template double SimUtil::dot(float**, float**, int, int); 226 | template double SimUtil::dot(double**, double**, int, int); 227 | 228 | template int SimUtil::max(int**, int, int); 229 | template float SimUtil::max(float**, int, int); 230 | template double SimUtil::max(double**, int, int); -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/SimUtil.h: -------------------------------------------------------------------------------- 1 | #ifndef SIM_UTIL_H 2 | #define SIM_UTIL_H 3 | 4 | #include 5 | 6 | namespace SimUtil { 7 | typedef int** Mat2Di; 8 | typedef float** Mat2Df; 9 | typedef double** Mat2Dd; 10 | typedef int*** Mat3Di; 11 | typedef float*** Mat3Df; 12 | typedef double*** Mat3Dd; 13 | 14 | //---------------------------------------------------------------------- 15 | // Constants 16 | //---------------------------------------------------------------------- 17 | 18 | const int SOLID = 0; 19 | const int FLUID = 1; 20 | const int AIR = 2; 21 | 22 | //---------------------------------------------------------------------- 23 | // Data Structures 24 | //---------------------------------------------------------------------- 25 | 26 | struct Vec2 { 27 | float x, y; 28 | Vec2(float x, float y) : x(x), y(y) {} 29 | }; 30 | 31 | struct Vec3 { 32 | float x, y, z; 33 | Vec3(float x, float y, float z) : x(x), y(y), z(z) {} 34 | }; 35 | 36 | struct Particle2D { 37 | Vec2 pos; 38 | Vec2 vel; 39 | Particle2D(Vec2 pos, Vec2 vel) : pos(pos), vel(vel) {} 40 | }; 41 | 42 | struct Particle3D { 43 | Vec3 pos; 44 | Vec3 vel; 45 | Particle3D(Vec3 pos, Vec3 vel) : pos(pos), vel(vel) {} 46 | }; 47 | 48 | //---------------------------------------------------------------------- 49 | // Functions 50 | //---------------------------------------------------------------------- 51 | 52 | /* 53 | Initializes a 2D matrix. 54 | Args: 55 | m - num rows 56 | n - num cols 57 | Returns: 58 | T** - the dynamic array 59 | */ 60 | template T** initMat2D(int, int); 61 | /* 62 | Deletes a 2D matrix. 63 | Args: 64 | m - num rows 65 | n - num cols 66 | mat - matrix to delete 67 | */ 68 | template void deleteMat2D(int, int, T**); 69 | /* 70 | Prints the given matrix to stdout. 71 | Args: 72 | m - num rows 73 | n - num cols 74 | T** - matrix to print 75 | */ 76 | template void printMat2D(int, int, T**); 77 | 78 | /* 79 | Initializes a 2D grid. This is done in column major so the grid can lie on 80 | a cartesian coordinate system so that (0,0) is at the bottom left corner of grid cell [0][0]. And 81 | generally grid cells can be accessed [x][y]. 82 | Args: 83 | x - x dimension width (in number of cells) 84 | y - y dimension height (in number of cells) 85 | Returns: 86 | T** - the dynamic array 87 | */ 88 | template T** initGrid2D(int, int); 89 | /* 90 | Deletes a 2D grid. 91 | Args: 92 | x - x dimension width 93 | y - y dimension height 94 | grid - grid to delete 95 | */ 96 | template void deleteGrid2D(int, int, T**); 97 | /* 98 | Prints the given grid to stdout. 99 | Args: 100 | x - x dimension width 101 | n - y dimension height 102 | T** - grid to print 103 | */ 104 | template void printGrid2D(int, int, T**); 105 | 106 | /* 107 | Initializes a 3D matrix. 108 | Args: 109 | m - num rows 110 | n - num cols 111 | l - depth 112 | Returns: 113 | T*** - the dynamic array 114 | */ 115 | template T*** initMat3D(int, int, int); 116 | /* 117 | Deletes a 3D matrix. 118 | Args: 119 | m - num rows 120 | n - num cols 121 | l - depth 122 | mat - matrix to delete 123 | */ 124 | template void deleteMat3D(int, int, int, T***); 125 | 126 | /* 127 | Initializes a 3D grid. This is done in column major so the grid can lie on 128 | a cartesian coordinate system so that (0,0,0) is at the bottom left back corner of grid cell [0][0][0]. And 129 | generally grid cells can be accessed [x][y][z]. 130 | Args: 131 | x - x dimension width (in grid cells) 132 | y - y dimension height (in grid cells) 133 | z - z dimension depth (in grid cells) 134 | Returns: 135 | T** - the dynamic array 136 | */ 137 | template T*** initGrid3D(int, int, int); 138 | /* 139 | Deletes a 3D grid. 140 | Args: 141 | x - x dimension width 142 | y - y dimension height 143 | z - z dimension depth 144 | grid - grid to delete 145 | */ 146 | template void deleteGrid3D(int, int, int, T***); 147 | 148 | /* 149 | Builds initial grid of dimensions (x, y) that contains the initial 150 | geometry for the system to simulate. Cell [0][0] in the grid is at the bottom 151 | left corner of the input geometry, so it's treated as if the input grid was initialized 152 | using initGrid2D. x is positive right, y is positive up. 153 | It reads the initial geometry from the specified input file parameter. 154 | Args: 155 | x, y - grid dimensions in number of cells 156 | geomFile - the file containing the geometry 157 | grid - the 2D array to put the initial grid in 158 | */ 159 | void readInGeom2D(int, int, std::string, SimUtil::Mat2Di); 160 | 161 | /* 162 | Finds the physical location of the cell with index [x][y] 163 | in a grid where [0][0] is the center of the bottom left cell, based on the given dx. 164 | Integer indices are treated in the center of cells while fractional indices may lie anywhere 165 | in a grid cell. 166 | Args: 167 | i - x index of cell 168 | j - y index of cell 169 | dx - single cell dimension 170 | Returns: 171 | Vec2 (x, y) containing physical location from bottom left corner of grid. 172 | */ 173 | Vec2 getGridCellPosition(float, float, float); 174 | /* 175 | Returns array of size 2 that contains the integer grid cell with index [i][j] at its center that contains the given position. 176 | Args: 177 | pos - a Vec2 (x,y) coordinate containing the position to use based on the origin at the bottom left of the simulation. 178 | dx - single cell dimension 179 | */ 180 | int* getGridCellIndex(Vec2 pos, float); 181 | 182 | // vec operations 183 | 184 | /* 185 | Calculates the sum of vec1 and vec2 (vec1 + vec2) and returns a new vector containing this subtraction. 186 | Args 187 | vec1 - first vector 188 | vec2 - second vector 189 | */ 190 | Vec2 add(Vec2, Vec2); 191 | /* 192 | Calculates the sum of vec1 and vec2 (vec1 + vec2) and returns a new vector containing this subtraction. 193 | Args 194 | vec1 - first vector 195 | vec2 - second vector 196 | */ 197 | Vec3 add(Vec3, Vec3); 198 | /* 199 | Calculates the difference of vec1 and vec2 (vec1 - vec2) and returns a new vector containing this subtraction. 200 | Args 201 | vec1 - first vector 202 | vec2 - second vector 203 | */ 204 | Vec2 sub(Vec2, Vec2); 205 | /* 206 | Calculates the difference of vec1 and vec2 (vec1 - vec2) and returns a new vector containing this subtraction. 207 | Args 208 | vec1 - first vector 209 | vec2 - second vector 210 | */ 211 | Vec3 sub(Vec3, Vec3); 212 | /* 213 | Scales the given vector by a scalar and returns the new scaled vector. 214 | Args 215 | vec1 - the vector 216 | scalar - the value to scale by 217 | */ 218 | Vec2 scale(Vec2, float); 219 | /* 220 | Scales the given vector by a scalar and returns the new scaled vector. 221 | Args 222 | vec1 - the vector 223 | scalar - the value to scale by 224 | */ 225 | Vec3 scale(Vec3, float); 226 | /* 227 | Calculates Euclidean norm of the given vector. 228 | Args 229 | vec - the vector to calculate norm of. 230 | */ 231 | float norm(Vec2); 232 | /* 233 | Calculates Euclidean norm of the given vector. 234 | Args 235 | vec - the vector to calculate norm of. 236 | */ 237 | float norm(Vec3); 238 | /* 239 | Calculates the dot product of two vectors being stored 240 | as 2D grids (grid1 dot grid2). 241 | Args: 242 | grid1 - the first vector (2D grid) 243 | grid2 - the second vector (2D grid) 244 | x/y - grid dimensions 245 | */ 246 | template double dot(T**, T**, int, int); 247 | /* 248 | Finds the maximum value in a grid. 249 | Args: 250 | grid1 - the grid to look in 251 | x/y - grid dimensions 252 | */ 253 | template T max(T**, int, int); 254 | } 255 | 256 | #endif //SIM_UTIL_H 257 | 258 | -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/FluidSim2D.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {8E9E4E9A-2697-4BFA-A1B6-331C81F99EB3} 23 | Win32Proj 24 | FluidSim2D 25 | 8.1 26 | 27 | 28 | 29 | Application 30 | true 31 | v140 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v140 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v140 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v140 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | false 83 | 84 | 85 | 86 | 87 | 88 | Level3 89 | Disabled 90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 91 | 92 | 93 | Console 94 | true 95 | 96 | 97 | 98 | 99 | 100 | 101 | Level3 102 | Disabled 103 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 104 | 105 | 106 | Console 107 | true 108 | 109 | 110 | 111 | 112 | Level3 113 | 114 | 115 | MaxSpeed 116 | true 117 | true 118 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 119 | 120 | 121 | Console 122 | true 123 | true 124 | true 125 | 126 | 127 | 128 | 129 | Level3 130 | 131 | 132 | MaxSpeed 133 | true 134 | true 135 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 136 | 137 | 138 | Console 139 | true 140 | true 141 | true 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 181 | 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/FluidRenderer2d.cpp: -------------------------------------------------------------------------------- 1 | #include "FluidRenderer2d.h" 2 | #include "FluidSolver2d.h" 3 | #include "LoadProgram.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | // current instance of the renderer 14 | FluidRenderer2D* g_rendererContext; 15 | 16 | extern "C" 17 | void displayCallback() { 18 | g_rendererContext->display(); 19 | } 20 | 21 | extern "C" 22 | void timerCallback(int id) { 23 | g_rendererContext->timer(id); 24 | } 25 | 26 | FluidRenderer2D::FluidRenderer2D(std::string geomFile, std::string particleFile, float frameRate, int gridWidth, int gridHeight, float cellWidth) : m_geomFile(geomFile), m_particleFile(particleFile), m_width(gridWidth), m_height(gridHeight), m_dx(cellWidth) { 27 | // initialize vertex data arrays 28 | m_particleVertData = new VertexData[1]; 29 | 30 | m_currentFrame = 0; 31 | m_frameTime = 1.0f / frameRate; 32 | } 33 | 34 | FluidRenderer2D::~FluidRenderer2D() { 35 | delete[] m_particleVertData; 36 | delete[] m_solidVertData; 37 | delete[] m_solidIndData; 38 | } 39 | 40 | void FluidRenderer2D::init(int argc, char** argv) { 41 | // read in particle data to array 42 | readInParticleData(); 43 | // read in geometry data 44 | m_geomGrid = SimUtil::initGrid2D(m_width, m_height); 45 | SimUtil::readInGeom2D(m_width, m_height, m_geomFile, m_geomGrid); 46 | 47 | // set up glut and glew 48 | glutInit(&argc, argv); 49 | glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); 50 | glutInitWindowSize(720, 720); 51 | glutCreateWindow("Fluid Simulation"); 52 | glewInit(); 53 | 54 | // set up OpenGL 55 | initGL(); 56 | 57 | g_rendererContext = this; 58 | glutDisplayFunc(displayCallback); 59 | /*glutReshapeFunc(reshape); 60 | glutKeyboardFunc(key); 61 | glutSpecialFunc(specialKey); 62 | glutMouseFunc(mouse); 63 | glutMotionFunc(drag); 64 | glutPassiveMotionFunc(trackMousePos);*/ 65 | 66 | } 67 | 68 | void FluidRenderer2D::render() { 69 | glutMainLoop(); 70 | } 71 | 72 | //---------------------------------------------------------------------- 73 | // Private Functions 74 | //---------------------------------------------------------------------- 75 | 76 | /* 77 | Fills array of particle VertexData with particle data from the given frame. 78 | If the frame is greater than the total number of frames, it will show the 79 | given frameNum % totalNumFrames. 80 | Args: 81 | - frameNum - the frame to update the array with 82 | */ 83 | void FluidRenderer2D::updateParticleVertexData(int frameNum) { 84 | int totalFrames = m_particlePosData.size(); 85 | // clear array from previous frame 86 | delete[] m_particleVertData; 87 | // reallocate to proper size 88 | m_numParticlesInFrame = m_particlePosData[frameNum % totalFrames].size(); 89 | m_particleVertData = new VertexData[m_numParticlesInFrame]; 90 | 91 | // populate array 92 | for (int i = 0; i < m_numParticlesInFrame; i++) { 93 | SimUtil::Vec2 curParticle = m_particlePosData[frameNum % totalFrames][i]; 94 | GLfloat particlePos[2] = { curParticle.x, curParticle.y }; 95 | m_particleVertData[i] = VertexData(particlePos, PARTICLE_COLOR); 96 | } 97 | } 98 | 99 | /* 100 | Fills array of solid VertexData and index data with the solid objects. 101 | */ 102 | void FluidRenderer2D::initSolidVertexData() { 103 | // max size is if every cell in the grid solid 104 | m_solidVertData = new VertexData[m_width*m_height * VERTICES_PER_QUAD]; 105 | m_solidIndData = new GLushort[m_width*m_height * INDICES_PER_QUAD]; 106 | 107 | // traverse geometry grid to find solid cells 108 | m_numberSolidCells = 0; 109 | for (int i = 0; i < m_width; i++) { 110 | for (int j = 0; j < m_height; j++) { 111 | if (m_geomGrid[i][j] == SimUtil::SOLID) { 112 | // build quad over that cell 113 | SimUtil::Vec2 cellCenter = SimUtil::getGridCellPosition(i, j, m_dx); 114 | GLfloat nwPos[2] = { cellCenter.x - 0.5f*m_dx, cellCenter.y + 0.5f*m_dx }; 115 | GLfloat nePos[2] = { cellCenter.x + 0.5f*m_dx, cellCenter.y + 0.5f*m_dx }; 116 | GLfloat sePos[2] = { cellCenter.x + 0.5f*m_dx, cellCenter.y - 0.5f*m_dx }; 117 | GLfloat swPos[2] = { cellCenter.x - 0.5f*m_dx, cellCenter.y - 0.5f*m_dx }; 118 | // add to vert array 119 | GLushort nwInd = m_numberSolidCells*VERTICES_PER_QUAD + 0; 120 | GLushort neInd = m_numberSolidCells*VERTICES_PER_QUAD + 1; 121 | GLushort seInd = m_numberSolidCells*VERTICES_PER_QUAD + 2; 122 | GLushort swInd = m_numberSolidCells*VERTICES_PER_QUAD + 3; 123 | m_solidVertData[nwInd] = VertexData(nwPos, SOLID_COLOR); 124 | m_solidVertData[neInd] = VertexData(nePos, SOLID_COLOR); 125 | m_solidVertData[seInd] = VertexData(sePos, SOLID_COLOR); 126 | m_solidVertData[swInd] = VertexData(swPos, SOLID_COLOR); 127 | // add to index array 128 | m_solidIndData[m_numberSolidCells*INDICES_PER_QUAD + 0] = nwInd; 129 | m_solidIndData[m_numberSolidCells*INDICES_PER_QUAD + 1] = swInd; 130 | m_solidIndData[m_numberSolidCells*INDICES_PER_QUAD + 2] = seInd; 131 | m_solidIndData[m_numberSolidCells*INDICES_PER_QUAD + 3] = nwInd; 132 | m_solidIndData[m_numberSolidCells*INDICES_PER_QUAD + 4] = seInd; 133 | m_solidIndData[m_numberSolidCells*INDICES_PER_QUAD + 5] = neInd; 134 | 135 | m_numberSolidCells++; 136 | } 137 | } 138 | } 139 | } 140 | 141 | /* 142 | Updates the buffers for the current frame being rendered. 143 | */ 144 | void FluidRenderer2D::updateBufferData(int frameNum) { 145 | // first update the particle data for this frame 146 | updateParticleVertexData(frameNum); 147 | 148 | // refill the buffer with new data 149 | glBindBuffer(GL_ARRAY_BUFFER, m_pvBuffer); 150 | glBufferSubData(GL_ARRAY_BUFFER, 0, m_numParticlesInFrame * sizeof(VertexData), m_particleVertData); 151 | 152 | // solid data does not change frame to frame 153 | } 154 | 155 | /* 156 | Initializes OpenGL for use by initializing buffers, shaders, and attributes. 157 | */ 158 | void FluidRenderer2D::initGL() { 159 | // enable blending 160 | glEnable(GL_BLEND); 161 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 162 | glPointSize(4); 163 | 164 | // fill particle vertex array with initial data 165 | updateParticleVertexData(0); 166 | // fill solids vertex array with initial data 167 | initSolidVertexData(); 168 | // create transformation matrix 169 | float scale = 2.0f / (m_width*m_dx); 170 | glm::mat4 scaleMat = glm::scale(glm::mat4(1.0f), glm::vec3(scale, scale, 1.0f)); 171 | glm::mat4 translateMat = glm::translate(glm::mat4(1.0f), glm::vec3((-m_width*m_dx) / 2.0f, (-m_height*m_dx) / 2.0f, 0.0f)); 172 | m_transMat = scaleMat* translateMat; 173 | 174 | // calculate offset for color in VertexData object 175 | m_vColorOffset = BYTES_PER_FLOAT * 2; 176 | 177 | // create buffers 178 | GLuint buffs[3]; 179 | glGenBuffers(3, buffs); 180 | m_pvBuffer = buffs[0]; 181 | m_svBuffer = buffs[1]; 182 | m_siBuffer = buffs[2]; 183 | 184 | //init buffers 185 | // particle vertex buffer 186 | glBindBuffer(GL_ARRAY_BUFFER, m_pvBuffer); 187 | glBufferData(GL_ARRAY_BUFFER, m_numParticlesInFrame * sizeof(VertexData), m_particleVertData, GL_DYNAMIC_DRAW); 188 | // solid vertex buffer 189 | glBindBuffer(GL_ARRAY_BUFFER, m_svBuffer); 190 | glBufferData(GL_ARRAY_BUFFER, m_numberSolidCells * VERTICES_PER_QUAD * sizeof(VertexData), m_solidVertData, GL_STATIC_DRAW); 191 | // solid index buffer 192 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_siBuffer); 193 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_numberSolidCells * INDICES_PER_QUAD * sizeof(GLushort), m_solidIndData, GL_STATIC_DRAW); 194 | 195 | // create shaders 196 | const char* vShadeFile = "vert.glsl"; 197 | const char* fShadeFile = "frag.glsl"; 198 | 199 | m_shaderProgram = LoadProgram(vShadeFile, fShadeFile); 200 | m_vPos = glGetAttribLocation(m_shaderProgram, "vPos"); 201 | m_vColor = glGetAttribLocation(m_shaderProgram, "vColor"); 202 | m_MVP = glGetUniformLocation(m_shaderProgram, "MVP"); 203 | 204 | glClearColor(BACKGROUND_COLOR[0], BACKGROUND_COLOR[1], BACKGROUND_COLOR[2], 1.0f); 205 | } 206 | 207 | // called at certain time increments to redraw and calculate fps 208 | void FluidRenderer2D::timer(int id) { 209 | glutPostRedisplay(); 210 | } 211 | 212 | /* 213 | Renders current particle and solid data. 214 | */ 215 | void FluidRenderer2D::display() { 216 | 217 | // update buffer data 218 | updateBufferData(m_currentFrame); 219 | 220 | glClear(GL_COLOR_BUFFER_BIT); 221 | 222 | glUseProgram(m_shaderProgram); 223 | // draw solids 224 | glBindBuffer(GL_ARRAY_BUFFER, m_svBuffer); 225 | glVertexAttribPointer(m_vPos, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), BUFFER_OFFSET(0)); 226 | glVertexAttribPointer(m_vColor, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), BUFFER_OFFSET(m_vColorOffset)); 227 | glEnableVertexAttribArray(m_vPos); 228 | glEnableVertexAttribArray(m_vColor); 229 | glUniformMatrix4fv(m_MVP, 1, GL_FALSE, glm::value_ptr(m_transMat)); 230 | 231 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_siBuffer); 232 | glDrawElements(GL_TRIANGLES, m_numberSolidCells * INDICES_PER_QUAD, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0)); 233 | 234 | // draw particles 235 | glBindBuffer(GL_ARRAY_BUFFER, m_pvBuffer); 236 | glVertexAttribPointer(m_vPos, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), BUFFER_OFFSET(0)); 237 | glVertexAttribPointer(m_vColor, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), BUFFER_OFFSET(m_vColorOffset)); 238 | glEnableVertexAttribArray(m_vPos); 239 | glEnableVertexAttribArray(m_vColor); 240 | glUniformMatrix4fv(m_MVP, 1, GL_FALSE, glm::value_ptr(m_transMat)); 241 | 242 | glDrawArrays(GL_POINTS, 0, m_numParticlesInFrame); 243 | 244 | // free buffers 245 | glBindBuffer(GL_ARRAY_BUFFER, 0); 246 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 247 | 248 | // actually draw 249 | glutSwapBuffers(); 250 | 251 | m_currentFrame++; 252 | 253 | // call timer function 254 | // set redisplay at inputted fps 255 | glutTimerFunc(m_frameTime*1000, timerCallback, 0); 256 | } 257 | 258 | /* 259 | Reads in particle position data from the particle file and uses it to initialize 260 | the particle position data array. 261 | */ 262 | void FluidRenderer2D::readInParticleData() { 263 | std::cout << "Reading in particle data for..." << std::endl; 264 | // open the particle data file 265 | std::ifstream particleFile(m_particleFile); 266 | if (particleFile.is_open()) { 267 | int curFrame = 0; 268 | while (particleFile.good()) { 269 | std::cout << "Frame " << curFrame << std::endl; 270 | std::vector frameVec; 271 | // loop through all frames and fill particle data array 272 | std::string lineStr; 273 | 274 | std::getline(particleFile, lineStr); 275 | std::vector tokens; 276 | strSplit(lineStr, ',', tokens); 277 | for (int i = 0; i < tokens.size(); i++) { 278 | // parse particle position (e.g. "0.0345 0.1235") 279 | std::vector strPos; 280 | strSplit(tokens[i], ' ', strPos); 281 | SimUtil::Vec2 pos(atof(strPos[0].c_str()), atof(strPos[1].c_str())); 282 | frameVec.push_back(pos); 283 | } 284 | 285 | if (frameVec.size() > 0) { 286 | m_particlePosData.push_back(frameVec); 287 | } 288 | curFrame++; 289 | } 290 | particleFile.close(); 291 | } 292 | } 293 | 294 | /* 295 | Splits a string based on delimeter. 296 | Grabbed from http://stackoverflow.com/a/236803. 297 | */ 298 | void FluidRenderer2D::strSplit(const std::string &s, char delim, std::vector &elems) { 299 | std::stringstream ss; 300 | ss.str(s); 301 | std::string item; 302 | while (std::getline(ss, item, delim)) { 303 | elems.push_back(item); 304 | } 305 | } -------------------------------------------------------------------------------- /FluidSim2D/FluidSim2D/FluidSolver2d.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "FluidSolver2d.h" 9 | #include "SimUtil.h" 10 | 11 | #define DEBUG 0 12 | 13 | using namespace SimUtil; 14 | 15 | //---------------------------------------------------------------------- 16 | // Constructors 17 | //---------------------------------------------------------------------- 18 | 19 | FluidSolver2D::FluidSolver2D(int width, int height, float dx, float dt){ 20 | m_gridWidth = width; 21 | m_gridHeight = height; 22 | m_dx = dx; 23 | m_dt = dt; 24 | 25 | m_particles = new std::vector(); 26 | } 27 | 28 | //---------------------------------------------------------------------- 29 | // Destructor 30 | //---------------------------------------------------------------------- 31 | 32 | FluidSolver2D::~FluidSolver2D(){ 33 | // clean up grid 34 | deleteGrid2D(m_gridWidth, m_gridHeight, m_label); 35 | deleteGrid2D(m_gridWidth, m_gridHeight, m_p); 36 | deleteGrid2D(m_gridWidth + 1, m_gridHeight, m_u); 37 | deleteGrid2D(m_gridWidth + 1, m_gridHeight, m_uSaved); 38 | deleteGrid2D(m_gridWidth, m_gridHeight + 1, m_v); 39 | deleteGrid2D(m_gridWidth, m_gridHeight + 1, m_vSaved); 40 | 41 | delete m_particles; 42 | } 43 | 44 | //---------------------------------------------------------------------- 45 | // Public Functions 46 | //---------------------------------------------------------------------- 47 | 48 | void FluidSolver2D::init(std::string initialGeometryFile){ 49 | // set up the grid for simulation by initializing arrays 50 | m_label = initGrid2D(m_gridWidth, m_gridHeight); 51 | m_p = initGrid2D(m_gridWidth, m_gridHeight); 52 | m_u = initGrid2D(m_gridWidth + 1, m_gridHeight); 53 | m_uSaved = initGrid2D(m_gridWidth + 1, m_gridHeight); 54 | m_v = initGrid2D(m_gridWidth, m_gridHeight + 1); 55 | m_vSaved = initGrid2D(m_gridWidth, m_gridHeight + 1); 56 | 57 | // init vel grids with unknown label value 58 | initGridValues(m_u, m_gridWidth + 1, m_gridHeight, VEL_UNKNOWN); 59 | initGridValues(m_v, m_gridWidth, m_gridHeight + 1, VEL_UNKNOWN); 60 | if (DEBUG) printGrid2D(m_gridWidth + 1, m_gridHeight, m_u); 61 | if (DEBUG) printGrid2D(m_gridWidth, m_gridHeight + 1, m_v); 62 | 63 | // read in initial geometry to populate label grid 64 | readInGeom2D(m_gridWidth, m_gridHeight, initialGeometryFile, m_label); 65 | if (DEBUG) printGrid2D(m_gridWidth, m_gridHeight, m_label); 66 | 67 | // seed particles using label grid 68 | seedParticles(PARTICLES_PER_CELL, m_particles); 69 | } 70 | 71 | void FluidSolver2D::step() { 72 | // update the grid labels 73 | labelGrid(); 74 | if (DEBUG) printGrid2D(m_gridWidth, m_gridHeight, m_label); 75 | // transfer particle vel to grid 76 | particlesToGrid(); 77 | if (DEBUG) printGrid2D(m_gridWidth + 1, m_gridHeight, m_u); 78 | if (DEBUG) printGrid2D(m_gridWidth, m_gridHeight + 1, m_v); 79 | // extrapolate fluid data out one cell for accurate divergence calculations 80 | extrapolateGridFluidData(m_u, m_gridWidth + 1, m_gridHeight, 2); 81 | extrapolateGridFluidData(m_v, m_gridWidth, m_gridHeight + 1, 2); 82 | if (DEBUG) printGrid2D(m_gridWidth + 1, m_gridHeight, m_u); 83 | if (DEBUG) printGrid2D(m_gridWidth, m_gridHeight + 1, m_v); 84 | // save copy of current grid velocities for FLIP update 85 | saveVelocityGrids(); 86 | // apply body forces on grid (gravity) 87 | applyBodyForces(); 88 | if (DEBUG) printGrid2D(m_gridWidth + 1, m_gridHeight, m_u); 89 | if (DEBUG) printGrid2D(m_gridWidth, m_gridHeight + 1, m_v); 90 | // solve for pressure 91 | pressureSolve(); 92 | if (DEBUG) printGrid2D(m_gridWidth, m_gridHeight, m_p); 93 | // apply pressure force 94 | applyPressure(); 95 | if (DEBUG) printGrid2D(m_gridWidth + 1, m_gridHeight, m_u); 96 | if (DEBUG) printGrid2D(m_gridWidth, m_gridHeight + 1, m_v); 97 | // TODO is grid getting cleared before this? 98 | // transfer grid velocities back to particles 99 | gridToParticles(PIC_WEIGHT); 100 | // advect particles 101 | extrapolateGridFluidData(m_u, m_gridWidth + 1, m_gridHeight, m_gridWidth); 102 | extrapolateGridFluidData(m_v, m_gridWidth, m_gridHeight + 1, m_gridHeight); 103 | advectParticles(ADVECT_MAX); 104 | // detect particles that have penetrated solid boundary and move back inside fluid 105 | cleanupParticles(m_dx / 4.0f); 106 | } 107 | 108 | void FluidSolver2D::saveParticleData(std::ofstream *particleOut) { 109 | if (particleOut->is_open()) { 110 | // print out all particle data on same line, each pos separated by "," 111 | size_t numParticles = m_particles->size(); 112 | if (numParticles > 0) { 113 | for (int i = 0; i < numParticles - 1; i++) { 114 | (*particleOut) << m_particles->at(i).pos.x << " " << m_particles->at(i).pos.y << ","; 115 | } 116 | (*particleOut) << m_particles->at(numParticles - 1).pos.x << " " << m_particles->at(numParticles - 1).pos.y << "\n"; 117 | } else { 118 | (*particleOut) << "\n"; 119 | } 120 | } 121 | } 122 | 123 | 124 | //---------------------------------------------------------------------- 125 | // Private Main Solver Step Functions 126 | //---------------------------------------------------------------------- 127 | 128 | /* 129 | Seeds the initial simulation particles. Particles are created for each fluid-labeled 130 | cell in a random-jittered subgrid pattern. 131 | Args: 132 | particlesPerCell - number of particles to seed in each fluid cell. 133 | particleList - list to place the new particles in 134 | */ 135 | void FluidSolver2D::seedParticles(int particlesPerCell, std::vector *particleList) { 136 | // set random seed 137 | srand(time(NULL)); 138 | // go through all cells marked fluid 139 | for (int i = 0; i < m_gridWidth; i++) { 140 | for (int j = 0; j < m_gridHeight; j++) { 141 | if (m_label[i][j] == SimUtil::FLUID) { 142 | // seed randomly in 2x2 subgrid of the cell 143 | Vec2 cellCenter = getGridCellPosition(i, j, m_dx); 144 | Vec2 subCenters[] = { 145 | Vec2(cellCenter.x - 0.25f*m_dx, cellCenter.y + 0.25f*m_dx), // top left 146 | Vec2(cellCenter.x + 0.25f*m_dx, cellCenter.y + 0.25f*m_dx), // top right 147 | Vec2(cellCenter.x + 0.25f*m_dx, cellCenter.y - 0.25f*m_dx), // bottom right 148 | Vec2(cellCenter.x - 0.25f*m_dx, cellCenter.y - 0.25f*m_dx) // bottom left 149 | }; 150 | // cycle through subgrid to place all particles 151 | for (int k = 0; k < particlesPerCell; k++) { 152 | // randomly jitter from subgrid center 153 | // give a random factor from [-0.24, 0.24] multiplied by dx 154 | float jitterX = ((float)((rand() % 49) - 24) / 100.0f) * m_dx; 155 | float jitterY = ((float)((rand() % 49) - 24) / 100.0f) * m_dx; 156 | Vec2 pos(subCenters[i % 4].x + jitterX, subCenters[i % 4].y + jitterY); 157 | Vec2 vel(0.0f, 0.0f); 158 | particleList->push_back(Particle2D(pos, vel)); 159 | } 160 | } 161 | } 162 | } 163 | } 164 | 165 | /* 166 | Updates the label grid based on particle positions. Grid cells containing particles 167 | are fluid, solids remain the same, and all other are air. 168 | */ 169 | void FluidSolver2D::labelGrid() { 170 | // first clear grid labels (mark everything air, but leave solids) 171 | for (int i = 0; i < m_gridWidth; i++) { 172 | for (int j = 0; j < m_gridHeight; j++) { 173 | if (m_label[i][j] != SOLID) { 174 | m_label[i][j] = AIR; 175 | } 176 | } 177 | } 178 | 179 | // mark any cell containing a particle FLUID 180 | for (int i = 0; i < m_particles->size(); i++) { 181 | // get cell containing the particle 182 | int *cell = getGridCellIndex(m_particles->at(i).pos, m_dx); 183 | m_label[cell[0]][cell[1]] = FLUID; 184 | } 185 | } 186 | 187 | /* 188 | Transfers particle values to the grid for cells labeled as a fluid. 189 | */ 190 | void FluidSolver2D::particlesToGrid() { 191 | // init vel grids with unknown label value 192 | initGridValues(m_u, m_gridWidth + 1, m_gridHeight, VEL_UNKNOWN); 193 | initGridValues(m_v, m_gridWidth, m_gridHeight + 1, VEL_UNKNOWN); 194 | 195 | // For each component of velocity in each fluid grid cell 196 | // we calculate weighted average of particles around it defined 197 | // by a kernel function and set this as the vel in the cell. 198 | 199 | // structures to accumulate grid numerator and denominator of weighted average before divide 200 | Mat2Dd uNum = initGrid2D(m_gridWidth+1, m_gridHeight); 201 | Mat2Dd uDen = initGrid2D(m_gridWidth+1, m_gridHeight); 202 | Mat2Dd vNum = initGrid2D(m_gridWidth, m_gridHeight+1); 203 | Mat2Dd vDen = initGrid2D(m_gridWidth, m_gridHeight+1); 204 | 205 | // clear accumulators 206 | for (int i = 0; i < m_gridWidth + 1; i++) { 207 | for (int j = 0; j < m_gridHeight + 1; j++) { 208 | if (j < m_gridHeight) { 209 | uNum[i][j] = 0.0; 210 | uDen[i][j] = 0.0; 211 | } 212 | if (i < m_gridWidth) { 213 | vNum[i][j] = 0.0; 214 | vDen[i][j] = 0.0; 215 | } 216 | } 217 | } 218 | 219 | 220 | // loop over particles and accumulate num and den at each grid point 221 | for (int p = 0; p < m_particles->size(); p++) { 222 | Particle2D curParticle = m_particles->at(p); 223 | for (int i = 0; i < m_gridWidth + 1; i++) { 224 | for (int j = 0; j < m_gridHeight + 1; j++) { 225 | if (j < m_gridHeight) { 226 | double kernel = trilinearHatKernel(sub(curParticle.pos, getGridCellPosition(i - 0.5f, j, m_dx))); 227 | uNum[i][j] += curParticle.vel.x * kernel; 228 | uDen[i][j] += kernel; 229 | } 230 | if (i < m_gridWidth) { 231 | double kernel = trilinearHatKernel(sub(curParticle.pos, getGridCellPosition(i, j - 0.5f, m_dx))); 232 | vNum[i][j] += curParticle.vel.y * kernel; 233 | vDen[i][j] += kernel; 234 | } 235 | } 236 | } 237 | } 238 | 239 | if (DEBUG) printGrid2D(m_gridWidth + 1, m_gridHeight, uNum); 240 | if (DEBUG) printGrid2D(m_gridWidth + 1, m_gridHeight, uDen); 241 | if (DEBUG) printGrid2D(m_gridWidth, m_gridHeight + 1, vNum); 242 | if (DEBUG) printGrid2D(m_gridWidth, m_gridHeight + 1, vDen); 243 | 244 | // additional pass over grid to divide and update actual velocities 245 | for (int i = 0; i < m_gridWidth + 1; i++) { 246 | for (int j = 0; j < m_gridHeight + 1; j++) { 247 | if (j < m_gridHeight) { 248 | if (uDen[i][j] != 0.0) { 249 | m_u[i][j] = uNum[i][j] / uDen[i][j]; 250 | } 251 | } 252 | if (i < m_gridWidth) { 253 | if (vDen[i][j] != 0.0) { 254 | m_v[i][j] = vNum[i][j] / vDen[i][j]; 255 | } 256 | } 257 | } 258 | } 259 | 260 | deleteGrid2D(m_gridWidth+1, m_gridHeight, uNum); 261 | deleteGrid2D(m_gridWidth+1, m_gridHeight, uDen); 262 | deleteGrid2D(m_gridWidth, m_gridHeight+1, vNum); 263 | deleteGrid2D(m_gridWidth, m_gridHeight+1, vDen); 264 | } 265 | 266 | /* 267 | Extrapolates the data in fluid cells of the given grid out using a breadth-first 268 | search technique. 269 | Args: 270 | grid - the grid with data to extrapolate 271 | x, y - the grid dimensions 272 | depth - the number of cells away from fluid cells to extrapolate to. 273 | */ 274 | void FluidSolver2D::extrapolateGridFluidData(Mat2Df grid, int x, int y, int depth) { 275 | // initialize marker array 276 | Mat2Di d = initGrid2D(x, y); 277 | // set d to 0 for known values, max int for unknown 278 | for (int i = 0; i < x; i++) { 279 | for (int j = 0; j < y; j++) { 280 | if (grid[i][j] != VEL_UNKNOWN) { 281 | d[i][j] = 0; 282 | } else { 283 | d[i][j] = INT_MAX; 284 | } 285 | } 286 | } 287 | 288 | // define neighbors 289 | int numNeighbors = 8; 290 | int neighbors[8][2] = { 291 | {-1, 1}, // top left 292 | {-1, 0}, // middle left 293 | {-1, -1}, // bottom left 294 | {0, 1}, // top middle 295 | {0, -1}, // bottom middle 296 | {1, 1}, // top right 297 | {1, 0}, // middle right 298 | {1, -1} // bottom right 299 | }; 300 | 301 | // initialize first wavefront 302 | std::vector W; 303 | int dim[2] = { x, y }; 304 | for (int i = 0; i < x; i++) { 305 | for (int j = 0; j < y; j++) { 306 | // current value is not known 307 | if (d[i][j] != 0) { 308 | int ind[2] = { i, j }; 309 | if (!checkNeighbors(d, dim, ind, neighbors, numNeighbors, 0).empty()) { 310 | // a neighbor is known 311 | d[i][j] = 1; 312 | W.push_back(Vec2(i, j)); 313 | } 314 | } 315 | } 316 | } 317 | 318 | // list of all wavefronts, only want to go through the given depth 319 | std::vector> wavefronts; 320 | wavefronts.push_back(W); 321 | int curWave = 0; 322 | while (curWave < depth) { 323 | // get wavefront 324 | std::vector curW = wavefronts.at(curWave); 325 | // initialize next wavefront 326 | std::vector nextW; 327 | // go through current wave and extrapolate values 328 | for (int i = 0; i < curW.size(); i++) { 329 | Vec2 ind = curW.at(i); 330 | // average neighbors 331 | float avg = 0.0f; 332 | int numUsed = 0; 333 | for (int i = 0; i < numNeighbors; i++) { 334 | int offsetX = neighbors[i][0]; 335 | int offsetY = neighbors[i][1]; 336 | int neighborX = ind.x + offsetX; 337 | int neighborY = ind.y + offsetY; 338 | 339 | // make sure valid indices 340 | if ((neighborX >= 0 && neighborX < dim[0]) && (neighborY >= 0 && neighborY < dim[1])) { 341 | // only want to add to average if neighbor d is less than current d 342 | if (d[neighborX][neighborY] < d[(int)ind.x][(int)ind.y]) { 343 | avg += grid[neighborX][neighborY]; 344 | numUsed++; 345 | } else if (d[neighborX][neighborY] == INT_MAX) { 346 | d[neighborX][neighborY] = d[(int)ind.x][(int)ind.y] + 1; 347 | nextW.push_back(Vec2(neighborX, neighborY)); 348 | } 349 | } 350 | } 351 | 352 | avg /= numUsed; 353 | // set current value to average of neighbors 354 | grid[(int)ind.x][(int)ind.y] = avg; 355 | } 356 | 357 | // push next wave to list 358 | wavefronts.push_back(nextW); 359 | curWave++; 360 | } 361 | 362 | // clean up 363 | deleteGrid2D(x, y, d); 364 | 365 | } 366 | 367 | /* 368 | Saves a copy of the current velocity grids to be used on the FLIP updated 369 | */ 370 | void FluidSolver2D::saveVelocityGrids() { 371 | // save u grid 372 | for (int i = 0; i < m_gridWidth + 1; i++) { 373 | for (int j = 0; j < m_gridHeight; j++) { 374 | m_uSaved[i][j] = m_u[i][j]; 375 | } 376 | } 377 | 378 | // save v grid 379 | for (int i = 0; i < m_gridWidth; i++) { 380 | for (int j = 0; j < m_gridHeight + 1; j++) { 381 | m_vSaved[i][j] = m_v[i][j]; 382 | } 383 | } 384 | } 385 | 386 | /* 387 | Applies the force of gravity to velocity field on the grid 388 | */ 389 | void FluidSolver2D::applyBodyForces() { 390 | // traverse all grid cells and apply force to each velocity component 391 | // The new velocity is calculated using forward euler 392 | for (int i = 0; i < m_gridWidth + 1; i++) { 393 | for (int j = 0; j < m_gridHeight + 1; j++) { 394 | if (j < m_gridHeight) { 395 | // make sure we know the velocity 396 | if (m_u[i][j] != VEL_UNKNOWN) { 397 | // update u component 398 | m_u[i][j] += m_dt*GRAVITY.x; 399 | } 400 | } 401 | if (i < m_gridWidth) { 402 | if (m_v[i][j] != VEL_UNKNOWN) { 403 | // update v component 404 | m_v[i][j] += m_dt*GRAVITY.y; 405 | } 406 | } 407 | } 408 | } 409 | } 410 | 411 | /* 412 | Solves for pressure using the current velocity field. 413 | */ 414 | void FluidSolver2D::pressureSolve() { 415 | // initialize all grids to solve for pressure 416 | // using double for more accuracy 417 | Mat2Dd rhs = initGrid2D(m_gridWidth, m_gridHeight); 418 | constructRHS(rhs); 419 | if (DEBUG) printGrid2D(m_gridWidth, m_gridHeight, rhs); 420 | Mat2Dd Adiag = initGrid2D(m_gridWidth, m_gridHeight); 421 | Mat2Dd Ax = initGrid2D(m_gridWidth, m_gridHeight); 422 | Mat2Dd Ay = initGrid2D(m_gridWidth, m_gridHeight); 423 | constructA(Adiag, Ax, Ay); 424 | if (DEBUG) printGrid2D(m_gridWidth, m_gridHeight, Adiag); 425 | if (DEBUG) printGrid2D(m_gridWidth, m_gridHeight, Ax); 426 | if (DEBUG) printGrid2D(m_gridWidth, m_gridHeight, Ay); 427 | Mat2Dd precon = initGrid2D(m_gridWidth, m_gridHeight); 428 | constructPrecon(precon, Adiag, Ax, Ay); 429 | if (DEBUG) printGrid2D(m_gridWidth, m_gridHeight, precon); 430 | 431 | // solve for pressure using PCG 432 | PCG(Adiag, Ax, Ay, rhs, precon); 433 | 434 | // cleanup 435 | deleteGrid2D(m_gridWidth, m_gridHeight, rhs); 436 | deleteGrid2D(m_gridWidth, m_gridHeight, Adiag); 437 | deleteGrid2D(m_gridWidth, m_gridHeight, Ax); 438 | deleteGrid2D(m_gridWidth, m_gridHeight, Ay); 439 | deleteGrid2D(m_gridWidth, m_gridHeight, precon); 440 | } 441 | 442 | /* 443 | Applies the pressure force to the current velocity field. 444 | */ 445 | void FluidSolver2D::applyPressure() { 446 | float scale = m_dt / (FLUID_DENSITY * m_dx); 447 | for (int i = 0; i < m_gridWidth; i++) { 448 | for (int j = 0; j < m_gridHeight; j++) { 449 | // update u 450 | if (i - 1 >= 0) { 451 | if (m_label[i - 1][j] == FLUID || m_label[i][j] == FLUID) { 452 | if (m_label[i - 1][j] == SOLID || m_label[i][j] == SOLID) { 453 | // TODO add solid velocities 454 | m_u[i][j] = 0.0f; // usolid[i][j] 455 | } else { 456 | m_u[i][j] -= scale * (m_p[i][j] - m_p[i - 1][j]); 457 | } 458 | } else { 459 | m_u[i][j] = VEL_UNKNOWN; 460 | } 461 | } else { 462 | // edge of grid, keep the same velocity 463 | } 464 | 465 | // update v 466 | if (j - 1 >= 0) { 467 | if (m_label[i][j - 1] == FLUID || m_label[i][j] == FLUID) { 468 | if (m_label[i][j - 1] == SOLID || m_label[i][j] == SOLID) { 469 | // TODO add solid velocities 470 | m_v[i][j] = 0.0f; // vsolid[i][j] 471 | } 472 | else { 473 | m_v[i][j] -= scale * (m_p[i][j] - m_p[i][j-1]); 474 | } 475 | } else { 476 | m_v[i][j] = VEL_UNKNOWN; 477 | } 478 | } else { 479 | // edge of grid, keep the same velocity 480 | } 481 | } 482 | } 483 | } 484 | 485 | /* 486 | Transfer the velocities from the grid back to the particles. This is done 487 | with a PIC/FLIP mix, where the PIC update has a weight of the given alpha. 488 | Args: 489 | alpha - weight in the update for PIC, should be in [0, 1]. Then the FLIP update is weighted (1 - alpha). 490 | */ 491 | void FluidSolver2D::gridToParticles(float alpha) { 492 | // build grid for change in velocity to use for FLIP update 493 | Mat2Df duGrid = initGrid2D(m_gridWidth + 1, m_gridHeight); 494 | Mat2Df dvGrid = initGrid2D(m_gridWidth, m_gridHeight + 1); 495 | // calc u grid 496 | for (int i = 0; i < m_gridWidth + 1; i++) { 497 | for (int j = 0; j < m_gridHeight; j++) { 498 | duGrid[i][j] = m_u[i][j] - m_uSaved[i][j]; 499 | } 500 | } 501 | // calc v grid 502 | for (int i = 0; i < m_gridWidth; i++) { 503 | for (int j = 0; j < m_gridHeight + 1; j++) { 504 | dvGrid[i][j] = m_v[i][j] - m_vSaved[i][j]; 505 | } 506 | } 507 | 508 | // go through particles and interpolate each velocity component 509 | // the update is a PIC/FLIP mix weighted with alpha 510 | // alpha = 1.0 is entirely PIC, alpha = 0.0 is all FLIP 511 | for (int i = 0; i < m_particles->size(); i++) { 512 | Particle2D *curParticle = &(m_particles->at(i)); 513 | Vec2 picInterp = interpVel(m_u, m_v, curParticle->pos); 514 | Vec2 flipInterp = interpVel(duGrid, dvGrid, curParticle->pos); 515 | // u_new = alpha * interp(u_gridNew, x_p) + (1 - alpha) * (u_pOld + interp(u_dGrid, x_p)) 516 | curParticle->vel = add(scale(picInterp, alpha), scale(add(curParticle->vel, flipInterp), 1.0f - alpha)); 517 | } 518 | 519 | deleteGrid2D(m_gridWidth + 1, m_gridHeight, duGrid); 520 | deleteGrid2D(m_gridWidth, m_gridHeight + 1, dvGrid); 521 | } 522 | 523 | /* 524 | Advects the particles through the current velocity field using a Runge-Kutta 3 method. 525 | This uses substeps so that the particles are never advected greater than C*dx in a single 526 | substep. 527 | Args: 528 | C - the maximum number of grid cells a particle should move when advected. This helps define substep sizes. 529 | */ 530 | void FluidSolver2D::advectParticles(int C) { 531 | for (int i = 0; i < m_particles->size(); i++) { 532 | Particle2D *curParticle = &(m_particles->at(i)); 533 | float subTime = 0; 534 | bool finished = false; 535 | //float dT = m_dt / 4.999f; 536 | while (!finished) { 537 | Vec2 curVel = interpVel(m_u, m_v, curParticle->pos); 538 | 539 | // calc max substep size 540 | float dT = (C * m_dx) / (norm(curVel) + FLT_MIN); 541 | // update substep time so we don't go past normal time step 542 | if (subTime + dT >= m_dt) { 543 | dT = m_dt - subTime; 544 | finished = true; 545 | } else if (subTime + 2 * dT >= m_dt) { 546 | dT = 0.5f * (m_dt - subTime); 547 | } 548 | 549 | RK3(curParticle, curVel, dT, m_u, m_v); 550 | subTime += dT; 551 | 552 | if (curParticle->pos.x < 0 || curParticle->pos.y < 0 || isnan(curParticle->pos.x) || isnan(curParticle->pos.y)) { 553 | // there's been an error in RK3, just skip it 554 | std::cout << "RK3 error...skipping particle" << std::endl; 555 | break; 556 | } 557 | 558 | int *cell = getGridCellIndex(curParticle->pos, m_dx); 559 | int j = cell[0]; 560 | int k = cell[1]; 561 | if (m_label[j][k] == SOLID) { 562 | //std::cout << "Advected into SOLID, projecting back!\n"; 563 | if (!projectParticle(curParticle, m_dx / 4.0f)) { 564 | std::cout << "RK3 error...skipping particle" << std::endl; 565 | break; 566 | } 567 | } 568 | 569 | } 570 | } 571 | } 572 | 573 | /* 574 | Finds particles that have traveled into solid boundaries and projects them back into the fluid region. 575 | They will be put at the closest boundary + the given dx into the fluid. 576 | Args 577 | dx - the amount to project stray particles away from the wall. 578 | */ 579 | void FluidSolver2D::cleanupParticles(float dx) { 580 | int i = 0; 581 | bool finished = false; 582 | int numDeleted = 0; 583 | while(!finished && m_particles->size() > 0) { 584 | int *cell = getGridCellIndex(m_particles->at(i).pos, m_dx); 585 | int ind[2] = { cell[0], cell[1] }; 586 | // if either of cells are negative or greater than sim dimensions it has left sim area 587 | if (ind[0] < 0 || ind[1] < 0 || ind[0] >= m_gridWidth || ind[1] >= m_gridHeight || isnan(m_particles->at(i).pos.x) || isnan(m_particles->at(i).pos.y)) { 588 | m_particles->erase(m_particles->begin() + i); 589 | numDeleted++; 590 | if (i >= m_particles->size()) { 591 | finished = true; 592 | } 593 | } else if (m_label[ind[0]][ind[1]] == SOLID) { 594 | // project back into fluid 595 | bool success = projectParticle(&(m_particles->at(i)), dx); 596 | if (!success) { 597 | // no near fluid, just delete 598 | m_particles->erase(m_particles->begin() + i); 599 | numDeleted++; 600 | if (i >= m_particles->size()) { 601 | finished = true; 602 | } 603 | } 604 | } else { 605 | i++; 606 | if (i >= m_particles->size()) { 607 | finished = true; 608 | } 609 | } 610 | } 611 | 612 | if (DEBUG) std::cout << "Removed " << numDeleted << " particles from sim.\n"; 613 | } 614 | 615 | 616 | 617 | //---------------------------------------------------------------------- 618 | // Private Helper Functions 619 | //---------------------------------------------------------------------- 620 | 621 | /* 622 | Populates the given grid with the value given. 623 | Args: 624 | grid - the grid to fill 625 | x/y - the dimensions of the grid 626 | value - the value to fill it with 627 | */ 628 | template 629 | void FluidSolver2D::initGridValues(T** grid, int x, int y, T value) { 630 | for (int i = 0; i < x; i++) { 631 | for (int j = 0; j < y; j++) { 632 | grid[i][j] = value; 633 | } 634 | } 635 | } 636 | 637 | /* 638 | Checks neighbors of the given index in the given grid for the given value. Returns a vector 639 | of neighbor indices (row index in the given neighbor array) that have the given value. 640 | Args 641 | grid - the 2D grid to look in 642 | dim - the grid dimensions [x y] 643 | index - the (i, j) index of the cell to look around 644 | neighbors - the definintion of neighbors, this is a n x 2 array where each row is a pair of offsets from the index of interest 645 | numNeighbors - the number of neighbors 646 | value - the value to look for 647 | */ 648 | std::vector FluidSolver2D::checkNeighbors(Mat2Di grid, int dim[2], int index[2], int neighbors[][2], int numNeighbors, int value) { 649 | std::vector neighborsTrue; 650 | for (int i = 0; i < numNeighbors; i++) { 651 | int offsetX = neighbors[i][0]; 652 | int offsetY = neighbors[i][1]; 653 | int neighborX = index[0] + offsetX; 654 | int neighborY = index[1] + offsetY; 655 | 656 | // make sure valid indices 657 | if ((neighborX >= 0 && neighborX < dim[0]) && (neighborY >= 0 && neighborY < dim[1])) { 658 | if (grid[neighborX][neighborY] == value) { 659 | neighborsTrue.push_back(i); 660 | } 661 | } 662 | } 663 | 664 | return neighborsTrue; 665 | } 666 | 667 | 668 | /* 669 | Returns the value of the trilinear hat function for the given 670 | distance (x, y). 671 | */ 672 | double FluidSolver2D::trilinearHatKernel(SimUtil::Vec2 dist) { 673 | return hatFunction(dist.x / m_dx) * hatFunction(dist.y / m_dx); 674 | } 675 | 676 | /* 677 | Calculates the value of hat function for the given r. 678 | */ 679 | double FluidSolver2D::hatFunction(double r) { 680 | double rAbs = abs(r); 681 | if (rAbs <= 1) { 682 | return 1.0 - rAbs; 683 | } else { 684 | return 0.0; 685 | } 686 | } 687 | 688 | 689 | /* 690 | Returns the value of the quadratic B-spline function for the 691 | given distance (x, y). 692 | */ 693 | double FluidSolver2D::quadBSplineKernel(SimUtil::Vec2) { 694 | // TODO 695 | return 0; 696 | } 697 | 698 | /* 699 | Interpolates the value in the given velocity grid at the given position using bilinear interpolation. 700 | Returns velocity unkown if position is not on simulation grid. 701 | Args: 702 | uGrid - the u component grid to interpolate from 703 | vGrid - the v component grid to interpolate from 704 | pos - the position to interpolate at 705 | */ 706 | Vec2 FluidSolver2D::interpVel(SimUtil::Mat2Df uGrid, SimUtil::Mat2Df vGrid, Vec2 pos) { 707 | // get grid cell containing position 708 | int *cell = getGridCellIndex(pos, m_dx); 709 | int i = cell[0]; 710 | int j = cell[1]; 711 | // make sure this is a valid index 712 | if (i >= 0 && i < m_gridWidth && j >= 0 && j < m_gridHeight) { 713 | // get positions of u and v component stored on each side of cell 714 | Vec2 cellLoc = getGridCellPosition(i, j, m_dx); 715 | float offset = m_dx / 2.0f; 716 | float x1 = cellLoc.x - offset; 717 | float x2 = cellLoc.x + offset; 718 | float y1 = cellLoc.y - offset; 719 | float y2 = cellLoc.y + offset; 720 | // get actual values at these positions 721 | float u1 = uGrid[i][j]; 722 | float u2 = uGrid[i + 1][j]; 723 | float v1 = vGrid[i][j]; 724 | float v2 = vGrid[i][j + 1]; 725 | 726 | // the interpolated values 727 | float u = ((x2 - pos.x) / (x2 - x1)) * u1 + ((pos.x - x1) / (x2 - x1)) * u2; 728 | float v = ((y2 - pos.y) / (y2 - y1)) * v1 + ((pos.y - y1) / (y2 - y1)) * v2; 729 | return Vec2(u, v); 730 | } else { 731 | return Vec2(VEL_UNKNOWN, VEL_UNKNOWN); 732 | } 733 | } 734 | 735 | /* 736 | Advects a particle using Runge-Kutta 3 through the given velocity field. 737 | Args: 738 | particle - the particle to advect 739 | initVel - the particles initial velocity in the current field, can leave UNKNOWN 740 | dt - the time step 741 | uGrid/vGrid - the velocity grids to advect through 742 | */ 743 | void FluidSolver2D::RK3(SimUtil::Particle2D *particle, SimUtil::Vec2 initVel, float dt, SimUtil::Mat2Df uGrid, SimUtil::Mat2Df vGrid) { 744 | if (initVel.x == VEL_UNKNOWN && initVel.y == VEL_UNKNOWN) { 745 | initVel = interpVel(uGrid, vGrid, particle->pos); 746 | } 747 | 748 | Vec2 k1 = initVel; 749 | Vec2 k2 = interpVel(uGrid, vGrid, add(particle->pos, scale(k1, 0.5f*dt))); 750 | Vec2 k3 = interpVel(uGrid, vGrid, add(particle->pos, scale(k2, 0.75f*dt))); 751 | k1 = scale(k1, (2.0f / 9.0f)*dt); 752 | k2 = scale(k2, (3.0f / 9.0f)*dt); 753 | k3 = scale(k3, (4.0f / 9.0f)*dt); 754 | 755 | particle->pos = add(particle->pos, add(k1, add(k2, k3))); 756 | } 757 | 758 | /* 759 | Sets up the right hand side of the system to solve for pressure. This is the negative 760 | divergence at each cell center modified to account for the velocity of solids at boundaries. 761 | Args: 762 | rhs - the grid to use for the RHS 763 | */ 764 | void FluidSolver2D::constructRHS(Mat2Dd rhs) { 765 | // initialize to 0 766 | initGridValues(rhs, m_gridWidth, m_gridHeight, 0.0); 767 | // calculate negative divergence 768 | double scale = 1.0f / m_dx; 769 | for (int i = 0; i < m_gridWidth; i++) { 770 | for (int j = 0; j < m_gridHeight; j++) { 771 | if (isFluid(i, j)) { 772 | rhs[i][j] = -scale * (m_u[i + 1][j] - m_u[i][j] + m_v[i][j + 1] - m_v[i][j]); 773 | // if it's on boundary must update to consider solid velocity 774 | // TODO create actual solid velocity grids, for right now just 0 775 | if (m_label[i - 1][j] == SOLID) { 776 | rhs[i][j] -= scale * (m_u[i][j] - 0.0f); //m_usolid[i][j] 777 | } 778 | if (m_label[i + 1][j] == SOLID) { 779 | rhs[i][j] += scale * (m_u[i+1][j] - 0.0f); //m_usolid[i+1][j] 780 | } 781 | if (m_label[i][j - 1] == SOLID) { 782 | rhs[i][j] -= scale * (m_v[i][j] - 0.0f); //m_vsolid[i][j] 783 | } 784 | if (m_label[i][j + 1] == SOLID) { 785 | rhs[i][j] += scale * (m_v[i][j+1] - 0.0f); //m_vsolid[i][j+1] 786 | } 787 | } 788 | } 789 | } 790 | } 791 | 792 | /* 793 | Constructs the A matrix for the system to solve for pressure. This a sparse coefficient matrix 794 | for the pressure terms, stored in 3 separate grids. If index i, j, k is not a fluid cell, then 795 | it is 0.0 in all 3 grids that store the matix. 796 | Args: 797 | Adiag - grid to store the diagonal of the matrix in. 798 | Ax - grid to store the coefficients for pressure in the (i+1) cell for each grid cell with x index i 799 | Ay - grid to store the coefficients for pressure in the (j+1) cell for each grid cell with y index j 800 | */ 801 | void FluidSolver2D::constructA(Mat2Dd Adiag, Mat2Dd Ax, Mat2Dd Ay) { 802 | // clear to all zeros so can increment 803 | initGridValues(Adiag, m_gridWidth, m_gridHeight, 0.0); 804 | initGridValues(Ax, m_gridWidth, m_gridHeight, 0.0); 805 | initGridValues(Ay, m_gridWidth, m_gridHeight, 0.0); 806 | 807 | // populate with coefficients for pressure unknowns 808 | double scale = m_dt / (FLUID_DENSITY * m_dx * m_dx); 809 | for (int i = 0; i < m_gridWidth; i++) { 810 | for (int j = 0; j < m_gridHeight; j++) { 811 | if (isFluid(i, j)) { 812 | // handle negative x neighbor 813 | if (m_label[i - 1][j] == FLUID || m_label[i - 1][j] == AIR) { 814 | Adiag[i][j] += scale; 815 | } 816 | // handle positive x neighbor 817 | if (m_label[i + 1][j] == FLUID) { 818 | Adiag[i][j] += scale; 819 | Ax[i][j] = -scale; 820 | } else if (m_label[i + 1][j] == AIR) { 821 | Adiag[i][j] += scale; 822 | } 823 | // handle negative y neighbor 824 | if (m_label[i][j - 1] == FLUID || m_label[i][j - 1] == AIR) { 825 | Adiag[i][j] += scale; 826 | } 827 | // handle positive y neighbor 828 | if (m_label[i][j + 1] == FLUID) { 829 | Adiag[i][j] += scale; 830 | Ay[i][j] = -scale; 831 | } else if (m_label[i][j + 1] == AIR) { 832 | Adiag[i][j] += scale; 833 | } 834 | } 835 | } 836 | } 837 | } 838 | 839 | /* 840 | Constructs the preconditioner used when performing the preconditioned conjugate gradient (PCG) 841 | algorithm to solve for pressure. 842 | Args: 843 | precon - grid to store the preconditioner in 844 | Adiag, Ax, Ay - the grids that make up the A coefficient matrix 845 | */ 846 | void FluidSolver2D::constructPrecon(Mat2Dd precon, Mat2Dd Adiag, Mat2Dd Ax, Mat2Dd Ay) { 847 | initGridValues(precon, m_gridWidth, m_gridHeight, 0.0); 848 | 849 | // tuning constant 850 | double tau = 0.97; 851 | // safety constant 852 | double sigma = 0.25; 853 | 854 | for (int i = 0; i < m_gridWidth; i++) { 855 | for (int j = 0; j < m_gridHeight; j++) { 856 | if (isFluid(i, j)) { 857 | double Adiag_ij = Adiag[i][j]; 858 | double Ax_im1j = 0.0; 859 | double Ax_ijm1 = 0.0; 860 | double Ay_ijm1 = 0.0; 861 | double Ay_im1j = 0.0; 862 | double precon_im1j = 0.0; 863 | double precon_ijm1 = 0.0; 864 | // want to stay at zero if off the grid 865 | // non-fluid entries in A are already 0 866 | if (i - 1 >= 0 && i - 1 < m_gridWidth) { 867 | if (isFluid(i - 1, j)) { 868 | Ax_im1j = Ax[i - 1][j]; 869 | Ay_im1j = Ay[i - 1][j]; 870 | precon_im1j = precon[i - 1][j]; 871 | } 872 | } 873 | if (j - 1 >= 0 && j - 1 < m_gridHeight) { 874 | if (isFluid(i, j - 1)) { 875 | Ax_ijm1 = Ax[i][j - 1]; 876 | Ay_ijm1 = Ay[i][j - 1]; 877 | precon_ijm1 = precon[i][j - 1]; 878 | } 879 | } 880 | 881 | double e = Adiag_ij - pow(Ax_im1j * precon_im1j, 2.0) 882 | - pow(Ay_ijm1 * precon_ijm1, 2.0) 883 | - tau * ( 884 | Ax_im1j * Ay_im1j * pow(precon_im1j, 2.0) 885 | + Ay_ijm1 * Ax_ijm1 * pow(precon_ijm1, 2.0) 886 | ); 887 | 888 | if (e < (sigma * Adiag_ij)) { 889 | e = Adiag_ij; 890 | } 891 | 892 | precon[i][j] = 1.0 / sqrt(e); 893 | } 894 | } 895 | } 896 | } 897 | 898 | /* 899 | Performs the Modified Incomplete Cholesky Conjugate Gradient Level Zero 900 | (preconditioned conjugate gradient, PCG) algorithm to solve the linear system 901 | Ap = b for p. The result are placed on the pressure grid. 902 | Args: 903 | Adiag, Ax, Ay - the grids that make up the A coefficient matrix 904 | b - the right hand side of the equation 905 | precon - the preconditioner to use 906 | */ 907 | void FluidSolver2D::PCG(Mat2Dd Adiag, Mat2Dd Ax, Mat2Dd Ay, Mat2Dd b, Mat2Dd precon) { 908 | // reset pressure vec to 0 909 | initGridValues(m_p, m_gridWidth, m_gridHeight, 0.0f); 910 | // residiual vector is b to start 911 | Mat2Dd r = initGrid2D(m_gridWidth, m_gridHeight); 912 | for (int i = 0; i < m_gridWidth; i++) { 913 | for (int j = 0; j < m_gridHeight; j++) { 914 | r[i][j] = b[i][j]; 915 | } 916 | } 917 | 918 | // check if r = 0 919 | bool r0 = true; 920 | for (int i = 0; i < m_gridWidth; i++) { 921 | for (int j = 0; j < m_gridHeight; j++) { 922 | if (r[i][j] != 0) { 923 | r0 = false; 924 | break; 925 | } 926 | } 927 | } 928 | 929 | if (r0) { 930 | std::cout << "Did not run PCG b/c of 0 residual to start.\n"; 931 | deleteGrid2D(m_gridWidth, m_gridHeight, r); 932 | return; 933 | } 934 | 935 | // auxiliary vector 936 | Mat2Dd z = initGrid2D(m_gridWidth, m_gridHeight); 937 | // search vector 938 | Mat2Dd s = initGrid2D(m_gridWidth, m_gridHeight); 939 | 940 | // initialize auxiliary and search 941 | applyPrecon(z, r, precon, Adiag, Ax, Ay); 942 | // search is set to auxiliary to start 943 | for (int i = 0; i < m_gridWidth; i++) { 944 | for (int j = 0; j < m_gridHeight; j++) { 945 | s[i][j] = z[i][j]; 946 | } 947 | } 948 | 949 | double sigma = dot(z, r, m_gridWidth, m_gridHeight); 950 | 951 | // start the main iteration until tolerance is reach or max out iterations 952 | bool converged = false; 953 | for (int iters = 0; iters < PCG_MAX_ITERS; iters++) { 954 | applyA(z, s, Adiag, Ax, Ay); 955 | double alpha = sigma / dot(z, s, m_gridWidth, m_gridHeight); 956 | // update pressure and residual 957 | for (int i = 0; i < m_gridWidth; i++) { 958 | for (int j = 0; j < m_gridHeight; j++) { 959 | m_p[i][j] += (alpha * s[i][j]); 960 | r[i][j] -= (alpha * z[i][j]); 961 | } 962 | } 963 | // check if we're under the tolerance 964 | if (max(r, m_gridWidth, m_gridHeight) <= PCG_TOL) { 965 | if (DEBUG) std::cout << "PCG converged after " << iters << " iterations.\n"; 966 | converged = true; 967 | break; 968 | } 969 | // otherwise new auxiliary vector 970 | applyPrecon(z, r, precon, Adiag, Ax, Ay); 971 | double newSigma = dot(z, r, m_gridWidth, m_gridHeight); 972 | double beta = newSigma / sigma; 973 | // update search vector 974 | for (int i = 0; i < m_gridWidth; i++) { 975 | for (int j = 0; j < m_gridHeight; j++) { 976 | s[i][j] = z[i][j] + (beta * s[i][j]); 977 | } 978 | } 979 | // update sigma 980 | sigma = newSigma; 981 | } 982 | 983 | if (!converged) { 984 | std::cout << "PCG did not converge, stopped after " << PCG_MAX_ITERS << " iterations!\n"; 985 | } 986 | 987 | // cleanup 988 | deleteGrid2D(m_gridWidth, m_gridHeight, r); 989 | deleteGrid2D(m_gridWidth, m_gridHeight, z); 990 | deleteGrid2D(m_gridWidth, m_gridHeight, s); 991 | } 992 | 993 | /* 994 | Applies the given preconditioner to the given vector and places the result in given "vector" z. 995 | Args: 996 | z - the vector (2D grid) to place the result in 997 | r - the vector (2D grid) to multiply the preconditioner by 998 | precon - the preconditioner 999 | Adiag, Ax, Ay - the grids that make up the coefficient matrix 1000 | */ 1001 | void FluidSolver2D::applyPrecon(Mat2Dd z, Mat2Dd r, Mat2Dd precon, Mat2Dd Adiag, Mat2Dd Ax, Mat2Dd Ay) { 1002 | // first solve Lq = r 1003 | Mat2Dd q = initGrid2D(m_gridWidth, m_gridHeight); 1004 | initGridValues(q, m_gridWidth, m_gridHeight, 0.0); 1005 | for (int i = 0; i < m_gridWidth; i++) { 1006 | for (int j = 0; j < m_gridHeight; j++) { 1007 | if (isFluid(i, j)) { 1008 | double Ax_im1j = 0.0; 1009 | double Ay_ijm1 = 0.0; 1010 | double precon_im1j = 0.0; 1011 | double precon_ijm1 = 0.0; 1012 | double q_im1j = 0.0; 1013 | double q_ijm1 = 0.0; 1014 | 1015 | if (i - 1 >= 0 && i - 1 < m_gridWidth) { 1016 | if (isFluid(i - 1, j)) { 1017 | Ax_im1j = Ax[i - 1][j]; 1018 | precon_im1j = precon[i - 1][j]; 1019 | q_im1j = q[i - 1][j]; 1020 | } 1021 | } 1022 | if (j - 1 >= 0 && j - 1 < m_gridHeight) { 1023 | if (isFluid(i, j - 1)) { 1024 | Ay_ijm1 = Ay[i][j - 1]; 1025 | precon_ijm1 = precon[i][j - 1]; 1026 | q_ijm1 = q[i][j - 1]; 1027 | } 1028 | } 1029 | 1030 | double t = r[i][j] - (Ax_im1j * precon_im1j * q_im1j) 1031 | - (Ay_ijm1 * precon_ijm1 * q_ijm1); 1032 | 1033 | q[i][j] = t * precon[i][j]; 1034 | } 1035 | } 1036 | } 1037 | 1038 | // now solve L^T z = q 1039 | initGridValues(z, m_gridWidth, m_gridHeight, 0.0); 1040 | for (int i = m_gridWidth - 1; i >= 0; i--) { 1041 | for (int j = m_gridHeight; j >= 0; j--) { 1042 | if (isFluid(i, j)) { 1043 | double Ax_ij = Ax[i][j]; 1044 | double Ay_ij = Ay[i][j]; 1045 | double precon_ij = precon[i][j]; 1046 | double z_ip1j = 0.0; 1047 | double z_ijp1 = 0.0; 1048 | 1049 | if (i + 1 >= 0 && i + 1 < m_gridWidth) { 1050 | if (isFluid(i + 1, j)) { 1051 | z_ip1j = z[i + 1][j]; 1052 | } 1053 | } 1054 | if (j + 1 >= 0 && j + 1 < m_gridHeight) { 1055 | if (isFluid(i, j + 1)) { 1056 | z_ijp1 = z[i][j + 1]; 1057 | } 1058 | } 1059 | 1060 | double t = q[i][j] - (Ax_ij * precon_ij * z_ip1j) 1061 | - (Ay_ij * precon_ij * z_ijp1); 1062 | 1063 | z[i][j] = t * precon_ij; 1064 | } 1065 | } 1066 | } 1067 | 1068 | // cleanup 1069 | deleteGrid2D(m_gridWidth, m_gridHeight, q); 1070 | } 1071 | 1072 | /* 1073 | Multiplies A by the given vector (a 2D grid). 1074 | Args: 1075 | z - the vector (2D grid) to place the result in 1076 | s - the vector (2D grid) to multiply A by 1077 | Adiag, Ax, Ay - the grids that make up the coefficient matrix A 1078 | */ 1079 | void FluidSolver2D::applyA(Mat2Dd z, Mat2Dd s, Mat2Dd Adiag, Mat2Dd Ax, Mat2Dd Ay) { 1080 | initGridValues(z, m_gridWidth, m_gridHeight, 0.0); 1081 | for (int i = 0; i < m_gridWidth; i++) { 1082 | for (int j = 0; j < m_gridHeight; j++) { 1083 | if (isFluid(i, j)) { 1084 | z[i][j] = Adiag[i][j] * s[i][j] 1085 | + Ax[i][j] * s[i + 1][j] 1086 | + Ay[i][j] * s[i][j + 1]; 1087 | if (i - 1 >= 0 && i - 1 < m_gridWidth) { 1088 | z[i][j] += Ax[i - 1][j] * s[i - 1][j]; 1089 | } 1090 | if (j - 1 >= 0 && j - 1 < m_gridHeight) { 1091 | z[i][j] += Ay[i][j - 1] * s[i][j - 1]; 1092 | } 1093 | } 1094 | } 1095 | } 1096 | } 1097 | 1098 | /* 1099 | Projects a particle within a solid back into the closest fluid or air. Returns true if 1100 | successful and false otherwise. 1101 | Args 1102 | particle - the particle to project. 1103 | dx - the amount to project the particle from the solid wall 1104 | */ 1105 | bool FluidSolver2D::projectParticle(Particle2D *particle, float dx) { 1106 | // project back into fluid 1107 | // find neighbors that are fluid 1108 | // define neighbors 1109 | int numNeighbors = 8; 1110 | int neighbors[8][2] = { 1111 | { -1, 1 }, // top left 1112 | { -1, 0 }, // middle left 1113 | { -1, -1 }, // bottom left 1114 | { 0, 1 }, // top middle 1115 | { 0, -1 }, // bottom middle 1116 | { 1, 1 }, // top right 1117 | { 1, 0 }, // middle right 1118 | { 1, -1 } // bottom right 1119 | }; 1120 | int dim[2] = { m_gridWidth, m_gridHeight }; 1121 | int *cell = getGridCellIndex(particle->pos, m_dx); 1122 | int index[2] = { cell[0], cell[1] }; 1123 | // get neighbors that are fluid 1124 | std::vector neighborInd = checkNeighbors(m_label, dim, index, neighbors, numNeighbors, FLUID); 1125 | if (neighborInd.size() == 0) { 1126 | // try with air 1127 | neighborInd = checkNeighbors(m_label, dim, index, neighbors, numNeighbors, AIR); 1128 | } 1129 | // find closest to particle 1130 | int closestInd = -1; 1131 | float closestDist = std::numeric_limits::max(); 1132 | Vec2 closestVec(0.0f, 0.0f); 1133 | for (int j = 0; j < neighborInd.size(); j++) { 1134 | // get vec from particle to neighbor ind 1135 | int ind[2] = { cell[0] + neighbors[neighborInd.at(j)][0], cell[1] + neighbors[neighborInd.at(j)][1] }; 1136 | Vec2 cellPos = getGridCellPosition(ind[0], ind[1], m_dx); 1137 | Vec2 distVec = sub(cellPos, particle->pos); 1138 | float dist = norm(distVec); 1139 | if (dist < closestDist) { 1140 | closestDist = dist; 1141 | closestInd = neighborInd.at(j); 1142 | closestVec = distVec; 1143 | } 1144 | } 1145 | 1146 | if (closestInd == -1) { 1147 | return false; 1148 | } 1149 | else { 1150 | // project different ways based on where closest neighbor is 1151 | // also make sure to only project the amount given 1152 | Vec2 projectVec(0.0f, 0.0f); 1153 | if (closestInd == 1) { // middle left 1154 | projectVec.x = closestVec.x + (-dx + (m_dx / 2.0f)); 1155 | } 1156 | else if (closestInd == 3) { // top middle 1157 | projectVec.y = closestVec.y + (dx - (m_dx / 2.0f)); 1158 | } 1159 | else if (closestInd == 4) { // bottom middle 1160 | projectVec.y = closestVec.y + (-dx + (m_dx / 2.0f)); 1161 | } 1162 | else if (closestInd == 6) { // middle right 1163 | projectVec.x = closestVec.x + (dx - (m_dx / 2.0f)); 1164 | } 1165 | else if (closestInd == 5) { // top right 1166 | projectVec.x = closestVec.x + (dx - (m_dx / 2.0f)); 1167 | projectVec.y = closestVec.y + (dx - (m_dx / 2.0f)); 1168 | } 1169 | else if (closestInd == 0) { // top left 1170 | projectVec.x = closestVec.x + (-dx + (m_dx / 2.0f)); 1171 | projectVec.y = closestVec.y + (dx - (m_dx / 2.0f)); 1172 | } 1173 | else if (closestInd == 2) { // bottom left 1174 | projectVec.x = closestVec.x + (-dx + (m_dx / 2.0f)); 1175 | projectVec.y = closestVec.y + (-dx + (m_dx / 2.0f)); 1176 | } 1177 | else if (closestInd == 7) { // bottom right 1178 | projectVec.x = closestVec.x + (dx - (m_dx / 2.0f)); 1179 | projectVec.y = closestVec.y + (-dx + (m_dx / 2.0f)); 1180 | } 1181 | 1182 | particle->pos = add(particle->pos, projectVec); 1183 | 1184 | return true; 1185 | } 1186 | } 1187 | 1188 | 1189 | /* 1190 | Determines if the given grid cell is considered a fluid based on the label grid. Also takes 1191 | into account velocity components on the edge of the grid. For example, if the index passed in 1192 | is one cell outside the label grid, it is assumed to be a velocity component index, and whether the cell is 1193 | fluid or not is determined by the cell that it borders. Otherwise false is returned. 1194 | Args 1195 | i - x cell index 1196 | j - y cell index 1197 | */ 1198 | bool FluidSolver2D::isFluid(int i, int j) { 1199 | bool isFluid = false; 1200 | // see if velocity on edge of grid 1201 | // if it is we can't check the label at that point, must check the one previous 1202 | if (i == m_gridWidth || j == m_gridHeight) { 1203 | // i and j should never both be out of label range 1204 | // should only happen in one dimension because of vel comp grids 1205 | if (i == m_gridWidth && j == m_gridHeight) { 1206 | isFluid = false; 1207 | } 1208 | else if (i == m_gridWidth) { 1209 | if (m_label[i - 1][j] == FLUID) { 1210 | isFluid = true; 1211 | } 1212 | } 1213 | else if (j == m_gridHeight) { 1214 | if (m_label[i][j - 1] == FLUID) { 1215 | isFluid = true; 1216 | } 1217 | } 1218 | } 1219 | else if (m_label[i][j] == FLUID) { 1220 | isFluid = true; 1221 | } 1222 | 1223 | return isFluid; 1224 | } 1225 | 1226 | --------------------------------------------------------------------------------