Android Jetpack Compose 实现WCSPH

261 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情

光滑粒子流体动力学方法SPH (Smoothed Particle Hydrodynamics)是近20多年来逐步发展起来的一种无网格方法,该方法的基本思想是将连续的流体(或固体)用相互作用的质点组来描述,各个物质点上承载各种物理量,包括质量、速度等,通过求解质点组的动力学方程和跟踪每个质点的运动轨道,求得整个系统的力学行为。这类似于物理学中的粒子云particle-in-cell)模拟,从原理上说,只要质点的数目足够多,就能精确地描述力学过程

本文是将Github上一篇由python实现的WCSPH代码改成(翻译)Android Jetpack Compose 项目

python项目效果

image.png

android项目效果

tyve3-oppwp.gif 注:数据集、粒子数量、部分参数不一样,所以效果和原项目有差异

公式及实现

1656210641606.png

根据周围粒子计算出Density

/**
 * 计算Density
 */
private fun computeDensities() {
    particleList.forEach { p_i ->
        p_i.density = 0.0
        //在半径内的点
        val neighbors = getParticleNeighbors(p_i)
        neighbors.forEach { p_j ->
            p_i.density += mV * cubicKernel((p_i.x - p_j.x).norm())
        }
        p_i.density *= density0
    }
}

1656210957785.png 计算速度

private fun viscosityForce(p_i: Particle, p_j: Particle, r: PointF): PointF {
    val vXy = (p_i.v - p_j.v).dot(r)
    return 2 * (dimension + 2) * viscosity * (mass / (p_j.density)) * vXy / (r.norm()
        .pow(2) + 0.01 * supportRadius.pow(2)) * cubicKernelDerivative(r)
}

1656211063522.png 计算粒子压强

private fun pressureForce(p_i: Particle, p_j: Particle, r: PointF): PointF {
    return -density0 * mV * (p_i.pressure / (p_i.density.pow(2)) + p_j.pressure / (p_j.density.pow(2))) * cubicKernelDerivative(r)
}
private fun computePressureForces() {

    particleList.forEach { p_i ->
        p_i.density = max(p_i.density, density0)
        p_i.pressure = stiffness * ((p_i.density / density0).pow(exponent) - 1.0)
    }
    particleList.forEach { p_i ->
        if (p_i.material == materialFluid) {
            val xi = p_i.x
            var dv = PointF(0f, 0f)
            //在半径内的点
            val neighbors = getParticleNeighbors(p_i)
            neighbors.forEach { p_j ->
                val xj = p_j.x
                dv += pressureForce(p_i, p_j, xi - xj)
            }
            p_i.d_velocity += dv
        }
    }
}

最后更新粒子位置

_viewState.value = _viewState.value.map {
    /**
     * 根据d_velocity更新速度,根据速度更新位置
     */
    val v = it.v + (sph.dt * it.d_velocity)

    val x = it.x + (sph.dt * v)

    it.copy(x = x, v = v)
}

参考:
【太极图形课S1第10讲:流体仿真 01-哔哩哔哩】 b23.tv/ueBT4Nb
erizmr/taichi_sph: A Taichi implementation of WCSPH (github.com)

项目地址:chenjiancheng/fluid (github.com) 代码里使用了PointF(x,y)来代替Python numpy Vector