tsmathlib
Version:
Typescript Version Math/Physics/CG Library
169 lines (139 loc) • 4.71 kB
text/typescript
/*
* @Author: Xu.Wang
* @Date: 2020-03-31 15:12:02
* @Last Modified by: Xu.Wang
* @Last Modified time: 2020-04-22 19:03:34
*/
import { ParticleSystem } from '../physics/particle_system'
import { SphData } from './sph_data'
import { square } from '../math/math_utils'
import { SphKernelSpiky } from './sph_kernel'
import { PHY_WATER_DENSITY } from '../physics'
import { LOG } from '../log/log'
import { Vector3 } from '../math'
export class SPH extends ParticleSystem {
_viscosityCoefficient: number = 0.002
_gasCof: number = 5.0
constructor(
mass: number = 0.04,
pInKernel: number = 20,
targetDensity: number = PHY_WATER_DENSITY
) {
super(0.0, mass)
let sphParticles = new SphData(mass, pInKernel, targetDensity)
this.setParticleSystemData(sphParticles)
}
debug() {
LOG.LOGGER('SPH Debug Mode')
}
sphData(): SphData {
return this.particleSystemData() as SphData
}
viscosityCoefficient(): number {
return this._viscosityCoefficient
}
setViscosityCoefficient(newViscosityCoefficient: number) {
this._viscosityCoefficient = Math.max(newViscosityCoefficient, 0.0)
}
calcForces() {
this.calcExternalForces()
this.calcPressureForce()
this.calcViscosityForce()
}
calcPressureForce() {
this.computePressure()
let particles = this.sphData()
let p = particles.positions()
let d = particles.densities()
let pr = particles.pressures()
let f = particles.forces()
let numberOfParticles = particles.numberOfParticles()
let massSquared = square(particles.particleMass())
let kernel = new SphKernelSpiky(particles.kernelRadius())
for (let i = 0; i < numberOfParticles; i++) {
let neighbors: Array<number> = particles.neighborLists()[i]
// waste my 8hours
for (let idx = 0; idx < neighbors.length; idx++) {
let j = neighbors[idx]
let dist = p[i].distanceTo(p[j])
if (dist > 0.0) {
let dir = p[j].sub(p[i]).div(dist)
let tmpFCoef =
(pr[i] / (d[i] * d[i]) + pr[j] / (d[j] * d[j])) * massSquared
let tmpF = kernel.getGradientByDistance(dist, dir).mul(tmpFCoef)
f[i] = f[i].sub(tmpF)
}
}
// console.log(f[i].x(),f[i].y(),f[i].z())
}
}
calcViscosityForce() {
let particles = this.sphData()
let numberOfParticles = particles.numberOfParticles()
let x = particles.positions()
let v = particles.velocities()
let d = particles.densities()
let f = particles.forces()
let massSquared: number = square(particles.particleMass())
let kernel: SphKernelSpiky = new SphKernelSpiky(particles.kernelRadius())
for (let i = 0; i < numberOfParticles; i++) {
let neighbors: Array<number> = particles.neighborLists()[i]
for (let idx = 0; idx < neighbors.length; idx++) {
let j = neighbors[idx]
let dist = x[i].distanceTo(x[j])
let tmpVCoef =
kernel.getSecondDerivative(dist) *
massSquared *
this.viscosityCoefficient()
let tmpV = v[j].sub(v[i]).div(d[j]).mul(tmpVCoef)
f[i] = f[i].add(tmpV)
}
}
}
update() {
let particles = this.sphData()
// clear forces
let forces = particles.forces()
for (let idx = 0; idx < particles.numberOfParticles(); idx++) {
forces[idx] = new Vector3()
}
// update collider
this.allocateBuffers()
// build neighbor searcher
particles.buildSphNeighborSearcher()
particles.buildSphNeighborLists()
// update density
particles.calcDensities()
this.calcForces()
// time
this.timeIntegration(0.005)
this.resolveCollision()
this.updateParticlesData()
}
computePressure() {
let particles = this.sphData()
let targetDensity = particles.targetDensity()
let numberOfParticles = particles.numberOfParticles()
let d = particles.densities()
let p = particles.pressures()
for (let i = 0; i < numberOfParticles; i++) {
p[i] = (d[i] - targetDensity) * this._gasCof
}
// not good for real-time SPH
// See Murnaghan-Tait equation of state from
// https://en.wikipedia.org/wiki/Tait_equation
// let targetDensity = particles.targetDensity()
// let eosScale = targetDensity * square(this._speedOfSound)
// for (let i = 0; i < numberOfParticles; i++) {
// // LOG.LOGGER('computePressure, d[i]=' + d[i] + ', target=' + targetDensity)
// p[i] = computePressureFromEos(
// d[i],
// targetDensity,
// eosScale,
// this.eosExponent(),
// this.negativePressureScale()
// )
// }
// LOG.LOGGER('after computePressure, p[50]=' + p[50])
}
}