michael@0: /** michael@0: * Copyright 2012 the V8 project authors. All rights reserved. michael@0: * Copyright 2009 Oliver Hunt michael@0: * michael@0: * Permission is hereby granted, free of charge, to any person michael@0: * obtaining a copy of this software and associated documentation michael@0: * files (the "Software"), to deal in the Software without michael@0: * restriction, including without limitation the rights to use, michael@0: * copy, modify, merge, publish, distribute, sublicense, and/or sell michael@0: * copies of the Software, and to permit persons to whom the michael@0: * Software is furnished to do so, subject to the following michael@0: * conditions: michael@0: * michael@0: * The above copyright notice and this permission notice shall be michael@0: * included in all copies or substantial portions of the Software. michael@0: * michael@0: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, michael@0: * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES michael@0: * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND michael@0: * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT michael@0: * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, michael@0: * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING michael@0: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR michael@0: * OTHER DEALINGS IN THE SOFTWARE. michael@0: */ michael@0: michael@0: var NavierStokes = new BenchmarkSuite('NavierStokes', 1484000, michael@0: [new Benchmark('NavierStokes', michael@0: runNavierStokes, michael@0: setupNavierStokes, michael@0: tearDownNavierStokes)]); michael@0: michael@0: var solver = null; michael@0: michael@0: function runNavierStokes() michael@0: { michael@0: solver.update(); michael@0: } michael@0: michael@0: function setupNavierStokes() michael@0: { michael@0: solver = new FluidField(null); michael@0: solver.setResolution(128, 128); michael@0: solver.setIterations(20); michael@0: solver.setDisplayFunction(function(){}); michael@0: solver.setUICallback(prepareFrame); michael@0: solver.reset(); michael@0: } michael@0: michael@0: function tearDownNavierStokes() michael@0: { michael@0: solver = null; michael@0: } michael@0: michael@0: function addPoints(field) { michael@0: var n = 64; michael@0: for (var i = 1; i <= n; i++) { michael@0: field.setVelocity(i, i, n, n); michael@0: field.setDensity(i, i, 5); michael@0: field.setVelocity(i, n - i, -n, -n); michael@0: field.setDensity(i, n - i, 20); michael@0: field.setVelocity(128 - i, n + i, -n, -n); michael@0: field.setDensity(128 - i, n + i, 30); michael@0: } michael@0: } michael@0: michael@0: var framesTillAddingPoints = 0; michael@0: var framesBetweenAddingPoints = 5; michael@0: michael@0: function prepareFrame(field) michael@0: { michael@0: if (framesTillAddingPoints == 0) { michael@0: addPoints(field); michael@0: framesTillAddingPoints = framesBetweenAddingPoints; michael@0: framesBetweenAddingPoints++; michael@0: } else { michael@0: framesTillAddingPoints--; michael@0: } michael@0: } michael@0: michael@0: // Code from Oliver Hunt (http://nerget.com/fluidSim/pressure.js) starts here. michael@0: function FluidField(canvas) { michael@0: function addFields(x, s, dt) michael@0: { michael@0: for (var i=0; i Wp5) michael@0: x = Wp5; michael@0: var i0 = x | 0; michael@0: var i1 = i0 + 1; michael@0: if (y < 0.5) michael@0: y = 0.5; michael@0: else if (y > Hp5) michael@0: y = Hp5; michael@0: var j0 = y | 0; michael@0: var j1 = j0 + 1; michael@0: var s1 = x - i0; michael@0: var s0 = 1 - s1; michael@0: var t1 = y - j0; michael@0: var t0 = 1 - t1; michael@0: var row1 = j0 * rowSize; michael@0: var row2 = j1 * rowSize; michael@0: d[pos] = s0 * (t0 * d0[i0 + row1] + t1 * d0[i0 + row2]) + s1 * (t0 * d0[i1 + row1] + t1 * d0[i1 + row2]); michael@0: } michael@0: } michael@0: set_bnd(b, d); michael@0: } michael@0: michael@0: function project(u, v, p, div) michael@0: { michael@0: var h = -0.5 / Math.sqrt(width * height); michael@0: for (var j = 1 ; j <= height; j++ ) { michael@0: var row = j * rowSize; michael@0: var previousRow = (j - 1) * rowSize; michael@0: var prevValue = row - 1; michael@0: var currentRow = row; michael@0: var nextValue = row + 1; michael@0: var nextRow = (j + 1) * rowSize; michael@0: for (var i = 1; i <= width; i++ ) { michael@0: div[++currentRow] = h * (u[++nextValue] - u[++prevValue] + v[++nextRow] - v[++previousRow]); michael@0: p[currentRow] = 0; michael@0: } michael@0: } michael@0: set_bnd(0, div); michael@0: set_bnd(0, p); michael@0: michael@0: lin_solve(0, p, div, 1, 4 ); michael@0: var wScale = 0.5 * width; michael@0: var hScale = 0.5 * height; michael@0: for (var j = 1; j<= height; j++ ) { michael@0: var prevPos = j * rowSize - 1; michael@0: var currentPos = j * rowSize; michael@0: var nextPos = j * rowSize + 1; michael@0: var prevRow = (j - 1) * rowSize; michael@0: var currentRow = j * rowSize; michael@0: var nextRow = (j + 1) * rowSize; michael@0: michael@0: for (var i = 1; i<= width; i++) { michael@0: u[++currentPos] -= wScale * (p[++nextPos] - p[++prevPos]); michael@0: v[currentPos] -= hScale * (p[++nextRow] - p[++prevRow]); michael@0: } michael@0: } michael@0: set_bnd(1, u); michael@0: set_bnd(2, v); michael@0: } michael@0: michael@0: function dens_step(x, x0, u, v, dt) michael@0: { michael@0: addFields(x, x0, dt); michael@0: diffuse(0, x0, x, dt ); michael@0: advect(0, x, x0, u, v, dt ); michael@0: } michael@0: michael@0: function vel_step(u, v, u0, v0, dt) michael@0: { michael@0: addFields(u, u0, dt ); michael@0: addFields(v, v0, dt ); michael@0: var temp = u0; u0 = u; u = temp; michael@0: var temp = v0; v0 = v; v = temp; michael@0: diffuse2(u,u0,v,v0, dt); michael@0: project(u, v, u0, v0); michael@0: var temp = u0; u0 = u; u = temp; michael@0: var temp = v0; v0 = v; v = temp; michael@0: advect(1, u, u0, u0, v0, dt); michael@0: advect(2, v, v0, u0, v0, dt); michael@0: project(u, v, u0, v0 ); michael@0: } michael@0: var uiCallback = function(d,u,v) {}; michael@0: michael@0: function Field(dens, u, v) { michael@0: // Just exposing the fields here rather than using accessors is a measurable win during display (maybe 5%) michael@0: // but makes the code ugly. michael@0: this.setDensity = function(x, y, d) { michael@0: dens[(x + 1) + (y + 1) * rowSize] = d; michael@0: } michael@0: this.getDensity = function(x, y) { michael@0: return dens[(x + 1) + (y + 1) * rowSize]; michael@0: } michael@0: this.setVelocity = function(x, y, xv, yv) { michael@0: u[(x + 1) + (y + 1) * rowSize] = xv; michael@0: v[(x + 1) + (y + 1) * rowSize] = yv; michael@0: } michael@0: this.getXVelocity = function(x, y) { michael@0: return u[(x + 1) + (y + 1) * rowSize]; michael@0: } michael@0: this.getYVelocity = function(x, y) { michael@0: return v[(x + 1) + (y + 1) * rowSize]; michael@0: } michael@0: this.width = function() { return width; } michael@0: this.height = function() { return height; } michael@0: } michael@0: function queryUI(d, u, v) michael@0: { michael@0: for (var i = 0; i < size; i++) michael@0: u[i] = v[i] = d[i] = 0.0; michael@0: uiCallback(new Field(d, u, v)); michael@0: } michael@0: michael@0: this.update = function () { michael@0: queryUI(dens_prev, u_prev, v_prev); michael@0: vel_step(u, v, u_prev, v_prev, dt); michael@0: dens_step(dens, dens_prev, u, v, dt); michael@0: displayFunc(new Field(dens, u, v)); michael@0: } michael@0: this.setDisplayFunction = function(func) { michael@0: displayFunc = func; michael@0: } michael@0: michael@0: this.iterations = function() { return iterations; } michael@0: this.setIterations = function(iters) { michael@0: if (iters > 0 && iters <= 100) michael@0: iterations = iters; michael@0: } michael@0: this.setUICallback = function(callback) { michael@0: uiCallback = callback; michael@0: } michael@0: var iterations = 10; michael@0: var visc = 0.5; michael@0: var dt = 0.1; michael@0: var dens; michael@0: var dens_prev; michael@0: var u; michael@0: var u_prev; michael@0: var v; michael@0: var v_prev; michael@0: var width; michael@0: var height; michael@0: var rowSize; michael@0: var size; michael@0: var displayFunc; michael@0: function reset() michael@0: { michael@0: rowSize = width + 2; michael@0: size = (width+2)*(height+2); michael@0: dens = new Array(size); michael@0: dens_prev = new Array(size); michael@0: u = new Array(size); michael@0: u_prev = new Array(size); michael@0: v = new Array(size); michael@0: v_prev = new Array(size); michael@0: for (var i = 0; i < size; i++) michael@0: dens_prev[i] = u_prev[i] = v_prev[i] = dens[i] = u[i] = v[i] = 0; michael@0: } michael@0: this.reset = reset; michael@0: this.setResolution = function (hRes, wRes) michael@0: { michael@0: var res = wRes * hRes; michael@0: if (res > 0 && res < 1000000 && (wRes != width || hRes != height)) { michael@0: width = wRes; michael@0: height = hRes; michael@0: reset(); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: this.setResolution(64, 64); michael@0: }