Program Listing for File PositionBasedFluids.cpp

Return to documentation for file (PositionBasedDynamics/PositionBasedFluids.cpp)

#include "PositionBasedFluids.h"
#include <cfloat>
#include "SPHKernels.h"

using namespace PBD;

// ----------------------------------------------------------------------------------------------
bool PositionBasedFluids::computePBFDensity(
    const unsigned int particleIndex,
    const unsigned int numberOfParticles,
    const Vector3r x[],
    const Real mass[],
    const Vector3r boundaryX[],
    const Real boundaryPsi[],
    const unsigned int numNeighbors,
    const unsigned int neighbors[],
    const Real density0,
    const bool boundaryHandling,
    Real &density_err,
    Real &density)
{
    // Compute current density for particle i
    density = mass[particleIndex] * CubicKernel::W_zero();
    for (unsigned int j = 0; j < numNeighbors; j++)
    {
        const unsigned int neighborIndex = neighbors[j];
        if (neighborIndex < numberOfParticles)      // Test if fluid particle
        {
            density += mass[neighborIndex] * CubicKernel::W(x[particleIndex] - x[neighborIndex]);
        }
        else if (boundaryHandling)
        {
            // Boundary: Akinci2012
            density += boundaryPsi[neighborIndex - numberOfParticles] * CubicKernel::W(x[particleIndex] - boundaryX[neighborIndex - numberOfParticles]);
        }
    }

    density_err = std::max(density, density0) - density0;
    return true;
}

// ----------------------------------------------------------------------------------------------
bool PositionBasedFluids::computePBFLagrangeMultiplier(
    const unsigned int particleIndex,
    const unsigned int numberOfParticles,
    const Vector3r x[],
    const Real mass[],
    const Vector3r boundaryX[],
    const Real boundaryPsi[],
    const Real density,
    const unsigned int numNeighbors,
    const unsigned int neighbors[],
    const Real density0,
    const bool boundaryHandling,
    Real &lambda)
{
    const Real eps = static_cast<Real>(1.0e-6);

    // Evaluate constraint function
    const Real C = std::max(density / density0 - static_cast<Real>(1.0), static_cast<Real>(0.0));           // clamp to prevent particle clumping at surface

    if (C != 0.0)
    {
        // Compute gradients dC/dx_j
        Real sum_grad_C2 = 0.0;
        Vector3r gradC_i(0.0, 0.0, 0.0);

        for (unsigned int j = 0; j < numNeighbors; j++)
        {
            const unsigned int neighborIndex = neighbors[j];
            if (neighborIndex < numberOfParticles)      // Test if fluid particle
            {
                const Vector3r gradC_j = -mass[neighborIndex] / density0 * CubicKernel::gradW(x[particleIndex] - x[neighborIndex]);
                sum_grad_C2 += gradC_j.squaredNorm();
                gradC_i -= gradC_j;
            }
            else if (boundaryHandling)
            {
                // Boundary: Akinci2012
                const Vector3r gradC_j = -boundaryPsi[neighborIndex - numberOfParticles] / density0 * CubicKernel::gradW(x[particleIndex] - boundaryX[neighborIndex - numberOfParticles]);
                sum_grad_C2 += gradC_j.squaredNorm();
                gradC_i -= gradC_j;
            }
        }

        sum_grad_C2 += gradC_i.squaredNorm();

        // Compute lambda
        lambda = -C / (sum_grad_C2 + eps);
    }
    else
        lambda = 0.0;

    return true;
}

// ----------------------------------------------------------------------------------------------
bool PositionBasedFluids::solveDensityConstraint(
    const unsigned int particleIndex,
    const unsigned int numberOfParticles,
    const Vector3r x[],
    const Real mass[],
    const Vector3r boundaryX[],
    const Real boundaryPsi[],
    const unsigned int numNeighbors,
    const unsigned int neighbors[],
    const Real density0,
    const bool boundaryHandling,
    const Real lambda[],
    Vector3r &corr)
{
    // Compute position correction
    corr.setZero();
    for (unsigned int j = 0; j < numNeighbors; j++)
    {
        const unsigned int neighborIndex = neighbors[j];
        if (neighborIndex < numberOfParticles)      // Test if fluid particle
        {
            const Vector3r gradC_j = -mass[neighborIndex] / density0 * CubicKernel::gradW(x[particleIndex] - x[neighborIndex]);
            corr -= (lambda[particleIndex] + lambda[neighborIndex]) * gradC_j;
        }
        else if (boundaryHandling)
        {
            // Boundary: Akinci2012
            const Vector3r gradC_j = -boundaryPsi[neighborIndex - numberOfParticles] / density0 * CubicKernel::gradW(x[particleIndex] - boundaryX[neighborIndex - numberOfParticles]);
            corr -= (lambda[particleIndex]) * gradC_j;
        }
    }

    return true;
}