|
|
|
@ -31,6 +31,7 @@ float visc_constant = 0.0007;
@@ -31,6 +31,7 @@ float visc_constant = 0.0007;
|
|
|
|
|
float stiffness_k = 1100; |
|
|
|
|
float h = 0.1; // smoothing radius
|
|
|
|
|
float mass; |
|
|
|
|
float gas_const =0.000001;
|
|
|
|
|
|
|
|
|
|
float invh; |
|
|
|
|
float invmass; // 1/mass
|
|
|
|
@ -60,6 +61,9 @@ void setup() {
@@ -60,6 +61,9 @@ void setup() {
|
|
|
|
|
inv_restdenssity = 1.0/rest_density; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* spiky kernel for density , and hence pressure calculation. |
|
|
|
|
*/ |
|
|
|
|
float spiky_kernel_f(float q) { |
|
|
|
|
float s = 3.0 / (2 * M_PI); |
|
|
|
|
if (0 <= q && q < 1) { |
|
|
|
@ -82,6 +86,17 @@ float spiky_kernel_dfdq(float q) {
@@ -82,6 +86,17 @@ float spiky_kernel_dfdq(float q) {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Vec3 gradW_muller_spiky(Vec3 r) { |
|
|
|
|
float q = mod_vec3(r); |
|
|
|
|
float res = (-45 * invh * invh * invh*invh * invh * invh / M_PI ); |
|
|
|
|
if (0 <= q && q <= h) { |
|
|
|
|
return r * (1/q) * (h - q) * (h - q) * res; |
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Vec3 {0,0,0}; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
float W_spiky_kernel(Vec3 xi, Vec3 xj) { |
|
|
|
|
float q = mod_vec3(Vec3{ |
|
|
|
|
xi.x - xj.x, |
|
|
|
@ -90,17 +105,52 @@ float W_spiky_kernel(Vec3 xi, Vec3 xj) {
@@ -90,17 +105,52 @@ float W_spiky_kernel(Vec3 xi, Vec3 xj) {
|
|
|
|
|
return spiky_kernel_f(q) * (invh * invh * invh); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
float W_muller_poly6_kernel(float r) { |
|
|
|
|
float res = 315.0 / 64; |
|
|
|
|
res /= M_PI; |
|
|
|
|
res *= pow(invh, 9); |
|
|
|
|
if (0 <= r && r <= h) { |
|
|
|
|
return res * (h * h - r * r) * (h * h - r * r)* (h * h - r * r); |
|
|
|
|
} |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Vec3 gradW_muller_poly6(Vec3 r) { |
|
|
|
|
float res = 915.0 / (32 * M_PI * pow(h,9)); |
|
|
|
|
float m = mod_vec3(r); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
float W_muller_spiky_kernel(float r) { |
|
|
|
|
if (r <= h && 0 <= r) { |
|
|
|
|
return (15 / M_PI) * invh * invh * invh * invh * invh * invh
|
|
|
|
|
* (h - r)* (h - r)* (h - r); |
|
|
|
|
} |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float W_spiky_kernel(float q) { |
|
|
|
|
return spiky_kernel_f(q) * (invh * invh * invh); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
inline float laplW_viscosity_kernel(float q) { |
|
|
|
|
|
|
|
|
|
if (q <= h && 0 <= q) { |
|
|
|
|
return (h - q) *invh * invh * invh * invh * invh * invh * 45 / M_PI; |
|
|
|
|
} |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float mod_gradW_spiky (Vec3 xi, Vec3 xj) { |
|
|
|
|
float q = mod_vec3(Vec3 { |
|
|
|
|
xi.x - xj.x, |
|
|
|
|
xi.y - xj.y, |
|
|
|
|
xi.z - xj.z}) * invh; |
|
|
|
|
// TODO: CHECK
|
|
|
|
|
xi.z - xj.z}) ; |
|
|
|
|
// TODO: CHECK / h
|
|
|
|
|
return spiky_kernel_dfdq(q) * (invh * invh * invh * invh); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -136,7 +186,7 @@ Vec3 grad_pressure(particle i, const std::vector<particle> &locals) {
@@ -136,7 +186,7 @@ Vec3 grad_pressure(particle i, const std::vector<particle> &locals) {
|
|
|
|
|
for (const auto &j : locals) { |
|
|
|
|
float inv_dens_sq = 1.0/(j.density * j.density); |
|
|
|
|
float temp = mass * (i.pressure * inv_dens_sq + (j.pressure * inv_dens_sq)); |
|
|
|
|
Vec3 gw = gradW_spiky(i.pos, j.pos); |
|
|
|
|
Vec3 gw = gradW_spiky(i.pos , j.pos); |
|
|
|
|
res = res + gw * temp; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -167,6 +217,57 @@ inline float pressure(float density) {
@@ -167,6 +217,57 @@ inline float pressure(float density) {
|
|
|
|
|
//return (rest_density * 45 * 45 / 7) * (pow(density / rest_density, 7) - 1);
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
inline float gas_pressure(float density) { |
|
|
|
|
/* see test case "pow vs multiply" in sphash-test.cpp */ |
|
|
|
|
return gas_const * (density - rest_density); |
|
|
|
|
//return (rest_density * 45 * 45 / 7) * (pow(density / rest_density, 7) - 1);
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pair<Vec3>
|
|
|
|
|
muller_update_density_pressure_gradpressure(particle &i, const std::vector<particle> &locals)
|
|
|
|
|
{ |
|
|
|
|
// eq 6
|
|
|
|
|
double density = 0; |
|
|
|
|
|
|
|
|
|
for (const auto &j : locals) { |
|
|
|
|
density += mass * W_muller_poly6_kernel(mod_vec3(i.pos- j.pos)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
i.density = density; |
|
|
|
|
i.pressure = pressure(density); |
|
|
|
|
Vec3 lapl_vel {0,0,0}; |
|
|
|
|
Vec3 grad_pres {0,0,0}; |
|
|
|
|
|
|
|
|
|
for (int j =0 ;j < locals.size(); j++) { |
|
|
|
|
float inv_dens_sq = 1.0/(locals[j].density * locals[j].density); |
|
|
|
|
// last frame density/pressure on locals j
|
|
|
|
|
auto gradW = gradW_muller_spiky(i.pos - locals[j].pos); |
|
|
|
|
//float temp = mass * (i.pressure * inv_dens_sq + (locals[j].pressure * inv_dens_sq));
|
|
|
|
|
grad_pres = grad_pres +
|
|
|
|
|
((i.pressure + locals[j].pressure) / (2 * locals[j].density)) * gradW; |
|
|
|
|
|
|
|
|
|
Vec3 vij = i.vel - locals[j].vel; |
|
|
|
|
Vec3 xij = i.pos - locals[j].pos; |
|
|
|
|
|
|
|
|
|
// lapl_vel = lapl_vel + 2 * (i.vel - locals[j].vel) *
|
|
|
|
|
// (((mass / locals[j].density) * (Vec3_dot(xij, gradW))) /
|
|
|
|
|
// (Vec3_dot(xij, xij) + 0.01 * h * h));
|
|
|
|
|
|
|
|
|
|
//lapl_vel = lapl_vel + laplW_viscosity_kernel(mod_vec3(i.pos - locals[j].pos))
|
|
|
|
|
// * ((locals[j].vel - i.vel) * (1.0/ locals[j].density));
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grad_pres = 1.0 * grad_pres * mass; |
|
|
|
|
lapl_vel = lapl_vel * visc_constant * mass; |
|
|
|
|
|
|
|
|
|
return {grad_pres, lapl_vel}; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pair<Vec3>
|
|
|
|
|
update_density_pressure_gradpressure(particle &i, const std::vector<particle> &locals)
|
|
|
|
|
{ |
|
|
|
@ -186,7 +287,7 @@ update_density_pressure_gradpressure(particle &i, const std::vector<particle> &l
@@ -186,7 +287,7 @@ update_density_pressure_gradpressure(particle &i, const std::vector<particle> &l
|
|
|
|
|
for (int j =0 ;j < locals.size(); j++) { |
|
|
|
|
float inv_dens_sq = 1.0/(locals[j].density * locals[j].density); |
|
|
|
|
// last frame density/pressure on locals j
|
|
|
|
|
auto gradW = gradW_spiky(i.pos, locals[j].pos); |
|
|
|
|
auto gradW = gradW_spiky(i.pos , locals[j].pos); |
|
|
|
|
float temp = mass * (i.pressure * inv_dens_sq + (locals[j].pressure * inv_dens_sq)); |
|
|
|
|
grad_pres = grad_pres + gradW * temp; |
|
|
|
|
|
|
|
|
@ -200,8 +301,6 @@ update_density_pressure_gradpressure(particle &i, const std::vector<particle> &l
@@ -200,8 +301,6 @@ update_density_pressure_gradpressure(particle &i, const std::vector<particle> &l
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grad_pres = grad_pres * density; |
|
|
|
|
|
|
|
|
|
return {grad_pres, lapl_vel}; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
@ -309,6 +408,18 @@ Vec3 lapl_vel_w(const particle i, const std::vector<particle> &locals) {
@@ -309,6 +408,18 @@ Vec3 lapl_vel_w(const particle i, const std::vector<particle> &locals) {
|
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Vec3 muller_visc(const particle p,
|
|
|
|
|
const std::vector<particle> &locals) { |
|
|
|
|
Vec3 Fvisc = {0,0,0}; |
|
|
|
|
for (auto j : locals) { |
|
|
|
|
float q = mod_vec3(p.pos - j.pos); |
|
|
|
|
auto lapl_w = laplW_viscosity_kernel(q); |
|
|
|
|
Fvisc = Fvisc + ((j.vel - p.vel) * (1.0/j.density)) * lapl_w; |
|
|
|
|
} |
|
|
|
|
return Fvisc * mass * visc_constant; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float step(std::vector<particle> &particles) { |
|
|
|
|
std::vector<std::vector<particle>> locals; |
|
|
|
|
|
|
|
|
@ -392,13 +503,22 @@ float step(std::vector<particle> &particles) {
@@ -392,13 +503,22 @@ float step(std::vector<particle> &particles) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float step(spatial_hash_map<float, particle> &particles) { |
|
|
|
|
std::vector<std::vector<particle>> locals; |
|
|
|
|
float step(struct sim_data &data) { |
|
|
|
|
|
|
|
|
|
auto &particles = data.particles; |
|
|
|
|
|
|
|
|
|
int rep = particles.repair_map(); |
|
|
|
|
|
|
|
|
|
// find neighbours
|
|
|
|
|
for (auto p : particles.particles) { |
|
|
|
|
locals.push_back(particles.get_locality(p.second.pos)); |
|
|
|
|
//
|
|
|
|
|
{ |
|
|
|
|
int i = 0;
|
|
|
|
|
for (auto &p : particles.particles) { |
|
|
|
|
data.working_area[i].p = p.second; |
|
|
|
|
data.working_area[i].part_ref = &p.second; |
|
|
|
|
particles.get_locality(p.second.pos, data.working_area[i].locality); |
|
|
|
|
i++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -419,85 +539,58 @@ float step(spatial_hash_map<float, particle> &particles) {
@@ -419,85 +539,58 @@ float step(spatial_hash_map<float, particle> &particles) {
|
|
|
|
|
|
|
|
|
|
float dt = TIMESTEP; |
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
int i = 0; |
|
|
|
|
for (auto &p: particles.particles) { |
|
|
|
|
pair<Vec3> gradp_laplvel = sph::update_density_pressure_gradpressure(p.second, locals[i]); |
|
|
|
|
// Vec3 gradp = sph::grad_pressure(p.second, locals[i]);
|
|
|
|
|
Vec3 Fp = gradp_laplvel.first; |
|
|
|
|
Fp.x *= (-mass / p.second.density); |
|
|
|
|
Fp.y *= (-mass / p.second.density); |
|
|
|
|
Fp.z *= (-mass / p.second.density); |
|
|
|
|
|
|
|
|
|
//Vec3 Fvisc = lapl_vel(p.second, locals[i]);
|
|
|
|
|
Vec3 Fvisc = gradp_laplvel.second; |
|
|
|
|
Fvisc.x *= mass * visc_constant; |
|
|
|
|
Fvisc.y *= mass * visc_constant; |
|
|
|
|
Fvisc.z *= mass * visc_constant; |
|
|
|
|
{int i = 0; |
|
|
|
|
for (auto &pp : data.particles.particles) { |
|
|
|
|
particle old_p = pp.second; |
|
|
|
|
particle new_p = pp.second; |
|
|
|
|
|
|
|
|
|
pair<Vec3> gradp_laplvel = sph::update_density_pressure_gradpressure( |
|
|
|
|
new_p,
|
|
|
|
|
data.working_area[i].locality); |
|
|
|
|
Vec3 Fp = -mass * gradp_laplvel.first; |
|
|
|
|
Vec3 Fvisc = mass * visc_constant * gradp_laplvel.second; |
|
|
|
|
|
|
|
|
|
Vec3 Fother = Vec3{0,0,-9.8 * mass}; |
|
|
|
|
|
|
|
|
|
float rev = -0.5; |
|
|
|
|
|
|
|
|
|
Vec3 forces = { |
|
|
|
|
Fvisc.x + Fp.x + Fother.x, |
|
|
|
|
Fvisc.y + Fp.y + Fother.y, |
|
|
|
|
Fvisc.z + Fp.z + Fother.z, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
new_p.vel = new_p.vel + dt * invmass * forces; |
|
|
|
|
new_p.pos = new_p.pos + dt * new_p.vel;
|
|
|
|
|
|
|
|
|
|
// stop
|
|
|
|
|
Vec3 newp = p.second.pos; |
|
|
|
|
if (newp.z < 0) { |
|
|
|
|
newp.z = 0 + (0 - newp.z); |
|
|
|
|
p.second.vel.z *= rev; |
|
|
|
|
if (new_p.pos.z < 0) { |
|
|
|
|
new_p.pos.z = 0 + (0 - new_p.pos.z); |
|
|
|
|
new_p.vel.z *= rev; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (newp.x < 0) { |
|
|
|
|
//newp.x = 0 - eps - particles[i].pos.x;
|
|
|
|
|
p.second.vel.x *= rev; |
|
|
|
|
if (new_p.pos.x < 0) { |
|
|
|
|
new_p.vel.x *= rev; |
|
|
|
|
} |
|
|
|
|
if (newp.x > room_width) { |
|
|
|
|
// Fother.x -= mass * 1.0 * (-room_width +newp.x) / dt ;
|
|
|
|
|
//newp.x = room_width + eps - particles[i].pos.x;
|
|
|
|
|
p.second.vel.x *= rev; |
|
|
|
|
if (new_p.pos.x > room_width) { |
|
|
|
|
new_p.vel.x *= rev; |
|
|
|
|
} |
|
|
|
|
if (newp.y < 0) { |
|
|
|
|
//Fother.y += mass * 1.0 * (0 - newp.y) / dt ;
|
|
|
|
|
//newp.y = 0 - eps - particles[i].pos.y;
|
|
|
|
|
p.second.vel.y *= rev; |
|
|
|
|
if (new_p.pos.y < 0) { |
|
|
|
|
new_p.vel.y *= rev; |
|
|
|
|
} |
|
|
|
|
if (newp.y > room_width) { |
|
|
|
|
//newp.y = room_width + eps - particles[i].pos.y;
|
|
|
|
|
p.second.vel.y *= rev; |
|
|
|
|
if (new_p.pos.y > room_width) { |
|
|
|
|
new_p.vel.y *= rev; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
forces[i] = { |
|
|
|
|
Fvisc.x + Fp.x + Fother.x, |
|
|
|
|
Fvisc.y + Fp.y + Fother.y, |
|
|
|
|
Fvisc.z + Fp.z + Fother.z, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
p.second.vel = p.second.vel + (forces[i] + forces_old[i]) * invmass * 0.5 * dt; |
|
|
|
|
particle newpart {p.second}; |
|
|
|
|
newpart.pos = newp; |
|
|
|
|
newpart.pos = p.second.pos + p.second.vel * dt + (forces[i] * invmass * 0.5 * dt)* dt; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
p.second.vel.x += dt * forces[i].x * invmass; |
|
|
|
|
p.second.vel.y += dt * forces[i].y * invmass; |
|
|
|
|
p.second.vel.z += dt * forces[i].z * invmass; |
|
|
|
|
|
|
|
|
|
particle newpart {p.second}; |
|
|
|
|
newpart.pos = newp; |
|
|
|
|
|
|
|
|
|
newpart.pos.x += dt * p.second.vel.x; |
|
|
|
|
newpart.pos.y += dt * p.second.vel.y; |
|
|
|
|
newpart.pos.z += dt * p.second.vel.z; |
|
|
|
|
*/ |
|
|
|
|
if (!particles.update(newpart, p.second.pos)) { |
|
|
|
|
p.second.pos = newpart.pos; |
|
|
|
|
|
|
|
|
|
if (!particles.update(new_p, data.working_area[i].part_ref->pos)) { |
|
|
|
|
/* If the particle has not crossed a grid boundary we can update it
|
|
|
|
|
* directly. */ |
|
|
|
|
*data.working_area[i].part_ref = new_p; |
|
|
|
|
} |
|
|
|
|
i++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
forces_old = forces; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return dt; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -531,7 +624,6 @@ void setup_particles(spatial_hash_map<float, particle> &particles, int n) {
@@ -531,7 +624,6 @@ void setup_particles(spatial_hash_map<float, particle> &particles, int n) {
|
|
|
|
|
}; |
|
|
|
|
i ++; |
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|