numerics
Loading...
Searching...
No Matches
fluid.cpp
Go to the documentation of this file.
1/// @file backends/seq/fluid.cpp
2/// @brief Sequential SPH backend -- Newton's 3rd law pair traversal
3///
4/// All physics loops use grid.iterate_pairs() which visits each unique
5/// {i,j} pair once. Forces and density contributions are accumulated
6/// symmetrically to both particles -> O(n*k/2) instead of O(n*k).
7
8#include "impl.hpp"
9#include "kernel.hpp"
11#include <cmath>
12#include <algorithm>
13#include <cfloat>
14
16
17// -- Density (Poly6) + pressure (Tait EOS) ------------------------------------
18
19void compute_density_pressure(std::vector<Particle>& particles,
20 const FluidParams& params,
21 const SpatialHash& grid) {
22 const float h = params.h;
23 const float m = params.mass;
24 const float rho0 = params.rho0;
25 const float B = rho0 * params.c0 * params.c0 / static_cast<float>(params.gamma);
26 const float supp_sq = 4.0f * h * h;
27
28 const float W0 = Kernel::W(0.0f, h);
29 for (Particle& p : particles)
30 p.density = m * W0;
31
32 grid.iterate_pairs([&](int i, int j) {
33 const float rx = particles[i].x - particles[j].x;
34 const float ry = particles[i].y - particles[j].y;
35 const float r2 = rx * rx + ry * ry;
36 if (r2 >= supp_sq) return;
37 const float w = m * Kernel::W(std::sqrt(r2), h);
38 particles[i].density += w;
39 particles[j].density += w;
40 });
41
42 for (Particle& p : particles) {
43 p.density = std::max(p.density, rho0 * 0.1f);
44 p.pressure = std::max(0.0f, B * (num::ipow<7>(p.density / rho0) - 1.0f));
45 }
46}
47
48// -- Forces: pressure (Spiky) + viscosity (Morris) + gravity ------------------
49
50void compute_forces(std::vector<Particle>& particles,
51 const FluidParams& params,
52 const SpatialHash& grid) {
53 const float h = params.h;
54 const float m = params.mass;
55 const float mu = params.mu;
56 const float supp_sq = 4.0f * h * h;
57 const float eps2 = 0.01f * h * h;
58
59 for (Particle& p : particles) { p.ax = params.gx; p.ay = params.gy; }
60
61 grid.iterate_pairs([&](int i, int j) {
62 Particle& pi = particles[i];
63 Particle& pj = particles[j];
64 const float rx = pi.x - pj.x, ry = pi.y - pj.y;
65 const float r2 = rx * rx + ry * ry;
66 if (r2 >= supp_sq || r2 < 1e-10f) return;
67 const float r = std::sqrt(r2);
68
69 float gx, gy;
70 Kernel::Spiky_gradW(rx, ry, r, h, gx, gy);
71 const float pterm = pi.pressure / (pi.density * pi.density)
72 + pj.pressure / (pj.density * pj.density);
73 const float fpx = -m * pterm * gx, fpy = -m * pterm * gy;
74 pi.ax += fpx; pi.ay += fpy;
75 pj.ax -= fpx; pj.ay -= fpy;
76
77 const float lap = 2.0f * Kernel::Spiky_dW_dr(r, h) * r / (r2 + eps2);
78 const float visc = m * mu / (pi.density * pj.density) * lap;
79 const float fvx = visc * (pi.evx - pj.evx), fvy = visc * (pi.evy - pj.evy);
80 pi.ax += fvx; pi.ay += fvy;
81 pj.ax -= fvx; pj.ay -= fvy;
82 });
83}
84
85// -- Remaining phases -- all O(n) or O(n*M) with small M ----------------------
86
87void body_collisions(std::vector<Particle>& particles,
88 const std::vector<RigidBody>& bodies,
89 const FluidParams& params) {
90 for (Particle& p : particles) {
91 for (const RigidBody& body : bodies) {
92 const float dx = p.x - body.x, dy = p.y - body.y;
93 const float d = std::sqrt(dx * dx + dy * dy);
94 if (d < body.radius && d > 1e-8f) {
95 const float nx = dx / d, ny = dy / d;
96 p.x = body.x + body.radius * nx;
97 p.y = body.y + body.radius * ny;
98 const float vn = p.vx * nx + p.vy * ny;
99 if (vn < 0.0f) {
100 p.vx -= (1.0f + params.restitution) * vn * nx;
101 p.vy -= (1.0f + params.restitution) * vn * ny;
102 }
103 }
104 }
105 }
106}
107
108void integrate(std::vector<Particle>& particles, const FluidParams& params) {
109 const float dt = params.dt;
110 for (Particle& p : particles) {
111 p.vx += p.ax * dt; p.vy += p.ay * dt;
112 p.x += p.vx * dt; p.y += p.vy * dt;
113 p.evx = 0.5f * (p.evx + p.vx);
114 p.evy = 0.5f * (p.evy + p.vy);
115 p.temperature = std::clamp(p.temperature + p.dT_dt * dt, -100.0f, 300.0f);
116 }
117}
118
119void enforce_boundaries(std::vector<Particle>& particles, const FluidParams& params) {
120 const float e = params.restitution;
121 for (Particle& p : particles) {
122 if (p.x < params.xmin) { p.x = params.xmin; p.vx = std::abs(p.vx) * e; }
123 if (p.x > params.xmax) { p.x = params.xmax; p.vx = -std::abs(p.vx) * e; }
124 if (p.y < params.ymin) { p.y = params.ymin; p.vy = std::abs(p.vy) * e; }
125 if (p.y > params.ymax) { p.y = params.ymax; p.vy = -std::abs(p.vy) * e; }
126 }
127}
128
129void update_temp_range(const std::vector<Particle>& particles,
130 const std::vector<RigidBody>& bodies,
131 float& T_min, float& T_max) {
132 if (particles.empty()) return;
133 T_min = T_max = particles[0].temperature;
134 for (const Particle& p : particles) {
135 T_min = std::min(T_min, p.temperature);
136 T_max = std::max(T_max, p.temperature);
137 }
138 for (const RigidBody& b : bodies) {
139 T_min = std::min(T_min, b.temperature);
140 T_max = std::max(T_max, b.temperature);
141 }
142}
143
144void integrate_bodies(std::vector<RigidBody>& bodies, const FluidParams& params) {
145 const float dt = params.dt, e = params.restitution;
146 for (RigidBody& b : bodies) {
147 if (b.fixed) continue;
148 b.vx += params.gx * dt; b.vy += params.gy * dt;
149 b.x += b.vx * dt; b.y += b.vy * dt;
150 const float r = b.radius;
151 if (b.x - r < params.xmin) { b.x = params.xmin + r; b.vx = std::abs(b.vx) * e; }
152 if (b.x + r > params.xmax) { b.x = params.xmax - r; b.vx = -std::abs(b.vx) * e; }
153 if (b.y - r < params.ymin) { b.y = params.ymin + r; b.vy = std::abs(b.vy) * e; }
154 if (b.y + r > params.ymax) { b.y = params.ymax - r; b.vy = -std::abs(b.vy) * e; }
155 }
156}
157
158} // namespace physics::backends::seq
void iterate_pairs(F &&f) const
Compile-time integer exponentiation via repeated squaring.
constexpr T ipow(T x) noexcept
Compute x^N at compile time via repeated squaring.
void enforce_boundaries(std::vector< Particle > &particles, const FluidParams &params)
Definition fluid.cpp:119
void body_collisions(std::vector< Particle > &particles, const std::vector< RigidBody > &bodies, const FluidParams &params)
Definition fluid.cpp:87
void integrate(std::vector< Particle > &particles, const FluidParams &params)
Definition fluid.cpp:108
void compute_density_pressure(std::vector< Particle > &particles, const FluidParams &params, const SpatialHash &grid)
Newton's 3rd law pair traversal – O(n*k/2).
Definition fluid.cpp:19
void update_temp_range(const std::vector< Particle > &particles, const std::vector< RigidBody > &bodies, float &T_min, float &T_max)
Definition fluid.cpp:129
void integrate_bodies(std::vector< RigidBody > &bodies, const FluidParams &params)
Definition fluid.cpp:144
void compute_forces(std::vector< Particle > &particles, const FluidParams &params, const SpatialHash &grid)
Newton's 3rd law pair traversal – O(n*k/2).
Definition fluid.cpp:50
std::experimental::simd butterfly for FFT.
float rho0
Rest density [kg/m^3].
Definition fluid.hpp:37
float mu
Dynamic viscosity [Pa*s].
Definition fluid.hpp:40
int gamma
Tait EOS exponent.
Definition fluid.hpp:38
float h
Smoothing length [m].
Definition fluid.hpp:34
float c0
Speed of sound [m/s] -> B = rho_0c_0^2/gamma.
Definition fluid.hpp:39
float gy
Gravity y [m/s^2].
Definition fluid.hpp:45
float restitution
Velocity restitution at walls.
Definition fluid.hpp:55
float gx
Gravity x [m/s^2].
Definition fluid.hpp:44
float dt
Timestep [s] (must satisfy CFL: dt < h/c0)
Definition fluid.hpp:48
float mass
Particle mass [kg] (~= rho_0*dx^2, dx=0.8h)
Definition fluid.hpp:41
static float Spiky_dW_dr(float r, float h)
Definition kernel.hpp:19
static void Spiky_gradW(float rx, float ry, float r, float h, float &gx, float &gy)
Definition kernel.hpp:22
static float W(float r, float h)
Definition kernel.hpp:13
A single SPH fluid particle (float precision for performance)
Definition particle.hpp:8
float y
Position [m].
Definition particle.hpp:9
float pressure
Pressure p_i [Pa].
Definition particle.hpp:15
float density
SPH density rho_i [kg/m^3].
Definition particle.hpp:14
float ay
Acceleration [m/s^2] (updated each step)
Definition particle.hpp:13
A rigid spherical body that interacts with fluid particles.
Definition rigid_body.hpp:8