Simulating Fluid Dynamics: A Dive into Euler's Method in WL Notebooks

November 9, 2024, 2:40 am
Wolfram
Wolfram
AnalyticsDataDevelopmentFinTechPlatformResearchScienceSoftwareTechnologyTools
Location: United States, Illinois, Champaign
Employees: 501-1000
Founded date: 1987
SIGGRAPH Web site
Employees: 51-200
Founded date: 1999
Fluid dynamics is a complex dance of forces and motions. In the realm of computer graphics and simulations, understanding how to replicate this dance is crucial. This article explores the implementation of fluid simulation using Euler's method in WL (Wolfram Language) Notebooks, drawing inspiration from foundational works in the field.

The journey begins with the concept of incompressible fluids. Imagine a river flowing steadily, its surface smooth and unbroken. This is the essence of what we aim to simulate. The method we adopt is rooted in the pioneering work of Jos Stam, particularly his "Stable Fluids" paper presented at SIGGRAPH in 1999. This foundational work, along with Carl Sims' tutorials, serves as our compass.

### The Environment: WLJS Notebook

Before diving into the code, let's understand our environment. The WLJS Notebook is an open platform for creating and editing notebooks using Wolfram Language and JavaScript. It resembles Jupyter Notebook, where the interface is rendered in a browser, and computations occur on a server. This setup allows for dynamic calculations, making it ideal for our fluid simulation.

### Setting Up the Grid

We start by creating a two-dimensional grid. Picture a chessboard, each square representing a point in our fluid simulation. We initialize this grid with velocity vectors, which will dictate how our fluid moves. The grid is a simple array, a matrix of points where each point holds a vector representing the fluid's velocity.

```wolfram
grid = Table[{0, 0}, {5}, {5}];
grid[[3, 3]] = {0, 1}; (* A vector pointing upwards *)
```

### Visualizing the Velocity Field

Next, we visualize this grid as a vector field. Each arrow in the field represents the velocity at that point. This visualization is crucial for understanding how the fluid behaves. We can use `ListVectorPlot` to display our grid, turning abstract numbers into a tangible representation.

### Addressing Divergence

In fluid dynamics, divergence is a critical concept. It describes how much fluid is expanding or compressing at a point. For incompressible fluids, divergence should be zero. We need to ensure our simulation adheres to this principle.

To remove divergence, we implement an iterative method. Think of it as a sculptor chiseling away at a block of marble, refining the shape until it meets our expectations. We adjust the velocity vectors based on neighboring values, ensuring that the flow remains consistent and realistic.

```wolfram
removeDivergence[grid_] := Module[{...}, ...] (* Implementation details omitted for brevity *)
```

### Advection: Moving the Fluid

Once we have a stable grid, we introduce advection. This process describes how quantities (like mass or color) are transported by the fluid's velocity field. Imagine leaves floating down a stream; they move with the water's current.

We start with a scalar field, representing a quantity we want to advect. The naive approach might lead to inaccuracies, such as negative densities, which are non-physical. To correct this, we employ the donor-cell method, a technique that ensures we only take values from neighboring cells that contribute positively to the flow.

```wolfram
advect[v_, u_, δt_:0.1] := Module[{...}, ...] (* Implementation details omitted for brevity *)
```

### Visualizing Advection

With our advection function in place, we can visualize how our scalar field moves over time. By iterating through our grid, we can see how the initial conditions evolve. The results can be plotted using `MatrixPlot`, showing the distribution of our scalar field at various time steps.

### Integrating Velocity and Advection

The next step is to integrate our velocity field with the advection process. This is where the magic happens. The velocity field not only carries the scalar quantities but also evolves over time. We can treat the velocity field as a dynamic entity, updating it based on the advection of itself.

### Real-Time Simulation

The culmination of our efforts is a real-time fluid simulation. We can interact with the fluid, adding forces and observing how it responds. This interactivity transforms our static grid into a living, breathing simulation.

To achieve this, we implement mouse handlers that allow users to draw velocity vectors directly onto the grid. As users interact, the fluid responds, creating a captivating visual experience.

### Particles: Tracers in the Flow

To enhance our simulation, we introduce particles that follow the flow of the fluid. These particles act as tracers, providing a visual representation of the fluid's movement. By applying bilinear interpolation, we can accurately position these particles within the grid, ensuring they move smoothly with the fluid.

```wolfram
advectParticles[v_, pts_, δt_: 0.02] := Map[Function[p, p + δt*(bilinearInterpolation[v, p])], pts]
```

### Conclusion

Simulating fluid dynamics is a challenging yet rewarding endeavor. By leveraging Euler's method within the WLJS Notebook, we can create a dynamic and interactive fluid simulation. This exploration not only deepens our understanding of fluid mechanics but also showcases the power of computational tools in visualizing complex phenomena.

As we continue to refine our simulation, we can explore more advanced techniques, such as incorporating pressure dynamics and external forces. The journey into fluid dynamics is just beginning, and the possibilities are as vast as the oceans themselves.