js/src/v8/navier-stokes.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /**
michael@0 2 * Copyright 2012 the V8 project authors. All rights reserved.
michael@0 3 * Copyright 2009 Oliver Hunt <http://nerget.com>
michael@0 4 *
michael@0 5 * Permission is hereby granted, free of charge, to any person
michael@0 6 * obtaining a copy of this software and associated documentation
michael@0 7 * files (the "Software"), to deal in the Software without
michael@0 8 * restriction, including without limitation the rights to use,
michael@0 9 * copy, modify, merge, publish, distribute, sublicense, and/or sell
michael@0 10 * copies of the Software, and to permit persons to whom the
michael@0 11 * Software is furnished to do so, subject to the following
michael@0 12 * conditions:
michael@0 13 *
michael@0 14 * The above copyright notice and this permission notice shall be
michael@0 15 * included in all copies or substantial portions of the Software.
michael@0 16 *
michael@0 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
michael@0 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
michael@0 19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
michael@0 20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
michael@0 21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
michael@0 22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
michael@0 23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
michael@0 24 * OTHER DEALINGS IN THE SOFTWARE.
michael@0 25 */
michael@0 26
michael@0 27 var NavierStokes = new BenchmarkSuite('NavierStokes', 1484000,
michael@0 28 [new Benchmark('NavierStokes',
michael@0 29 runNavierStokes,
michael@0 30 setupNavierStokes,
michael@0 31 tearDownNavierStokes)]);
michael@0 32
michael@0 33 var solver = null;
michael@0 34
michael@0 35 function runNavierStokes()
michael@0 36 {
michael@0 37 solver.update();
michael@0 38 }
michael@0 39
michael@0 40 function setupNavierStokes()
michael@0 41 {
michael@0 42 solver = new FluidField(null);
michael@0 43 solver.setResolution(128, 128);
michael@0 44 solver.setIterations(20);
michael@0 45 solver.setDisplayFunction(function(){});
michael@0 46 solver.setUICallback(prepareFrame);
michael@0 47 solver.reset();
michael@0 48 }
michael@0 49
michael@0 50 function tearDownNavierStokes()
michael@0 51 {
michael@0 52 solver = null;
michael@0 53 }
michael@0 54
michael@0 55 function addPoints(field) {
michael@0 56 var n = 64;
michael@0 57 for (var i = 1; i <= n; i++) {
michael@0 58 field.setVelocity(i, i, n, n);
michael@0 59 field.setDensity(i, i, 5);
michael@0 60 field.setVelocity(i, n - i, -n, -n);
michael@0 61 field.setDensity(i, n - i, 20);
michael@0 62 field.setVelocity(128 - i, n + i, -n, -n);
michael@0 63 field.setDensity(128 - i, n + i, 30);
michael@0 64 }
michael@0 65 }
michael@0 66
michael@0 67 var framesTillAddingPoints = 0;
michael@0 68 var framesBetweenAddingPoints = 5;
michael@0 69
michael@0 70 function prepareFrame(field)
michael@0 71 {
michael@0 72 if (framesTillAddingPoints == 0) {
michael@0 73 addPoints(field);
michael@0 74 framesTillAddingPoints = framesBetweenAddingPoints;
michael@0 75 framesBetweenAddingPoints++;
michael@0 76 } else {
michael@0 77 framesTillAddingPoints--;
michael@0 78 }
michael@0 79 }
michael@0 80
michael@0 81 // Code from Oliver Hunt (http://nerget.com/fluidSim/pressure.js) starts here.
michael@0 82 function FluidField(canvas) {
michael@0 83 function addFields(x, s, dt)
michael@0 84 {
michael@0 85 for (var i=0; i<size ; i++ ) x[i] += dt*s[i];
michael@0 86 }
michael@0 87
michael@0 88 function set_bnd(b, x)
michael@0 89 {
michael@0 90 if (b===1) {
michael@0 91 for (var i = 1; i <= width; i++) {
michael@0 92 x[i] = x[i + rowSize];
michael@0 93 x[i + (height+1) *rowSize] = x[i + height * rowSize];
michael@0 94 }
michael@0 95
michael@0 96 for (var j = 1; i <= height; i++) {
michael@0 97 x[j * rowSize] = -x[1 + j * rowSize];
michael@0 98 x[(width + 1) + j * rowSize] = -x[width + j * rowSize];
michael@0 99 }
michael@0 100 } else if (b === 2) {
michael@0 101 for (var i = 1; i <= width; i++) {
michael@0 102 x[i] = -x[i + rowSize];
michael@0 103 x[i + (height + 1) * rowSize] = -x[i + height * rowSize];
michael@0 104 }
michael@0 105
michael@0 106 for (var j = 1; j <= height; j++) {
michael@0 107 x[j * rowSize] = x[1 + j * rowSize];
michael@0 108 x[(width + 1) + j * rowSize] = x[width + j * rowSize];
michael@0 109 }
michael@0 110 } else {
michael@0 111 for (var i = 1; i <= width; i++) {
michael@0 112 x[i] = x[i + rowSize];
michael@0 113 x[i + (height + 1) * rowSize] = x[i + height * rowSize];
michael@0 114 }
michael@0 115
michael@0 116 for (var j = 1; j <= height; j++) {
michael@0 117 x[j * rowSize] = x[1 + j * rowSize];
michael@0 118 x[(width + 1) + j * rowSize] = x[width + j * rowSize];
michael@0 119 }
michael@0 120 }
michael@0 121 var maxEdge = (height + 1) * rowSize;
michael@0 122 x[0] = 0.5 * (x[1] + x[rowSize]);
michael@0 123 x[maxEdge] = 0.5 * (x[1 + maxEdge] + x[height * rowSize]);
michael@0 124 x[(width+1)] = 0.5 * (x[width] + x[(width + 1) + rowSize]);
michael@0 125 x[(width+1)+maxEdge] = 0.5 * (x[width + maxEdge] + x[(width + 1) + height * rowSize]);
michael@0 126 }
michael@0 127
michael@0 128 function lin_solve(b, x, x0, a, c)
michael@0 129 {
michael@0 130 if (a === 0 && c === 1) {
michael@0 131 for (var j=1 ; j<=height; j++) {
michael@0 132 var currentRow = j * rowSize;
michael@0 133 ++currentRow;
michael@0 134 for (var i = 0; i < width; i++) {
michael@0 135 x[currentRow] = x0[currentRow];
michael@0 136 ++currentRow;
michael@0 137 }
michael@0 138 }
michael@0 139 set_bnd(b, x);
michael@0 140 } else {
michael@0 141 var invC = 1 / c;
michael@0 142 for (var k=0 ; k<iterations; k++) {
michael@0 143 for (var j=1 ; j<=height; j++) {
michael@0 144 var lastRow = (j - 1) * rowSize;
michael@0 145 var currentRow = j * rowSize;
michael@0 146 var nextRow = (j + 1) * rowSize;
michael@0 147 var lastX = x[currentRow];
michael@0 148 ++currentRow;
michael@0 149 for (var i=1; i<=width; i++)
michael@0 150 lastX = x[currentRow] = (x0[currentRow] + a*(lastX+x[++currentRow]+x[++lastRow]+x[++nextRow])) * invC;
michael@0 151 }
michael@0 152 set_bnd(b, x);
michael@0 153 }
michael@0 154 }
michael@0 155 }
michael@0 156
michael@0 157 function diffuse(b, x, x0, dt)
michael@0 158 {
michael@0 159 var a = 0;
michael@0 160 lin_solve(b, x, x0, a, 1 + 4*a);
michael@0 161 }
michael@0 162
michael@0 163 function lin_solve2(x, x0, y, y0, a, c)
michael@0 164 {
michael@0 165 if (a === 0 && c === 1) {
michael@0 166 for (var j=1 ; j <= height; j++) {
michael@0 167 var currentRow = j * rowSize;
michael@0 168 ++currentRow;
michael@0 169 for (var i = 0; i < width; i++) {
michael@0 170 x[currentRow] = x0[currentRow];
michael@0 171 y[currentRow] = y0[currentRow];
michael@0 172 ++currentRow;
michael@0 173 }
michael@0 174 }
michael@0 175 set_bnd(1, x);
michael@0 176 set_bnd(2, y);
michael@0 177 } else {
michael@0 178 var invC = 1/c;
michael@0 179 for (var k=0 ; k<iterations; k++) {
michael@0 180 for (var j=1 ; j <= height; j++) {
michael@0 181 var lastRow = (j - 1) * rowSize;
michael@0 182 var currentRow = j * rowSize;
michael@0 183 var nextRow = (j + 1) * rowSize;
michael@0 184 var lastX = x[currentRow];
michael@0 185 var lastY = y[currentRow];
michael@0 186 ++currentRow;
michael@0 187 for (var i = 1; i <= width; i++) {
michael@0 188 lastX = x[currentRow] = (x0[currentRow] + a * (lastX + x[currentRow] + x[lastRow] + x[nextRow])) * invC;
michael@0 189 lastY = y[currentRow] = (y0[currentRow] + a * (lastY + y[++currentRow] + y[++lastRow] + y[++nextRow])) * invC;
michael@0 190 }
michael@0 191 }
michael@0 192 set_bnd(1, x);
michael@0 193 set_bnd(2, y);
michael@0 194 }
michael@0 195 }
michael@0 196 }
michael@0 197
michael@0 198 function diffuse2(x, x0, y, y0, dt)
michael@0 199 {
michael@0 200 var a = 0;
michael@0 201 lin_solve2(x, x0, y, y0, a, 1 + 4 * a);
michael@0 202 }
michael@0 203
michael@0 204 function advect(b, d, d0, u, v, dt)
michael@0 205 {
michael@0 206 var Wdt0 = dt * width;
michael@0 207 var Hdt0 = dt * height;
michael@0 208 var Wp5 = width + 0.5;
michael@0 209 var Hp5 = height + 0.5;
michael@0 210 for (var j = 1; j<= height; j++) {
michael@0 211 var pos = j * rowSize;
michael@0 212 for (var i = 1; i <= width; i++) {
michael@0 213 var x = i - Wdt0 * u[++pos];
michael@0 214 var y = j - Hdt0 * v[pos];
michael@0 215 if (x < 0.5)
michael@0 216 x = 0.5;
michael@0 217 else if (x > Wp5)
michael@0 218 x = Wp5;
michael@0 219 var i0 = x | 0;
michael@0 220 var i1 = i0 + 1;
michael@0 221 if (y < 0.5)
michael@0 222 y = 0.5;
michael@0 223 else if (y > Hp5)
michael@0 224 y = Hp5;
michael@0 225 var j0 = y | 0;
michael@0 226 var j1 = j0 + 1;
michael@0 227 var s1 = x - i0;
michael@0 228 var s0 = 1 - s1;
michael@0 229 var t1 = y - j0;
michael@0 230 var t0 = 1 - t1;
michael@0 231 var row1 = j0 * rowSize;
michael@0 232 var row2 = j1 * rowSize;
michael@0 233 d[pos] = s0 * (t0 * d0[i0 + row1] + t1 * d0[i0 + row2]) + s1 * (t0 * d0[i1 + row1] + t1 * d0[i1 + row2]);
michael@0 234 }
michael@0 235 }
michael@0 236 set_bnd(b, d);
michael@0 237 }
michael@0 238
michael@0 239 function project(u, v, p, div)
michael@0 240 {
michael@0 241 var h = -0.5 / Math.sqrt(width * height);
michael@0 242 for (var j = 1 ; j <= height; j++ ) {
michael@0 243 var row = j * rowSize;
michael@0 244 var previousRow = (j - 1) * rowSize;
michael@0 245 var prevValue = row - 1;
michael@0 246 var currentRow = row;
michael@0 247 var nextValue = row + 1;
michael@0 248 var nextRow = (j + 1) * rowSize;
michael@0 249 for (var i = 1; i <= width; i++ ) {
michael@0 250 div[++currentRow] = h * (u[++nextValue] - u[++prevValue] + v[++nextRow] - v[++previousRow]);
michael@0 251 p[currentRow] = 0;
michael@0 252 }
michael@0 253 }
michael@0 254 set_bnd(0, div);
michael@0 255 set_bnd(0, p);
michael@0 256
michael@0 257 lin_solve(0, p, div, 1, 4 );
michael@0 258 var wScale = 0.5 * width;
michael@0 259 var hScale = 0.5 * height;
michael@0 260 for (var j = 1; j<= height; j++ ) {
michael@0 261 var prevPos = j * rowSize - 1;
michael@0 262 var currentPos = j * rowSize;
michael@0 263 var nextPos = j * rowSize + 1;
michael@0 264 var prevRow = (j - 1) * rowSize;
michael@0 265 var currentRow = j * rowSize;
michael@0 266 var nextRow = (j + 1) * rowSize;
michael@0 267
michael@0 268 for (var i = 1; i<= width; i++) {
michael@0 269 u[++currentPos] -= wScale * (p[++nextPos] - p[++prevPos]);
michael@0 270 v[currentPos] -= hScale * (p[++nextRow] - p[++prevRow]);
michael@0 271 }
michael@0 272 }
michael@0 273 set_bnd(1, u);
michael@0 274 set_bnd(2, v);
michael@0 275 }
michael@0 276
michael@0 277 function dens_step(x, x0, u, v, dt)
michael@0 278 {
michael@0 279 addFields(x, x0, dt);
michael@0 280 diffuse(0, x0, x, dt );
michael@0 281 advect(0, x, x0, u, v, dt );
michael@0 282 }
michael@0 283
michael@0 284 function vel_step(u, v, u0, v0, dt)
michael@0 285 {
michael@0 286 addFields(u, u0, dt );
michael@0 287 addFields(v, v0, dt );
michael@0 288 var temp = u0; u0 = u; u = temp;
michael@0 289 var temp = v0; v0 = v; v = temp;
michael@0 290 diffuse2(u,u0,v,v0, dt);
michael@0 291 project(u, v, u0, v0);
michael@0 292 var temp = u0; u0 = u; u = temp;
michael@0 293 var temp = v0; v0 = v; v = temp;
michael@0 294 advect(1, u, u0, u0, v0, dt);
michael@0 295 advect(2, v, v0, u0, v0, dt);
michael@0 296 project(u, v, u0, v0 );
michael@0 297 }
michael@0 298 var uiCallback = function(d,u,v) {};
michael@0 299
michael@0 300 function Field(dens, u, v) {
michael@0 301 // Just exposing the fields here rather than using accessors is a measurable win during display (maybe 5%)
michael@0 302 // but makes the code ugly.
michael@0 303 this.setDensity = function(x, y, d) {
michael@0 304 dens[(x + 1) + (y + 1) * rowSize] = d;
michael@0 305 }
michael@0 306 this.getDensity = function(x, y) {
michael@0 307 return dens[(x + 1) + (y + 1) * rowSize];
michael@0 308 }
michael@0 309 this.setVelocity = function(x, y, xv, yv) {
michael@0 310 u[(x + 1) + (y + 1) * rowSize] = xv;
michael@0 311 v[(x + 1) + (y + 1) * rowSize] = yv;
michael@0 312 }
michael@0 313 this.getXVelocity = function(x, y) {
michael@0 314 return u[(x + 1) + (y + 1) * rowSize];
michael@0 315 }
michael@0 316 this.getYVelocity = function(x, y) {
michael@0 317 return v[(x + 1) + (y + 1) * rowSize];
michael@0 318 }
michael@0 319 this.width = function() { return width; }
michael@0 320 this.height = function() { return height; }
michael@0 321 }
michael@0 322 function queryUI(d, u, v)
michael@0 323 {
michael@0 324 for (var i = 0; i < size; i++)
michael@0 325 u[i] = v[i] = d[i] = 0.0;
michael@0 326 uiCallback(new Field(d, u, v));
michael@0 327 }
michael@0 328
michael@0 329 this.update = function () {
michael@0 330 queryUI(dens_prev, u_prev, v_prev);
michael@0 331 vel_step(u, v, u_prev, v_prev, dt);
michael@0 332 dens_step(dens, dens_prev, u, v, dt);
michael@0 333 displayFunc(new Field(dens, u, v));
michael@0 334 }
michael@0 335 this.setDisplayFunction = function(func) {
michael@0 336 displayFunc = func;
michael@0 337 }
michael@0 338
michael@0 339 this.iterations = function() { return iterations; }
michael@0 340 this.setIterations = function(iters) {
michael@0 341 if (iters > 0 && iters <= 100)
michael@0 342 iterations = iters;
michael@0 343 }
michael@0 344 this.setUICallback = function(callback) {
michael@0 345 uiCallback = callback;
michael@0 346 }
michael@0 347 var iterations = 10;
michael@0 348 var visc = 0.5;
michael@0 349 var dt = 0.1;
michael@0 350 var dens;
michael@0 351 var dens_prev;
michael@0 352 var u;
michael@0 353 var u_prev;
michael@0 354 var v;
michael@0 355 var v_prev;
michael@0 356 var width;
michael@0 357 var height;
michael@0 358 var rowSize;
michael@0 359 var size;
michael@0 360 var displayFunc;
michael@0 361 function reset()
michael@0 362 {
michael@0 363 rowSize = width + 2;
michael@0 364 size = (width+2)*(height+2);
michael@0 365 dens = new Array(size);
michael@0 366 dens_prev = new Array(size);
michael@0 367 u = new Array(size);
michael@0 368 u_prev = new Array(size);
michael@0 369 v = new Array(size);
michael@0 370 v_prev = new Array(size);
michael@0 371 for (var i = 0; i < size; i++)
michael@0 372 dens_prev[i] = u_prev[i] = v_prev[i] = dens[i] = u[i] = v[i] = 0;
michael@0 373 }
michael@0 374 this.reset = reset;
michael@0 375 this.setResolution = function (hRes, wRes)
michael@0 376 {
michael@0 377 var res = wRes * hRes;
michael@0 378 if (res > 0 && res < 1000000 && (wRes != width || hRes != height)) {
michael@0 379 width = wRes;
michael@0 380 height = hRes;
michael@0 381 reset();
michael@0 382 return true;
michael@0 383 }
michael@0 384 return false;
michael@0 385 }
michael@0 386 this.setResolution(64, 64);
michael@0 387 }

mercurial