API Docs for: 0.6.1
Show:

File: src/objects/SPHSystem.js

  1. module.exports = SPHSystem;
  2.  
  3. var Shape = require('../shapes/Shape');
  4. var Vec3 = require('../math/Vec3');
  5. var Quaternion = require('../math/Quaternion');
  6. var Particle = require('../shapes/Particle');
  7. var Body = require('../objects/Body');
  8. var Material = require('../material/Material');
  9.  
  10. /**
  11. * Smoothed-particle hydrodynamics system
  12. * @class SPHSystem
  13. * @constructor
  14. */
  15. function SPHSystem(){
  16. this.particles = [];
  17. /**
  18. * Density of the system (kg/m3).
  19. * @property {number} density
  20. */
  21. this.density = 1;
  22. /**
  23. * Distance below which two particles are considered to be neighbors.
  24. * It should be adjusted so there are about 15-20 neighbor particles within this radius.
  25. * @property {number} smoothingRadius
  26. */
  27. this.smoothingRadius = 1;
  28. this.speedOfSound = 1;
  29. /**
  30. * Viscosity of the system.
  31. * @property {number} viscosity
  32. */
  33. this.viscosity = 0.01;
  34. this.eps = 0.000001;
  35.  
  36. // Stuff Computed per particle
  37. this.pressures = [];
  38. this.densities = [];
  39. this.neighbors = [];
  40. }
  41.  
  42. /**
  43. * Add a particle to the system.
  44. * @method add
  45. * @param {Body} particle
  46. */
  47. SPHSystem.prototype.add = function(particle){
  48. this.particles.push(particle);
  49. if(this.neighbors.length < this.particles.length){
  50. this.neighbors.push([]);
  51. }
  52. };
  53.  
  54. /**
  55. * Remove a particle from the system.
  56. * @method remove
  57. * @param {Body} particle
  58. */
  59. SPHSystem.prototype.remove = function(particle){
  60. var idx = this.particles.indexOf(particle);
  61. if(idx !== -1){
  62. this.particles.splice(idx,1);
  63. if(this.neighbors.length > this.particles.length){
  64. this.neighbors.pop();
  65. }
  66. }
  67. };
  68.  
  69. /**
  70. * Get neighbors within smoothing volume, save in the array neighbors
  71. * @method getNeighbors
  72. * @param {Body} particle
  73. * @param {Array} neighbors
  74. */
  75. var SPHSystem_getNeighbors_dist = new Vec3();
  76. SPHSystem.prototype.getNeighbors = function(particle,neighbors){
  77. var N = this.particles.length,
  78. id = particle.id,
  79. R2 = this.smoothingRadius * this.smoothingRadius,
  80. dist = SPHSystem_getNeighbors_dist;
  81. for(var i=0; i!==N; i++){
  82. var p = this.particles[i];
  83. p.position.vsub(particle.position,dist);
  84. if(id!==p.id && dist.norm2() < R2){
  85. neighbors.push(p);
  86. }
  87. }
  88. };
  89.  
  90. // Temp vectors for calculation
  91. var SPHSystem_update_dist = new Vec3(),
  92. SPHSystem_update_a_pressure = new Vec3(),
  93. SPHSystem_update_a_visc = new Vec3(),
  94. SPHSystem_update_gradW = new Vec3(),
  95. SPHSystem_update_r_vec = new Vec3(),
  96. SPHSystem_update_u = new Vec3(); // Relative velocity
  97. SPHSystem.prototype.update = function(){
  98. var N = this.particles.length,
  99. dist = SPHSystem_update_dist,
  100. cs = this.speedOfSound,
  101. eps = this.eps;
  102.  
  103. for(var i=0; i!==N; i++){
  104. var p = this.particles[i]; // Current particle
  105. var neighbors = this.neighbors[i];
  106.  
  107. // Get neighbors
  108. neighbors.length = 0;
  109. this.getNeighbors(p,neighbors);
  110. neighbors.push(this.particles[i]); // Add current too
  111. var numNeighbors = neighbors.length;
  112.  
  113. // Accumulate density for the particle
  114. var sum = 0.0;
  115. for(var j=0; j!==numNeighbors; j++){
  116.  
  117. //printf("Current particle has position %f %f %f\n",objects[id].pos.x(),objects[id].pos.y(),objects[id].pos.z());
  118. p.position.vsub(neighbors[j].position, dist);
  119. var len = dist.norm();
  120.  
  121. var weight = this.w(len);
  122. sum += neighbors[j].mass * weight;
  123. }
  124.  
  125. // Save
  126. this.densities[i] = sum;
  127. this.pressures[i] = cs * cs * (this.densities[i] - this.density);
  128. }
  129.  
  130. // Add forces
  131.  
  132. // Sum to these accelerations
  133. var a_pressure= SPHSystem_update_a_pressure;
  134. var a_visc = SPHSystem_update_a_visc;
  135. var gradW = SPHSystem_update_gradW;
  136. var r_vec = SPHSystem_update_r_vec;
  137. var u = SPHSystem_update_u;
  138.  
  139. for(var i=0; i!==N; i++){
  140.  
  141. var particle = this.particles[i];
  142.  
  143. a_pressure.set(0,0,0);
  144. a_visc.set(0,0,0);
  145.  
  146. // Init vars
  147. var Pij;
  148. var nabla;
  149. var Vij;
  150.  
  151. // Sum up for all other neighbors
  152. var neighbors = this.neighbors[i];
  153. var numNeighbors = neighbors.length;
  154.  
  155. //printf("Neighbors: ");
  156. for(var j=0; j!==numNeighbors; j++){
  157.  
  158. var neighbor = neighbors[j];
  159. //printf("%d ",nj);
  160.  
  161. // Get r once for all..
  162. particle.position.vsub(neighbor.position,r_vec);
  163. var r = r_vec.norm();
  164.  
  165. // Pressure contribution
  166. Pij = -neighbor.mass * (this.pressures[i] / (this.densities[i]*this.densities[i] + eps) + this.pressures[j] / (this.densities[j]*this.densities[j] + eps));
  167. this.gradw(r_vec, gradW);
  168. // Add to pressure acceleration
  169. gradW.mult(Pij , gradW);
  170. a_pressure.vadd(gradW, a_pressure);
  171.  
  172. // Viscosity contribution
  173. neighbor.velocity.vsub(particle.velocity, u);
  174. u.mult( 1.0 / (0.0001+this.densities[i] * this.densities[j]) * this.viscosity * neighbor.mass , u );
  175. nabla = this.nablaw(r);
  176. u.mult(nabla,u);
  177. // Add to viscosity acceleration
  178. a_visc.vadd( u, a_visc );
  179. }
  180.  
  181. // Calculate force
  182. a_visc.mult(particle.mass, a_visc);
  183. a_pressure.mult(particle.mass, a_pressure);
  184.  
  185. // Add force to particles
  186. particle.force.vadd(a_visc, particle.force);
  187. particle.force.vadd(a_pressure, particle.force);
  188. }
  189. };
  190.  
  191. // Calculate the weight using the W(r) weightfunction
  192. SPHSystem.prototype.w = function(r){
  193. // 315
  194. var h = this.smoothingRadius;
  195. return 315.0/(64.0*Math.PI*Math.pow(h,9)) * Math.pow(h*h-r*r,3);
  196. };
  197.  
  198. // calculate gradient of the weight function
  199. SPHSystem.prototype.gradw = function(rVec,resultVec){
  200. var r = rVec.norm(),
  201. h = this.smoothingRadius;
  202. rVec.mult(945.0/(32.0*Math.PI*Math.pow(h,9)) * Math.pow((h*h-r*r),2) , resultVec);
  203. };
  204.  
  205. // Calculate nabla(W)
  206. SPHSystem.prototype.nablaw = function(r){
  207. var h = this.smoothingRadius;
  208. var nabla = 945.0/(32.0*Math.PI*Math.pow(h,9)) * (h*h-r*r)*(7*r*r - 3*h*h);
  209. return nabla;
  210. };
  211.