Program Listing for File VorticityRefinement_Liu2021.cpp

Return to documentation for file (SPlisHSPlasH/Vorticity/VorticityRefinement_Liu2021.cpp)

#include "VorticityRefinement_Liu2021.h"
#include <iostream>
#include "../TimeManager.h"
#include "../Simulation.h"
#include "SPlisHSPlasH/BoundaryModel_Akinci2012.h"
#include "SPlisHSPlasH/BoundaryModel_Koschier2017.h"
#include "SPlisHSPlasH/BoundaryModel_Bender2019.h"


using namespace SPH;
using namespace GenParam;

std::string VorticityRefinement_Liu2021::METHOD_NAME = "Liu et al. 2021";
int VorticityRefinement_Liu2021::VORTICITY_COEFFICIENT = -1;
int VorticityRefinement_Liu2021::KINEMATIC_VISCOSITY = -1;


VorticityRefinement_Liu2021::VorticityRefinement_Liu2021(FluidModel *model) :
    NonPressureForceBase(model)
{
    m_vorticityCoeff = static_cast<Real>(1.0);
    m_viscosityCoefficient = static_cast<Real>(0.05);

    m_vorticity.resize(model->numParticles(), Vector3r::Zero());
    m_dissipatedVorticity.resize(model->numParticles(), Vector3r::Zero());
    m_streamFunction.resize(model->numParticles(), Vector3r::Zero());

    model->addField({ "vorticity", METHOD_NAME, FieldType::Vector3, [&](const unsigned int i) -> Real* { return &m_vorticity[i][0]; }, true });
    model->addField({ "dissipated vorticity", METHOD_NAME, FieldType::Vector3, [&](const unsigned int i) -> Real* { return &m_dissipatedVorticity[i][0]; }, true });
    model->addField({ "stream function", METHOD_NAME, FieldType::Vector3, [&](const unsigned int i) -> Real* { return &m_streamFunction[i][0]; }, true });
}

VorticityRefinement_Liu2021::~VorticityRefinement_Liu2021(void)
{
    m_model->removeFieldByName("vorticity");
    m_model->removeFieldByName("dissipated vorticity");
    m_model->removeFieldByName("stream function");

    m_vorticity.clear();
    m_dissipatedVorticity.clear();
    m_streamFunction.clear();
}

void VorticityRefinement_Liu2021::initParameters()
{
    NonPressureForceBase::initParameters();

    VORTICITY_COEFFICIENT = createNumericParameter("vorticity", "Vorticity coefficient", &m_vorticityCoeff);
    setGroup(VORTICITY_COEFFICIENT, "Fluid Model|Vorticity");
    setDescription(VORTICITY_COEFFICIENT, "Coefficient for the vorticity force computation");
    RealParameter* rparam = static_cast<RealParameter*>(getParameter(VORTICITY_COEFFICIENT));
    rparam->setMinValue(0.0);

    KINEMATIC_VISCOSITY = createNumericParameter("kinetmaticViscosity", "Viscosity coefficient", &m_viscosityCoefficient);
    setGroup(KINEMATIC_VISCOSITY, "Fluid Model|Vorticity");
    setDescription(KINEMATIC_VISCOSITY, "Coefficient for the viscosity force computation");
    rparam = static_cast<RealParameter*>(getParameter(KINEMATIC_VISCOSITY));
    rparam->setMinValue(0.0);
}

