Program Listing for File MicropolarModel_Bender2017.cpp
↰ Return to documentation for file (SPlisHSPlasH/Vorticity/MicropolarModel_Bender2017.cpp)
#include "MicropolarModel_Bender2017.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 MicropolarModel_Bender2017::METHOD_NAME = "Bender et al. 2017";
int MicropolarModel_Bender2017::VORTICITY_COEFFICIENT = -1;
int MicropolarModel_Bender2017::VISCOSITY_OMEGA = -1;
int MicropolarModel_Bender2017::INERTIA_INVERSE = -1;
MicropolarModel_Bender2017::MicropolarModel_Bender2017(FluidModel *model) :
NonPressureForceBase(model)
{
m_omega.resize(model->numParticles(), Vector3r::Zero());
m_angularAcceleration.resize(model->numParticles(), Vector3r::Zero());
m_vorticityCoeff = static_cast<Real>(0.01);
m_inertiaInverse = static_cast<Real>(0.5);
m_viscosityOmega = static_cast<Real>(0.1);
model->addField({ "angular velocity", METHOD_NAME, FieldType::Vector3, [&](const unsigned int i) -> Real* { return &m_omega[i][0]; }, true });
}
MicropolarModel_Bender2017::~MicropolarModel_Bender2017(void)
{
m_model->removeFieldByName("angular velocity");
m_omega.clear();
m_angularAcceleration.clear();
}
void MicropolarModel_Bender2017::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);
VISCOSITY_OMEGA = createNumericParameter("viscosityOmega", "Angular viscosity coefficient", &m_viscosityOmega);
setGroup(VISCOSITY_OMEGA, "Fluid Model|Vorticity");
setDescription(VISCOSITY_OMEGA, "Viscosity coefficient for the angular velocity field.");
rparam = static_cast<RealParameter*>(getParameter(VISCOSITY_OMEGA));
rparam->setMinValue(0.0);
INERTIA_INVERSE = createNumericParameter("inertiaInverse", "Inertia inverse", &m_inertiaInverse);
setGroup(INERTIA_INVERSE, "Fluid Model|Vorticity");
setDescription(INERTIA_INVERSE, "Inverse microinertia used in the micropolar model.");
rparam = static_cast<RealParameter*>(getParameter(INERTIA_INVERSE));
rparam->setMinValue(0.0);
}
#ifdef USE_AVX
void MicropolarModel_Bender2017::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 nu_t = m_vorticityCoeff;
const Real zeta = m_viscosityOmega;
const Real h = sim->getSupportRadius();
const Real h2 = h*h;
const Scalarf8 density0_avx(density0);
const Scalarf8 factor_avx(invDt * m_inertiaInverse * zeta *density0);
//Real d = 10.0;
//if (sim->is2DSimulation())
// d = 8.0;
#pragma omp parallel default(shared)
{
#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);
const Vector3r &omegai = m_omega[i];
Vector3r &ai = m_model->getAcceleration(i);
Vector3r &angAcceli = m_angularAcceleration[i];
angAcceli.setZero();
const Real density_i = m_model->getDensity(i);
const Vector3f8 xi_avx(xi);
const Vector3f8 vi_avx(vi);
const Scalarf8 mi_avx(m_model->getMass(i));
const Vector3f8 omegai_avx(omegai);
const Scalarf8 density_i_avx(density_i);
const Scalarf8 nut_density_i(nu_t / density_i);
const Scalarf8 nut_density_i_intertiaInverse(nu_t / density_i * m_inertiaInverse);
Vector3f8 delta_ai_avx;
delta_ai_avx.setZero();
Vector3f8 delta_angAcceli_avx;
delta_angAcceli_avx.setZero();
// Fluid
forall_fluid_neighbors_in_same_phase_avx(
const Scalarf8 Vj_avx = convert_zero(model->getVolume(0), count);
compute_Vj_gradW_samephase();
const Vector3f8 vj_avx = convertVec_zero(&sim->getNeighborList(fluidModelIndex, fluidModelIndex, i)[j], &model->getVelocity(0), count);
const Vector3f8 omegaj_avx = convertVec_zero(&sim->getNeighborList(fluidModelIndex, fluidModelIndex, i)[j], &m_omega[0], count);
// Viscosity
const Scalarf8 density_j_avx = convert_one(&sim->getNeighborList(fluidModelIndex, fluidModelIndex, i)[j], &model->getDensity(0), count);
const Vector3f8 omegaij = omegai_avx - omegaj_avx;
// XSPH for angular velocity field
const Scalarf8 mj_avx = convert_zero(model->getMass(0), count);
delta_angAcceli_avx -= omegaij * factor_avx * (Vj_avx / density_j_avx) * CubicKernel_AVX::W(xi_avx - xj_avx);
// difference curl
delta_ai_avx += (omegaij % V_gradW) * (nut_density_i * density0_avx);
delta_angAcceli_avx += ((vi_avx - vj_avx) % V_gradW) * (nut_density_i_intertiaInverse * density0_avx);
);
ai[0] += delta_ai_avx.x().reduce();
ai[1] += delta_ai_avx.y().reduce();
ai[2] += delta_ai_avx.z().reduce();
angAcceli[0] += delta_angAcceli_avx.x().reduce();
angAcceli[1] += delta_angAcceli_avx.y().reduce();
angAcceli[2] += delta_angAcceli_avx.z().reduce();
angAcceli -= 2.0 * m_inertiaInverse * nu_t * omegai;
}
}
#pragma omp parallel default(shared)
{
#pragma omp for schedule(static)
for (int i = 0; i < (int)numParticles; i++)
{
m_omega[i] += dt*m_angularAcceleration[i];
}
}
}
#else
void MicropolarModel_Bender2017::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 nu_t = m_vorticityCoeff;
const Real zeta = m_viscosityOmega;
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)
{
#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);
const Vector3r &omegai = m_omega[i];
Vector3r &ai = m_model->getAcceleration(i);
Vector3r &angAcceli = m_angularAcceleration[i];
angAcceli.setZero();
const Real density_i = m_model->getDensity(i);
// Fluid
forall_fluid_neighbors_in_same_phase(
const Vector3r &vj = m_model->getVelocity(neighborIndex);
const Vector3r &omegaj = m_omega[neighborIndex];
// Viscosity
const Real density_j = m_model->getDensity(neighborIndex);
const Vector3r xij = xi - xj;
const Vector3r omegaij = omegai - omegaj;
const Vector3r gradW = sim->gradW(xij);
// XSPH for angular velocity field
angAcceli -= invDt * m_inertiaInverse * zeta * (m_model->getMass(neighborIndex) / density_j) * omegaij * sim->W(xij);
//angAcceli += d * m_inertiaInverse * zeta * (m_model->getMass(neighborIndex) / density_i) * omegaij.dot(xij) / (xij.squaredNorm() + 0.01*h2) * gradW;
// difference curl
ai += nu_t * 1.0/density_i * m_model->getMass(neighborIndex) * (omegaij.cross(gradW));
angAcceli += nu_t * 1.0/density_i * m_inertiaInverse * (m_model->getMass(neighborIndex) * (vi - vj).cross(gradW));
);
angAcceli -= 2.0 * m_inertiaInverse * nu_t * omegai;
}
}
#pragma omp parallel default(shared)
{
#pragma omp for schedule(static)
for (int i = 0; i < static_cast<int>(numParticles); i++)
{
m_omega[i] += dt*m_angularAcceleration[i];
}
}
}
#endif
void MicropolarModel_Bender2017::reset()
{
for (unsigned int i = 0; i < m_model->numParticles(); i++)
m_omega[i].setZero();
}
void SPH::MicropolarModel_Bender2017::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_omega[0]);
}