- module.exports = SPHSystem;
-
- var Shape = require('../shapes/Shape');
- var Vec3 = require('../math/Vec3');
- var Quaternion = require('../math/Quaternion');
- var Particle = require('../shapes/Particle');
- var Body = require('../objects/Body');
- var Material = require('../material/Material');
-
- /**
- * Smoothed-particle hydrodynamics system
- * @class SPHSystem
- * @constructor
- */
- function SPHSystem(){
- this.particles = [];
-
- /**
- * Density of the system (kg/m3).
- * @property {number} density
- */
- this.density = 1;
-
- /**
- * Distance below which two particles are considered to be neighbors.
- * It should be adjusted so there are about 15-20 neighbor particles within this radius.
- * @property {number} smoothingRadius
- */
- this.smoothingRadius = 1;
- this.speedOfSound = 1;
-
- /**
- * Viscosity of the system.
- * @property {number} viscosity
- */
- this.viscosity = 0.01;
- this.eps = 0.000001;
-
- // Stuff Computed per particle
- this.pressures = [];
- this.densities = [];
- this.neighbors = [];
- }
-
- /**
- * Add a particle to the system.
- * @method add
- * @param {Body} particle
- */
- SPHSystem.prototype.add = function(particle){
- this.particles.push(particle);
- if(this.neighbors.length < this.particles.length){
- this.neighbors.push([]);
- }
- };
-
- /**
- * Remove a particle from the system.
- * @method remove
- * @param {Body} particle
- */
- SPHSystem.prototype.remove = function(particle){
- var idx = this.particles.indexOf(particle);
- if(idx !== -1){
- this.particles.splice(idx,1);
- if(this.neighbors.length > this.particles.length){
- this.neighbors.pop();
- }
- }
- };
-
- /**
- * Get neighbors within smoothing volume, save in the array neighbors
- * @method getNeighbors
- * @param {Body} particle
- * @param {Array} neighbors
- */
- var SPHSystem_getNeighbors_dist = new Vec3();
- SPHSystem.prototype.getNeighbors = function(particle,neighbors){
- var N = this.particles.length,
- id = particle.id,
- R2 = this.smoothingRadius * this.smoothingRadius,
- dist = SPHSystem_getNeighbors_dist;
- for(var i=0; i!==N; i++){
- var p = this.particles[i];
- p.position.vsub(particle.position,dist);
- if(id!==p.id && dist.norm2() < R2){
- neighbors.push(p);
- }
- }
- };
-
- // Temp vectors for calculation
- var SPHSystem_update_dist = new Vec3(),
- SPHSystem_update_a_pressure = new Vec3(),
- SPHSystem_update_a_visc = new Vec3(),
- SPHSystem_update_gradW = new Vec3(),
- SPHSystem_update_r_vec = new Vec3(),
- SPHSystem_update_u = new Vec3(); // Relative velocity
- SPHSystem.prototype.update = function(){
- var N = this.particles.length,
- dist = SPHSystem_update_dist,
- cs = this.speedOfSound,
- eps = this.eps;
-
- for(var i=0; i!==N; i++){
- var p = this.particles[i]; // Current particle
- var neighbors = this.neighbors[i];
-
- // Get neighbors
- neighbors.length = 0;
- this.getNeighbors(p,neighbors);
- neighbors.push(this.particles[i]); // Add current too
- var numNeighbors = neighbors.length;
-
- // Accumulate density for the particle
- var sum = 0.0;
- for(var j=0; j!==numNeighbors; j++){
-
- //printf("Current particle has position %f %f %f\n",objects[id].pos.x(),objects[id].pos.y(),objects[id].pos.z());
- p.position.vsub(neighbors[j].position, dist);
- var len = dist.norm();
-
- var weight = this.w(len);
- sum += neighbors[j].mass * weight;
- }
-
- // Save
- this.densities[i] = sum;
- this.pressures[i] = cs * cs * (this.densities[i] - this.density);
- }
-
- // Add forces
-
- // Sum to these accelerations
- var a_pressure= SPHSystem_update_a_pressure;
- var a_visc = SPHSystem_update_a_visc;
- var gradW = SPHSystem_update_gradW;
- var r_vec = SPHSystem_update_r_vec;
- var u = SPHSystem_update_u;
-
- for(var i=0; i!==N; i++){
-
- var particle = this.particles[i];
-
- a_pressure.set(0,0,0);
- a_visc.set(0,0,0);
-
- // Init vars
- var Pij;
- var nabla;
- var Vij;
-
- // Sum up for all other neighbors
- var neighbors = this.neighbors[i];
- var numNeighbors = neighbors.length;
-
- //printf("Neighbors: ");
- for(var j=0; j!==numNeighbors; j++){
-
- var neighbor = neighbors[j];
- //printf("%d ",nj);
-
- // Get r once for all..
- particle.position.vsub(neighbor.position,r_vec);
- var r = r_vec.norm();
-
- // Pressure contribution
- Pij = -neighbor.mass * (this.pressures[i] / (this.densities[i]*this.densities[i] + eps) + this.pressures[j] / (this.densities[j]*this.densities[j] + eps));
- this.gradw(r_vec, gradW);
- // Add to pressure acceleration
- gradW.mult(Pij , gradW);
- a_pressure.vadd(gradW, a_pressure);
-
- // Viscosity contribution
- neighbor.velocity.vsub(particle.velocity, u);
- u.mult( 1.0 / (0.0001+this.densities[i] * this.densities[j]) * this.viscosity * neighbor.mass , u );
- nabla = this.nablaw(r);
- u.mult(nabla,u);
- // Add to viscosity acceleration
- a_visc.vadd( u, a_visc );
- }
-
- // Calculate force
- a_visc.mult(particle.mass, a_visc);
- a_pressure.mult(particle.mass, a_pressure);
-
- // Add force to particles
- particle.force.vadd(a_visc, particle.force);
- particle.force.vadd(a_pressure, particle.force);
- }
- };
-
- // Calculate the weight using the W(r) weightfunction
- SPHSystem.prototype.w = function(r){
- // 315
- var h = this.smoothingRadius;
- return 315.0/(64.0*Math.PI*Math.pow(h,9)) * Math.pow(h*h-r*r,3);
- };
-
- // calculate gradient of the weight function
- SPHSystem.prototype.gradw = function(rVec,resultVec){
- var r = rVec.norm(),
- h = this.smoothingRadius;
- rVec.mult(945.0/(32.0*Math.PI*Math.pow(h,9)) * Math.pow((h*h-r*r),2) , resultVec);
- };
-
- // Calculate nabla(W)
- SPHSystem.prototype.nablaw = function(r){
- var h = this.smoothingRadius;
- var nabla = 945.0/(32.0*Math.PI*Math.pow(h,9)) * (h*h-r*r)*(7*r*r - 3*h*h);
- return nabla;
- };
-
-