void VorticityRefinement_Liu2021::step()
{
    Simulation *sim = Simulation::getCurrent();
    const unsigned int numParticles = m_model->numActiveParticles();
    if (numParticles == 0)
        return;

    const unsigned int fluidModelIndex = m_model->getPointSetIndex();
    const unsigned int nFluids = sim->numberOfFluidModels();
    const unsigned int nBoundaries = sim->numberOfBoundaryModels();
    FluidModel *model = m_model;
    const Real density0 = model->getDensity0();

    const Real dt = TimeManager::getCurrent()->getTimeStepSize();
    const Real invDt = static_cast<Real>(1.0) / dt;

    const Real alpha = m_vorticityCoeff;

    const Real h = sim->getSupportRadius();
    const Real h2 = h*h;

    Real d = 10.0;
    if (sim->is2DSimulation())
        d = 8.0;

    #pragma omp parallel default(shared)
    {
        // compute vorticity through linear field
        #pragma omp for schedule(static)
        for (int i = 0; i < (int)numParticles; i++)
        {
            const Vector3r &xi = m_model->getPosition(i);
            const Vector3r &vi = m_model->getVelocity(i);
            Vector3r &vorticity_i = m_vorticity[i];
            Matrix3r grad_v = Matrix3r::Zero();
            Vector3r vorticityLaplacian = Vector3r::Zero();
            Vector3r vorticity_linear_field = Vector3r::Zero();

            // Fluid
            forall_fluid_neighbors_in_same_phase(
                const Vector3r &vj = m_model->getVelocity(neighborIndex);
                const Real density_j = m_model->getDensity(neighborIndex);
                const Vector3r xij = xi - xj;
                const Vector3r vij = vi - vj;
                const Vector3r gradW = sim->gradW(xij);
                const Real Vj = m_model->getMass(neighborIndex) / density_j;
                const Vector3r& vorticity_j = m_vorticity[neighborIndex];

                // compute vorticity through linear field
                vorticity_linear_field += Vj * vij.cross(gradW);
                // compute grad v
                grad_v -= Vj * vij * gradW.transpose();
                // compute Laplacian of vorticity
                vorticityLaplacian += d * Vj * (vorticity_i - vorticity_j).dot(xij) / (xij.squaredNorm() + 0.01 * h2) * gradW;
            );

            const Vector3r strechingTerm = grad_v * vorticity_i;
            const Vector3r vorticityPrediction = vorticity_i + dt * (strechingTerm + m_viscosityCoefficient * vorticityLaplacian);

            Vector3r& dissipatedVorticity_i = m_dissipatedVorticity[i];
            dissipatedVorticity_i = vorticityPrediction - vorticity_linear_field;
        }

        // compute stream function
        #pragma omp for schedule(static)
        for (int i = 0; i < static_cast<int>(numParticles); i++)
        {
            const Vector3r& xi = m_model->getPosition(i);
            Vector3r& streamFunction_i = m_streamFunction[i];
            streamFunction_i.setZero();

            // Fluid
            const Real epsilon = static_cast<Real>(0.1) * h;
            forall_fluid_neighbors_in_same_phase(
                const Real density_j = m_model->getDensity(neighborIndex);
                const Vector3r& dissipatedVorticity_j = m_dissipatedVorticity[neighborIndex];
                const Real Vj = m_model->getMass(neighborIndex) / density_j;
                streamFunction_i += dissipatedVorticity_j * Vj / ((xi - xj).norm() + epsilon);      // avoid a division by zero using epsilon in the denominator
            );

            streamFunction_i *= static_cast<Real>(0.25 / M_PI);
        }

        // compute refinement of linear velocity
        #pragma omp for schedule(static)
        for (int i = 0; i < static_cast<int>(numParticles); i++)
        {
            const Vector3r& xi = m_model->getPosition(i);
            const Vector3r& streamFunction_i = m_streamFunction[i];
            Vector3r& vi = m_model->getVelocity(i);

            Vector3r delta_vi = Vector3r::Zero();

            // Fluid
            forall_fluid_neighbors_in_same_phase(
                const Real density_j = m_model->getDensity(neighborIndex);
                const Vector3r& streamFunction_j = m_streamFunction[neighborIndex];
                const Vector3r gradW = sim->gradW(xi - xj);
                const Real Vj = m_model->getMass(neighborIndex) / density_j;

                delta_vi += Vj * (streamFunction_i - streamFunction_j).cross(gradW);
            );

            if (m_model->getParticleState(i) == ParticleState::Active)
                vi += m_vorticityCoeff * delta_vi;
        }

        // store the vorticity for the next time step
        #pragma omp for schedule(static)
        for (int i = 0; i < static_cast<int>(numParticles); i++)
        {
            const Vector3r& xi = m_model->getPosition(i);
            const Vector3r& vi = m_model->getVelocity(i);
            Vector3r& vorticity_i = m_vorticity[i];
            vorticity_i.setZero();

            // Fluid

            forall_fluid_neighbors_in_same_phase(
                const Vector3r & vj = m_model->getVelocity(neighborIndex);
                const Real density_j = m_model->getDensity(neighborIndex);
                const Vector3r gradW = sim->gradW(xi - xj);

                vorticity_i += m_model->getMass(neighborIndex) / density_j * (vi - vj).cross(gradW);
            );
        }
    }
}

void VorticityRefinement_Liu2021::reset()
{
    for (unsigned int i = 0; i < m_model->numParticles(); i++)
    {
        m_vorticity[i].setZero();
        m_dissipatedVorticity[i].setZero();
        m_streamFunction[i].setZero();
    }
}

void SPH::VorticityRefinement_Liu2021::performNeighborhoodSearchSort()
{
    const unsigned int numPart = m_model->numActiveParticles();
    if (numPart == 0)
        return;

    Simulation *sim = Simulation::getCurrent();
    auto const& d = sim->getNeighborhoodSearch()->point_set(m_model->getPointSetIndex());
    d.sort_field(&m_vorticity[0]);
}