Smoothed-Particle Hydrodynamics: Fluid Simulation

Aadith Charugundla

This page is for showcasing my SPH Fluid Simulation.

Intro

Fluid Simulations

What even is a fluid simulation? At its most basic, a fluid simulation is a way of visualizing the movement of fluid. Fluid sims can vary a lot in terms of style and complexity. For this project, I was specifically focusing on physically-based fluid simulations as opposed to something more cartoon-y. This type of approach is called Computational Fluid Dynamics (CFD) because as the name implies we are computationally measuring the movement of the fluid using approximations of real-world physics. To accomplish this, I used the smoothed-particle hydrodynamics (SPH) approach.

Eulerian vs Lagrangian

Computational Fluid Dynamics discretizes space in one of two ways: Eulerian and Lagrangian. The Eulerian approach is also typically called the 'Grid Method' since it relies on partitioning space into a grid/mesh, where we calculate and track the velocity at fixed grid locations. The Lagrangian approach does not use a mesh, but instead tracks the position and velocity of individual moving particles in space, relying on calculating the effects of external forces, viscosity, pressure field changes, and more. Both approaches have their own pros and cons, and after weighing the choices I ultimatley chose to go with a Lagrangian approach like SPH.

Goal

I have always been fascinated with widgets like this. I wanted to create something similar (i.e. a particle-based representation of fluid, interactivity via clicking and dragging the mouse, and collision detection with boundaries of the container.

Credit

I'd like to give credit where credit is due. I couldn't have done a huge part of this project without the wonderful resource that Lucas-Schuermann provided on his webite where he detailed his approach to the problem. You can find it here. You will notice some similarities between his project and mine, since I used his approach as a template for my work. However there are differences between our code, both in terms of implementation and libraries used.

Architecture/System

Libraries/Language

For this project I used C++ with OpenGL. One of my reasons for choosing this project was to get more familiar with OpenGL, since I felt I only got a brief introduction to it in prior courses. I used C++ because it's the language I'm most familiar with. In order to do efficient matrix operations, I used the Eigen library. To help manage OpenGL windows I used the GLFW library, and I also used some of the OpenGL extensions with GLEW. In order to parallelize some of my code, I used OpenMP.

Functions/Methods

After reading this paper I set out to start implementing the equations listed under section 3 of the paper, Modeling Fluids with Particles. This paper had the equations needed to account for the pressure, viscosity, surface tension, and external forces on a given fluid particle. However, upon implementing this I realized that I needed to find a way to integrate, so I decided to go with Euler's Method, similar to what Lucas-Schuermann did. However even after doing all this, my particles were bouncing around like crazy with way too much velocity. I eventually realized this was becuase the smoothing kernels that the paper used were for 3-dimensional fluid simulations, whereas mine was a 2D one. Fortunately for me, Lucas-Schuermann had my back again and documented the specific constants he happened to use for his 2D fluid simulation. This was what got the ball rolling for me, as I now had a decent (but more importantly working) fluid simulation.

Particle Processing

At the start of the code after initializing the window, I create a grid of particles above the lower boundary of the container. The goal is to see how the fluid particles crash against the boundary and disperse. At each time step the udpate() function is called, which calculates the various forces applied on each particle at that time, before figuring out how the particle should move for the next time step. This updated information then gets sent to my OpenGL shaders which process the new positions, resulting in the animated effect.

Advanced Architecture

What I have described so far is very similar to the Lucas-Schuermann implementation. I wanted to go a bit beyond what was described in the article and represented in his code. To do this, I implemented 2 optimizations and added 1 new feature.

The first optimization was in the form of parallelizing the for-loops in the particle force calculation using the OpenMP library. Parallelizing this code was not a challenge, since at each time step we are calculating how a particle should move based on the orientation of all the other particles at that time step. Since we are not worried about particles after the time step affecting the calculations (i.e. there is no order to how they should be calculated), this is a situation where race conditions will not occur, we can simply calculate how each particle moves in parallel threads. The second optimization had to do with partitioning the space into a spatial grid to help with neighbor calculations. The way the smoothing kernels work is by weighing the contributions from all neighbors within a certain distance from a particle. Previously I was looping through every particle in the scene, determining whether they were at the right distance, and then applying the kernel. This is very expensive, as we have to loop over every other particle FOR every particle. To solve this problem, I took a spatial hashing approach, outlined in this article. This approach was the key change needed to speed up my slow fluid simulation.

In addition to these 2 optimizations, I also added a feature I didn't see mentioned anywhere in the Lucas-Schuermann article. As I mentioned previously in the document, I was heavily inspired by those simulations where the user could drag their mouse to add a force to the particles. In order to implement this feature, I keep track of whenever the user clicks their mouse inside the application window. After that, they can move their mouse whereever they want to, but only the FINAL destination of the mouse upon release is used. This of course means that the forces that the user can apply on the particles must be in a straight line. The difference between the start and end position is used to create a force vector which gets added to the particle. This was by far the most satisfying change for me, since it meant I got to play around with the fluid simulation like I always wanted to.

Results

Fluid Sim with 200 Particles:



Fluid Sim with 400 Particles (Slower):



Mouse Drag in Fluid Simulation:

Future Work

Source Code

Source code is only available upon request.