/* Simple forward Euler method for velocity integration in time */ void euler(double &x, double &y, double timestep, const FluidQuantity &u, const FluidQuantity &v) const { double uVel = u.lerp(x, y)/_hx; double vVel = v.lerp(x, y)/_hx; x -= uVel*timestep; y -= vVel*timestep; }
double maxTimestep() { double maxVelocity = 0.0; for (int y = 0; y < _h; y++) { for (int x = 0; x < _w; x++) { double u = _u->lerp(x + 0.5, y + 0.5); double v = _v->lerp(x + 0.5, y + 0.5); double velocity = sqrt(u*u + v*v); maxVelocity = max(maxVelocity, velocity); } } double maxTimestep = 4.0*_hx/maxVelocity; return min(maxTimestep, 1.0); }
/* Returns the maximum allowed timestep. Note that the actual timestep * taken should usually be much below this to ensure accurate * simulation - just never above. */ double maxTimestep() { double maxVelocity = 0.0; for (int y = 0; y < _h; y++) { for (int x = 0; x < _w; x++) { /* Average velocity at grid cell center */ double u = _u->lerp(x + 0.5, y + 0.5); double v = _v->lerp(x + 0.5, y + 0.5); double velocity = sqrt(u*u + v*v); maxVelocity = max(maxVelocity, velocity); } } /* Fluid should not flow more than two grid cells per iteration */ double maxTimestep = 2.0*_hx/maxVelocity; /* Clamp to sensible maximum value in case of very small velocities */ return min(maxTimestep, 1.0); }
/* Third order Runge-Kutta for velocity integration in time */ void rungeKutta3(double &x, double &y, double timestep, const FluidQuantity &u, const FluidQuantity &v) const { double firstU = u.lerp(x, y)/_hx; double firstV = v.lerp(x, y)/_hx; double midX = x - 0.5*timestep*firstU; double midY = y - 0.5*timestep*firstV; double midU = u.lerp(midX, midY)/_hx; double midV = v.lerp(midX, midY)/_hx; double lastX = x - 0.75*timestep*midU; double lastY = y - 0.75*timestep*midV; double lastU = u.lerp(lastX, lastY); double lastV = v.lerp(lastX, lastY); x -= timestep*((2.0/9.0)*firstU + (3.0/9.0)*midU + (4.0/9.0)*lastU); y -= timestep*((2.0/9.0)*firstV + (3.0/9.0)*midV + (4.0/9.0)*lastV); }