From 2c69c380fb6d270ba324b657ff1aa9990a5dea03 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Wed, 29 Mar 2023 17:06:10 +0200 Subject: [PATCH 01/38] Time Integration without rotation --- SPlisHSPlasH/DynamicRigidBody.h | 718 +++++++++++++++++++++++++ Simulator/DynamicBoundarySimulator.cpp | 227 ++++++++ Simulator/DynamicBoundarySimulator.h | 31 ++ Simulator/SimulatorBase.cpp | 15 +- Simulator/main.cpp | 3 +- 5 files changed, 986 insertions(+), 8 deletions(-) create mode 100644 SPlisHSPlasH/DynamicRigidBody.h create mode 100644 Simulator/DynamicBoundarySimulator.cpp create mode 100644 Simulator/DynamicBoundarySimulator.h diff --git a/SPlisHSPlasH/DynamicRigidBody.h b/SPlisHSPlasH/DynamicRigidBody.h new file mode 100644 index 00000000..d4f4a778 --- /dev/null +++ b/SPlisHSPlasH/DynamicRigidBody.h @@ -0,0 +1,718 @@ +#ifndef __StaticRigidBody_h__ +#define __StaticRigidBody_h__ + +#include "Common.h" +#include "RigidBodyObject.h" +#include "TriangleMesh.h" +#include "TimeManager.h" + +namespace SPH { + /** \brief This class stores the information of a dynamic rigid body which + * is used for the strong coupling method introduced in + * Interlinked SPH Pressure Solvers for Strong Fluid-Rigid Coupling. Gissler et al. https://doi.org/10.1145/3284980 + */ + class DynamicRigidBody : public RigidBodyObject { + // Some fields are from PBD::RigidBody + private: + /** mass */ + Real m_mass; + /** inverse mass */ + Real m_invMass; + /** center of mass */ + Vector3r m_x; + Vector3r m_lastX; + Vector3r m_oldX; + Vector3r m_x0; + /** center of mass velocity */ + Vector3r m_v; + Vector3r m_v0; + /** acceleration (by external forces) */ + Vector3r m_a; + + /** Inertia tensor in the principal axis system: \n + * After the main axis transformation the inertia tensor is a diagonal matrix. + * So only three values are required to store the inertia tensor. These values + * are constant over time. + */ + Vector3r m_inertiaTensor; + /** 3x3 matrix, inertia tensor in world space */ + Matrix3r m_inertiaTensorW; + /** Inverse inertia tensor in body space */ + Vector3r m_inertiaTensorInverse; + /** 3x3 matrix, inverse of the inertia tensor in world space */ + Matrix3r m_inertiaTensorInverseW; + /** Quaternion that describes the rotation of the body in world space */ + Quaternionr m_q; + Quaternionr m_lastQ; + Quaternionr m_oldQ; + Quaternionr m_q0; + /** Quaternion representing the rotation of the main axis transformation + that is performed to get a diagonal inertia tensor */ + Quaternionr m_q_mat; + /** Quaternion representing the initial rotation of the geometry */ + Quaternionr m_q_initial; + /** difference of the initial translation and the translation of the main axis transformation */ + Vector3r m_x0_mat; + /** rotationMatrix = 3x3 matrix. + * Important for the transformation from world in body space and vice versa. + * When using quaternions the rotation matrix is computed out of the quaternion. + */ + Matrix3r m_rot; + /** Angular velocity, defines rotation axis and velocity (magnitude of the vector) */ + Vector3r m_omega; + Vector3r m_omega0; + /** external torque */ + Vector3r m_torque; + + Real m_restitutionCoeff; + Real m_frictionCoeff; + + // transformation required to transform a point to local space or vice vera + Matrix3r m_transformation_R; + Vector3r m_transformation_v1; + Vector3r m_transformation_v2; + Vector3r m_transformation_R_X_v1; + protected: + + TriangleMesh m_geometry; + + public: + DynamicRigidBody() { + m_isAnimated = true; + } + + + ~DynamicRigidBody(void) + { + } + + void initBody(const Real mass, const Vector3r &x, + const Vector3r &inertiaTensor, const Quaternionr &rotation, + const Vector3r &scale = Vector3r(1.0, 1.0, 1.0)) + { + setMass(mass); + m_x = x; + m_x0 = x; + m_lastX = x; + m_oldX = x; + m_v.setZero(); + m_v0.setZero(); + m_a.setZero(); + + setInertiaTensor(inertiaTensor); + m_q = rotation; + m_q0 = rotation; + m_lastQ = rotation; + m_oldQ = rotation; + m_rot = m_q.matrix(); + m_q_mat = Quaternionr(1.0, 0.0, 0.0, 0.0); + m_q_initial = Quaternionr(1.0, 0.0, 0.0, 0.0); + m_x0_mat.setZero(); + rotationUpdated(); + m_omega.setZero(); + m_omega0.setZero(); + m_torque.setZero(); + + m_restitutionCoeff = static_cast(0.6); + m_frictionCoeff = static_cast(0.2); + updateMeshTransformation(); + } + + //void initBody(const Real density, const Vector3r &x, const Quaternionr &rotation, + // const Vector3r &scale = Vector3r(1.0, 1.0, 1.0)) + //{ + // m_mass = 1.0; + // m_inertiaTensor = Vector3r(1.0, 1.0, 1.0); + // m_x = x; + // m_x0 = x; + // m_lastX = x; + // m_oldX = x; + // m_v.setZero(); + // m_v0.setZero(); + // m_a.setZero(); + + // m_q = rotation; + // m_q0 = rotation; + // m_lastQ = rotation; + // m_oldQ = rotation; + // m_rot = m_q.matrix(); + // rotationUpdated(); + // m_omega.setZero(); + // m_omega0.setZero(); + // m_torque.setZero(); + + // m_restitutionCoeff = static_cast(0.6); + // m_frictionCoeff = static_cast(0.2); + + // determineMassProperties(density); + // getGeometry().updateMeshTransformation(getPosition(), getRotationMatrix()); + //} + + void reset() + { + m_x = m_x0; + getOldPosition() = getPosition0(); + getLastPosition() = getPosition0(); + + m_q = m_q0; + getOldRotation() = getRotation0(); + getLastRotation() = getRotation0(); + + m_v = m_v0; + m_omega = m_omega0; + + getAcceleration().setZero(); + getTorque().setZero(); + + rotationUpdated(); + + updateMeshTransformation(); + } + + void updateInverseTransformation() + { + // remove the rotation of the main axis transformation that is performed + // to get a diagonal inertia tensor since the distance function is + // evaluated in local coordinates + // + // transformation world to local: + // p_local = R_initial^T ( R_MAT R^T (p_world - x) - x_initial + x_MAT) + // + // transformation local to world: + // p_world = R R_MAT^T (R_initial p_local + x_initial - x_MAT) + x + // + m_transformation_R = (getRotationInitial().inverse() * getRotationMAT() * getRotation().inverse()).matrix(); + m_transformation_v1 = -getRotationInitial().inverse().matrix() * getPositionInitial_MAT(); + m_transformation_v2 = (getRotation()*getRotationMAT().inverse()).matrix() * getPositionInitial_MAT() + getPosition(); + m_transformation_R_X_v1 = -m_transformation_R * getPosition() + m_transformation_v1; + } + + void rotationUpdated() + { + if (m_mass != 0.0) + { + m_rot = m_q.matrix(); + updateInertiaW(); + updateInverseTransformation(); + } + } + + void updateInertiaW() + { + if (m_mass != 0.0) + { + m_inertiaTensorW = m_rot * m_inertiaTensor.asDiagonal() * m_rot.transpose(); + m_inertiaTensorInverseW = m_rot * m_inertiaTensorInverse.asDiagonal() * m_rot.transpose(); + } + } + + /** Determine mass and inertia tensor of the given geometry. + */ + //void determineMassProperties(const Real density) + //{ + // // apply initial rotation + // VertexData &vd = m_geometry.getVertexDataLocal(); + // + // Utilities::VolumeIntegration vi(m_geometry.getVertexDataLocal().size(), m_geometry.getMesh().numFaces(), &m_geometry.getVertexDataLocal().getPosition(0), m_geometry.getMesh().getFaces().data()); + // vi.compute_inertia_tensor(density); + // + // // Diagonalize Inertia Tensor + // Eigen::SelfAdjointEigenSolver es(vi.getInertia()); + // Vector3r inertiaTensor = es.eigenvalues(); + // Matrix3r R = es.eigenvectors(); + // + // setMass(1.0); + // setInertiaTensor(inertiaTensor); + // + // if (R.determinant() < 0.0) + // R = -R; + // + // for (unsigned int i = 0; i < vd.size(); i++) + // vd.getPosition(i) = m_rot * vd.getPosition(i) + m_x0; + // + // Vector3r x_MAT = vi.getCenterOfMass(); + // R = m_rot * R; + // x_MAT = m_rot * x_MAT + m_x0; + // + // // rotate vertices back + // for (unsigned int i = 0; i < vd.size(); i++) + // vd.getPosition(i) = R.transpose() * (vd.getPosition(i) - x_MAT); + // + // // set rotation + // Quaternionr qR = Quaternionr(R); + // qR.normalize(); + // m_q_mat = qR; + // m_q_initial = m_q0; + // m_x0_mat = m_x0 - x_MAT; + // + // m_q0 = qR; + // m_q = m_q0; + // m_lastQ = m_q0; + // m_oldQ = m_q0; + // rotationUpdated(); + // + // // set translation + // m_x0 = x_MAT; + // m_x = m_x0; + // m_lastX = m_x0; + // m_oldX = m_x0; + // updateInverseTransformation(); + //} + + const Matrix3r &getTransformationR() { return m_transformation_R; } + const Vector3r &getTransformationV1() { return m_transformation_v1; } + const Vector3r &getTransformationV2() { return m_transformation_v2; } + const Vector3r &getTransformationRXV1() { return m_transformation_R_X_v1; } + + //FORCE_INLINE Real &getMass() + //{ + // return m_mass; + //} + FORCE_INLINE void setMass(const Real &value) + { + m_mass = value; + if (m_mass != 0.0) + m_invMass = static_cast(1.0) / m_mass; + else + m_invMass = 0.0; + } + + FORCE_INLINE const Real &getInvMass() const + { + return m_invMass; + } + + //FORCE_INLINE Vector3r &getPosition() + //{ + // return m_x; + //} + + //FORCE_INLINE const Vector3r &getPosition() const + //{ + // return m_x; + //} + + //FORCE_INLINE void setPosition(const Vector3r &pos) + //{ + // m_x = pos; + //} + + FORCE_INLINE Vector3r &getLastPosition() + { + return m_lastX; + } + + FORCE_INLINE const Vector3r &getLastPosition() const + { + return m_lastX; + } + + FORCE_INLINE void setLastPosition(const Vector3r &pos) + { + m_lastX = pos; + } + + FORCE_INLINE Vector3r &getOldPosition() + { + return m_oldX; + } + + FORCE_INLINE const Vector3r &getOldPosition() const + { + return m_oldX; + } + + FORCE_INLINE void setOldPosition(const Vector3r &pos) + { + m_oldX = pos; + } + + //FORCE_INLINE Vector3r &getPosition0() + //{ + // return m_x0; + //} + + //FORCE_INLINE const Vector3r &getPosition0() const + //{ + // return m_x0; + //} + + //FORCE_INLINE void setPosition0(const Vector3r &pos) + //{ + // m_x0 = pos; + //} + + FORCE_INLINE Vector3r &getPositionInitial_MAT() + { + return m_x0_mat; + } + + FORCE_INLINE const Vector3r &getPositionInitial_MAT() const + { + return m_x0_mat; + } + + FORCE_INLINE void setPositionInitial_MAT(const Vector3r &pos) + { + m_x0_mat = pos; + } + + //FORCE_INLINE Vector3r &getVelocity() + //{ + // return m_v; + //} + + //FORCE_INLINE const Vector3r &getVelocity() const + //{ + // return m_v; + //} + +/* FORCE_INLINE void setVelocity(const Vector3r &value) + { + m_v = value; + } */ + + //FORCE_INLINE Vector3r &getVelocity0() + //{ + // return m_v0; + //} + + //FORCE_INLINE const Vector3r &getVelocity0() const + //{ + // return m_v0; + //} + + //FORCE_INLINE void setVelocity0(const Vector3r &value) + //{ + // m_v0 = value; + //} + + FORCE_INLINE Vector3r &getAcceleration() + { + return m_a; + } + + FORCE_INLINE const Vector3r &getAcceleration() const + { + return m_a; + } + + FORCE_INLINE void setAcceleration(const Vector3r &accel) + { + m_a = accel; + } + + FORCE_INLINE const Vector3r &getInertiaTensor() const + { + return m_inertiaTensor; + } + + FORCE_INLINE void setInertiaTensor(const Vector3r &value) + { + m_inertiaTensor = value; + m_inertiaTensorInverse = Vector3r(static_cast(1.0) / value[0], static_cast(1.0) / value[1], static_cast(1.0) / value[2]); + } + + FORCE_INLINE Matrix3r& getInertiaTensorW() + { + return m_inertiaTensorW; + } + + FORCE_INLINE const Matrix3r& getInertiaTensorW() const + { + return m_inertiaTensorW; + } + + FORCE_INLINE const Vector3r &getInertiaTensorInverse() const + { + return m_inertiaTensorInverse; + } + + FORCE_INLINE Matrix3r &getInertiaTensorInverseW() + { + return m_inertiaTensorInverseW; + } + + FORCE_INLINE const Matrix3r &getInertiaTensorInverseW() const + { + return m_inertiaTensorInverseW; + } + + FORCE_INLINE void setInertiaTensorInverseW(const Matrix3r &value) + { + m_inertiaTensorInverseW = value; + } + + //FORCE_INLINE Quaternionr &getRotation() + //{ + // return m_q; + //} + + //FORCE_INLINE const Quaternionr &getRotation() const + //{ + // return m_q; + //} + + //FORCE_INLINE void setRotation(const Quaternionr &value) + //{ + // m_q = value; + //} + + FORCE_INLINE Quaternionr &getLastRotation() + { + return m_lastQ; + } + + FORCE_INLINE const Quaternionr &getLastRotation() const + { + return m_lastQ; + } + + FORCE_INLINE void setLastRotation(const Quaternionr &value) + { + m_lastQ = value; + } + + FORCE_INLINE Quaternionr &getOldRotation() + { + return m_oldQ; + } + + FORCE_INLINE const Quaternionr &getOldRotation() const + { + return m_oldQ; + } + + FORCE_INLINE void setOldRotation(const Quaternionr &value) + { + m_oldQ = value; + } + + //FORCE_INLINE Quaternionr &getRotation0() + //{ + // return m_q0; + //} + + //FORCE_INLINE const Quaternionr &getRotation0() const + //{ + // return m_q0; + //} + + //FORCE_INLINE void setRotation0(const Quaternionr &value) + //{ + // m_q0 = value; + //} + + FORCE_INLINE Quaternionr &getRotationMAT() + { + return m_q_mat; + } + + FORCE_INLINE const Quaternionr &getRotationMAT() const + { + return m_q_mat; + } + + FORCE_INLINE void setRotationMAT(const Quaternionr &value) + { + m_q_mat = value; + } + + FORCE_INLINE Quaternionr &getRotationInitial() + { + return m_q_initial; + } + + FORCE_INLINE const Quaternionr &getRotationInitial() const + { + return m_q_initial; + } + + FORCE_INLINE void setRotationInitial(const Quaternionr &value) + { + m_q_initial = value; + } + + FORCE_INLINE Matrix3r &getRotationMatrix() + { + return m_rot; + } + + FORCE_INLINE const Matrix3r &getRotationMatrix() const + { + return m_rot; + } + + FORCE_INLINE void setRotationMatrix(const Matrix3r &value) + { + m_rot = value; + } + + //FORCE_INLINE Vector3r &getAngularVelocity() + //{ + // return m_omega; + //} + + //FORCE_INLINE const Vector3r &getAngularVelocity() const + //{ + // return m_omega; + //} + + //FORCE_INLINE void setAngularVelocity(const Vector3r &value) + //{ + // m_omega = value; + //} + + FORCE_INLINE Vector3r &getAngularVelocity0() + { + return m_omega0; + } + + FORCE_INLINE const Vector3r &getAngularVelocity0() const + { + return m_omega0; + } + + FORCE_INLINE void setAngularVelocity0(const Vector3r &value) + { + m_omega0 = value; + } + + FORCE_INLINE Vector3r &getTorque() + { + return m_torque; + } + + FORCE_INLINE const Vector3r &getTorque() const + { + return m_torque; + } + + FORCE_INLINE void setTorque(const Vector3r &value) + { + m_torque = value; + } + + FORCE_INLINE Real getRestitutionCoeff() const + { + return m_restitutionCoeff; + } + + FORCE_INLINE void setRestitutionCoeff(Real val) + { + m_restitutionCoeff = val; + } + + FORCE_INLINE Real getFrictionCoeff() const + { + return m_frictionCoeff; + } + + FORCE_INLINE void setFrictionCoeff(Real val) + { + m_frictionCoeff = val; + } + + + virtual bool isDynamic() const { + return m_mass != 0.0; + } + + virtual Real const getMass() const { + return m_mass; + } + virtual Vector3r const& getPosition() const { + return m_x; + } + virtual void setPosition(const Vector3r& x) { + m_x = x; + } + Vector3r const& getPosition0() const { + return m_x0; + } + void setPosition0(const Vector3r& x) { + m_x0 = x; + } + virtual Vector3r getWorldSpacePosition() const { + return m_x; + } + virtual Vector3r const& getVelocity() const { + return m_v; + } + virtual void setVelocity(const Vector3r& v) { + if (m_isAnimated) m_v = v; + } + virtual Quaternionr const& getRotation() const { + return m_q; + } + virtual void setRotation(const Quaternionr& q) { + m_q = q; + } + Quaternionr const& getRotation0() const { + return m_q0; + } + void setRotation0(const Quaternionr& q) { + m_q0 = q; + } + virtual Matrix3r getWorldSpaceRotation() const { + return m_q.toRotationMatrix(); + } + virtual Vector3r const& getAngularVelocity() const { + return m_omega; + } + virtual void setAngularVelocity(const Vector3r& v) { + if (m_isAnimated) m_omega = v; + } + virtual void addForce(const Vector3r& f) { + const Real dt = SPH::TimeManager::getCurrent()->getTimeStepSize(); + m_v += (1.0 / m_mass) * f * dt; + } + + virtual void addTorque(const Vector3r& t) { + const Real dt = SPH::TimeManager::getCurrent()->getTimeStepSize(); + m_omega += m_inertiaTensorInverseW * t * dt; + } + void animate() { + const Real dt = TimeManager::getCurrent()->getTimeStepSize(); + m_x += m_v * dt; + Quaternionr angVelQ(0.0, m_omega[0], m_omega[1], m_omega[2]); + m_q.coeffs() += dt * 0.5 * (angVelQ * m_q).coeffs(); + m_q.normalize(); + updateMeshTransformation(); + } + + virtual const std::vector& getVertices() const { + return m_geometry.getVertices(); + }; + virtual const std::vector& getVertexNormals() const { + return m_geometry.getVertexNormals(); + }; + virtual const std::vector& getFaces() const { + return m_geometry.getFaces(); + }; + + void setWorldSpacePosition(const Vector3r& x) { + m_x = x; + } + void setWorldSpaceRotation(const Matrix3r& r) { + m_q = Quaternionr(r); + } + TriangleMesh& getGeometry() { + return m_geometry; + } + + virtual void updateMeshTransformation() { + m_geometry.updateMeshTransformation(m_x, m_q.toRotationMatrix()); + m_geometry.updateNormals(); + m_geometry.updateVertexNormals(); + } + + //void reset() { + // m_x = m_x0; + // m_q = m_q0; + // updateMeshTransformation(); + //} + }; +} + +#endif \ No newline at end of file diff --git a/Simulator/DynamicBoundarySimulator.cpp b/Simulator/DynamicBoundarySimulator.cpp new file mode 100644 index 00000000..786e7d3b --- /dev/null +++ b/Simulator/DynamicBoundarySimulator.cpp @@ -0,0 +1,227 @@ +#include "DynamicBoundarySimulator.h" +#include "SimulatorBase.h" +#include "Utilities/FileSystem.h" +#include "SPlisHSPlasH/Simulation.h" +#include "Utilities/PartioReaderWriter.h" +#include "SPlisHSPlasH/DynamicRigidBody.h" +#include "Utilities/Logger.h" +#include "Utilities/Timing.h" +#include "SPlisHSPlasH/Utilities/SurfaceSampling.h" +#include "SPlisHSPlasH/TriangleMesh.h" +#include "Simulator/SceneConfiguration.h" +#include "SPlisHSPlasH/Utilities/MeshImport.h" + +using namespace std; +using namespace SPH; +using namespace Utilities; + + +DynamicBoundarySimulator::DynamicBoundarySimulator(SimulatorBase* base) { + m_base = base; +} + +DynamicBoundarySimulator::~DynamicBoundarySimulator() { + +} + +void DynamicBoundarySimulator::initBoundaryData() { + const std::string& sceneFile = SceneConfiguration::getCurrent()->getSceneFile(); + const Utilities::SceneLoader::Scene& scene = SceneConfiguration::getCurrent()->getScene(); + std::string scene_path = FileSystem::getFilePath(sceneFile); + std::string scene_file_name = FileSystem::getFileName(sceneFile); + // no cache for 2D scenes + // 2D sampling is fast, but storing it would require storing the transformation as well + const bool useCache = m_base->getUseParticleCaching() && !scene.sim2D; + Simulation* sim = Simulation::getCurrent(); + + string cachePath = scene_path + "/Cache"; + + for (unsigned int i = 0; i < scene.boundaryModels.size(); i++) { + string meshFileName = scene.boundaryModels[i]->meshFile; + if (FileSystem::isRelativePath(meshFileName)) + meshFileName = FileSystem::normalizePath(scene_path + "/" + scene.boundaryModels[i]->meshFile); + + // check if mesh file has changed + std::string md5FileName = FileSystem::normalizePath(cachePath + "/" + FileSystem::getFileNameWithExt(meshFileName) + ".md5"); + bool md5 = false; + if (useCache) { + string md5Str = FileSystem::getFileMD5(meshFileName); + if (FileSystem::fileExists(md5FileName)) + md5 = FileSystem::checkMD5(md5Str, md5FileName); + } + + DynamicRigidBody* rb = new DynamicRigidBody(); + rb->setIsAnimated(true); + TriangleMesh& geo = rb->getGeometry(); + MeshImport::importMesh(meshFileName, geo, Vector3r::Zero(), Matrix3r::Identity(), scene.boundaryModels[i]->scale); + + std::vector boundaryParticles; + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { + // if a samples file is given, use this one + if (scene.boundaryModels[i]->samplesFile != "") { + string particleFileName = scene_path + "/" + scene.boundaryModels[i]->samplesFile; + PartioReaderWriter::readParticles(particleFileName, Vector3r::Zero(), Matrix3r::Identity(), scene.boundaryModels[i]->scale[0], boundaryParticles); + } else // if no samples file is given, sample the surface model + { + // Cache sampling + std::string mesh_base_path = FileSystem::getFilePath(scene.boundaryModels[i]->meshFile); + std::string mesh_file_name = FileSystem::getFileName(scene.boundaryModels[i]->meshFile); + + const string resStr = StringTools::real2String(scene.boundaryModels[i]->scale[0]) + "_" + StringTools::real2String(scene.boundaryModels[i]->scale[1]) + "_" + StringTools::real2String(scene.boundaryModels[i]->scale[2]); + const string modeStr = "_m" + std::to_string(scene.boundaryModels[i]->samplingMode); + const string particleFileName = FileSystem::normalizePath(cachePath + "/" + mesh_file_name + "_sb_" + StringTools::real2String(scene.particleRadius) + "_" + resStr + modeStr + ".bgeo"); + + // check MD5 if cache file is available + bool foundCacheFile = false; + + if (useCache) + foundCacheFile = FileSystem::fileExists(particleFileName); + + if (useCache && foundCacheFile && md5) { + PartioReaderWriter::readParticles(particleFileName, Vector3r::Zero(), Matrix3r::Identity(), 1.0, boundaryParticles); + LOG_INFO << "Loaded cached boundary sampling: " << particleFileName; + } + + if (!useCache || !foundCacheFile || !md5) { + if (!scene.sim2D) { + const auto samplePoissonDisk = [&]() { + LOG_INFO << "Poisson disk surface sampling of " << meshFileName; + START_TIMING("Poisson disk sampling"); + PoissonDiskSampling sampling; + sampling.sampleMesh(geo.numVertices(), geo.getVertices().data(), geo.numFaces(), geo.getFaces().data(), scene.particleRadius, 10, 1, boundaryParticles); + STOP_TIMING_AVG; + }; + const auto sampleRegularTriangle = [&]() { + LOG_INFO << "Regular triangle surface sampling of " << meshFileName; + START_TIMING("Regular triangle sampling"); + RegularTriangleSampling sampling; + sampling.sampleMesh(geo.numVertices(), geo.getVertices().data(), geo.numFaces(), geo.getFaces().data(), 1.5f * scene.particleRadius, boundaryParticles); + STOP_TIMING_AVG; + }; + if (SurfaceSamplingMode::PoissonDisk == scene.boundaryModels[i]->samplingMode) + samplePoissonDisk(); + else if (SurfaceSamplingMode::RegularTriangle == scene.boundaryModels[i]->samplingMode) + sampleRegularTriangle(); + else { + LOG_WARN << "Unknown surface sampling method: " << scene.boundaryModels[i]->samplingMode; + LOG_WARN << "Falling back to:"; + sampleRegularTriangle(); + } + } else { + LOG_INFO << "2D regular sampling of " << meshFileName; + START_TIMING("2D regular sampling"); + RegularSampling2D sampling; + sampling.sampleMesh(Matrix3r::Identity(), Vector3r::Zero(), + geo.numVertices(), geo.getVertices().data(), geo.numFaces(), + geo.getFaces().data(), 1.75f * scene.particleRadius, boundaryParticles); + STOP_TIMING_AVG; + } + + // Cache sampling + if (useCache && (FileSystem::makeDir(cachePath) == 0)) { + LOG_INFO << "Save particle sampling: " << particleFileName; + PartioReaderWriter::writeParticles(particleFileName, (unsigned int)boundaryParticles.size(), boundaryParticles.data(), nullptr, scene.particleRadius); + } + } + } + } + + Matrix3r rot = AngleAxisr(scene.boundaryModels[i]->angle, scene.boundaryModels[i]->axis).toRotationMatrix(); + Quaternionr q(rot); + rb->setPosition0(scene.boundaryModels[i]->translation); + rb->setPosition(scene.boundaryModels[i]->translation); + rb->setRotation0(q); + rb->setRotation(q); + if (scene.boundaryModels[i]->dynamic) { + rb->initBody(1.0, scene.boundaryModels[i]->translation, Vector3r(1, 1, 1), q); + } else { + rb->initBody(0.0, scene.boundaryModels[i]->translation, Vector3r(1, 1, 1), q); + } + + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { + BoundaryModel_Akinci2012* bm = new BoundaryModel_Akinci2012(); + bm->initModel(rb, static_cast(boundaryParticles.size()), &boundaryParticles[0]); + sim->addBoundaryModel(bm); + } else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) { + BoundaryModel_Koschier2017* bm = new BoundaryModel_Koschier2017(); + bm->initModel(rb); + sim->addBoundaryModel(bm); + SPH::TriangleMesh& mesh = rb->getGeometry(); + m_base->initDensityMap(mesh.getVertices(), mesh.getFaces(), scene.boundaryModels[i], md5, false, bm); + } else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Bender2019) { + BoundaryModel_Bender2019* bm = new BoundaryModel_Bender2019(); + bm->initModel(rb); + sim->addBoundaryModel(bm); + SPH::TriangleMesh& mesh = rb->getGeometry(); + m_base->initVolumeMap(mesh.getVertices(), mesh.getFaces(), scene.boundaryModels[i], md5, false, bm); + } + if (useCache && !md5) + FileSystem::writeMD5File(meshFileName, md5FileName); + rb->updateMeshTransformation(); + + } +} + +void DynamicBoundarySimulator::deferredInit() { + Simulation* sim = Simulation::getCurrent(); + sim->performNeighborhoodSearchSort(); + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { + m_base->updateBoundaryParticles(true); + Simulation::getCurrent()->updateBoundaryVolume(); + } else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) + m_base->updateDMVelocity(); + else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Bender2019) + m_base->updateVMVelocity(); + +#ifdef GPU_NEIGHBORHOOD_SEARCH + // copy the particle data to the GPU + sim->getNeighborhoodSearch()->update_point_sets(); +#endif +} + +void DynamicBoundarySimulator::timeStep() { + + // Do Update Here + updateBoundaryForces(); + Simulation* sim = Simulation::getCurrent(); + + START_TIMING("SimStep - Dynamic Boundary"); + Real h = TimeManager::getCurrent()->getTimeStepSize(); + const unsigned int nObjects = sim->numberOfBoundaryModels(); + for (unsigned int i = 0; i < nObjects; i++) { + BoundaryModel* bm = sim->getBoundaryModel(i); + RigidBodyObject* rbo = bm->getRigidBodyObject(); + if (rbo->isDynamic()) { + DynamicRigidBody* drb = dynamic_cast(rbo); + const Vector3r grav(sim->getVecValue(Simulation::GRAVITATION)); + drb->setVelocity(drb->getVelocity() + grav * h); + drb->setPosition(drb->getPosition() + drb->getVelocity() * h); + drb->updateMeshTransformation(); + } + } + STOP_TIMING_AVG; + + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + m_base->updateBoundaryParticles(false); + else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) + m_base->updateDMVelocity(); + else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Bender2019) + m_base->updateVMVelocity(); +} + +void DynamicBoundarySimulator::reset() { + Simulation* sim = Simulation::getCurrent(); + for (unsigned int i = 0; i < sim->numberOfBoundaryModels(); i++) { + BoundaryModel* bm = sim->getBoundaryModel(i); + if (bm->getRigidBodyObject()->isDynamic() || bm->getRigidBodyObject()->isAnimated()) { + ((DynamicRigidBody*)bm->getRigidBodyObject())->reset(); + } + } + + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + m_base->updateBoundaryParticles(true); + else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) + m_base->updateDMVelocity(); + else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Bender2019) + m_base->updateVMVelocity(); +} diff --git a/Simulator/DynamicBoundarySimulator.h b/Simulator/DynamicBoundarySimulator.h new file mode 100644 index 00000000..eeff6f18 --- /dev/null +++ b/Simulator/DynamicBoundarySimulator.h @@ -0,0 +1,31 @@ +#ifndef __DynamicBoundarySimulator_h__ +#define __DynamicBoundarySimualtor_h__ +#include "BoundarySimulator.h" +namespace SPH { + class SimulatorBase; + class TriangleMesh; + + // This class is used for the strong coupling method. See DynamicRigidBody. + class DynamicBoundarySimulator : public BoundarySimulator { + protected: + SimulatorBase* m_base; + + public: + DynamicBoundarySimulator(SimulatorBase* base); + virtual ~DynamicBoundarySimulator(); + + virtual void initBoundaryData(); + /** This function is called after the simulation scene is loaded and all + * parameters are initialized. While reading a scene file several parameters + * can change. The deferred init function should initialize all values which + * depend on these parameters. + */ + virtual void deferredInit(); + + virtual void timeStep(); + virtual void reset(); + }; + +} + +#endif diff --git a/Simulator/SimulatorBase.cpp b/Simulator/SimulatorBase.cpp index 04109681..fa1e9359 100644 --- a/Simulator/SimulatorBase.cpp +++ b/Simulator/SimulatorBase.cpp @@ -26,6 +26,7 @@ #include "StaticBoundarySimulator.h" #include "Exporter/ExporterBase.h" #include "SPlisHSPlasH/Utilities/MeshImport.h" +#include "DynamicBoundarySimulator.h" #if USE_NFD_FILE_DIALOG #include "extern/nfd/include/nfd.h" #endif @@ -430,7 +431,8 @@ void SimulatorBase::init(int argc, char **argv, const std::string &windowName) else { LOG_INFO << "Initialize dynamic boundary simulation"; - m_boundarySimulator = new PBDBoundarySimulator(this); + //m_boundarySimulator = new PBDBoundarySimulator(this); + m_boundarySimulator = new DynamicBoundarySimulator(this); } initExporters(); @@ -584,7 +586,6 @@ void SimulatorBase::deferredInit() void SimulatorBase::runSimulation() { deferredInit(); - if (getStateFile() != "") { // avoid that command line parameter is overwritten @@ -596,7 +597,6 @@ void SimulatorBase::runSimulation() m_doPause = false; } setCommandLineParameter(); - if (!m_useGUI) { const Real stopAt = getValue(SimulatorBase::STOP_AT); @@ -612,8 +612,9 @@ void SimulatorBase::runSimulation() break; } } - else + else { m_gui->run(); + } } void SimulatorBase::cleanup() @@ -834,7 +835,6 @@ void SimulatorBase::reset() #ifdef USE_DEBUG_TOOLS Simulation::getCurrent()->getDebugTools()->reset(); #endif - m_boundarySimulator->reset(); if (m_gui) m_gui->reset(); @@ -905,11 +905,12 @@ void SimulatorBase::timeStep() for (unsigned int i = 0; i < numSteps; i++) { START_TIMING("SimStep"); + Simulation::getCurrent()->getTimeStep()->step(); STOP_TIMING_AVG; - + START_TIMING("SimStepBoundary"); m_boundarySimulator->timeStep(); - + STOP_TIMING_AVG; step(); INCREASE_COUNTER("Time step size", TimeManager::getCurrent()->getTimeStepSize()); diff --git a/Simulator/main.cpp b/Simulator/main.cpp index 8dd5f33e..94c1dc46 100644 --- a/Simulator/main.cpp +++ b/Simulator/main.cpp @@ -30,7 +30,8 @@ int main( int argc, char **argv ) if (base->isStaticScene()) gui = new Simulator_GUI_imgui(base); else - gui = new PBD_Simulator_GUI_imgui(base, ((PBDBoundarySimulator*)base->getBoundarySimulator())->getPBDWrapper()); + //gui = new PBD_Simulator_GUI_imgui(base, ((PBDBoundarySimulator*)base->getBoundarySimulator())->getPBDWrapper()); + gui = new Simulator_GUI_imgui(base); base->setGui(gui); } base->run(); From 4a29ca68705b3b712a0f99f9e8dfc39c6e1fed42 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Sat, 1 Apr 2023 21:42:50 +0200 Subject: [PATCH 02/38] dynamic rigid body (cube only) --- SPlisHSPlasH/CMakeLists.txt | 1 + SPlisHSPlasH/DynamicRigidBody.h | 186 +++++++++++------- .../Utilities/SceneParameterObjects.cpp | 5 + .../Utilities/SceneParameterObjects.h | 6 +- Simulator/CMakeLists.txt | 2 + Simulator/DynamicBoundarySimulator.cpp | 26 +-- Simulator/DynamicBoundarySimulator.h | 2 + 7 files changed, 132 insertions(+), 96 deletions(-) diff --git a/SPlisHSPlasH/CMakeLists.txt b/SPlisHSPlasH/CMakeLists.txt index b0238866..1a123ba3 100644 --- a/SPlisHSPlasH/CMakeLists.txt +++ b/SPlisHSPlasH/CMakeLists.txt @@ -209,6 +209,7 @@ add_library(SPlisHSPlasH BoundaryModel_Bender2019.h BoundaryModel_Koschier2017.cpp BoundaryModel_Koschier2017.h + DynamicRigidBody.h Emitter.cpp Emitter.h EmitterSystem.cpp diff --git a/SPlisHSPlasH/DynamicRigidBody.h b/SPlisHSPlasH/DynamicRigidBody.h index d4f4a778..536cf8a3 100644 --- a/SPlisHSPlasH/DynamicRigidBody.h +++ b/SPlisHSPlasH/DynamicRigidBody.h @@ -28,6 +28,8 @@ namespace SPH { Vector3r m_v0; /** acceleration (by external forces) */ Vector3r m_a; + /* external forces*/ + Vector3r m_force; /** Inertia tensor in the principal axis system: \n * After the main axis transformation the inertia tensor is a diagonal matrix. @@ -61,10 +63,12 @@ namespace SPH { /** Angular velocity, defines rotation axis and velocity (magnitude of the vector) */ Vector3r m_omega; Vector3r m_omega0; + /* Angular accelaration*/ + Vector3r m_a_omega; /** external torque */ Vector3r m_torque; - Real m_restitutionCoeff; + // Real m_restitutionCoeff; Real m_frictionCoeff; // transformation required to transform a point to local space or vice vera @@ -98,6 +102,7 @@ namespace SPH { m_v.setZero(); m_v0.setZero(); m_a.setZero(); + m_force.setZero(); setInertiaTensor(inertiaTensor); m_q = rotation; @@ -113,40 +118,40 @@ namespace SPH { m_omega0.setZero(); m_torque.setZero(); - m_restitutionCoeff = static_cast(0.6); + // m_restitutionCoeff = static_cast(0.6); m_frictionCoeff = static_cast(0.2); updateMeshTransformation(); } - //void initBody(const Real density, const Vector3r &x, const Quaternionr &rotation, - // const Vector3r &scale = Vector3r(1.0, 1.0, 1.0)) - //{ - // m_mass = 1.0; - // m_inertiaTensor = Vector3r(1.0, 1.0, 1.0); - // m_x = x; - // m_x0 = x; - // m_lastX = x; - // m_oldX = x; - // m_v.setZero(); - // m_v0.setZero(); - // m_a.setZero(); - - // m_q = rotation; - // m_q0 = rotation; - // m_lastQ = rotation; - // m_oldQ = rotation; - // m_rot = m_q.matrix(); - // rotationUpdated(); - // m_omega.setZero(); - // m_omega0.setZero(); - // m_torque.setZero(); + void initBody(const Real density, const bool isDynamic, const Vector3r &position, const Quaternionr &rotation, + const Vector3r &scale = Vector3r(1.0, 1.0, 1.0)) + { + determineMassProperties(density, isDynamic, scale); + //m_inertiaTensor = Vector3r(1.0, 1.0, 1.0); + m_x = position; + m_x0 = position; + m_lastX = position; + m_oldX = position; + m_v.setZero(); + m_v0.setZero(); + m_a.setZero(); + m_force.setZero(); - // m_restitutionCoeff = static_cast(0.6); - // m_frictionCoeff = static_cast(0.2); + m_q = rotation; + m_q0 = rotation; + m_lastQ = rotation; + m_oldQ = rotation; + m_rot = m_q.matrix(); + rotationUpdated(); + m_omega.setZero(); + m_omega0.setZero(); + m_torque.setZero(); - // determineMassProperties(density); - // getGeometry().updateMeshTransformation(getPosition(), getRotationMatrix()); - //} + //m_restitutionCoeff = static_cast(0.6); + m_frictionCoeff = static_cast(0.2); + + updateMeshTransformation(); + } void reset() { @@ -167,6 +172,8 @@ namespace SPH { rotationUpdated(); updateMeshTransformation(); + + clearForceAndTorque(); } void updateInverseTransformation() @@ -187,6 +194,19 @@ namespace SPH { m_transformation_R_X_v1 = -m_transformation_R * getPosition() + m_transformation_v1; } + // Determine mass and inertia tensor + void determineMassProperties(const Real density, bool isDynamic, const Vector3r scale) { + // for now only consider cubiod which is scaled from a unit cube + if (isDynamic) { + setMass(density * scale.x() * scale.y() * scale.z()); + } else { + setMass(0.0); + } + Vector3r value = m_mass * Vector3r((scale.y() * scale.y() + scale.z() * scale.z()) / 12, (scale.x() * scale.x() + scale.z() * scale.z()) / 12, (scale.x() * scale.x() + scale.z() * scale.z()) / 12); + m_inertiaTensor = value; + m_inertiaTensorInverse = Vector3r(static_cast(1.0) / value[0], static_cast(1.0) / value[1], static_cast(1.0) / value[2]); + } + void rotationUpdated() { if (m_mass != 0.0) @@ -327,20 +347,20 @@ namespace SPH { m_oldX = pos; } - //FORCE_INLINE Vector3r &getPosition0() - //{ - // return m_x0; - //} + FORCE_INLINE Vector3r &getForce() + { + return m_force; + } - //FORCE_INLINE const Vector3r &getPosition0() const - //{ - // return m_x0; - //} + FORCE_INLINE const Vector3r &getForce() const + { + return m_force; + } - //FORCE_INLINE void setPosition0(const Vector3r &pos) - //{ - // m_x0 = pos; - //} + FORCE_INLINE void setForce(const Vector3r &force) + { + m_force = force; + } FORCE_INLINE Vector3r &getPositionInitial_MAT() { @@ -548,20 +568,20 @@ namespace SPH { m_rot = value; } - //FORCE_INLINE Vector3r &getAngularVelocity() - //{ - // return m_omega; - //} + FORCE_INLINE Vector3r &getAngularAccelaration() + { + return m_a_omega; + } - //FORCE_INLINE const Vector3r &getAngularVelocity() const - //{ - // return m_omega; - //} + FORCE_INLINE const Vector3r &getAngularAccelaration() const + { + return m_a_omega; + } - //FORCE_INLINE void setAngularVelocity(const Vector3r &value) - //{ - // m_omega = value; - //} + FORCE_INLINE void setAngularAccelaration(const Vector3r &value) + { + m_a_omega = value; + } FORCE_INLINE Vector3r &getAngularVelocity0() { @@ -593,15 +613,15 @@ namespace SPH { m_torque = value; } - FORCE_INLINE Real getRestitutionCoeff() const - { - return m_restitutionCoeff; - } + //FORCE_INLINE Real getRestitutionCoeff() const + //{ + // return m_restitutionCoeff; + //} - FORCE_INLINE void setRestitutionCoeff(Real val) - { - m_restitutionCoeff = val; - } + //FORCE_INLINE void setRestitutionCoeff(Real val) + //{ + // m_restitutionCoeff = val; + //} FORCE_INLINE Real getFrictionCoeff() const { @@ -664,21 +684,45 @@ namespace SPH { if (m_isAnimated) m_omega = v; } virtual void addForce(const Vector3r& f) { - const Real dt = SPH::TimeManager::getCurrent()->getTimeStepSize(); - m_v += (1.0 / m_mass) * f * dt; + m_force += f; + //const Real dt = SPH::TimeManager::getCurrent()->getTimeStepSize(); + //m_v += (1.0 / m_mass) * f * dt; } virtual void addTorque(const Vector3r& t) { - const Real dt = SPH::TimeManager::getCurrent()->getTimeStepSize(); - m_omega += m_inertiaTensorInverseW * t * dt; + m_torque += t; + //const Real dt = SPH::TimeManager::getCurrent()->getTimeStepSize(); + //m_omega += m_inertiaTensorInverseW * t * dt; + } + + void clearForceAndTorque() { + m_force.setZero(); + m_torque.setZero(); } - void animate() { + + void timeStep(DynamicBoundarySimulator* simulator) { + Simulation* sim = Simulation::getCurrent(); + const Vector3r gravAccel(sim->getVecValue(Simulation::GRAVITATION)); const Real dt = TimeManager::getCurrent()->getTimeStepSize(); + // Save old values + m_lastX = m_oldX; + m_oldX = m_x; + m_lastQ = m_oldQ; + m_oldQ = m_q; + // Semi implicit Euler + m_a = m_invMass * m_force + gravAccel; + m_v += m_a * dt; + m_v *= (static_cast(1.0) - simulator->m_dampingCoeff); m_x += m_v * dt; - Quaternionr angVelQ(0.0, m_omega[0], m_omega[1], m_omega[2]); - m_q.coeffs() += dt * 0.5 * (angVelQ * m_q).coeffs(); + m_a_omega = m_inertiaTensorInverseW * m_torque; + m_omega += m_a_omega * dt; + m_omega *= (static_cast(1.0) - simulator->m_dampingCoeff); + Quaternionr omegaTilde(0.0, m_omega[0], m_omega[1], m_omega[2]); + m_q.coeffs() += 0.5 * (omegaTilde * m_q).coeffs() * dt; m_q.normalize(); + rotationUpdated(); updateMeshTransformation(); + clearForceAndTorque(); } virtual const std::vector& getVertices() const { @@ -706,12 +750,6 @@ namespace SPH { m_geometry.updateNormals(); m_geometry.updateVertexNormals(); } - - //void reset() { - // m_x = m_x0; - // m_q = m_q0; - // updateMeshTransformation(); - //} }; } diff --git a/SPlisHSPlasH/Utilities/SceneParameterObjects.cpp b/SPlisHSPlasH/Utilities/SceneParameterObjects.cpp index 87431e97..e00c1683 100644 --- a/SPlisHSPlasH/Utilities/SceneParameterObjects.cpp +++ b/SPlisHSPlasH/Utilities/SceneParameterObjects.cpp @@ -318,6 +318,7 @@ int BoundaryParameterObject::BOUNDARY_MAP_THICKNESS = -1; int BoundaryParameterObject::BOUNDARY_MAP_RESOLUTION = -1; int BoundaryParameterObject::BOUNDARY_SAMPLING_MODE = -1; int BoundaryParameterObject::BOUNDARY_IS_ANIMATED = -1; +int BoundaryParameterObject::BOUNDARY_DENSITY = -1; void BoundaryParameterObject::initParameters() { @@ -380,4 +381,8 @@ void BoundaryParameterObject::initParameters() BOUNDARY_IS_ANIMATED = createBoolParameter("isAnimated", "Animated", &isAnimated); setGroup(BOUNDARY_IS_ANIMATED, "Boundary"); setDescription(BOUNDARY_IS_ANIMATED, "Defines if the body is animated (e.g. by a script)."); + + BOUNDARY_DENSITY = createNumericParameter("density", "Density", &density); + setGroup(BOUNDARY_DENSITY, "Boundary"); + setDescription(BOUNDARY_DENSITY, "Density of the rigid body."); } \ No newline at end of file diff --git a/SPlisHSPlasH/Utilities/SceneParameterObjects.h b/SPlisHSPlasH/Utilities/SceneParameterObjects.h index e2bba70e..34736c46 100644 --- a/SPlisHSPlasH/Utilities/SceneParameterObjects.h +++ b/SPlisHSPlasH/Utilities/SceneParameterObjects.h @@ -324,6 +324,7 @@ namespace Utilities Vector3r axis; Real angle; Vector3r scale; + Real density; bool dynamic; bool isWall; Eigen::Matrix color; @@ -342,6 +343,7 @@ namespace Utilities translation = Vector3r::Zero(); axis = Vector3r(1, 0, 0); angle = 0.0; + density = 1000.0; scale = Vector3r::Ones(); dynamic = false; isWall = false; @@ -357,7 +359,7 @@ namespace Utilities BoundaryParameterObject(std::string samplesFile_, std::string meshFile_, Vector3r translation_, Vector3r axis_, Real angle_, Vector3r scale_, bool dynamic_, bool isWall_, Eigen::Matrix color_, std::string mapFile_, bool mapInvert_, - Real mapThickness_, Eigen::Matrix mapResolution_, unsigned int samplingMode_, bool isAnimated_) + Real mapThickness_, Eigen::Matrix mapResolution_, unsigned int samplingMode_, bool isAnimated_, Real density_ = 1000.0) { samplesFile = samplesFile_; meshFile = meshFile_; @@ -365,6 +367,7 @@ namespace Utilities axis = axis_; angle = angle_; scale = scale_; + density = density_; dynamic = dynamic_; isWall = isWall_; color = color_; @@ -392,6 +395,7 @@ namespace Utilities static int BOUNDARY_MAP_RESOLUTION; static int BOUNDARY_SAMPLING_MODE; static int BOUNDARY_IS_ANIMATED; + static int BOUNDARY_DENSITY; virtual void initParameters(); }; diff --git a/Simulator/CMakeLists.txt b/Simulator/CMakeLists.txt index 2ff4af93..5288a230 100644 --- a/Simulator/CMakeLists.txt +++ b/Simulator/CMakeLists.txt @@ -87,6 +87,8 @@ add_library(SimulatorBase ${PROJECT_SOURCE_DIR}/Simulator/BoundarySimulator.h ${PROJECT_SOURCE_DIR}/Simulator/StaticBoundarySimulator.cpp ${PROJECT_SOURCE_DIR}/Simulator/StaticBoundarySimulator.h + ${PROJECT_SOURCE_DIR}/Simulator/DynamicBoundarySimulator.cpp + ${PROJECT_SOURCE_DIR}/Simulator/DynamicBoundarySimulator.h ${PROJECT_SOURCE_DIR}/Simulator/GUI/OpenGL/Simulator_OpenGL.cpp ${PROJECT_SOURCE_DIR}/Simulator/GUI/OpenGL/Simulator_OpenGL.h diff --git a/Simulator/DynamicBoundarySimulator.cpp b/Simulator/DynamicBoundarySimulator.cpp index 786e7d3b..92f6bad4 100644 --- a/Simulator/DynamicBoundarySimulator.cpp +++ b/Simulator/DynamicBoundarySimulator.cpp @@ -128,15 +128,8 @@ void DynamicBoundarySimulator::initBoundaryData() { Matrix3r rot = AngleAxisr(scene.boundaryModels[i]->angle, scene.boundaryModels[i]->axis).toRotationMatrix(); Quaternionr q(rot); - rb->setPosition0(scene.boundaryModels[i]->translation); - rb->setPosition(scene.boundaryModels[i]->translation); - rb->setRotation0(q); - rb->setRotation(q); - if (scene.boundaryModels[i]->dynamic) { - rb->initBody(1.0, scene.boundaryModels[i]->translation, Vector3r(1, 1, 1), q); - } else { - rb->initBody(0.0, scene.boundaryModels[i]->translation, Vector3r(1, 1, 1), q); - } + + rb->initBody(scene.boundaryModels[i]->density, scene.boundaryModels[i]->dynamic, scene.boundaryModels[i]->translation, q, scene.boundaryModels[i]->scale); if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { BoundaryModel_Akinci2012* bm = new BoundaryModel_Akinci2012(); @@ -180,27 +173,18 @@ void DynamicBoundarySimulator::deferredInit() { } void DynamicBoundarySimulator::timeStep() { - - // Do Update Here updateBoundaryForces(); Simulation* sim = Simulation::getCurrent(); - - START_TIMING("SimStep - Dynamic Boundary"); - Real h = TimeManager::getCurrent()->getTimeStepSize(); const unsigned int nObjects = sim->numberOfBoundaryModels(); - for (unsigned int i = 0; i < nObjects; i++) { + #pragma omp parallel for + for (int i = 0; i < nObjects; i++) { BoundaryModel* bm = sim->getBoundaryModel(i); RigidBodyObject* rbo = bm->getRigidBodyObject(); if (rbo->isDynamic()) { DynamicRigidBody* drb = dynamic_cast(rbo); - const Vector3r grav(sim->getVecValue(Simulation::GRAVITATION)); - drb->setVelocity(drb->getVelocity() + grav * h); - drb->setPosition(drb->getPosition() + drb->getVelocity() * h); - drb->updateMeshTransformation(); + drb->timeStep(this); } } - STOP_TIMING_AVG; - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) m_base->updateBoundaryParticles(false); else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) diff --git a/Simulator/DynamicBoundarySimulator.h b/Simulator/DynamicBoundarySimulator.h index eeff6f18..f0033f75 100644 --- a/Simulator/DynamicBoundarySimulator.h +++ b/Simulator/DynamicBoundarySimulator.h @@ -24,6 +24,8 @@ namespace SPH { virtual void timeStep(); virtual void reset(); + + Real m_dampingCoeff = 0.0; }; } From 706bd697949576f489ed8a6720d03d0221dba4d8 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Sun, 2 Apr 2023 18:37:23 +0200 Subject: [PATCH 03/38] added tab for boundary model --- Simulator/GUI/imgui/Simulator_GUI_imgui.cpp | 19 +++++++++++++++++++ Simulator/GUI/imgui/Simulator_GUI_imgui.h | 2 ++ 2 files changed, 21 insertions(+) diff --git a/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp b/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp index 293751b0..a38afc7e 100644 --- a/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp +++ b/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp @@ -30,6 +30,7 @@ Simulator_GUI_imgui::Simulator_GUI_imgui(SimulatorBase *base) : m_vsync = false; m_iniFound = false; m_showLogWindow = true; + m_currentBoundaryModel = 0; } Simulator_GUI_imgui::~Simulator_GUI_imgui(void) @@ -498,6 +499,24 @@ void Simulator_GUI_imgui::initSimulationParameterGUI() imguiParameters::createParameterObjectGUI((GenParam::ParameterObject*) model->getVorticityBase()); imguiParameters::createParameterObjectGUI((GenParam::ParameterObject*) model->getElasticityBase()); } + + // Enum for all boundary models + if (sim->numberOfBoundaryModels() > 0) { + BoundaryModel* model = sim->getBoundaryModel(m_currentBoundaryModel); + // Select boundary model + { + imguiParameters::imguiEnumParameter* param = new imguiParameters::imguiEnumParameter(); + param->description = "Select a boundary model to set its parameters below."; + param->label = "Current boundary model"; + param->readOnly = false; + for (unsigned int j = 0; j < sim->numberOfBoundaryModels(); j++) { + param->items.push_back(std::to_string(j)); + } + param->getFct = [this]() -> int { return m_currentBoundaryModel; }; + param->setFct = [this](int v) { m_currentBoundaryModel = v; initSimulationParameterGUI(); }; + imguiParameters::addParam("Boundary Model", "", param); + } + } initImguiParameters(); diff --git a/Simulator/GUI/imgui/Simulator_GUI_imgui.h b/Simulator/GUI/imgui/Simulator_GUI_imgui.h index c5dc7416..be34bed1 100644 --- a/Simulator/GUI/imgui/Simulator_GUI_imgui.h +++ b/Simulator/GUI/imgui/Simulator_GUI_imgui.h @@ -50,6 +50,8 @@ namespace SPH bool m_iniFound; LogWindow* m_logWindow; const float m_baseSize = 15.0f; + // gui for boundary + unsigned int m_currentBoundaryModel; std::vector>& getSelectedParticles() { return m_selectedParticles; } void initImgui(); From 9ffac690f05d362a46e0db47d1dcb4c1714b7159 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Tue, 4 Apr 2023 00:09:00 +0200 Subject: [PATCH 04/38] include bugs fix, more fields on GUI --- SPlisHSPlasH/DynamicRigidBody.h | 29 +++++++++++++++++---- Simulator/DynamicBoundarySimulator.cpp | 7 +++-- Simulator/GUI/imgui/Simulator_GUI_imgui.cpp | 22 +++++++++++++++- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/SPlisHSPlasH/DynamicRigidBody.h b/SPlisHSPlasH/DynamicRigidBody.h index 536cf8a3..d208e5e9 100644 --- a/SPlisHSPlasH/DynamicRigidBody.h +++ b/SPlisHSPlasH/DynamicRigidBody.h @@ -1,10 +1,11 @@ -#ifndef __StaticRigidBody_h__ -#define __StaticRigidBody_h__ +#ifndef __DynamicRigidBody_h__ +#define __DynamicRigidBody_h__ #include "Common.h" #include "RigidBodyObject.h" #include "TriangleMesh.h" #include "TimeManager.h" +#include "Simulation.h" namespace SPH { /** \brief This class stores the information of a dynamic rigid body which @@ -14,6 +15,8 @@ namespace SPH { class DynamicRigidBody : public RigidBodyObject { // Some fields are from PBD::RigidBody private: + Real m_density; + /** mass */ Real m_mass; /** inverse mass */ @@ -68,6 +71,9 @@ namespace SPH { /** external torque */ Vector3r m_torque; + // used to recompute mass properties, may dont need after implement the volume integrateion + Vector3r m_scale; + // Real m_restitutionCoeff; Real m_frictionCoeff; @@ -126,6 +132,8 @@ namespace SPH { void initBody(const Real density, const bool isDynamic, const Vector3r &position, const Quaternionr &rotation, const Vector3r &scale = Vector3r(1.0, 1.0, 1.0)) { + m_density = density; + m_scale = scale; determineMassProperties(density, isDynamic, scale); //m_inertiaTensor = Vector3r(1.0, 1.0, 1.0); m_x = position; @@ -302,6 +310,19 @@ namespace SPH { return m_invMass; } + FORCE_INLINE const Real& getDensity() const { + return m_density; + } + + FORCE_INLINE Real& getDensity() { + return m_density; + } + + FORCE_INLINE void setDensity(const Real& density) { + m_density = density; + determineMassProperties(density, isDynamic(), m_scale); + } + //FORCE_INLINE Vector3r &getPosition() //{ // return m_x; @@ -700,7 +721,7 @@ namespace SPH { m_torque.setZero(); } - void timeStep(DynamicBoundarySimulator* simulator) { + void timeStep() { Simulation* sim = Simulation::getCurrent(); const Vector3r gravAccel(sim->getVecValue(Simulation::GRAVITATION)); const Real dt = TimeManager::getCurrent()->getTimeStepSize(); @@ -712,11 +733,9 @@ namespace SPH { // Semi implicit Euler m_a = m_invMass * m_force + gravAccel; m_v += m_a * dt; - m_v *= (static_cast(1.0) - simulator->m_dampingCoeff); m_x += m_v * dt; m_a_omega = m_inertiaTensorInverseW * m_torque; m_omega += m_a_omega * dt; - m_omega *= (static_cast(1.0) - simulator->m_dampingCoeff); Quaternionr omegaTilde(0.0, m_omega[0], m_omega[1], m_omega[2]); m_q.coeffs() += 0.5 * (omegaTilde * m_q).coeffs() * dt; m_q.normalize(); diff --git a/Simulator/DynamicBoundarySimulator.cpp b/Simulator/DynamicBoundarySimulator.cpp index 92f6bad4..e66ef86a 100644 --- a/Simulator/DynamicBoundarySimulator.cpp +++ b/Simulator/DynamicBoundarySimulator.cpp @@ -182,8 +182,11 @@ void DynamicBoundarySimulator::timeStep() { RigidBodyObject* rbo = bm->getRigidBodyObject(); if (rbo->isDynamic()) { DynamicRigidBody* drb = dynamic_cast(rbo); - drb->timeStep(this); - } + drb->timeStep(); + // Apply damping + drb->setVelocity(drb->getVelocity() * (static_cast(1.0) - m_dampingCoeff)); + drb->setAngularVelocity(drb->getAngularVelocity() * (static_cast(1.0) - m_dampingCoeff)); + } } if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) m_base->updateBoundaryParticles(false); diff --git a/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp b/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp index a38afc7e..8d5f20d6 100644 --- a/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp +++ b/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp @@ -9,7 +9,7 @@ #include "Utilities/FileSystem.h" #include "Simulator/SceneConfiguration.h" #include "LogWindow.h" - +#include "SPlisHSPlasH/DynamicRigidBody.h" #include "imgui.h" #include "imgui_internal.h" #include "backends/imgui_impl_glfw.h" @@ -19,6 +19,7 @@ #include + using namespace SPH; using namespace Utilities; @@ -516,6 +517,25 @@ void Simulator_GUI_imgui::initSimulationParameterGUI() param->setFct = [this](int v) { m_currentBoundaryModel = v; initSimulationParameterGUI(); }; imguiParameters::addParam("Boundary Model", "", param); } + + // Show basic properties + { + imguiParameters::imguiBoolParameter* isDynamic = new imguiParameters::imguiBoolParameter(); + isDynamic->description = "Density of the rigid body"; + isDynamic->label = "Dynamic"; + isDynamic->readOnly = true; + isDynamic->getFct = [model]()->Real {return model->getRigidBodyObject()->isDynamic(); }; + imguiParameters::addParam("Boundary Model", "Property", isDynamic); + if (!this->getSimulatorBase()->isStaticScene()) { + DynamicRigidBody* drb = dynamic_cast(model->getRigidBodyObject()); + imguiParameters::imguiNumericParameter* density = new imguiParameters::imguiNumericParameter(); + density->description = "Density of the rigid body"; + density->label = "Density"; + density->getFct = [drb]() -> Real {return drb->getDensity(); }; + density->setFct = [drb](Real v) {drb->setDensity(v); }; + imguiParameters::addParam("Boundary Model", "Property", density); + } + } } initImguiParameters(); From f025d7dbbee21e93cee678cc75bffe77fc27e7ea Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Sun, 9 Apr 2023 16:39:53 +0200 Subject: [PATCH 05/38] more properties on GUI --- SPlisHSPlasH/DynamicRigidBody.h | 88 +------------------- Simulator/GUI/imgui/Simulator_GUI_imgui.cpp | 90 +++++++++++++-------- Simulator/main.cpp | 10 +-- 3 files changed, 66 insertions(+), 122 deletions(-) diff --git a/SPlisHSPlasH/DynamicRigidBody.h b/SPlisHSPlasH/DynamicRigidBody.h index d208e5e9..34485c10 100644 --- a/SPlisHSPlasH/DynamicRigidBody.h +++ b/SPlisHSPlasH/DynamicRigidBody.h @@ -135,7 +135,6 @@ namespace SPH { m_density = density; m_scale = scale; determineMassProperties(density, isDynamic, scale); - //m_inertiaTensor = Vector3r(1.0, 1.0, 1.0); m_x = position; m_x0 = position; m_lastX = position; @@ -292,10 +291,10 @@ namespace SPH { const Vector3r &getTransformationV2() { return m_transformation_v2; } const Vector3r &getTransformationRXV1() { return m_transformation_R_X_v1; } - //FORCE_INLINE Real &getMass() - //{ - // return m_mass; - //} + FORCE_INLINE const Vector3r& getScale() { + return m_scale; + } + FORCE_INLINE void setMass(const Real &value) { m_mass = value; @@ -323,21 +322,6 @@ namespace SPH { determineMassProperties(density, isDynamic(), m_scale); } - //FORCE_INLINE Vector3r &getPosition() - //{ - // return m_x; - //} - - //FORCE_INLINE const Vector3r &getPosition() const - //{ - // return m_x; - //} - - //FORCE_INLINE void setPosition(const Vector3r &pos) - //{ - // m_x = pos; - //} - FORCE_INLINE Vector3r &getLastPosition() { return m_lastX; @@ -398,36 +382,6 @@ namespace SPH { m_x0_mat = pos; } - //FORCE_INLINE Vector3r &getVelocity() - //{ - // return m_v; - //} - - //FORCE_INLINE const Vector3r &getVelocity() const - //{ - // return m_v; - //} - -/* FORCE_INLINE void setVelocity(const Vector3r &value) - { - m_v = value; - } */ - - //FORCE_INLINE Vector3r &getVelocity0() - //{ - // return m_v0; - //} - - //FORCE_INLINE const Vector3r &getVelocity0() const - //{ - // return m_v0; - //} - - //FORCE_INLINE void setVelocity0(const Vector3r &value) - //{ - // m_v0 = value; - //} - FORCE_INLINE Vector3r &getAcceleration() { return m_a; @@ -484,21 +438,6 @@ namespace SPH { m_inertiaTensorInverseW = value; } - //FORCE_INLINE Quaternionr &getRotation() - //{ - // return m_q; - //} - - //FORCE_INLINE const Quaternionr &getRotation() const - //{ - // return m_q; - //} - - //FORCE_INLINE void setRotation(const Quaternionr &value) - //{ - // m_q = value; - //} - FORCE_INLINE Quaternionr &getLastRotation() { return m_lastQ; @@ -529,21 +468,6 @@ namespace SPH { m_oldQ = value; } - //FORCE_INLINE Quaternionr &getRotation0() - //{ - // return m_q0; - //} - - //FORCE_INLINE const Quaternionr &getRotation0() const - //{ - // return m_q0; - //} - - //FORCE_INLINE void setRotation0(const Quaternionr &value) - //{ - // m_q0 = value; - //} - FORCE_INLINE Quaternionr &getRotationMAT() { return m_q_mat; @@ -706,14 +630,10 @@ namespace SPH { } virtual void addForce(const Vector3r& f) { m_force += f; - //const Real dt = SPH::TimeManager::getCurrent()->getTimeStepSize(); - //m_v += (1.0 / m_mass) * f * dt; } virtual void addTorque(const Vector3r& t) { m_torque += t; - //const Real dt = SPH::TimeManager::getCurrent()->getTimeStepSize(); - //m_omega += m_inertiaTensorInverseW * t * dt; } void clearForceAndTorque() { diff --git a/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp b/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp index 8d5f20d6..d9fc9fe8 100644 --- a/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp +++ b/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp @@ -501,43 +501,67 @@ void Simulator_GUI_imgui::initSimulationParameterGUI() imguiParameters::createParameterObjectGUI((GenParam::ParameterObject*) model->getElasticityBase()); } - // Enum for all boundary models - if (sim->numberOfBoundaryModels() > 0) { - BoundaryModel* model = sim->getBoundaryModel(m_currentBoundaryModel); - // Select boundary model - { - imguiParameters::imguiEnumParameter* param = new imguiParameters::imguiEnumParameter(); - param->description = "Select a boundary model to set its parameters below."; - param->label = "Current boundary model"; - param->readOnly = false; - for (unsigned int j = 0; j < sim->numberOfBoundaryModels(); j++) { - param->items.push_back(std::to_string(j)); + if (!m_simulatorBase->isStaticScene()) { + // Enum for all boundary models + if (sim->numberOfBoundaryModels() > 0) { + BoundaryModel* model = sim->getBoundaryModel(m_currentBoundaryModel); + // Select boundary model + { + imguiParameters::imguiEnumParameter* param = new imguiParameters::imguiEnumParameter(); + param->description = "Select a boundary model to set its parameters below."; + param->label = "Current boundary model"; + param->readOnly = false; + for (unsigned int j = 0; j < sim->numberOfBoundaryModels(); j++) { + param->items.push_back(std::to_string(j)); + } + param->getFct = [this]() -> int { return m_currentBoundaryModel; }; + param->setFct = [this](int v) { m_currentBoundaryModel = v; initSimulationParameterGUI(); }; + imguiParameters::addParam("Boundary Model", "", param); } - param->getFct = [this]() -> int { return m_currentBoundaryModel; }; - param->setFct = [this](int v) { m_currentBoundaryModel = v; initSimulationParameterGUI(); }; - imguiParameters::addParam("Boundary Model", "", param); - } - - // Show basic properties - { - imguiParameters::imguiBoolParameter* isDynamic = new imguiParameters::imguiBoolParameter(); - isDynamic->description = "Density of the rigid body"; - isDynamic->label = "Dynamic"; - isDynamic->readOnly = true; - isDynamic->getFct = [model]()->Real {return model->getRigidBodyObject()->isDynamic(); }; - imguiParameters::addParam("Boundary Model", "Property", isDynamic); - if (!this->getSimulatorBase()->isStaticScene()) { - DynamicRigidBody* drb = dynamic_cast(model->getRigidBodyObject()); - imguiParameters::imguiNumericParameter* density = new imguiParameters::imguiNumericParameter(); - density->description = "Density of the rigid body"; - density->label = "Density"; - density->getFct = [drb]() -> Real {return drb->getDensity(); }; - density->setFct = [drb](Real v) {drb->setDensity(v); }; - imguiParameters::addParam("Boundary Model", "Property", density); + + // Show basic properties + { + imguiParameters::imguiBoolParameter* isDynamic = new imguiParameters::imguiBoolParameter(); + isDynamic->description = "Density of the rigid body"; + isDynamic->label = "Dynamic"; + isDynamic->readOnly = true; + isDynamic->getFct = [model]()->Real {return model->getRigidBodyObject()->isDynamic(); }; + imguiParameters::addParam("Boundary Model", "Property", isDynamic); + + if (model->getRigidBodyObject()->isDynamic()) { + DynamicRigidBody* drb = dynamic_cast(model->getRigidBodyObject()); + imguiParameters::imguiNumericParameter* density = new imguiParameters::imguiNumericParameter(); + density->description = "Density of the rigid body"; + density->label = "Density"; + density->getFct = [drb]() -> Real {return drb->getDensity(); }; + density->setFct = [drb](Real v) {drb->setDensity(v); }; + imguiParameters::addParam("Boundary Model", "Property", density); + + imguiParameters::imguiVec3rParameter* scale = new imguiParameters::imguiVec3rParameter(); + scale->description = "Scale of the rigid body"; + scale->label = "Scale"; + scale->getFct = [drb]()-> Vector3r {return drb->getScale(); }; + scale->readOnly = true; + imguiParameters::addParam("Boundary Model", "Property", scale); + + imguiParameters::imguiVec3rParameter* velocity = new imguiParameters::imguiVec3rParameter(); + velocity->description = "Velocity of the rigid body"; + velocity->label = "Velocity"; + velocity->getFct = [drb]()-> Vector3r {return drb->getVelocity(); }; + velocity->readOnly = true; + imguiParameters::addParam("Boundary Model", "Property", velocity); + + imguiParameters::imguiVec3rParameter* angularVelocity = new imguiParameters::imguiVec3rParameter(); + angularVelocity->description = "Angular Velocity of the rigid body"; + angularVelocity->label = "Angular velocity"; + angularVelocity->getFct = [drb]()-> Vector3r {return drb->getAngularVelocity(); }; + angularVelocity->readOnly = true; + imguiParameters::addParam("Boundary Model", "Property", angularVelocity); + } } } } - + initImguiParameters(); if (m_simulatorBase) diff --git a/Simulator/main.cpp b/Simulator/main.cpp index 94c1dc46..f6b36d40 100644 --- a/Simulator/main.cpp +++ b/Simulator/main.cpp @@ -27,11 +27,11 @@ int main( int argc, char **argv ) if (base->getUseGUI()) { - if (base->isStaticScene()) - gui = new Simulator_GUI_imgui(base); - else - //gui = new PBD_Simulator_GUI_imgui(base, ((PBDBoundarySimulator*)base->getBoundarySimulator())->getPBDWrapper()); - gui = new Simulator_GUI_imgui(base); + //if (base->isStaticScene()) + // gui = new Simulator_GUI_imgui(base); + //else + // gui = new PBD_Simulator_GUI_imgui(base, ((PBDBoundarySimulator*)base->getBoundarySimulator())->getPBDWrapper()); + gui = new Simulator_GUI_imgui(base); base->setGui(gui); } base->run(); From 3064ad19d06f3c4e1af33106ea5ad802887bea54 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Thu, 20 Apr 2023 17:52:48 +0200 Subject: [PATCH 06/38] change update of angular accelaration --- SPlisHSPlasH/DynamicRigidBody.h | 14 ++------------ SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 3 +-- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/SPlisHSPlasH/DynamicRigidBody.h b/SPlisHSPlasH/DynamicRigidBody.h index 34485c10..25b5c682 100644 --- a/SPlisHSPlasH/DynamicRigidBody.h +++ b/SPlisHSPlasH/DynamicRigidBody.h @@ -558,16 +558,6 @@ namespace SPH { m_torque = value; } - //FORCE_INLINE Real getRestitutionCoeff() const - //{ - // return m_restitutionCoeff; - //} - - //FORCE_INLINE void setRestitutionCoeff(Real val) - //{ - // m_restitutionCoeff = val; - //} - FORCE_INLINE Real getFrictionCoeff() const { return m_frictionCoeff; @@ -650,11 +640,11 @@ namespace SPH { m_oldX = m_x; m_lastQ = m_oldQ; m_oldQ = m_q; - // Semi implicit Euler + // Semi-implicit Euler m_a = m_invMass * m_force + gravAccel; m_v += m_a * dt; m_x += m_v * dt; - m_a_omega = m_inertiaTensorInverseW * m_torque; + m_a_omega = m_inertiaTensorInverseW * (m_torque - (m_omega.cross(m_inertiaTensorW * m_omega))); m_omega += m_a_omega * dt; Quaternionr omegaTilde(0.0, m_omega[0], m_omega[1], m_omega[2]); m_q.coeffs() += 0.5 * (omegaTilde * m_q).coeffs() * dt; diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index 6fd56500..0aea917d 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -9,7 +9,6 @@ #include "SPlisHSPlasH/BoundaryModel_Koschier2017.h" #include "SPlisHSPlasH/BoundaryModel_Bender2019.h" - using namespace SPH; using namespace std; using namespace GenParam; @@ -171,7 +170,7 @@ void TimeStepWCSPH::computePressureAccels(const unsigned int fluidModelIndex) const Real dpi = m_simulationData.getPressure(fluidModelIndex, i) / (density_i*density_i); ////////////////////////////////////////////////////////////////////////// - // Fluid + // Fluid ////////////////////////////////////////////////////////////////////////// forall_fluid_neighbors( // Pressure From 30dc72332bf7d164c2c9a5cd4322115b97702482 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Fri, 21 Apr 2023 17:36:16 +0200 Subject: [PATCH 07/38] RigidBodyParticleExporter --- SPlisHSPlasH/BoundaryModel_Akinci2012.cpp | 31 +++ SPlisHSPlasH/BoundaryModel_Akinci2012.h | 8 + Simulator/CMakeLists.txt | 2 + .../RigidBodyParticleExporter_VTK.cpp | 245 ++++++++++++++++++ .../Exporter/RigidBodyParticleExporter_VTK.h | 40 +++ Simulator/ExporterRegistration.cpp | 2 + 6 files changed, 328 insertions(+) create mode 100644 Simulator/Exporter/RigidBodyParticleExporter_VTK.cpp create mode 100644 Simulator/Exporter/RigidBodyParticleExporter_VTK.h diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp index 46ec925b..9ff67f5e 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp @@ -18,6 +18,12 @@ BoundaryModel_Akinci2012::BoundaryModel_Akinci2012() : { m_sorted = false; m_pointSetIndex = 0; + + addField({ "position", FieldType::Vector3, [&](const unsigned int i) -> Real* { return &getPosition(i)[0]; }, true }); + addField({ "position0", FieldType::Vector3, [&](const unsigned int i) -> Real* { return &getPosition0(i)[0]; } }); + addField({ "velocity", FieldType::Vector3, [&](const unsigned int i) -> Real* { return &getVelocity(i)[0]; }, true }); + addField({ "volume", FieldType::Scalar, [&](const unsigned int i) -> Real* { return &getVolume(i); }, true }); + //addField({ "density", FieldType::Scalar, [&](const unsigned int i) -> Real* { return &getDensity(i); }, false }); } BoundaryModel_Akinci2012::~BoundaryModel_Akinci2012(void) @@ -45,6 +51,31 @@ void BoundaryModel_Akinci2012::reset() } } +void SPH::BoundaryModel_Akinci2012::addField(const FieldDescription& field) { + m_fields.push_back(field); + std::sort(m_fields.begin(), m_fields.end(), [](FieldDescription& i, FieldDescription& j) -> bool { return (i.name < j.name); }); +} + +const FieldDescription& SPH::BoundaryModel_Akinci2012::getField(const std::string& name) { + unsigned int index = 0; + for (auto i = 0; i < m_fields.size(); i++) { + if (m_fields[i].name == name) { + index = i; + break; + } + } + return m_fields[index]; +} + +void SPH::BoundaryModel_Akinci2012::removeFieldByName(const std::string& fieldName) { + for (auto it = m_fields.begin(); it != m_fields.end(); it++) { + if (it->name == fieldName) { + m_fields.erase(it); + break; + } + } +} + void BoundaryModel_Akinci2012::computeBoundaryVolume() { Simulation *sim = Simulation::getCurrent(); diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.h b/SPlisHSPlasH/BoundaryModel_Akinci2012.h index d0ee744b..8ba97354 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.h +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.h @@ -6,6 +6,7 @@ #include "BoundaryModel.h" #include "SPHKernels.h" +#include "FluidModel.h" namespace SPH @@ -33,8 +34,15 @@ namespace SPH std::vector m_x; std::vector m_v; std::vector m_V; + std::vector m_fields; public: + void addField(const FieldDescription& field); + const std::vector& getFields() {return m_fields;} + const FieldDescription& getField(const unsigned int i) {return m_fields[i];} + const FieldDescription& getField(const std::string& name); + const unsigned int numberOfFields() {return static_cast(m_fields.size());} + void removeFieldByName(const std::string& fieldName); unsigned int numberOfParticles() const { return static_cast(m_x.size()); } unsigned int getPointSetIndex() const { return m_pointSetIndex; } bool isSorted() const { return m_sorted; } diff --git a/Simulator/CMakeLists.txt b/Simulator/CMakeLists.txt index 5288a230..f354de07 100644 --- a/Simulator/CMakeLists.txt +++ b/Simulator/CMakeLists.txt @@ -56,6 +56,7 @@ set(EXPORTER_SOURCE_FILES ${PROJECT_SOURCE_DIR}/Simulator/Exporter/RigidBodyExporter_OBJ.cpp ${PROJECT_SOURCE_DIR}/Simulator/Exporter/RigidBodyExporter_PLY.cpp ${PROJECT_SOURCE_DIR}/Simulator/Exporter/RigidBodyExporter_VTK.cpp + ${PROJECT_SOURCE_DIR}/Simulator/Exporter/RigidBodyParticleExporter_VTK.cpp ) set(EXPORTER_HEADER_FILES @@ -66,6 +67,7 @@ set(EXPORTER_HEADER_FILES ${PROJECT_SOURCE_DIR}/Simulator/Exporter/RigidBodyExporter_OBJ.h ${PROJECT_SOURCE_DIR}/Simulator/Exporter/RigidBodyExporter_PLY.h ${PROJECT_SOURCE_DIR}/Simulator/Exporter/RigidBodyExporter_VTK.h + ${PROJECT_SOURCE_DIR}/Simulator/Exporter/RigidBodyParticleExporter_VTK.h ) if (USE_EMBEDDED_PYTHON) diff --git a/Simulator/Exporter/RigidBodyParticleExporter_VTK.cpp b/Simulator/Exporter/RigidBodyParticleExporter_VTK.cpp new file mode 100644 index 00000000..85e22d53 --- /dev/null +++ b/Simulator/Exporter/RigidBodyParticleExporter_VTK.cpp @@ -0,0 +1,245 @@ +#include "RigidBodyParticleExporter_VTK.h" +#include +#include +#include "SPlisHSPlasH/Simulation.h" +#include +using namespace SPH; +using namespace Utilities; + +RigidBodyParticleExporter_VTK::RigidBodyParticleExporter_VTK(SimulatorBase* base) : ExporterBase(base) { + m_isFirstFrame = true; +} + +RigidBodyParticleExporter_VTK::~RigidBodyParticleExporter_VTK(void) {} + +void RigidBodyParticleExporter_VTK::init(const std::string& outputPath) { + m_exportPath = FileSystem::normalizePath(outputPath + "/vtk"); +} + +void RigidBodyParticleExporter_VTK::step(const unsigned int frame) { + if (!m_active) { + return; + } + writeRigidBodies(frame); +} + +void RigidBodyParticleExporter_VTK::reset() { + m_isFirstFrame = true; +} + +void RigidBodyParticleExporter_VTK::setActive(const bool active) { + ExporterBase::setActive(active); + if (m_active) { + FileSystem::makeDirs(m_exportPath); + } +} + +void RigidBodyParticleExporter_VTK::writeRigidBodies(const unsigned int frame) { + Simulation* sim = Simulation::getCurrent(); + const unsigned int nBoundaryModels = sim->numberOfBoundaryModels(); + + // check if we have a static model + bool isStatic = true; + for (unsigned int i = 0; i < sim->numberOfBoundaryModels(); i++) { + BoundaryModel* bm = sim->getBoundaryModel(i); + if (bm->getRigidBodyObject()->isDynamic() || bm->getRigidBodyObject()->isAnimated()) { + isStatic = false; + break; + } + } + +#ifdef USE_DOUBLE + const char* real_str = " double\n"; +#else + const char* real_str = " float\n"; +#endif + + if (m_isFirstFrame || !isStatic) { + for (unsigned int i = 0; i < sim->numberOfBoundaryModels(); i++) { + std::string fileName = "rb_particle_data_"; + fileName = fileName + std::to_string(i) + "_" + std::to_string(frame) + ".vtk"; + std::string exportFileName = FileSystem::normalizePath(m_exportPath + "/" + fileName); + + // Open the file + std::ofstream outfile(exportFileName, std::ios::binary); + if (!outfile) { + LOG_WARN << "Cannot open a file to save VTK mesh."; + return; + } + + // Header + outfile << "# vtk DataFile Version 4.2\n"; + outfile << "SPlisHSPlasH rigid body particle data\n"; + outfile << "BINARY\n"; + outfile << "DATASET UNSTRUCTURED_GRID\n"; + + // add attributes + m_attributes.clear(); + StringTools::tokenize(m_base->getValue(SimulatorBase::PARTICLE_EXPORT_ATTRIBUTES), m_attributes, ";"); + + ////////////////////////////////////////////////////////////////////////// + // positions and ids exported anyways + m_attributes.erase( + std::remove_if(m_attributes.begin(), m_attributes.end(), [](const std::string& s) { return (s == "position" || s == "id"); }), + m_attributes.end()); + + BoundaryModel_Akinci2012* model = dynamic_cast(sim->getBoundaryModel(i)); + if (model != nullptr) { + Simulation* sim = Simulation::getCurrent(); + const unsigned int nFluids = sim->numberOfFluidModels(); + + const unsigned int numBoundaryParticles = model->numberOfParticles(); + + std::vector positions; + positions.reserve(numBoundaryParticles); + std::vector cells; + cells.reserve(numBoundaryParticles); + std::vector cellTypes; + cellTypes.reserve(numBoundaryParticles); + std::vector attrData; + attrData.reserve(numBoundaryParticles); + + unsigned int counter = 0; + for (unsigned int i = 0; i < numBoundaryParticles; i++) { + + + ////////////////////////////////////////////////////////////////////////// + // export position attribute as POINTS + { + positions.push_back(model->getPosition(i)); + // swap endianess + for (unsigned int c = 0; c < 3; c++) + swapByteOrder(&positions[positions.size() - 1][c]); + } + + ////////////////////////////////////////////////////////////////////////// + // export particle IDs as CELLS + { + unsigned int nodes_per_cell_swapped = 1; + swapByteOrder(&nodes_per_cell_swapped); + unsigned int idSwapped = counter++; + swapByteOrder(&idSwapped); + cells.push_back({ nodes_per_cell_swapped, idSwapped }); + } + ////////////////////////////////////////////////////////////////////////// + // export cell types + { + // the type of a particle cell is always 1 + int cellTypeSwapped = 1; + swapByteOrder(&cellTypeSwapped); + cellTypes.push_back(cellTypeSwapped); + } + + ////////////////////////////////////////////////////////////////////////// + // write additional attributes as per-particle data + //{ + // unsigned int id = model->getParticleId(i); + // swapByteOrder(&id); + // attrData.push_back(id); + //} + } + + //createParticleFile(fileName, model); + + if (outfile.good()) { + // export to vtk + const unsigned int nPoints = (unsigned int)positions.size(); + outfile << "POINTS " << nPoints << real_str; + outfile.write(reinterpret_cast(positions[0].data()), 3 * nPoints * sizeof(Real)); + outfile << "\n"; + + // particles are cells with one element and the index of the particle + outfile << "CELLS " << nPoints << " " << 2 * nPoints << "\n"; + outfile.write(reinterpret_cast(cells[0].data()), 2 * nPoints * sizeof(unsigned int)); + outfile << "\n"; + + outfile << "CELL_TYPES " << nPoints << "\n"; + outfile.write(reinterpret_cast(cellTypes.data()), nPoints * sizeof(int)); + outfile << "\n"; + + outfile << "POINT_DATA " << nPoints << "\n"; + // write IDs + outfile << "SCALARS id unsigned_int 1\n"; + outfile << "LOOKUP_TABLE id_table\n"; + outfile.write(reinterpret_cast(attrData.data()), nPoints * sizeof(unsigned int)); + outfile << "\n"; + + + + ////////////////////////////////////////////////////////////////////////// + // per point fields (all attributes except for positions) + const auto numFields = m_attributes.size(); + outfile << "FIELD FieldData " << std::to_string(numFields) << "\n"; + + // iterate over attributes. + for (const std::string& a : m_attributes) { + const FieldDescription& field = model->getField(a); + + std::string attrNameVTK; + std::regex_replace(std::back_inserter(attrNameVTK), a.begin(), a.end(), std::regex("\\s+"), "_"); + + if (field.type == FieldType::Scalar) { + // write header information + outfile << attrNameVTK << " 1 " << nPoints << real_str; + + // copy data + std::vector attrData; + attrData.reserve(nPoints); + for (unsigned int i = 0u; i < numBoundaryParticles; i++) { + Real val = *((Real*)field.getFct(i)); + swapByteOrder(&val); // swap endianess + attrData.emplace_back(val); + } + + // export to vtk + outfile.write(reinterpret_cast(attrData.data()), nPoints * sizeof(Real)); + } else if (field.type == FieldType::Vector3) { + // write header information + outfile << attrNameVTK << " 3 " << nPoints << real_str; + + // copy from partio data + std::vector attrData; + attrData.reserve(nPoints); + for (unsigned int i = 0u; i < numBoundaryParticles; i++) { + Vector3r val((Real*)field.getFct(i)); + for (unsigned int c = 0; c < 3; c++) + swapByteOrder(&val[c]); // swap endianess + attrData.emplace_back(val); + } + // export to vtk + outfile.write(reinterpret_cast(attrData[0].data()), 3 * nPoints * sizeof(Real)); + } else if (field.type == FieldType::UInt) { + // write header information + outfile << attrNameVTK << " 1 " << nPoints << " unsigned_int\n"; + + // copy data + std::vector attrData; + attrData.reserve(nPoints); + for (unsigned int i = 0u; i < numBoundaryParticles; i++) { + unsigned int val = *((unsigned int*)field.getFct(i)); + swapByteOrder(&val); // swap endianess + attrData.emplace_back(val); + } + // export to vtk + outfile.write(reinterpret_cast(attrData.data()), nPoints * sizeof(unsigned int)); + } + // TODO support other field types + else { + LOG_WARN << "Skipping attribute " << a << ", because it is of unsupported type\n"; + continue; + } + // end of block + outfile << "\n"; + + } + outfile.close(); + } + + } + + } + + m_isFirstFrame = false; + + } +} \ No newline at end of file diff --git a/Simulator/Exporter/RigidBodyParticleExporter_VTK.h b/Simulator/Exporter/RigidBodyParticleExporter_VTK.h new file mode 100644 index 00000000..a523f690 --- /dev/null +++ b/Simulator/Exporter/RigidBodyParticleExporter_VTK.h @@ -0,0 +1,40 @@ +#ifndef __RigidBodyParticleExporter_VTK_h__ +#define __RigidBodyParticleExporter_VTK_h__ + +#include "ExporterBase.h" +#include "SPlisHSPlasH/FluidModel.h" + +namespace SPH { + /** \brief Rigid body particle exporter for the VTK format. + */ + class RigidBodyParticleExporter_VTK : public ExporterBase { + protected: + bool m_isFirstFrame; + std::vector m_attributes; + std::string m_exportPath; + + void writeRigidBodies(const unsigned int frame); + + // VTK expects big endian + template + inline void swapByteOrder(T* v) { + constexpr size_t n = sizeof(T); + uint8_t* bytes = reinterpret_cast(v); + for (unsigned int c = 0u; c < n / 2; c++) + std::swap(bytes[c], bytes[n - c - 1]); + } + + public: + RigidBodyParticleExporter_VTK(SimulatorBase* base); + RigidBodyParticleExporter_VTK(const RigidBodyParticleExporter_VTK&) = delete; + RigidBodyParticleExporter_VTK& operator=(const RigidBodyParticleExporter_VTK&) = delete; + virtual ~RigidBodyParticleExporter_VTK(void); + + virtual void init(const std::string& outputPath); + virtual void step(const unsigned int frame); + virtual void reset(); + virtual void setActive(const bool active); + }; +} + +#endif diff --git a/Simulator/ExporterRegistration.cpp b/Simulator/ExporterRegistration.cpp index 34327646..d726a8e0 100644 --- a/Simulator/ExporterRegistration.cpp +++ b/Simulator/ExporterRegistration.cpp @@ -6,6 +6,7 @@ #include "Exporter/RigidBodyExporter_OBJ.h" #include "Exporter/RigidBodyExporter_PLY.h" #include "Exporter/RigidBodyExporter_VTK.h" +#include "Exporter/RigidBodyParticleExporter_VTK.h" using namespace SPH; @@ -18,4 +19,5 @@ void SimulatorBase::createExporters() addRigidBodyExporter("enableRigidBodyOBJExport", "Rigid Body OBJ Exporter", "Enable/disable rigid body OBJ export.", new RigidBodyExporter_OBJ(this)); addRigidBodyExporter("enableRigidBodyPLYExport", "Rigid Body PLY Exporter", "Enable/disable rigid body PLY export.", new RigidBodyExporter_PLY(this)); addRigidBodyExporter("enableRigidBodyVTKExport", "Rigid Body VTK Exporter", "Enable/disable rigid body VTK export.", new RigidBodyExporter_VTK(this)); + addRigidBodyExporter("enableRigidBodyParticleVTKExport", "Rigid Body Particle VTK Exporter", "Enable/disable rigid body particle VTK export.", new RigidBodyParticleExporter_VTK(this)); } \ No newline at end of file From 008c921a287ac98cf490518647f30af023fe6ac4 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Mon, 24 Apr 2023 16:10:27 +0200 Subject: [PATCH 08/38] Strong Couping Update for WCSPH --- SPlisHSPlasH/Simulation.h | 6 +++ SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 6 +++ Simulator/DynamicBoundarySimulator.cpp | 58 ++++++++++++++++++-------- Simulator/DynamicBoundarySimulator.h | 1 + 4 files changed, 53 insertions(+), 18 deletions(-) diff --git a/SPlisHSPlasH/Simulation.h b/SPlisHSPlasH/Simulation.h index d0f0260c..62123a2c 100644 --- a/SPlisHSPlasH/Simulation.h +++ b/SPlisHSPlasH/Simulation.h @@ -9,6 +9,7 @@ #include "BoundaryModel.h" #include "AnimationFieldSystem.h" #include "Utilities/FileSystem.h" + #ifdef USE_DEBUG_TOOLS #include "SPlisHSPlasH/Utilities/DebugTools.h" #endif @@ -167,6 +168,7 @@ for (unsigned int pid = 0; pid < nBoundaries; pid++) \ namespace SPH { + class DynamicBoundarySimulator; enum class SimulationMethods { WCSPH = 0, PCISPH, PBF, IISPH, DFSPH, PF, ICSPH, NumSimulationMethods }; enum class BoundaryHandlingMethods { Akinci2012 = 0, Koschier2017, Bender2019, NumSimulationMethods }; @@ -306,6 +308,7 @@ namespace SPH bool m_enableZSort; std::function m_simulationMethodChanged; int m_boundaryHandlingMethod; + DynamicBoundarySimulator* m_dynamicBoundarySimulator; std::string m_cachePath; bool m_useCache; std::vector m_dragMethods; @@ -366,6 +369,9 @@ namespace SPH BoundaryHandlingMethods getBoundaryHandlingMethod() const { return (BoundaryHandlingMethods) m_boundaryHandlingMethod; } void setBoundaryHandlingMethod(BoundaryHandlingMethods val) { m_boundaryHandlingMethod = (int) val; } + DynamicBoundarySimulator* getDynamicBoundarySimulator() const { return m_dynamicBoundarySimulator; } + void setDynamicBoundarySimulator(DynamicBoundarySimulator* simulator) { m_dynamicBoundarySimulator = simulator; } + int getKernel() const { return m_kernelMethod; } void setKernel(int val); int getGradKernel() const { return m_gradKernelMethod; } diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index 0aea917d..929a88d9 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -8,6 +8,7 @@ #include "SPlisHSPlasH/BoundaryModel_Akinci2012.h" #include "SPlisHSPlasH/BoundaryModel_Koschier2017.h" #include "SPlisHSPlasH/BoundaryModel_Bender2019.h" +#include "Simulator/DynamicBoundarySimulator.h" using namespace SPH; using namespace std; @@ -132,6 +133,11 @@ void TimeStepWCSPH::step() } } + // Only for strong coupling method with BoundaryModel_Akinci2012 + if (sim->getDynamicBoundarySimulator() != nullptr) { + sim->getDynamicBoundarySimulator()->timeStepStrongCoupling(); + } + sim->emitParticles(); sim->animateParticles(); diff --git a/Simulator/DynamicBoundarySimulator.cpp b/Simulator/DynamicBoundarySimulator.cpp index e66ef86a..62219dd7 100644 --- a/Simulator/DynamicBoundarySimulator.cpp +++ b/Simulator/DynamicBoundarySimulator.cpp @@ -18,6 +18,7 @@ using namespace Utilities; DynamicBoundarySimulator::DynamicBoundarySimulator(SimulatorBase* base) { m_base = base; + Simulation::getCurrent()->setDynamicBoundarySimulator(this); } DynamicBoundarySimulator::~DynamicBoundarySimulator() { @@ -173,27 +174,48 @@ void DynamicBoundarySimulator::deferredInit() { } void DynamicBoundarySimulator::timeStep() { - updateBoundaryForces(); Simulation* sim = Simulation::getCurrent(); - const unsigned int nObjects = sim->numberOfBoundaryModels(); - #pragma omp parallel for - for (int i = 0; i < nObjects; i++) { - BoundaryModel* bm = sim->getBoundaryModel(i); - RigidBodyObject* rbo = bm->getRigidBodyObject(); - if (rbo->isDynamic()) { - DynamicRigidBody* drb = dynamic_cast(rbo); - drb->timeStep(); - // Apply damping - drb->setVelocity(drb->getVelocity() * (static_cast(1.0) - m_dampingCoeff)); - drb->setAngularVelocity(drb->getAngularVelocity() * (static_cast(1.0) - m_dampingCoeff)); - } + if (sim->getBoundaryHandlingMethod() != BoundaryHandlingMethods::Akinci2012) { + updateBoundaryForces(); + const unsigned int nObjects = sim->numberOfBoundaryModels(); + #pragma omp parallel for + for (int i = 0; i < nObjects; i++) { + BoundaryModel* bm = sim->getBoundaryModel(i); + RigidBodyObject* rbo = bm->getRigidBodyObject(); + if (rbo->isDynamic()) { + DynamicRigidBody* drb = dynamic_cast(rbo); + drb->timeStep(); + // Apply damping + drb->setVelocity(drb->getVelocity() * (static_cast(1.0) - m_dampingCoeff)); + drb->setAngularVelocity(drb->getAngularVelocity() * (static_cast(1.0) - m_dampingCoeff)); + } + } + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) + m_base->updateDMVelocity(); + else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Bender2019) + m_base->updateVMVelocity(); } - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) +} + +void DynamicBoundarySimulator::timeStepStrongCoupling() { + Simulation* sim = Simulation::getCurrent(); + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { + updateBoundaryForces(); + const unsigned int nObjects = sim->numberOfBoundaryModels(); + #pragma omp parallel for + for (int i = 0; i < nObjects; i++) { + BoundaryModel* bm = sim->getBoundaryModel(i); + RigidBodyObject* rbo = bm->getRigidBodyObject(); + if (rbo->isDynamic()) { + DynamicRigidBody* drb = dynamic_cast(rbo); + drb->timeStep(); + // Apply damping + drb->setVelocity(drb->getVelocity() * (static_cast(1.0) - m_dampingCoeff)); + drb->setAngularVelocity(drb->getAngularVelocity() * (static_cast(1.0) - m_dampingCoeff)); + } + } m_base->updateBoundaryParticles(false); - else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) - m_base->updateDMVelocity(); - else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Bender2019) - m_base->updateVMVelocity(); + } } void DynamicBoundarySimulator::reset() { diff --git a/Simulator/DynamicBoundarySimulator.h b/Simulator/DynamicBoundarySimulator.h index f0033f75..dc5b9c67 100644 --- a/Simulator/DynamicBoundarySimulator.h +++ b/Simulator/DynamicBoundarySimulator.h @@ -23,6 +23,7 @@ namespace SPH { virtual void deferredInit(); virtual void timeStep(); + void timeStepStrongCoupling(); virtual void reset(); Real m_dampingCoeff = 0.0; From a2d5611cecf582149641816d04cd2c33ae0e7c0b Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Tue, 25 Apr 2023 21:16:25 +0200 Subject: [PATCH 09/38] save boundary particles to dynamic rigid body --- SPlisHSPlasH/DynamicRigidBody.h | 14 +++++++++++- SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 30 +++++++++++++++++++++++--- SPlisHSPlasH/WCSPH/TimeStepWCSPH.h | 2 +- Simulator/DynamicBoundarySimulator.cpp | 4 ++-- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/SPlisHSPlasH/DynamicRigidBody.h b/SPlisHSPlasH/DynamicRigidBody.h index 25b5c682..bc17d3b3 100644 --- a/SPlisHSPlasH/DynamicRigidBody.h +++ b/SPlisHSPlasH/DynamicRigidBody.h @@ -15,6 +15,9 @@ namespace SPH { class DynamicRigidBody : public RigidBodyObject { // Some fields are from PBD::RigidBody private: + // Boundary Particles + std::vector m_boundaryParticleLocalPositions; + Real m_density; /** mass */ @@ -130,8 +133,9 @@ namespace SPH { } void initBody(const Real density, const bool isDynamic, const Vector3r &position, const Quaternionr &rotation, - const Vector3r &scale = Vector3r(1.0, 1.0, 1.0)) + const Vector3r &scale, const std::vector& boundaryParticleLocalPositions) { + m_boundaryParticleLocalPositions = boundaryParticleLocalPositions; m_density = density; m_scale = scale; determineMassProperties(density, isDynamic, scale); @@ -291,6 +295,14 @@ namespace SPH { const Vector3r &getTransformationV2() { return m_transformation_v2; } const Vector3r &getTransformationRXV1() { return m_transformation_R_X_v1; } + FORCE_INLINE const Real& numberOfBoundaryParticles() const { + return m_boundaryParticleLocalPositions.size(); + } + + FORCE_INLINE const Vector3r& getBoundaryParticleLocalPosition(const Real& index) const { + return m_boundaryParticleLocalPositions[index]; + } + FORCE_INLINE const Vector3r& getScale() { return m_scale; } diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index 929a88d9..3f5c98e9 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -9,6 +9,7 @@ #include "SPlisHSPlasH/BoundaryModel_Koschier2017.h" #include "SPlisHSPlasH/BoundaryModel_Bender2019.h" #include "Simulator/DynamicBoundarySimulator.h" +#include "../DynamicRigidBody.h" using namespace SPH; using namespace std; @@ -110,6 +111,11 @@ void TimeStepWCSPH::step() computePressureAccels(fluidModelIndex); } + // TODO: rigid-rigid contact forces + if (sim->getDynamicBoundarySimulator() != nullptr && sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { + computeRigidRigidAccels(); + } + sim->updateTimeStepSize(); for (unsigned int fluidModelIndex = 0; fluidModelIndex < nModels; fluidModelIndex++) @@ -133,14 +139,14 @@ void TimeStepWCSPH::step() } } + sim->emitParticles(); + sim->animateParticles(); + // Only for strong coupling method with BoundaryModel_Akinci2012 if (sim->getDynamicBoundarySimulator() != nullptr) { sim->getDynamicBoundarySimulator()->timeStepStrongCoupling(); } - sim->emitParticles(); - sim->animateParticles(); - // Compute new time tm->setTime (tm->getTime () + h); } @@ -217,6 +223,24 @@ void TimeStepWCSPH::computePressureAccels(const unsigned int fluidModelIndex) } } +void TimeStepWCSPH::computeRigidRigidAccels() { + // Use dynamic boundary simulator and Akinci2012 + Simulation* sim = Simulation::getCurrent(); + DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + const unsigned int nFluids = sim->numberOfFluidModels(); + const unsigned int nBoundaries = sim->numberOfBoundaryModels(); + // For all boundary objects + for (unsigned int i = 0; i < nBoundaries; i++) { + // it must be a dynamic rb since we have a dynamic boundary simulator + DynamicRigidBody* rb = static_cast(sim->getBoundaryModel(i)->getRigidBodyObject()); + int boundaryPointSetIndex = nFluids + i; + // For all particles of the object i + for (unsigned int j = 0; j < rb->numberOfBoundaryParticles(); j++) { + + } + } +} + void TimeStepWCSPH::performNeighborhoodSearch() { if (Simulation::getCurrent()->zSortEnabled()) diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h index 598a0e6e..6f103991 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h @@ -27,7 +27,7 @@ namespace SPH /** Determine the pressure accelerations when the pressure is already known. */ void computePressureAccels(const unsigned int fluidModelIndex); - + void computeRigidRigidAccels(); /** Perform the neighborhood search for all fluid particles. */ void performNeighborhoodSearch(); diff --git a/Simulator/DynamicBoundarySimulator.cpp b/Simulator/DynamicBoundarySimulator.cpp index 62219dd7..3547f98e 100644 --- a/Simulator/DynamicBoundarySimulator.cpp +++ b/Simulator/DynamicBoundarySimulator.cpp @@ -130,7 +130,7 @@ void DynamicBoundarySimulator::initBoundaryData() { Matrix3r rot = AngleAxisr(scene.boundaryModels[i]->angle, scene.boundaryModels[i]->axis).toRotationMatrix(); Quaternionr q(rot); - rb->initBody(scene.boundaryModels[i]->density, scene.boundaryModels[i]->dynamic, scene.boundaryModels[i]->translation, q, scene.boundaryModels[i]->scale); + rb->initBody(scene.boundaryModels[i]->density, scene.boundaryModels[i]->dynamic, scene.boundaryModels[i]->translation, q, scene.boundaryModels[i]->scale, boundaryParticles); if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { BoundaryModel_Akinci2012* bm = new BoundaryModel_Akinci2012(); @@ -200,7 +200,7 @@ void DynamicBoundarySimulator::timeStep() { void DynamicBoundarySimulator::timeStepStrongCoupling() { Simulation* sim = Simulation::getCurrent(); if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { - updateBoundaryForces(); + // updateBoundaryForces(); this is already used to compute the source term const unsigned int nObjects = sim->numberOfBoundaryModels(); #pragma omp parallel for for (int i = 0; i < nObjects; i++) { From 014ae947849f25028eb14900155d21fa40f7665e Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Wed, 26 Apr 2023 13:31:05 +0200 Subject: [PATCH 10/38] move some properties to BoundaryModel_AKinci --- SPlisHSPlasH/BoundaryModel_Akinci2012.cpp | 15 ++++++-- SPlisHSPlasH/BoundaryModel_Akinci2012.h | 29 +++++++++++++- SPlisHSPlasH/DynamicRigidBody.h | 46 +---------------------- SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 2 - Simulator/DynamicBoundarySimulator.cpp | 4 +- 5 files changed, 44 insertions(+), 52 deletions(-) diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp index 9ff67f5e..49b8fb9e 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp @@ -14,7 +14,8 @@ BoundaryModel_Akinci2012::BoundaryModel_Akinci2012() : m_x0(), m_x(), m_v(), - m_V() + m_V(), + m_density() { m_sorted = false; m_pointSetIndex = 0; @@ -23,7 +24,7 @@ BoundaryModel_Akinci2012::BoundaryModel_Akinci2012() : addField({ "position0", FieldType::Vector3, [&](const unsigned int i) -> Real* { return &getPosition0(i)[0]; } }); addField({ "velocity", FieldType::Vector3, [&](const unsigned int i) -> Real* { return &getVelocity(i)[0]; }, true }); addField({ "volume", FieldType::Scalar, [&](const unsigned int i) -> Real* { return &getVolume(i); }, true }); - //addField({ "density", FieldType::Scalar, [&](const unsigned int i) -> Real* { return &getDensity(i); }, false }); + addField({ "density", FieldType::Scalar, [&](const unsigned int i) -> Real* { return &getDensity(i); }, true }); } BoundaryModel_Akinci2012::~BoundaryModel_Akinci2012(void) @@ -32,6 +33,7 @@ BoundaryModel_Akinci2012::~BoundaryModel_Akinci2012(void) m_x.clear(); m_v.clear(); m_V.clear(); + m_density.clear(); } void BoundaryModel_Akinci2012::reset() @@ -99,7 +101,8 @@ void BoundaryModel_Akinci2012::computeBoundaryVolume() delta += sim->W(getPosition(i) - bm_neighbor->getPosition(neighborIndex)); } } - const Real volume = static_cast(1.0) / delta; + const Real gamma = static_cast(1.0); + const Real volume = gamma / delta; m_V[i] = volume; } } @@ -111,6 +114,9 @@ void BoundaryModel_Akinci2012::initModel(RigidBodyObject *rbo, const unsigned in m_x.resize(numBoundaryParticles); m_v.resize(numBoundaryParticles); m_V.resize(numBoundaryParticles); + m_density.resize(numBoundaryParticles); + + m_density0 = 1; if (rbo->isDynamic()) { @@ -132,6 +138,7 @@ void BoundaryModel_Akinci2012::initModel(RigidBodyObject *rbo, const unsigned in m_x[i] = boundaryParticles[i]; m_v[i].setZero(); m_V[i] = 0.0; + m_density[i] = m_density0; } } m_rigidBody = rbo; @@ -155,6 +162,7 @@ void BoundaryModel_Akinci2012::performNeighborhoodSearchSort() d.sort_field(&m_x[0]); d.sort_field(&m_v[0]); d.sort_field(&m_V[0]); + d.sort_field(&m_density[0]); m_sorted = true; } @@ -176,4 +184,5 @@ void SPH::BoundaryModel_Akinci2012::resize(const unsigned int numBoundaryParticl m_x.resize(numBoundaryParticles); m_v.resize(numBoundaryParticles); m_V.resize(numBoundaryParticles); + m_density.resize(numBoundaryParticles); } diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.h b/SPlisHSPlasH/BoundaryModel_Akinci2012.h index 8ba97354..0e255916 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.h +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.h @@ -34,6 +34,8 @@ namespace SPH std::vector m_x; std::vector m_v; std::vector m_V; + std::vector m_density; + Real m_density0; std::vector m_fields; public: @@ -43,6 +45,7 @@ namespace SPH const FieldDescription& getField(const std::string& name); const unsigned int numberOfFields() {return static_cast(m_fields.size());} void removeFieldByName(const std::string& fieldName); + unsigned int numberOfParticles() const { return static_cast(m_x.size()); } unsigned int getPointSetIndex() const { return m_pointSetIndex; } bool isSorted() const { return m_sorted; } @@ -58,7 +61,31 @@ namespace SPH virtual void loadState(BinaryFileReader &binReader); void initModel(RigidBodyObject *rbo, const unsigned int numBoundaryParticles, Vector3r *boundaryParticles); - + + FORCE_INLINE const Real& getDensity(const Real& index) const { + return m_density[index]; + } + + FORCE_INLINE Real& getDensity(const Real& index) { + return m_density[index]; + } + + FORCE_INLINE void setDensity(const Real& index, const Real& value) { + m_density[index] = value; + } + + FORCE_INLINE const Real& getDensity0(const Real& index) const { + return m_density0; + } + + FORCE_INLINE Real& getDensity0(const Real& index) { + return m_density0; + } + + FORCE_INLINE void setDensity0(const Real& index, const Real& value) { + m_density0 = value; + } + FORCE_INLINE Vector3r &getPosition0(const unsigned int i) { return m_x0[i]; diff --git a/SPlisHSPlasH/DynamicRigidBody.h b/SPlisHSPlasH/DynamicRigidBody.h index bc17d3b3..667e5cfe 100644 --- a/SPlisHSPlasH/DynamicRigidBody.h +++ b/SPlisHSPlasH/DynamicRigidBody.h @@ -16,7 +16,7 @@ namespace SPH { // Some fields are from PBD::RigidBody private: // Boundary Particles - std::vector m_boundaryParticleLocalPositions; + Real m_density; @@ -99,43 +99,9 @@ namespace SPH { { } - void initBody(const Real mass, const Vector3r &x, - const Vector3r &inertiaTensor, const Quaternionr &rotation, - const Vector3r &scale = Vector3r(1.0, 1.0, 1.0)) - { - setMass(mass); - m_x = x; - m_x0 = x; - m_lastX = x; - m_oldX = x; - m_v.setZero(); - m_v0.setZero(); - m_a.setZero(); - m_force.setZero(); - - setInertiaTensor(inertiaTensor); - m_q = rotation; - m_q0 = rotation; - m_lastQ = rotation; - m_oldQ = rotation; - m_rot = m_q.matrix(); - m_q_mat = Quaternionr(1.0, 0.0, 0.0, 0.0); - m_q_initial = Quaternionr(1.0, 0.0, 0.0, 0.0); - m_x0_mat.setZero(); - rotationUpdated(); - m_omega.setZero(); - m_omega0.setZero(); - m_torque.setZero(); - - // m_restitutionCoeff = static_cast(0.6); - m_frictionCoeff = static_cast(0.2); - updateMeshTransformation(); - } - void initBody(const Real density, const bool isDynamic, const Vector3r &position, const Quaternionr &rotation, - const Vector3r &scale, const std::vector& boundaryParticleLocalPositions) + const Vector3r &scale) { - m_boundaryParticleLocalPositions = boundaryParticleLocalPositions; m_density = density; m_scale = scale; determineMassProperties(density, isDynamic, scale); @@ -295,14 +261,6 @@ namespace SPH { const Vector3r &getTransformationV2() { return m_transformation_v2; } const Vector3r &getTransformationRXV1() { return m_transformation_R_X_v1; } - FORCE_INLINE const Real& numberOfBoundaryParticles() const { - return m_boundaryParticleLocalPositions.size(); - } - - FORCE_INLINE const Vector3r& getBoundaryParticleLocalPosition(const Real& index) const { - return m_boundaryParticleLocalPositions[index]; - } - FORCE_INLINE const Vector3r& getScale() { return m_scale; } diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index 3f5c98e9..83a55de8 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -235,9 +235,7 @@ void TimeStepWCSPH::computeRigidRigidAccels() { DynamicRigidBody* rb = static_cast(sim->getBoundaryModel(i)->getRigidBodyObject()); int boundaryPointSetIndex = nFluids + i; // For all particles of the object i - for (unsigned int j = 0; j < rb->numberOfBoundaryParticles(); j++) { - } } } diff --git a/Simulator/DynamicBoundarySimulator.cpp b/Simulator/DynamicBoundarySimulator.cpp index 3547f98e..94c56efc 100644 --- a/Simulator/DynamicBoundarySimulator.cpp +++ b/Simulator/DynamicBoundarySimulator.cpp @@ -130,7 +130,7 @@ void DynamicBoundarySimulator::initBoundaryData() { Matrix3r rot = AngleAxisr(scene.boundaryModels[i]->angle, scene.boundaryModels[i]->axis).toRotationMatrix(); Quaternionr q(rot); - rb->initBody(scene.boundaryModels[i]->density, scene.boundaryModels[i]->dynamic, scene.boundaryModels[i]->translation, q, scene.boundaryModels[i]->scale, boundaryParticles); + rb->initBody(scene.boundaryModels[i]->density, scene.boundaryModels[i]->dynamic, scene.boundaryModels[i]->translation, q, scene.boundaryModels[i]->scale); if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { BoundaryModel_Akinci2012* bm = new BoundaryModel_Akinci2012(); @@ -200,7 +200,7 @@ void DynamicBoundarySimulator::timeStep() { void DynamicBoundarySimulator::timeStepStrongCoupling() { Simulation* sim = Simulation::getCurrent(); if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { - // updateBoundaryForces(); this is already used to compute the source term + updateBoundaryForces(); //this is already used to compute the source term const unsigned int nObjects = sim->numberOfBoundaryModels(); #pragma omp parallel for for (int i = 0; i < nObjects; i++) { From bd5a0b726b183350ac2f7c39532348cef9dde449 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Thu, 27 Apr 2023 12:14:46 +0200 Subject: [PATCH 11/38] compute source term --- SPlisHSPlasH/BoundaryModel_Akinci2012.cpp | 19 +++- SPlisHSPlasH/BoundaryModel_Akinci2012.h | 35 +++++- SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 123 ++++++++++++++-------- 3 files changed, 129 insertions(+), 48 deletions(-) diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp index 49b8fb9e..ecebf14f 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp @@ -15,7 +15,9 @@ BoundaryModel_Akinci2012::BoundaryModel_Akinci2012() : m_x(), m_v(), m_V(), - m_density() + m_density(), + m_v_s(), + m_s() { m_sorted = false; m_pointSetIndex = 0; @@ -34,6 +36,8 @@ BoundaryModel_Akinci2012::~BoundaryModel_Akinci2012(void) m_v.clear(); m_V.clear(); m_density.clear(); + m_v_s.clear(); + m_s.clear(); } void BoundaryModel_Akinci2012::reset() @@ -44,11 +48,14 @@ void BoundaryModel_Akinci2012::reset() // positions and velocities are already updated by updateBoundaryParticles if (!m_rigidBody->isDynamic() && !m_rigidBody->isAnimated()) { - // reset velocities and accelerations + // reset velocities, accelerations, densities and other fields for (int j = 0; j < (int)numberOfParticles(); j++) { m_x[j] = m_x0[j]; m_v[j].setZero(); + m_density[j] = m_density0; + m_v_s[j].setZero(); + m_s[j] = 0; } } } @@ -115,7 +122,8 @@ void BoundaryModel_Akinci2012::initModel(RigidBodyObject *rbo, const unsigned in m_v.resize(numBoundaryParticles); m_V.resize(numBoundaryParticles); m_density.resize(numBoundaryParticles); - + m_v_s.resize(numBoundaryParticles); + m_s.resize(numBoundaryParticles); m_density0 = 1; if (rbo->isDynamic()) @@ -139,6 +147,7 @@ void BoundaryModel_Akinci2012::initModel(RigidBodyObject *rbo, const unsigned in m_v[i].setZero(); m_V[i] = 0.0; m_density[i] = m_density0; + m_v_s[i].setZero(); } } m_rigidBody = rbo; @@ -163,6 +172,8 @@ void BoundaryModel_Akinci2012::performNeighborhoodSearchSort() d.sort_field(&m_v[0]); d.sort_field(&m_V[0]); d.sort_field(&m_density[0]); + d.sort_field(&m_v_s[0]); + d.sort_field(&m_s[0]); m_sorted = true; } @@ -185,4 +196,6 @@ void SPH::BoundaryModel_Akinci2012::resize(const unsigned int numBoundaryParticl m_v.resize(numBoundaryParticles); m_V.resize(numBoundaryParticles); m_density.resize(numBoundaryParticles); + m_v_s.resize(numBoundaryParticles); + m_s.resize(numBoundaryParticles); } diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.h b/SPlisHSPlasH/BoundaryModel_Akinci2012.h index 0e255916..5435de87 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.h +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.h @@ -34,9 +34,12 @@ namespace SPH std::vector m_x; std::vector m_v; std::vector m_V; + std::vector m_fields; + // values required for Gissler 2019 strong coupling based on Akinci 2012 std::vector m_density; Real m_density0; - std::vector m_fields; + std::vector m_v_s; + std::vector m_s; // source term public: void addField(const FieldDescription& field); @@ -74,15 +77,15 @@ namespace SPH m_density[index] = value; } - FORCE_INLINE const Real& getDensity0(const Real& index) const { + FORCE_INLINE const Real& getDensity0() const { return m_density0; } - FORCE_INLINE Real& getDensity0(const Real& index) { + FORCE_INLINE Real& getDensity0() { return m_density0; } - FORCE_INLINE void setDensity0(const Real& index, const Real& value) { + FORCE_INLINE void setDensity0(const Real& value) { m_density0 = value; } @@ -131,6 +134,30 @@ namespace SPH m_v[i] = vel; } + FORCE_INLINE Vector3r& getV_s(const unsigned int i) { + return m_v_s[i]; + } + + FORCE_INLINE const Vector3r& getV_s(const unsigned int i) const { + return m_v_s[i]; + } + + FORCE_INLINE void setV_s(const unsigned int i, const Vector3r& value) { + m_v_s[i] = value; + } + + FORCE_INLINE Real& getSourceTerm(const unsigned int i) { + return m_s[i]; + } + + FORCE_INLINE const Real& getSourceTerm(const unsigned int i) const { + return m_s[i]; + } + + FORCE_INLINE void setSourceTerm(const unsigned int i, const Real& value) { + m_s[i] = value; + } + FORCE_INLINE const Real& getVolume(const unsigned int i) const { return m_V[i]; diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index 83a55de8..106335e1 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -9,7 +9,7 @@ #include "SPlisHSPlasH/BoundaryModel_Koschier2017.h" #include "SPlisHSPlasH/BoundaryModel_Bender2019.h" #include "Simulator/DynamicBoundarySimulator.h" -#include "../DynamicRigidBody.h" +#include using namespace SPH; using namespace std; @@ -148,75 +148,67 @@ void TimeStepWCSPH::step() } // Compute new time - tm->setTime (tm->getTime () + h); + tm->setTime(tm->getTime() + h); } -void TimeStepWCSPH::reset() -{ +void TimeStepWCSPH::reset() { TimeStep::reset(); m_simulationData.reset(); m_counter = 0; } -void TimeStepWCSPH::computePressureAccels(const unsigned int fluidModelIndex) -{ - Simulation *sim = Simulation::getCurrent(); - FluidModel *model = sim->getFluidModel(fluidModelIndex); +void TimeStepWCSPH::computePressureAccels(const unsigned int fluidModelIndex) { + Simulation* sim = Simulation::getCurrent(); + FluidModel* model = sim->getFluidModel(fluidModelIndex); const Real density0 = model->getDensity0(); const unsigned int numParticles = model->numActiveParticles(); const unsigned int nFluids = sim->numberOfFluidModels(); const unsigned int nBoundaries = sim->numberOfBoundaryModels(); // Compute pressure forces - #pragma omp parallel default(shared) +#pragma omp parallel default(shared) { - #pragma omp for schedule(static) - for (int i = 0; i < (int)numParticles; i++) - { - const Vector3r &xi = model->getPosition(i); +#pragma omp for schedule(static) + for (int i = 0; i < (int)numParticles; i++) { + const Vector3r& xi = model->getPosition(i); const Real density_i = model->getDensity(i); - Vector3r &ai = m_simulationData.getPressureAccel(fluidModelIndex, i); + Vector3r& ai = m_simulationData.getPressureAccel(fluidModelIndex, i); ai.setZero(); - const Real dpi = m_simulationData.getPressure(fluidModelIndex, i) / (density_i*density_i); + const Real dpi = m_simulationData.getPressure(fluidModelIndex, i) / (density_i * density_i); ////////////////////////////////////////////////////////////////////////// // Fluid ////////////////////////////////////////////////////////////////////////// forall_fluid_neighbors( // Pressure const Real density_j = fm_neighbor->getDensity(neighborIndex) * density0 / fm_neighbor->getDensity0(); - const Real dpj = m_simulationData.getPressure(pid, neighborIndex) / (density_j*density_j); - ai -= density0 * fm_neighbor->getVolume(neighborIndex) * (dpi + dpj) * sim->gradW(xi - xj); + const Real dpj = m_simulationData.getPressure(pid, neighborIndex) / (density_j * density_j); + ai -= density0 * fm_neighbor->getVolume(neighborIndex) * (dpi + dpj) * sim->gradW(xi - xj); ); ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - const Real dpj = m_simulationData.getPressure(fluidModelIndex, i) / (density0*density0); - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) - { + const Real dpj = m_simulationData.getPressure(fluidModelIndex, i) / (density0 * density0); + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { forall_boundary_neighbors( - const Vector3r a = density0 * bm_neighbor->getVolume(neighborIndex) * (dpi + dpj)* sim->gradW(xi - xj); - ai -= a; - bm_neighbor->addForce(xj, model->getMass(i) * a); + const Vector3r a = density0 * bm_neighbor->getVolume(neighborIndex) * (dpi + dpj) * sim->gradW(xi - xj); + ai -= a; + bm_neighbor->addForce(xj, model->getMass(i) * a); ); - } - else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) - { + } else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) { forall_density_maps( - const Vector3r a = -density0 * (dpi + dpj)* gradRho; - ai -= a; - bm_neighbor->addForce(xj, model->getMass(i) * a); + const Vector3r a = -density0 * (dpi + dpj) * gradRho; + ai -= a; + bm_neighbor->addForce(xj, model->getMass(i) * a); ); - } - else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Bender2019) - { + } else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Bender2019) { forall_volume_maps( - const Vector3r a = density0 * Vj * (dpi + dpj)* sim->gradW(xi - xj); - ai -= a; - bm_neighbor->addForce(xj, model->getMass(i) * a); + const Vector3r a = density0 * Vj * (dpi + dpj) * sim->gradW(xi - xj); + ai -= a; + bm_neighbor->addForce(xj, model->getMass(i) * a); ); } } @@ -227,15 +219,64 @@ void TimeStepWCSPH::computeRigidRigidAccels() { // Use dynamic boundary simulator and Akinci2012 Simulation* sim = Simulation::getCurrent(); DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + TimeManager* tm = TimeManager::getCurrent(); + const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); const unsigned int nBoundaries = sim->numberOfBoundaryModels(); - // For all boundary objects - for (unsigned int i = 0; i < nBoundaries; i++) { - // it must be a dynamic rb since we have a dynamic boundary simulator - DynamicRigidBody* rb = static_cast(sim->getBoundaryModel(i)->getRigidBodyObject()); - int boundaryPointSetIndex = nFluids + i; - // For all particles of the object i + // Compute density and v_s for all particles + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + // compute v_s + Vector3r gravForce = rb->getMass() * Vector3r(sim->getVecValue(Simulation::GRAVITATION)); + // the rb->getForce() contains only fluid-rigid forces + Vector3r F_R = rb->getForce() + gravForce; + bm->setV_s(r, rb->getVelocity() + dt * rb->getInvMass() * F_R + + (rb->getAngularVelocity() + rb->getInertiaTensorInverseW() * (dt * rb->getTorque() + dt * (rb->getInertiaTensorW() * rb->getAngularVelocity()).cross(rb->getAngularVelocity()))).cross(bm->getPosition(r))); + + // compute density + Real particleDensity = 0; + // iterate over all rigid bodies + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + particleDensity += bm->getDensity0() * bm->getVolume(r) * sim->W(bm->getPosition0(r) - bm_neighbor->getPosition(k)); + } + } + bm->setDensity(r, particleDensity); + } + } + } + // compute source term s for all particles + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Real s = 0; + // iterate over all rigid bodies except bm, since the divergence of particles in the same rigid body should be 0. + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + if (boundaryPointSetIndex != pid) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + // sum up divergence of v_s + Real artificialVolumeK = (bm_neighbor->getDensity0() * bm_neighbor->getVolume(k)) / bm_neighbor->getDensity(k); + s += artificialVolumeK * bm_neighbor->getDensity(k) * (bm_neighbor->getV_s(k) - bm->getV_s(r)).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); + } + } + } + s += (bm->getDensity0() - bm->getDensity(r)) / dt; + bm->setSourceTerm(r, s); + } + } } } From d96e8541f416403161cbc3a2fb1ea99fe032f51a Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Fri, 28 Apr 2023 12:28:59 +0200 Subject: [PATCH 12/38] RHS of the equation (RHS to the source term) --- SPlisHSPlasH/BoundaryModel_Akinci2012.cpp | 25 +++++++- SPlisHSPlasH/BoundaryModel_Akinci2012.h | 69 +++++++++++++++++++- SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 77 ++++++++++++++++++++++- 3 files changed, 168 insertions(+), 3 deletions(-) diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp index ecebf14f..2508cd80 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp @@ -17,7 +17,10 @@ BoundaryModel_Akinci2012::BoundaryModel_Akinci2012() : m_V(), m_density(), m_v_s(), - m_s() + m_s(), + m_pressure(), + m_v_rr(), + m_minus_rho_div_v_rr() { m_sorted = false; m_pointSetIndex = 0; @@ -38,6 +41,9 @@ BoundaryModel_Akinci2012::~BoundaryModel_Akinci2012(void) m_density.clear(); m_v_s.clear(); m_s.clear(); + m_pressure.clear(); + m_v_rr.clear(); + m_minus_rho_div_v_rr.clear(); } void BoundaryModel_Akinci2012::reset() @@ -56,6 +62,9 @@ void BoundaryModel_Akinci2012::reset() m_density[j] = m_density0; m_v_s[j].setZero(); m_s[j] = 0; + m_pressure[j] = 0; + m_v_rr[j].setZero(); + m_minus_rho_div_v_rr[j].setZero(); } } } @@ -124,7 +133,13 @@ void BoundaryModel_Akinci2012::initModel(RigidBodyObject *rbo, const unsigned in m_density.resize(numBoundaryParticles); m_v_s.resize(numBoundaryParticles); m_s.resize(numBoundaryParticles); + m_pressure.resize(numBoundaryParticles); + m_v_rr.resize(numBoundaryParticles); + m_minus_rho_div_v_rr.resize(numBoundaryParticles); m_density0 = 1; + m_v_rr_body = Vector3r().setZero(); + m_omega_rr_body = Vector3r().setZero(); + if (rbo->isDynamic()) { @@ -148,6 +163,8 @@ void BoundaryModel_Akinci2012::initModel(RigidBodyObject *rbo, const unsigned in m_V[i] = 0.0; m_density[i] = m_density0; m_v_s[i].setZero(); + m_pressure[i] = 0; + m_v_rr[i].setZero(); } } m_rigidBody = rbo; @@ -174,6 +191,9 @@ void BoundaryModel_Akinci2012::performNeighborhoodSearchSort() d.sort_field(&m_density[0]); d.sort_field(&m_v_s[0]); d.sort_field(&m_s[0]); + d.sort_field(&m_pressure[0]); + d.sort_field(&m_v_rr[0]); + d.sort_field(&m_minus_rho_div_v_rr[0]); m_sorted = true; } @@ -198,4 +218,7 @@ void SPH::BoundaryModel_Akinci2012::resize(const unsigned int numBoundaryParticl m_density.resize(numBoundaryParticles); m_v_s.resize(numBoundaryParticles); m_s.resize(numBoundaryParticles); + m_pressure.resize(numBoundaryParticles); + m_v_rr.resize(numBoundaryParticles); + m_minus_rho_div_v_rr.resize(numBoundaryParticles); } diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.h b/SPlisHSPlasH/BoundaryModel_Akinci2012.h index 5435de87..2c10bd2a 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.h +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.h @@ -35,11 +35,17 @@ namespace SPH std::vector m_v; std::vector m_V; std::vector m_fields; + // values required for Gissler 2019 strong coupling based on Akinci 2012 std::vector m_density; - Real m_density0; + std::vector m_pressure; std::vector m_v_s; std::vector m_s; // source term + std::vector m_v_rr; + std::vector m_minus_rho_div_v_rr; // RHS to the source term + Real m_density0; + Vector3r m_v_rr_body; + Vector3r m_omega_rr_body; public: void addField(const FieldDescription& field); @@ -77,6 +83,19 @@ namespace SPH m_density[index] = value; } + FORCE_INLINE const Real& getPressure(const Real& index) const { + return m_pressure[index]; + } + + FORCE_INLINE Real& getPressure(const Real& index) { + return m_pressure[index]; + } + + FORCE_INLINE void setPressure(const Real& index, const Real& value) { + m_pressure[index] = value; + } + + FORCE_INLINE const Real& getDensity0() const { return m_density0; } @@ -88,6 +107,30 @@ namespace SPH FORCE_INLINE void setDensity0(const Real& value) { m_density0 = value; } + + FORCE_INLINE const Vector3r& getV_rr_body() const { + return m_v_rr_body; + } + + FORCE_INLINE Vector3r& getV_rr_body() { + return m_v_rr_body; + } + + FORCE_INLINE void setV_rr_body(const Vector3r& value) { + m_v_rr_body = value; + } + + FORCE_INLINE const Vector3r& getOmega_rr_body() const { + return m_omega_rr_body; + } + + FORCE_INLINE Vector3r& getOmega_rr_body() { + return m_omega_rr_body; + } + + FORCE_INLINE void setOmega_rr_body(const Vector3r& value) { + m_omega_rr_body = value; + } FORCE_INLINE Vector3r &getPosition0(const unsigned int i) { @@ -146,6 +189,30 @@ namespace SPH m_v_s[i] = value; } + FORCE_INLINE Vector3r& getV_rr(const unsigned int i) { + return m_v_rr[i]; + } + + FORCE_INLINE const Vector3r& getV_rr(const unsigned int i) const { + return m_v_rr[i]; + } + + FORCE_INLINE void setV_rr(const unsigned int i, const Vector3r& value) { + m_v_rr[i] = value; + } + + FORCE_INLINE Vector3r& getMinus_rho_div_v_rr(const unsigned int i) { + return m_minus_rho_div_v_rr[i]; + } + + FORCE_INLINE const Vector3r& getMinus_rho_div_v_rr(const unsigned int i) const { + return m_minus_rho_div_v_rr[i]; + } + + FORCE_INLINE void setMinus_rho_div_v_rr(const unsigned int i, const Vector3r& value) { + m_minus_rho_div_v_rr[i] = value; + } + FORCE_INLINE Real& getSourceTerm(const unsigned int i) { return m_s[i]; } diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index 106335e1..30a5a12c 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -224,7 +224,7 @@ void TimeStepWCSPH::computeRigidRigidAccels() { const unsigned int nFluids = sim->numberOfFluidModels(); const unsigned int nBoundaries = sim->numberOfBoundaryModels(); - // Compute density and v_s for all particles + // Compute density, pressure and v_s for all particles for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); @@ -250,6 +250,9 @@ void TimeStepWCSPH::computeRigidRigidAccels() { } } bm->setDensity(r, particleDensity); + + // compute density using the same method as the fluid solver (WCSPH) + bm->setPressure(r, m_stiffness * (pow(bm->getDensity(r) / bm->getDensity0(), m_exponent) - static_cast(1.0))); } } } @@ -278,6 +281,78 @@ void TimeStepWCSPH::computeRigidRigidAccels() { } } } + + // Next three loops compute the RHS of the equation (RHS to the source term) + { + // compute v_rr and omega_rr for rigid body using the pressure gradient + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + Vector3r v_rr_body = Vector3r().setZero(); + Vector3r omega_rr_body = Vector3r().setZero(); + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Vector3r pressureGrad_r = Vector3r().setZero(); + const Real density_r = bm->getDensity(r); + const Real volume_r = bm->getDensity0() / density_r * bm->getVolume(r); + const Real pressure_r = bm->getPressure(r); + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + const Real density_k = bm_neighbor->getDensity(k); + const Real volume_k = bm_neighbor->getDensity0() / density_k * bm_neighbor->getVolume(k); + const Real pressure_k = bm_neighbor->getPressure(k); + pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); + } + } + pressureGrad_r *= density_r; + v_rr_body += -dt * rb->getInvMass() * volume_r * pressureGrad_r; + omega_rr_body += -dt * rb->getInertiaTensorInverseW() * volume_r * bm->getPosition(r).cross(pressureGrad_r); + } + } + bm->setV_rr_body(v_rr_body); + bm->setOmega_rr_body(omega_rr_body); + } + // compute v_rr for all particles + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + bm->setV_rr(r, bm->getV_rr_body() + bm->getOmega_rr_body().cross(bm->getPosition(r))); + } + } + } + // compute the -rho * (div v_rr), which is the RHS to the source term + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Vector3r minus_rho_div_v_rr = Vector3r().setZero(); + const Vector3r v_rr_r = bm->getV_rr(r); + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + const Real density_k = bm_neighbor->getDensity(k); + const Real volume_k = bm_neighbor->getDensity0() / density_k * bm_neighbor->getVolume(k); + const Vector3r v_rr_k = bm_neighbor->getV_rr(k); + minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); + } + } + minus_rho_div_v_rr = -minus_rho_div_v_rr; + bm->setMinus_rho_div_v_rr(r, minus_rho_div_v_rr); + } + } + } + } + } void TimeStepWCSPH::performNeighborhoodSearch() From ccb919ef8f972866674a8ce34bd3a4d8ac622c9a Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Sun, 30 Apr 2023 12:21:40 +0200 Subject: [PATCH 13/38] gui update and bug fix --- SPlisHSPlasH/BoundaryModel_Akinci2012.cpp | 2 +- SPlisHSPlasH/BoundaryModel_Akinci2012.h | 8 +++---- SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 9 ++++---- Simulator/DynamicBoundarySimulator.h | 23 ++++++++++++++++++++- Simulator/GUI/imgui/Simulator_GUI_imgui.cpp | 23 +++++++++++++++++++-- 5 files changed, 53 insertions(+), 12 deletions(-) diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp index 2508cd80..f547e386 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp @@ -64,7 +64,7 @@ void BoundaryModel_Akinci2012::reset() m_s[j] = 0; m_pressure[j] = 0; m_v_rr[j].setZero(); - m_minus_rho_div_v_rr[j].setZero(); + m_minus_rho_div_v_rr[j] = 0; } } } diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.h b/SPlisHSPlasH/BoundaryModel_Akinci2012.h index 2c10bd2a..a4a1093b 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.h +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.h @@ -42,7 +42,7 @@ namespace SPH std::vector m_v_s; std::vector m_s; // source term std::vector m_v_rr; - std::vector m_minus_rho_div_v_rr; // RHS to the source term + std::vector m_minus_rho_div_v_rr; // RHS to the source term Real m_density0; Vector3r m_v_rr_body; Vector3r m_omega_rr_body; @@ -201,15 +201,15 @@ namespace SPH m_v_rr[i] = value; } - FORCE_INLINE Vector3r& getMinus_rho_div_v_rr(const unsigned int i) { + FORCE_INLINE Real& getMinus_rho_div_v_rr(const unsigned int i) { return m_minus_rho_div_v_rr[i]; } - FORCE_INLINE const Vector3r& getMinus_rho_div_v_rr(const unsigned int i) const { + FORCE_INLINE const Real& getMinus_rho_div_v_rr(const unsigned int i) const { return m_minus_rho_div_v_rr[i]; } - FORCE_INLINE void setMinus_rho_div_v_rr(const unsigned int i, const Vector3r& value) { + FORCE_INLINE void setMinus_rho_div_v_rr(const unsigned int i, const Real& value) { m_minus_rho_div_v_rr[i] = value; } diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index 30a5a12c..fa5107c2 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -251,7 +251,7 @@ void TimeStepWCSPH::computeRigidRigidAccels() { } bm->setDensity(r, particleDensity); - // compute density using the same method as the fluid solver (WCSPH) + // compute initial value of pressure using the same method as the fluid solver (WCSPH) bm->setPressure(r, m_stiffness * (pow(bm->getDensity(r) / bm->getDensity0(), m_exponent) - static_cast(1.0))); } } @@ -334,7 +334,7 @@ void TimeStepWCSPH::computeRigidRigidAccels() { { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - Vector3r minus_rho_div_v_rr = Vector3r().setZero(); + Real minus_rho_div_v_rr = 0; const Vector3r v_rr_r = bm->getV_rr(r); for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); @@ -343,7 +343,7 @@ void TimeStepWCSPH::computeRigidRigidAccels() { const Real density_k = bm_neighbor->getDensity(k); const Real volume_k = bm_neighbor->getDensity0() / density_k * bm_neighbor->getVolume(k); const Vector3r v_rr_k = bm_neighbor->getV_rr(k); - minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); + minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); } } minus_rho_div_v_rr = -minus_rho_div_v_rr; @@ -352,7 +352,8 @@ void TimeStepWCSPH::computeRigidRigidAccels() { } } } - + // solve the equation s = -rho * div¡¤v_rr w.r.t. pressure using relaxed jacobi + } void TimeStepWCSPH::performNeighborhoodSearch() diff --git a/Simulator/DynamicBoundarySimulator.h b/Simulator/DynamicBoundarySimulator.h index dc5b9c67..c0dec04c 100644 --- a/Simulator/DynamicBoundarySimulator.h +++ b/Simulator/DynamicBoundarySimulator.h @@ -7,6 +7,9 @@ namespace SPH { // This class is used for the strong coupling method. See DynamicRigidBody. class DynamicBoundarySimulator : public BoundarySimulator { + private: + Real m_dampingCoeff = 0.0; + Real m_maxIteration = 20; protected: SimulatorBase* m_base; @@ -26,7 +29,25 @@ namespace SPH { void timeStepStrongCoupling(); virtual void reset(); - Real m_dampingCoeff = 0.0; + FORCE_INLINE const Real& getDampingCoeff() const { + return m_dampingCoeff; + } + FORCE_INLINE Real& getDampingCoeff() { + return m_dampingCoeff; + } + FORCE_INLINE void setDampingCoeff(const Real& value) { + m_dampingCoeff = value; + } + + FORCE_INLINE const Real& getMaxIteration() const { + return m_maxIteration; + } + FORCE_INLINE Real& getMaxIteration() { + return m_maxIteration; + } + FORCE_INLINE void setMaxIteration(const Real& value) { + m_maxIteration = value; + } }; } diff --git a/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp b/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp index d9fc9fe8..fabec000 100644 --- a/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp +++ b/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp @@ -14,6 +14,7 @@ #include "imgui_internal.h" #include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_opengl3.h" +#include "Simulator/DynamicBoundarySimulator.h" #define GLFW_INCLUDE_NONE #include @@ -502,6 +503,24 @@ void Simulator_GUI_imgui::initSimulationParameterGUI() } if (!m_simulatorBase->isStaticScene()) { + DynamicBoundarySimulator* simulator = sim->getDynamicBoundarySimulator(); + // Fields for all boundary models + { + imguiParameters::imguiNumericParameter* damping = new imguiParameters::imguiNumericParameter(); + damping->description = "Damping of the system"; + damping->label = "Damping"; + damping->getFct = [simulator]()->Real {return simulator->getDampingCoeff(); }; + damping->setFct = [simulator](Real v) {simulator->setDampingCoeff(v); }; + imguiParameters::addParam("Boundary Model", "General", damping); + + imguiParameters::imguiNumericParameter* maxIteration = new imguiParameters::imguiNumericParameter; + maxIteration->description = "max iteration to solve the strong coupling method"; + maxIteration->label = "Max Iterations"; + maxIteration->getFct = [simulator]()->int {return simulator->getMaxIteration(); }; + maxIteration->setFct = [simulator](int v) {simulator->setMaxIteration(v); }; + imguiParameters::addParam("Boundary Model", "General", maxIteration); + } + // Enum for all boundary models if (sim->numberOfBoundaryModels() > 0) { BoundaryModel* model = sim->getBoundaryModel(m_currentBoundaryModel); @@ -516,7 +535,7 @@ void Simulator_GUI_imgui::initSimulationParameterGUI() } param->getFct = [this]() -> int { return m_currentBoundaryModel; }; param->setFct = [this](int v) { m_currentBoundaryModel = v; initSimulationParameterGUI(); }; - imguiParameters::addParam("Boundary Model", "", param); + imguiParameters::addParam("Boundary Model", "Property", param); } // Show basic properties @@ -529,7 +548,7 @@ void Simulator_GUI_imgui::initSimulationParameterGUI() imguiParameters::addParam("Boundary Model", "Property", isDynamic); if (model->getRigidBodyObject()->isDynamic()) { - DynamicRigidBody* drb = dynamic_cast(model->getRigidBodyObject()); + DynamicRigidBody* drb = static_cast(model->getRigidBodyObject()); imguiParameters::imguiNumericParameter* density = new imguiParameters::imguiNumericParameter(); density->description = "Density of the rigid body"; density->label = "Density"; From 7ffb13bd75adc05dae6d4029fd37a734ca7a5c58 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Mon, 1 May 2023 17:04:14 +0200 Subject: [PATCH 14/38] jacobi step, not working yet --- SPlisHSPlasH/BoundaryModel_Akinci2012.cpp | 15 +- SPlisHSPlasH/BoundaryModel_Akinci2012.h | 28 +++- SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 185 ++++++++++++++-------- SPlisHSPlasH/WCSPH/TimeStepWCSPH.h | 6 +- 4 files changed, 169 insertions(+), 65 deletions(-) diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp index f547e386..0f641859 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp @@ -16,11 +16,13 @@ BoundaryModel_Akinci2012::BoundaryModel_Akinci2012() : m_v(), m_V(), m_density(), + m_pressureGrad(), m_v_s(), m_s(), m_pressure(), m_v_rr(), - m_minus_rho_div_v_rr() + m_minus_rho_div_v_rr(), + m_diagonalElement() { m_sorted = false; m_pointSetIndex = 0; @@ -44,6 +46,8 @@ BoundaryModel_Akinci2012::~BoundaryModel_Akinci2012(void) m_pressure.clear(); m_v_rr.clear(); m_minus_rho_div_v_rr.clear(); + m_diagonalElement.clear(); + m_pressureGrad.clear(); } void BoundaryModel_Akinci2012::reset() @@ -65,6 +69,8 @@ void BoundaryModel_Akinci2012::reset() m_pressure[j] = 0; m_v_rr[j].setZero(); m_minus_rho_div_v_rr[j] = 0; + m_diagonalElement[j] = 0; + m_pressureGrad[j].setZero(); } } } @@ -136,6 +142,8 @@ void BoundaryModel_Akinci2012::initModel(RigidBodyObject *rbo, const unsigned in m_pressure.resize(numBoundaryParticles); m_v_rr.resize(numBoundaryParticles); m_minus_rho_div_v_rr.resize(numBoundaryParticles); + m_diagonalElement.resize(numBoundaryParticles); + m_pressureGrad.resize(numBoundaryParticles); m_density0 = 1; m_v_rr_body = Vector3r().setZero(); m_omega_rr_body = Vector3r().setZero(); @@ -165,6 +173,7 @@ void BoundaryModel_Akinci2012::initModel(RigidBodyObject *rbo, const unsigned in m_v_s[i].setZero(); m_pressure[i] = 0; m_v_rr[i].setZero(); + m_pressureGrad[i].setZero(); } } m_rigidBody = rbo; @@ -194,6 +203,8 @@ void BoundaryModel_Akinci2012::performNeighborhoodSearchSort() d.sort_field(&m_pressure[0]); d.sort_field(&m_v_rr[0]); d.sort_field(&m_minus_rho_div_v_rr[0]); + d.sort_field(&m_diagonalElement[0]); + d.sort_field(&m_pressureGrad[0]); m_sorted = true; } @@ -221,4 +232,6 @@ void SPH::BoundaryModel_Akinci2012::resize(const unsigned int numBoundaryParticl m_pressure.resize(numBoundaryParticles); m_v_rr.resize(numBoundaryParticles); m_minus_rho_div_v_rr.resize(numBoundaryParticles); + m_diagonalElement.resize(numBoundaryParticles); + m_pressureGrad.resize(numBoundaryParticles); } diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.h b/SPlisHSPlasH/BoundaryModel_Akinci2012.h index a4a1093b..2af51174 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.h +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.h @@ -41,9 +41,11 @@ namespace SPH std::vector m_pressure; std::vector m_v_s; std::vector m_s; // source term + std::vector m_pressureGrad; std::vector m_v_rr; std::vector m_minus_rho_div_v_rr; // RHS to the source term - Real m_density0; + std::vector m_diagonalElement; // diagonal element for jacobi iteration + Real m_density0; Vector3r m_v_rr_body; Vector3r m_omega_rr_body; @@ -201,6 +203,18 @@ namespace SPH m_v_rr[i] = value; } + FORCE_INLINE Vector3r& getPressureGrad(const unsigned int i) { + return m_pressureGrad[i]; + } + + FORCE_INLINE const Vector3r& getPressureGrad(const unsigned int i) const { + return m_pressureGrad[i]; + } + + FORCE_INLINE void setPressureGrad(const unsigned int i, const Vector3r& value) { + m_pressureGrad[i] = value; + } + FORCE_INLINE Real& getMinus_rho_div_v_rr(const unsigned int i) { return m_minus_rho_div_v_rr[i]; } @@ -213,6 +227,18 @@ namespace SPH m_minus_rho_div_v_rr[i] = value; } + FORCE_INLINE Real& getDiagonalElement(const unsigned int i) { + return m_diagonalElement[i]; + } + + FORCE_INLINE const Real& getDiagonalElement(const unsigned int i) const { + return m_diagonalElement[i]; + } + + FORCE_INLINE void setDiagonalElement(const unsigned int i, const Real& value) { + m_diagonalElement[i] = value; + } + FORCE_INLINE Real& getSourceTerm(const unsigned int i) { return m_s[i]; } diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index fa5107c2..1c5ea297 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -167,9 +167,9 @@ void TimeStepWCSPH::computePressureAccels(const unsigned int fluidModelIndex) { const unsigned int nBoundaries = sim->numberOfBoundaryModels(); // Compute pressure forces -#pragma omp parallel default(shared) + #pragma omp parallel default(shared) { -#pragma omp for schedule(static) + #pragma omp for schedule(static) for (int i = 0; i < (int)numParticles; i++) { const Vector3r& xi = model->getPosition(i); const Real density_i = model->getDensity(i); @@ -251,8 +251,8 @@ void TimeStepWCSPH::computeRigidRigidAccels() { } bm->setDensity(r, particleDensity); - // compute initial value of pressure using the same method as the fluid solver (WCSPH) - bm->setPressure(r, m_stiffness * (pow(bm->getDensity(r) / bm->getDensity0(), m_exponent) - static_cast(1.0))); + // start with 0 + bm->setPressure(r, 0); } } } @@ -282,78 +282,139 @@ void TimeStepWCSPH::computeRigidRigidAccels() { } } - // Next three loops compute the RHS of the equation (RHS to the source term) - { - // compute v_rr and omega_rr for rigid body using the pressure gradient - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - Vector3r v_rr_body = Vector3r().setZero(); - Vector3r omega_rr_body = Vector3r().setZero(); + computeSourceTermRHS(); + + // solve the equation s = -rho * div¡¤v_rr w.r.t. pressure using relaxed jacobi + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + std::vector bodyInContact = std::vector(); + unsigned int numContacts = 0; + // #pragma omp parallel default(shared) + //{ + // // compute number of contacts + // #pragma omp for schedule(static) + // for (int r = 0; r < bm->numberOfParticles(); r++) { + // for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + // if (boundaryPointSetIndex != pid) { + // BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + // //std::cout << sim->numberOfNeighbors(boundaryPointSetIndex, pid, r) << " 1" << std::endl; + // if (sim->numberOfNeighbors(boundaryPointSetIndex, pid, r) > 0 && std::find(bodyInContact.begin(), bodyInContact.end(), pid) == bodyInContact.end()) { + // std::cout << 1; + // bodyInContact.push_back(pid); + // } + // } + // } + // } + //} + //numContacts = bodyInContact.size(); + //if (numContacts == 0) { + // continue; + //} + // beta_r_RJ + Real relaxation = 0.5; + for (unsigned int i = 0; i < sim->getDynamicBoundarySimulator()->getMaxIteration(); i++) { #pragma omp parallel default(shared) { + // compute number of contacts #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - Vector3r pressureGrad_r = Vector3r().setZero(); - const Real density_r = bm->getDensity(r); - const Real volume_r = bm->getDensity0() / density_r * bm->getVolume(r); - const Real pressure_r = bm->getPressure(r); - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { - const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - const Real density_k = bm_neighbor->getDensity(k); - const Real volume_k = bm_neighbor->getDensity0() / density_k * bm_neighbor->getVolume(k); - const Real pressure_k = bm_neighbor->getPressure(k); - pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); - } - } - pressureGrad_r *= density_r; - v_rr_body += -dt * rb->getInvMass() * volume_r * pressureGrad_r; - omega_rr_body += -dt * rb->getInertiaTensorInverseW() * volume_r * bm->getPosition(r).cross(pressureGrad_r); + // compute diagonal element b_r by dividing the value of the RHS by the pressure + bm->setDiagonalElement(r, bm->getMinus_rho_div_v_rr(r) / bm->getPressure(r)); + Real pressureNextIter = bm->getPressure(r) + relaxation / bm->getDiagonalElement(r) * (bm->getSourceTerm(r) - bm->getMinus_rho_div_v_rr(r)); + bm->setPressure(r, pressureNextIter); } } - bm->setV_rr_body(v_rr_body); - bm->setOmega_rr_body(omega_rr_body); + computeSourceTermRHS(); } - // compute v_rr for all particles - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - bm->setV_rr(r, bm->getV_rr_body() + bm->getOmega_rr_body().cross(bm->getPosition(r))); - } + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Real artificialVolume = (bm->getDensity0() * bm->getVolume(r)) / bm->getDensity(r); + const Vector3r a = -1 / bm->getDensity(r) * bm->getPressureGrad(r); + bm->addForce(bm->getPosition(r), bm->getRigidBodyObject()->getMass() * a); } } - // compute the -rho * (div v_rr), which is the RHS to the source term - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - Real minus_rho_div_v_rr = 0; - const Vector3r v_rr_r = bm->getV_rr(r); - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { - const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - const Real density_k = bm_neighbor->getDensity(k); - const Real volume_k = bm_neighbor->getDensity0() / density_k * bm_neighbor->getVolume(k); - const Vector3r v_rr_k = bm_neighbor->getV_rr(k); - minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); - } + } +} + +void SPH::TimeStepWCSPH::computeSourceTermRHS() { + Simulation* sim = Simulation::getCurrent(); + DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + TimeManager* tm = TimeManager::getCurrent(); + const Real dt = tm->getTimeStepSize(); + const unsigned int nFluids = sim->numberOfFluidModels(); + const unsigned int nBoundaries = sim->numberOfBoundaryModels(); + + // compute v_rr and omega_rr for rigid body using the pressure gradient + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + Vector3r v_rr_body = Vector3r().setZero(); + Vector3r omega_rr_body = Vector3r().setZero(); + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Vector3r pressureGrad_r = Vector3r().setZero(); + const Real density_r = bm->getDensity(r); + const Real volume_r = bm->getDensity0() / density_r * bm->getVolume(r); + const Real pressure_r = bm->getPressure(r); + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + const Real density_k = bm_neighbor->getDensity(k); + const Real volume_k = bm_neighbor->getDensity0() / density_k * bm_neighbor->getVolume(k); + const Real pressure_k = bm_neighbor->getPressure(k); + pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); } - minus_rho_div_v_rr = -minus_rho_div_v_rr; - bm->setMinus_rho_div_v_rr(r, minus_rho_div_v_rr); } + pressureGrad_r *= density_r; + v_rr_body += -dt * rb->getInvMass() * volume_r * pressureGrad_r; + omega_rr_body += -dt * rb->getInertiaTensorInverseW() * volume_r * bm->getPosition(r).cross(pressureGrad_r); + bm->setPressureGrad(r, pressureGrad_r); } } - } - // solve the equation s = -rho * div¡¤v_rr w.r.t. pressure using relaxed jacobi + bm->setV_rr_body(v_rr_body); + bm->setOmega_rr_body(omega_rr_body); + } + // compute v_rr for all particles + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + bm->setV_rr(r, bm->getV_rr_body() + bm->getOmega_rr_body().cross(bm->getPosition(r))); + } + } + } + // compute the -rho * (div v_rr), which is the RHS to the source term + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Real minus_rho_div_v_rr = 0; + const Vector3r v_rr_r = bm->getV_rr(r); + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + const Real density_k = bm_neighbor->getDensity(k); + const Real volume_k = bm_neighbor->getDensity0() / density_k * bm_neighbor->getVolume(k); + const Vector3r v_rr_k = bm_neighbor->getV_rr(k); + minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); + } + } + minus_rho_div_v_rr = -minus_rho_div_v_rr; + bm->setMinus_rho_div_v_rr(r, minus_rho_div_v_rr); + } + } + } } void TimeStepWCSPH::performNeighborhoodSearch() diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h index 6f103991..db806da3 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h @@ -27,7 +27,7 @@ namespace SPH /** Determine the pressure accelerations when the pressure is already known. */ void computePressureAccels(const unsigned int fluidModelIndex); - void computeRigidRigidAccels(); + /** Perform the neighborhood search for all fluid particles. */ void performNeighborhoodSearch(); @@ -35,6 +35,10 @@ namespace SPH virtual void emittedParticles(FluidModel *model, const unsigned int startIndex); virtual void initParameters(); + void computeRigidRigidAccels(); + // for rigid-rigid forces + void computeSourceTermRHS(); + public: static int STIFFNESS; static int EXPONENT; From 870fe4adab03df1bf8ee6831dd4990843ca385c2 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Tue, 2 May 2023 21:42:45 +0200 Subject: [PATCH 15/38] bug fix and slight reconstruction, not working though --- SPlisHSPlasH/Simulation.cpp | 3 + SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 272 ++++++++++++++++----------- SPlisHSPlasH/WCSPH/TimeStepWCSPH.h | 4 + 3 files changed, 174 insertions(+), 105 deletions(-) diff --git a/SPlisHSPlasH/Simulation.cpp b/SPlisHSPlasH/Simulation.cpp index 79797b87..c59298e4 100644 --- a/SPlisHSPlasH/Simulation.cpp +++ b/SPlisHSPlasH/Simulation.cpp @@ -733,6 +733,9 @@ void Simulation::updateBoundaryVolume() for (unsigned int j = numberOfFluidModels(); j < m_neighborhoodSearch->point_sets().size(); j++) m_neighborhoodSearch->set_active(i, j, true); } + + // Activate all point sets for strong fluid-rigid coupling + m_neighborhoodSearch->set_active(true); } void SPH::Simulation::saveState(BinaryFileWriter &binWriter) diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index 1c5ea297..dc22e744 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -216,7 +216,17 @@ void TimeStepWCSPH::computePressureAccels(const unsigned int fluidModelIndex) { } void TimeStepWCSPH::computeRigidRigidAccels() { - // Use dynamic boundary simulator and Akinci2012 + + computeRigidParticleDensity(); + + computeSourceTerm(); + + computeSourceTermRHS(); + + solveRigidRigidPressure(); +} + +void TimeStepWCSPH::computeSourceTerm() { Simulation* sim = Simulation::getCurrent(); DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); TimeManager* tm = TimeManager::getCurrent(); @@ -224,121 +234,109 @@ void TimeStepWCSPH::computeRigidRigidAccels() { const unsigned int nFluids = sim->numberOfFluidModels(); const unsigned int nBoundaries = sim->numberOfBoundaryModels(); - // Compute density, pressure and v_s for all particles + // compute source term s for all particles for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - // compute v_s - Vector3r gravForce = rb->getMass() * Vector3r(sim->getVecValue(Simulation::GRAVITATION)); - // the rb->getForce() contains only fluid-rigid forces - Vector3r F_R = rb->getForce() + gravForce; - bm->setV_s(r, rb->getVelocity() + dt * rb->getInvMass() * F_R + - (rb->getAngularVelocity() + rb->getInertiaTensorInverseW() * (dt * rb->getTorque() + dt * (rb->getInertiaTensorW() * rb->getAngularVelocity()).cross(rb->getAngularVelocity()))).cross(bm->getPosition(r))); - - // compute density - Real particleDensity = 0; - // iterate over all rigid bodies - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { - const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - particleDensity += bm->getDensity0() * bm->getVolume(r) * sim->W(bm->getPosition0(r) - bm_neighbor->getPosition(k)); + if (bm->getRigidBodyObject()->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Real s = 0; + // iterate over all rigid bodies except bm, since the divergence of particles in the same rigid body should be 0. + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + if (boundaryPointSetIndex != pid) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + // sum up divergence of v_s + Real artificialVolumeK = (bm_neighbor->getDensity0() * bm_neighbor->getVolume(k)) / bm_neighbor->getDensity(k); + s += artificialVolumeK * bm_neighbor->getDensity(k) * (bm_neighbor->getV_s(k) - bm->getV_s(r)).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); + } + } } + s += (bm->getDensity0() - bm->getDensity(r)) / dt; + bm->setSourceTerm(r, s); } - bm->setDensity(r, particleDensity); - - // start with 0 - bm->setPressure(r, 0); } } + } - // compute source term s for all particles +} + +void TimeStepWCSPH::computeRigidParticleDensity() { + // Use dynamic boundary simulator and Akinci2012 + Simulation* sim = Simulation::getCurrent(); + DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + TimeManager* tm = TimeManager::getCurrent(); + const Real dt = tm->getTimeStepSize(); + const unsigned int nFluids = sim->numberOfFluidModels(); + const unsigned int nBoundaries = sim->numberOfBoundaryModels(); + + // Compute density, pressure and v_s for all particles for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - Real s = 0; - // iterate over all rigid bodies except bm, since the divergence of particles in the same rigid body should be 0. - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - if (boundaryPointSetIndex != pid) { + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + if (rb->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + // compute v_s + Vector3r gravForce = rb->getMass() * Vector3r(sim->getVecValue(Simulation::GRAVITATION)); + // the rb->getForce() contains only fluid-rigid forces + Vector3r F_R = rb->getForce() + gravForce; + bm->setV_s(r, rb->getVelocity() + dt * rb->getInvMass() * F_R + + (rb->getAngularVelocity() + rb->getInertiaTensorInverseW() * (dt * rb->getTorque() + dt * (rb->getInertiaTensorW() * rb->getAngularVelocity()).cross(rb->getAngularVelocity()))).cross(bm->getPosition(r))); + + // compute density + Real particleDensity = 0; + // iterate over all rigid bodies + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - // sum up divergence of v_s - Real artificialVolumeK = (bm_neighbor->getDensity0() * bm_neighbor->getVolume(k)) / bm_neighbor->getDensity(k); - s += artificialVolumeK * bm_neighbor->getDensity(k) * (bm_neighbor->getV_s(k) - bm->getV_s(r)).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); + particleDensity += bm->getDensity0() * bm->getVolume(r) * sim->W(bm->getPosition(r) - bm_neighbor->getPosition(k)); } } + bm->setDensity(r, particleDensity); } - s += (bm->getDensity0() - bm->getDensity(r)) / dt; - bm->setSourceTerm(r, s); } } + } +} - computeSourceTermRHS(); +void TimeStepWCSPH::computeV_s() { + // Use dynamic boundary simulator and Akinci2012 + Simulation* sim = Simulation::getCurrent(); + DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + TimeManager* tm = TimeManager::getCurrent(); + const Real dt = tm->getTimeStepSize(); + const unsigned int nFluids = sim->numberOfFluidModels(); - // solve the equation s = -rho * div¡¤v_rr w.r.t. pressure using relaxed jacobi + // Compute density, pressure and v_s for all particles for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - std::vector bodyInContact = std::vector(); - unsigned int numContacts = 0; - // #pragma omp parallel default(shared) - //{ - // // compute number of contacts - // #pragma omp for schedule(static) - // for (int r = 0; r < bm->numberOfParticles(); r++) { - // for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - // if (boundaryPointSetIndex != pid) { - // BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - // //std::cout << sim->numberOfNeighbors(boundaryPointSetIndex, pid, r) << " 1" << std::endl; - // if (sim->numberOfNeighbors(boundaryPointSetIndex, pid, r) > 0 && std::find(bodyInContact.begin(), bodyInContact.end(), pid) == bodyInContact.end()) { - // std::cout << 1; - // bodyInContact.push_back(pid); - // } - // } - // } - // } - //} - //numContacts = bodyInContact.size(); - //if (numContacts == 0) { - // continue; - //} - // beta_r_RJ - Real relaxation = 0.5; - for (unsigned int i = 0; i < sim->getDynamicBoundarySimulator()->getMaxIteration(); i++) { + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + if (rb->isDynamic()) { #pragma omp parallel default(shared) { - // compute number of contacts #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - // compute diagonal element b_r by dividing the value of the RHS by the pressure - bm->setDiagonalElement(r, bm->getMinus_rho_div_v_rr(r) / bm->getPressure(r)); - Real pressureNextIter = bm->getPressure(r) + relaxation / bm->getDiagonalElement(r) * (bm->getSourceTerm(r) - bm->getMinus_rho_div_v_rr(r)); - bm->setPressure(r, pressureNextIter); + // compute v_s + Vector3r gravForce = rb->getMass() * Vector3r(sim->getVecValue(Simulation::GRAVITATION)); + // the rb->getForce() contains only fluid-rigid forces + Vector3r F_R = rb->getForce() + gravForce; + bm->setV_s(r, rb->getVelocity() + dt * rb->getInvMass() * F_R + + (rb->getAngularVelocity() + rb->getInertiaTensorInverseW() * (dt * rb->getTorque() + dt * (rb->getInertiaTensorW() * rb->getAngularVelocity()).cross(rb->getAngularVelocity()))).cross(bm->getPosition(r))); } } - computeSourceTermRHS(); - } - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - Real artificialVolume = (bm->getDensity0() * bm->getVolume(r)) / bm->getDensity(r); - const Vector3r a = -1 / bm->getDensity(r) * bm->getPressureGrad(r); - bm->addForce(bm->getPosition(r), bm->getRigidBodyObject()->getMass() * a); - } } } } -void SPH::TimeStepWCSPH::computeSourceTermRHS() { +void TimeStepWCSPH::computeSourceTermRHS() { Simulation* sim = Simulation::getCurrent(); DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); TimeManager* tm = TimeManager::getCurrent(); @@ -352,31 +350,32 @@ void SPH::TimeStepWCSPH::computeSourceTermRHS() { DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); Vector3r v_rr_body = Vector3r().setZero(); Vector3r omega_rr_body = Vector3r().setZero(); - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - Vector3r pressureGrad_r = Vector3r().setZero(); - const Real density_r = bm->getDensity(r); - const Real volume_r = bm->getDensity0() / density_r * bm->getVolume(r); - const Real pressure_r = bm->getPressure(r); - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { - const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - const Real density_k = bm_neighbor->getDensity(k); - const Real volume_k = bm_neighbor->getDensity0() / density_k * bm_neighbor->getVolume(k); - const Real pressure_k = bm_neighbor->getPressure(k); - pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); + if (rb->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Vector3r pressureGrad_r = Vector3r().setZero(); + const Real density_r = bm->getDensity(r); + const Real volume_r = bm->getDensity0() / density_r * bm->getVolume(r); + const Real pressure_r = bm->getPressure(r); + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + const Real density_k = bm_neighbor->getDensity(k); + const Real volume_k = bm_neighbor->getDensity0() / density_k * bm_neighbor->getVolume(k); + const Real pressure_k = bm_neighbor->getPressure(k); + pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); + } } + pressureGrad_r *= density_r; + v_rr_body += -dt * rb->getInvMass() * volume_r * pressureGrad_r; + omega_rr_body += -dt * rb->getInertiaTensorInverseW() * volume_r * bm->getPosition(r).cross(pressureGrad_r); + bm->setPressureGrad(r, pressureGrad_r); } - pressureGrad_r *= density_r; - v_rr_body += -dt * rb->getInvMass() * volume_r * pressureGrad_r; - omega_rr_body += -dt * rb->getInertiaTensorInverseW() * volume_r * bm->getPosition(r).cross(pressureGrad_r); - bm->setPressureGrad(r, pressureGrad_r); } } - bm->setV_rr_body(v_rr_body); bm->setOmega_rr_body(omega_rr_body); } @@ -417,6 +416,69 @@ void SPH::TimeStepWCSPH::computeSourceTermRHS() { } } +void TimeStepWCSPH::solveRigidRigidPressure() { + Simulation* sim = Simulation::getCurrent(); + DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + TimeManager* tm = TimeManager::getCurrent(); + const Real dt = tm->getTimeStepSize(); + const unsigned int nFluids = sim->numberOfFluidModels(); + const unsigned int nBoundaries = sim->numberOfBoundaryModels(); + + // solve the equation s = -rho * div¡¤v_rr w.r.t. pressure using relaxed jacobi + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + if (bm->getRigidBodyObject()->isDynamic()) { + std::vector bodyInContact = std::vector(); + unsigned int numContacts = 1; + //#pragma omp parallel default(shared) + { + // compute number of contacts + //#pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + if (boundaryPointSetIndex != pid) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + if (sim->numberOfNeighbors(boundaryPointSetIndex, pid, r) > 0 && std::find(bodyInContact.begin(), bodyInContact.end(), pid) == bodyInContact.end()) { + bodyInContact.push_back(pid); + } + } + } + } + } + numContacts = bodyInContact.size(); + if (numContacts == 0) { + continue; + } + // beta_r_RJ + Real relaxation = 0.5; + + for (unsigned int i = 0; i < sim->getDynamicBoundarySimulator()->getMaxIteration(); i++) { + #pragma omp parallel default(shared) + { + // compute number of contacts + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + bm->setDiagonalElement(r, bm->getMinus_rho_div_v_rr(r) / bm->getPressure(r)); + Real pressureNextIter = bm->getPressure(r) + relaxation / bm->getDiagonalElement(r) * (bm->getSourceTerm(r) - bm->getMinus_rho_div_v_rr(r)); + bm->setPressure(r, pressureNextIter); + } + } + computeSourceTermRHS(); + } + + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Real artificialVolume = (bm->getDensity0() * bm->getVolume(r)) / bm->getDensity(r); + const Vector3r a = -1 / bm->getDensity(r) * bm->getPressureGrad(r); + bm->addForce(bm->getPosition(r), bm->getRigidBodyObject()->getMass() * a); + } + } + } + } +} + void TimeStepWCSPH::performNeighborhoodSearch() { if (Simulation::getCurrent()->zSortEnabled()) diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h index db806da3..b89a4bcc 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h @@ -37,7 +37,11 @@ namespace SPH void computeRigidRigidAccels(); // for rigid-rigid forces + void computeRigidParticleDensity(); + void computeV_s(); void computeSourceTermRHS(); + void computeSourceTerm(); + void solveRigidRigidPressure(); public: static int STIFFNESS; From 2c388f01a76096a08c2d573a798e34b8e878fedb Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Wed, 3 May 2023 22:05:18 +0200 Subject: [PATCH 16/38] compute diagonal element (not correct yet) --- SPlisHSPlasH/BoundaryModel_Akinci2012.cpp | 15 +- SPlisHSPlasH/BoundaryModel_Akinci2012.h | 27 +- SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 341 +++++++++++++++------- SPlisHSPlasH/WCSPH/TimeStepWCSPH.h | 3 +- Simulator/DynamicBoundarySimulator.h | 2 +- 5 files changed, 266 insertions(+), 122 deletions(-) diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp index 0f641859..90623cdc 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp @@ -22,7 +22,8 @@ BoundaryModel_Akinci2012::BoundaryModel_Akinci2012() : m_pressure(), m_v_rr(), m_minus_rho_div_v_rr(), - m_diagonalElement() + m_diagonalElement(), + m_artificialVolume() { m_sorted = false; m_pointSetIndex = 0; @@ -48,6 +49,7 @@ BoundaryModel_Akinci2012::~BoundaryModel_Akinci2012(void) m_minus_rho_div_v_rr.clear(); m_diagonalElement.clear(); m_pressureGrad.clear(); + m_artificialVolume.clear(); } void BoundaryModel_Akinci2012::reset() @@ -63,7 +65,7 @@ void BoundaryModel_Akinci2012::reset() { m_x[j] = m_x0[j]; m_v[j].setZero(); - m_density[j] = m_density0; + m_density[j] = m_restDensity; m_v_s[j].setZero(); m_s[j] = 0; m_pressure[j] = 0; @@ -71,6 +73,7 @@ void BoundaryModel_Akinci2012::reset() m_minus_rho_div_v_rr[j] = 0; m_diagonalElement[j] = 0; m_pressureGrad[j].setZero(); + m_artificialVolume[j] = 0; } } } @@ -144,7 +147,8 @@ void BoundaryModel_Akinci2012::initModel(RigidBodyObject *rbo, const unsigned in m_minus_rho_div_v_rr.resize(numBoundaryParticles); m_diagonalElement.resize(numBoundaryParticles); m_pressureGrad.resize(numBoundaryParticles); - m_density0 = 1; + m_artificialVolume.resize(numBoundaryParticles); + m_restDensity = 1; m_v_rr_body = Vector3r().setZero(); m_omega_rr_body = Vector3r().setZero(); @@ -169,11 +173,12 @@ void BoundaryModel_Akinci2012::initModel(RigidBodyObject *rbo, const unsigned in m_x[i] = boundaryParticles[i]; m_v[i].setZero(); m_V[i] = 0.0; - m_density[i] = m_density0; + m_density[i] = m_restDensity; m_v_s[i].setZero(); m_pressure[i] = 0; m_v_rr[i].setZero(); m_pressureGrad[i].setZero(); + m_artificialVolume[i] = 0.0; } } m_rigidBody = rbo; @@ -205,6 +210,7 @@ void BoundaryModel_Akinci2012::performNeighborhoodSearchSort() d.sort_field(&m_minus_rho_div_v_rr[0]); d.sort_field(&m_diagonalElement[0]); d.sort_field(&m_pressureGrad[0]); + d.sort_field(&m_artificialVolume[0]); m_sorted = true; } @@ -234,4 +240,5 @@ void SPH::BoundaryModel_Akinci2012::resize(const unsigned int numBoundaryParticl m_minus_rho_div_v_rr.resize(numBoundaryParticles); m_diagonalElement.resize(numBoundaryParticles); m_pressureGrad.resize(numBoundaryParticles); + m_artificialVolume.resize(numBoundaryParticles); } diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.h b/SPlisHSPlasH/BoundaryModel_Akinci2012.h index 2af51174..92b68af7 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.h +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.h @@ -39,13 +39,14 @@ namespace SPH // values required for Gissler 2019 strong coupling based on Akinci 2012 std::vector m_density; std::vector m_pressure; + std::vector m_artificialVolume; std::vector m_v_s; std::vector m_s; // source term std::vector m_pressureGrad; std::vector m_v_rr; std::vector m_minus_rho_div_v_rr; // RHS to the source term std::vector m_diagonalElement; // diagonal element for jacobi iteration - Real m_density0; + Real m_restDensity; Vector3r m_v_rr_body; Vector3r m_omega_rr_body; @@ -98,16 +99,16 @@ namespace SPH } - FORCE_INLINE const Real& getDensity0() const { - return m_density0; + FORCE_INLINE const Real& getRestDensity() const { + return m_restDensity; } - FORCE_INLINE Real& getDensity0() { - return m_density0; + FORCE_INLINE Real& getRestDensity() { + return m_restDensity; } - FORCE_INLINE void setDensity0(const Real& value) { - m_density0 = value; + FORCE_INLINE void setRestDensity(const Real& value) { + m_restDensity = value; } FORCE_INLINE const Vector3r& getV_rr_body() const { @@ -265,6 +266,18 @@ namespace SPH { m_V[i] = val; } + + FORCE_INLINE const Real& getArtificialVolume(const unsigned int i) const { + return m_artificialVolume[i]; + } + + FORCE_INLINE Real& getArtificialVolume(const unsigned int i) { + return m_artificialVolume[i]; + } + + FORCE_INLINE void setArtificialVolume(const unsigned int i, const Real& val) { + m_artificialVolume[i] = val; + } }; } diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index dc22e744..e1b517e9 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -216,23 +216,78 @@ void TimeStepWCSPH::computePressureAccels(const unsigned int fluidModelIndex) { } void TimeStepWCSPH::computeRigidRigidAccels() { + Simulation* sim = Simulation::getCurrent(); + DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + TimeManager* tm = TimeManager::getCurrent(); + const Real dt = tm->getTimeStepSize(); + const unsigned int nFluids = sim->numberOfFluidModels(); - computeRigidParticleDensity(); - - computeSourceTerm(); + // solve the equation s = -rho * div¡¤v_rr w.r.t. pressure using relaxed jacobi + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + if (bm->getRigidBodyObject()->isDynamic()) { + std::vector bodyInContact = std::vector(); + unsigned int numContacts = 1; + //#pragma omp parallel default(shared) + { + // compute number of contacts + //#pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + if (boundaryPointSetIndex != pid) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + if (sim->numberOfNeighbors(boundaryPointSetIndex, pid, r) > 0 && std::find(bodyInContact.begin(), bodyInContact.end(), pid) == bodyInContact.end()) { + bodyInContact.push_back(pid); + } + } + } + } + } + numContacts = bodyInContact.size(); + if (numContacts == 0) { + continue; + } + // beta_r_RJ + Real relaxation = 0.5 / numContacts; - computeSourceTermRHS(); + computeSourceTerm(); + for (unsigned int i = 0; i < 5; i++) { + computeRigidParticleDensity(); + computeRigidParticlePressureGrad(); + computeSourceTermRHS(); + computeDiagonalElement(); + #pragma omp parallel default(shared) + { + // compute number of contacts + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Real pressureNextIter = bm->getPressure(r) + relaxation / bm->getDiagonalElement(r) * (bm->getSourceTerm(r) - bm->getMinus_rho_div_v_rr(r)); + bm->setPressure(r, pressureNextIter); + } + } + } + computeRigidParticlePressureGrad(); - solveRigidRigidPressure(); + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Real artificialVolume = (bm->getRestDensity() * bm->getVolume(r)) / bm->getDensity(r); + const Vector3r a = -1 / bm->getDensity(r) * bm->getPressureGrad(r); + bm->addForce(bm->getPosition(r), bm->getRigidBodyObject()->getMass() * a); + } + } + } + } } void TimeStepWCSPH::computeSourceTerm() { + computeV_s(); Simulation* sim = Simulation::getCurrent(); DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); TimeManager* tm = TimeManager::getCurrent(); const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); - const unsigned int nBoundaries = sim->numberOfBoundaryModels(); // compute source term s for all particles for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { @@ -250,17 +305,132 @@ void TimeStepWCSPH::computeSourceTerm() { for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); // sum up divergence of v_s - Real artificialVolumeK = (bm_neighbor->getDensity0() * bm_neighbor->getVolume(k)) / bm_neighbor->getDensity(k); - s += artificialVolumeK * bm_neighbor->getDensity(k) * (bm_neighbor->getV_s(k) - bm->getV_s(r)).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); + s += bm_neighbor->getArtificialVolume(k) * bm_neighbor->getDensity(k) * (bm_neighbor->getV_s(k) - bm->getV_s(r)).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); } } } - s += (bm->getDensity0() - bm->getDensity(r)) / dt; + s += (bm->getRestDensity() - bm->getDensity(r)) / dt; bm->setSourceTerm(r, s); } } } + } +} +void TimeStepWCSPH::computeDiagonalElement() { + Simulation* sim = Simulation::getCurrent(); + DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + TimeManager* tm = TimeManager::getCurrent(); + const Real dt = tm->getTimeStepSize(); + const unsigned int nFluids = sim->numberOfFluidModels(); + + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + if (rb->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Matrix3r productMat_r; + Vector3r pos_r = bm->getPosition(r); + productMat_r << 0, -pos_r.z(), pos_r.y(), + pos_r.z(), 0, -pos_r.x(), + -pos_r.y(), pos_r.x(), 0; + + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + BoundaryModel_Akinci2012* bm_i = static_cast(sim->getBoundaryModelFromPointSet(pid)); + DynamicRigidBody* rb_i = static_cast(bm_i->getRigidBodyObject()); + Real diagonal = 0; + // neighbors of r + for (unsigned int m = 0; m < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); m++) { + + const unsigned int i = sim->getNeighbor(boundaryPointSetIndex, pid, r, m); + Vector3r coeffSum_ik; + + Vector3r gradWri = sim->gradW(bm->getPosition(r) - bm_i->getPosition(i)); + Matrix3r productMat_i; + Vector3r pos_i = bm_i->getPosition(i); + productMat_i << 0, -pos_i.z(), pos_i.y(), + pos_i.z(), 0, -pos_i.x(), + -pos_i.y(), pos_i.x(), 0; + + // neighbors of i + for (unsigned int pid2 = nFluids; pid2 < sim->numberOfPointSets(); pid2++) { + BoundaryModel_Akinci2012* bm_k = static_cast(sim->getBoundaryModelFromPointSet(pid2)); + for (unsigned int n = 0; n < sim->numberOfNeighbors(pid, pid2, i); n++) { + const unsigned int k = sim->getNeighbor(pid, pid2, i, n); + Vector3r coeffSum_kj; + + Vector3r pos_k = bm_k->getPosition(k); + Matrix3r productMat_k; + productMat_k << 0, -pos_k.z(), pos_k.y(), + pos_k.z(), 0, -pos_k.x(), + -pos_k.y(), pos_k.x(), 0; + Matrix3r K_ik = rb_i->getInvMass() * Matrix3r::Identity() - productMat_i * rb_i->getInertiaTensorInverseW() * productMat_k; + + // neighbors of k + for (unsigned int pid3 = nFluids; pid3 < sim->numberOfPointSets(); pid3++) { + BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pid3)); + for (unsigned int o = 0; o < sim->numberOfNeighbors(pid2, pid3, k); o++) { + const unsigned int j = sim->getNeighbor(pid2, pid3, k, o); + Vector3r gradWkj = sim->gradW(bm_k->getPosition(k) - bm_j->getPosition(j)); + if (pid2 == boundaryPointSetIndex && k == r) { + coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_k->getDensity(k) * bm_k->getDensity(k)) * gradWkj; + } + if (pid3 == boundaryPointSetIndex && j == r) { + coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_j->getDensity(j) * bm_j->getDensity(j)) * gradWkj; + } + } + } + coeffSum_kj = bm_k->getArtificialVolume(k) * K_ik * bm_k->getDensity(k) * coeffSum_kj; + coeffSum_ik += coeffSum_kj; + } + } + coeffSum_ik *= dt; + + Vector3r coeffSum_rk; + // neighbors of r + for (unsigned int pid2 = nFluids; pid2 < sim->numberOfPointSets(); pid2++) { + BoundaryModel_Akinci2012* bm_k = static_cast(sim->getBoundaryModelFromPointSet(pid2)); + for (unsigned int n = 0; n < sim->numberOfNeighbors(boundaryPointSetIndex, pid2, r); n++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid2, r, n); + Vector3r coeffSum_kj; + + Vector3r pos_k = bm_k->getPosition(k); + Matrix3r productMat_k; + productMat_k << 0, -pos_k.z(), pos_k.y(), + pos_k.z(), 0, -pos_k.x(), + -pos_k.y(), pos_k.x(), 0; + Matrix3r K_rk = rb->getInvMass() * Matrix3r::Identity() - productMat_r * rb->getInertiaTensorInverseW() * productMat_k; + + //neighbors of k + for (unsigned int pid3 = nFluids; pid3 < sim->numberOfPointSets(); pid3++) { + BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pid3)); + for (unsigned int o = 0; o < sim->numberOfNeighbors(pid2, pid3, k); o++) { + const unsigned int j = sim->getNeighbor(pid2, pid3, k, o); + Vector3r gradWkj = sim->gradW(bm_k->getPosition(k) - bm_j->getPosition(j)); + if (pid2 == boundaryPointSetIndex && k == r) { + coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_k->getDensity(k) * bm_k->getDensity(k)) * gradWkj; + } + if (pid3 == boundaryPointSetIndex && j == r) { + coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_j->getDensity(j) * bm_j->getDensity(j)) * gradWkj; + } + } + } + coeffSum_kj = bm_k->getArtificialVolume(k) * K_rk * bm_k->getDensity(k) * coeffSum_kj; + coeffSum_rk += coeffSum_kj; + } + } + coeffSum_rk *= dt; + + diagonal += bm_i->getArtificialVolume(i) * bm_i->getDensity(i) * (-coeffSum_ik + coeffSum_rk).dot(gradWri); + bm->getDiagonalElement(r) += diagonal; + } + } + } + } + } } } @@ -271,9 +441,8 @@ void TimeStepWCSPH::computeRigidParticleDensity() { TimeManager* tm = TimeManager::getCurrent(); const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); - const unsigned int nBoundaries = sim->numberOfBoundaryModels(); - // Compute density, pressure and v_s for all particles + // Compute density, artificial volume, and v_s for all particles for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); @@ -282,13 +451,6 @@ void TimeStepWCSPH::computeRigidParticleDensity() { { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - // compute v_s - Vector3r gravForce = rb->getMass() * Vector3r(sim->getVecValue(Simulation::GRAVITATION)); - // the rb->getForce() contains only fluid-rigid forces - Vector3r F_R = rb->getForce() + gravForce; - bm->setV_s(r, rb->getVelocity() + dt * rb->getInvMass() * F_R + - (rb->getAngularVelocity() + rb->getInertiaTensorInverseW() * (dt * rb->getTorque() + dt * (rb->getInertiaTensorW() * rb->getAngularVelocity()).cross(rb->getAngularVelocity()))).cross(bm->getPosition(r))); - // compute density Real particleDensity = 0; // iterate over all rigid bodies @@ -296,15 +458,53 @@ void TimeStepWCSPH::computeRigidParticleDensity() { BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - particleDensity += bm->getDensity0() * bm->getVolume(r) * sim->W(bm->getPosition(r) - bm_neighbor->getPosition(k)); + particleDensity += bm->getRestDensity() * bm->getVolume(r) * sim->W(bm->getPosition(r) - bm_neighbor->getPosition(k)); } } - bm->setDensity(r, particleDensity); + // 0.8 for compensation + bm->setDensity(r, particleDensity / 0.8); + bm->setArtificialVolume(r, bm->getRestDensity() * bm->getVolume(r) / bm->getDensity(r)); } } } + } +} +void TimeStepWCSPH::computeRigidParticlePressureGrad() { + Simulation* sim = Simulation::getCurrent(); + DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + TimeManager* tm = TimeManager::getCurrent(); + const Real dt = tm->getTimeStepSize(); + const unsigned int nFluids = sim->numberOfFluidModels(); + + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + if (rb->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Vector3r pressureGrad_r = Vector3r().setZero(); + const Real density_r = bm->getDensity(r); + const Real pressure_r = bm->getPressure(r); + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + const Real density_k = bm_neighbor->getDensity(k); + const Real volume_k = bm_neighbor->getRestDensity() / density_k * bm_neighbor->getVolume(k); + const Real pressure_k = bm_neighbor->getPressure(k); + pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); + } + } + pressureGrad_r *= density_r; + bm->setPressureGrad(r, pressureGrad_r); + } + } + } } + } void TimeStepWCSPH::computeV_s() { @@ -315,7 +515,7 @@ void TimeStepWCSPH::computeV_s() { const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); - // Compute density, pressure and v_s for all particles + // Compute v_s for all particles for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); @@ -342,7 +542,6 @@ void TimeStepWCSPH::computeSourceTermRHS() { TimeManager* tm = TimeManager::getCurrent(); const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); - const unsigned int nBoundaries = sim->numberOfBoundaryModels(); // compute v_rr and omega_rr for rigid body using the pressure gradient for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { @@ -355,24 +554,8 @@ void TimeStepWCSPH::computeSourceTermRHS() { { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - Vector3r pressureGrad_r = Vector3r().setZero(); - const Real density_r = bm->getDensity(r); - const Real volume_r = bm->getDensity0() / density_r * bm->getVolume(r); - const Real pressure_r = bm->getPressure(r); - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { - const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - const Real density_k = bm_neighbor->getDensity(k); - const Real volume_k = bm_neighbor->getDensity0() / density_k * bm_neighbor->getVolume(k); - const Real pressure_k = bm_neighbor->getPressure(k); - pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); - } - } - pressureGrad_r *= density_r; - v_rr_body += -dt * rb->getInvMass() * volume_r * pressureGrad_r; - omega_rr_body += -dt * rb->getInertiaTensorInverseW() * volume_r * bm->getPosition(r).cross(pressureGrad_r); - bm->setPressureGrad(r, pressureGrad_r); + v_rr_body += -dt * rb->getInvMass() * bm->getArtificialVolume(r) * bm->getPressureGrad(r); + omega_rr_body += -dt * rb->getInertiaTensorInverseW() * bm->getArtificialVolume(r) * bm->getPosition(r).cross(bm->getPressureGrad(r)); } } } @@ -382,11 +565,14 @@ void TimeStepWCSPH::computeSourceTermRHS() { // compute v_rr for all particles for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - bm->setV_rr(r, bm->getV_rr_body() + bm->getOmega_rr_body().cross(bm->getPosition(r))); + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + if (rb->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + bm->setV_rr(r, bm->getV_rr_body() + bm->getOmega_rr_body().cross(bm->getPosition(r))); + } } } } @@ -404,7 +590,7 @@ void TimeStepWCSPH::computeSourceTermRHS() { for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); const Real density_k = bm_neighbor->getDensity(k); - const Real volume_k = bm_neighbor->getDensity0() / density_k * bm_neighbor->getVolume(k); + const Real volume_k = bm_neighbor->getArtificialVolume(k); const Vector3r v_rr_k = bm_neighbor->getV_rr(k); minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); } @@ -416,69 +602,6 @@ void TimeStepWCSPH::computeSourceTermRHS() { } } -void TimeStepWCSPH::solveRigidRigidPressure() { - Simulation* sim = Simulation::getCurrent(); - DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); - TimeManager* tm = TimeManager::getCurrent(); - const Real dt = tm->getTimeStepSize(); - const unsigned int nFluids = sim->numberOfFluidModels(); - const unsigned int nBoundaries = sim->numberOfBoundaryModels(); - - // solve the equation s = -rho * div¡¤v_rr w.r.t. pressure using relaxed jacobi - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - if (bm->getRigidBodyObject()->isDynamic()) { - std::vector bodyInContact = std::vector(); - unsigned int numContacts = 1; - //#pragma omp parallel default(shared) - { - // compute number of contacts - //#pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - if (boundaryPointSetIndex != pid) { - BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - if (sim->numberOfNeighbors(boundaryPointSetIndex, pid, r) > 0 && std::find(bodyInContact.begin(), bodyInContact.end(), pid) == bodyInContact.end()) { - bodyInContact.push_back(pid); - } - } - } - } - } - numContacts = bodyInContact.size(); - if (numContacts == 0) { - continue; - } - // beta_r_RJ - Real relaxation = 0.5; - - for (unsigned int i = 0; i < sim->getDynamicBoundarySimulator()->getMaxIteration(); i++) { - #pragma omp parallel default(shared) - { - // compute number of contacts - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - bm->setDiagonalElement(r, bm->getMinus_rho_div_v_rr(r) / bm->getPressure(r)); - Real pressureNextIter = bm->getPressure(r) + relaxation / bm->getDiagonalElement(r) * (bm->getSourceTerm(r) - bm->getMinus_rho_div_v_rr(r)); - bm->setPressure(r, pressureNextIter); - } - } - computeSourceTermRHS(); - } - - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - Real artificialVolume = (bm->getDensity0() * bm->getVolume(r)) / bm->getDensity(r); - const Vector3r a = -1 / bm->getDensity(r) * bm->getPressureGrad(r); - bm->addForce(bm->getPosition(r), bm->getRigidBodyObject()->getMass() * a); - } - } - } - } -} - void TimeStepWCSPH::performNeighborhoodSearch() { if (Simulation::getCurrent()->zSortEnabled()) diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h index b89a4bcc..5c0373f0 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h @@ -38,10 +38,11 @@ namespace SPH void computeRigidRigidAccels(); // for rigid-rigid forces void computeRigidParticleDensity(); + void computeRigidParticlePressureGrad(); void computeV_s(); void computeSourceTermRHS(); void computeSourceTerm(); - void solveRigidRigidPressure(); + void computeDiagonalElement(); public: static int STIFFNESS; diff --git a/Simulator/DynamicBoundarySimulator.h b/Simulator/DynamicBoundarySimulator.h index c0dec04c..034a31ec 100644 --- a/Simulator/DynamicBoundarySimulator.h +++ b/Simulator/DynamicBoundarySimulator.h @@ -9,7 +9,7 @@ namespace SPH { class DynamicBoundarySimulator : public BoundarySimulator { private: Real m_dampingCoeff = 0.0; - Real m_maxIteration = 20; + Real m_maxIteration = 10; protected: SimulatorBase* m_base; From 310a7190eae768e8d3d1206c6e919e4a410d55f9 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Thu, 4 May 2023 19:25:34 +0200 Subject: [PATCH 17/38] changed computeDiagonalElement (still not correct) --- SPlisHSPlasH/BoundaryModel_Akinci2012.cpp | 16 +- SPlisHSPlasH/BoundaryModel_Akinci2012.h | 31 +++- SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 185 ++++++++++++---------- Simulator/DynamicBoundarySimulator.cpp | 2 +- Simulator/SimulatorBase.cpp | 2 +- 5 files changed, 144 insertions(+), 92 deletions(-) diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp index 90623cdc..e938e1b2 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp @@ -23,7 +23,9 @@ BoundaryModel_Akinci2012::BoundaryModel_Akinci2012() : m_v_rr(), m_minus_rho_div_v_rr(), m_diagonalElement(), - m_artificialVolume() + m_artificialVolume(), + m_particleID(), + m_lastPressure() { m_sorted = false; m_pointSetIndex = 0; @@ -50,6 +52,8 @@ BoundaryModel_Akinci2012::~BoundaryModel_Akinci2012(void) m_diagonalElement.clear(); m_pressureGrad.clear(); m_artificialVolume.clear(); + m_particleID.clear(); + m_lastPressure.clear(); } void BoundaryModel_Akinci2012::reset() @@ -74,6 +78,8 @@ void BoundaryModel_Akinci2012::reset() m_diagonalElement[j] = 0; m_pressureGrad[j].setZero(); m_artificialVolume[j] = 0; + m_particleID[j] = j; + m_lastPressure[j] = 0; } } } @@ -148,6 +154,8 @@ void BoundaryModel_Akinci2012::initModel(RigidBodyObject *rbo, const unsigned in m_diagonalElement.resize(numBoundaryParticles); m_pressureGrad.resize(numBoundaryParticles); m_artificialVolume.resize(numBoundaryParticles); + m_particleID.resize(numBoundaryParticles); + m_lastPressure.resize(numBoundaryParticles); m_restDensity = 1; m_v_rr_body = Vector3r().setZero(); m_omega_rr_body = Vector3r().setZero(); @@ -179,6 +187,8 @@ void BoundaryModel_Akinci2012::initModel(RigidBodyObject *rbo, const unsigned in m_v_rr[i].setZero(); m_pressureGrad[i].setZero(); m_artificialVolume[i] = 0.0; + m_particleID[i] = i; + m_lastPressure[i] = 0; } } m_rigidBody = rbo; @@ -211,6 +221,8 @@ void BoundaryModel_Akinci2012::performNeighborhoodSearchSort() d.sort_field(&m_diagonalElement[0]); d.sort_field(&m_pressureGrad[0]); d.sort_field(&m_artificialVolume[0]); + d.sort_field(&m_particleID[0]); + d.sort_field(&m_lastPressure[0]); m_sorted = true; } @@ -241,4 +253,6 @@ void SPH::BoundaryModel_Akinci2012::resize(const unsigned int numBoundaryParticl m_diagonalElement.resize(numBoundaryParticles); m_pressureGrad.resize(numBoundaryParticles); m_artificialVolume.resize(numBoundaryParticles); + m_particleID.resize(numBoundaryParticles); + m_lastPressure.resize(numBoundaryParticles); } diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.h b/SPlisHSPlasH/BoundaryModel_Akinci2012.h index 92b68af7..6dfc0a8a 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.h +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.h @@ -37,8 +37,10 @@ namespace SPH std::vector m_fields; // values required for Gissler 2019 strong coupling based on Akinci 2012 + std::vector m_particleID; std::vector m_density; std::vector m_pressure; + std::vector m_lastPressure; std::vector m_artificialVolume; std::vector m_v_s; std::vector m_s; // source term @@ -74,6 +76,18 @@ namespace SPH void initModel(RigidBodyObject *rbo, const unsigned int numBoundaryParticles, Vector3r *boundaryParticles); + FORCE_INLINE const unsigned int& getParticleID(const Real& index) const { + return m_particleID[index]; + } + + FORCE_INLINE unsigned int& getParticleID(const Real& index) { + return m_particleID[index]; + } + + FORCE_INLINE void setParticleID(const Real& index, const Real& value) { + m_particleID[index] = value; + } + FORCE_INLINE const Real& getDensity(const Real& index) const { return m_density[index]; } @@ -98,6 +112,17 @@ namespace SPH m_pressure[index] = value; } + FORCE_INLINE const Real& getLastPressure(const Real& index) const { + return m_lastPressure[index]; + } + + FORCE_INLINE Real& getLastPressure(const Real& index) { + return m_lastPressure[index]; + } + + FORCE_INLINE void setLastPressure(const Real& index, const Real& value) { + m_lastPressure[index] = value; + } FORCE_INLINE const Real& getRestDensity() const { return m_restDensity; @@ -216,15 +241,15 @@ namespace SPH m_pressureGrad[i] = value; } - FORCE_INLINE Real& getMinus_rho_div_v_rr(const unsigned int i) { + FORCE_INLINE Real& getSourceTermRHS(const unsigned int i) { return m_minus_rho_div_v_rr[i]; } - FORCE_INLINE const Real& getMinus_rho_div_v_rr(const unsigned int i) const { + FORCE_INLINE const Real& getSourceTermRHS(const unsigned int i) const { return m_minus_rho_div_v_rr[i]; } - FORCE_INLINE void setMinus_rho_div_v_rr(const unsigned int i, const Real& value) { + FORCE_INLINE void setSourceTermRHS(const unsigned int i, const Real& value) { m_minus_rho_div_v_rr[i] = value; } diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index e1b517e9..892d883a 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -184,8 +184,8 @@ void TimeStepWCSPH::computePressureAccels(const unsigned int fluidModelIndex) { forall_fluid_neighbors( // Pressure const Real density_j = fm_neighbor->getDensity(neighborIndex) * density0 / fm_neighbor->getDensity0(); - const Real dpj = m_simulationData.getPressure(pid, neighborIndex) / (density_j * density_j); - ai -= density0 * fm_neighbor->getVolume(neighborIndex) * (dpi + dpj) * sim->gradW(xi - xj); + const Real dpj = m_simulationData.getPressure(pid, neighborIndex) / (density_j * density_j); + ai -= density0 * fm_neighbor->getVolume(neighborIndex) * (dpi + dpj) * sim->gradW(xi - xj); ); ////////////////////////////////////////////////////////////////////////// @@ -195,20 +195,20 @@ void TimeStepWCSPH::computePressureAccels(const unsigned int fluidModelIndex) { if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { forall_boundary_neighbors( const Vector3r a = density0 * bm_neighbor->getVolume(neighborIndex) * (dpi + dpj) * sim->gradW(xi - xj); - ai -= a; - bm_neighbor->addForce(xj, model->getMass(i) * a); + ai -= a; + bm_neighbor->addForce(xj, model->getMass(i) * a); ); } else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) { forall_density_maps( const Vector3r a = -density0 * (dpi + dpj) * gradRho; - ai -= a; - bm_neighbor->addForce(xj, model->getMass(i) * a); + ai -= a; + bm_neighbor->addForce(xj, model->getMass(i) * a); ); } else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Bender2019) { forall_volume_maps( const Vector3r a = density0 * Vj * (dpi + dpj) * sim->gradW(xi - xj); - ai -= a; - bm_neighbor->addForce(xj, model->getMass(i) * a); + ai -= a; + bm_neighbor->addForce(xj, model->getMass(i) * a); ); } } @@ -225,6 +225,7 @@ void TimeStepWCSPH::computeRigidRigidAccels() { // solve the equation s = -rho * div¡¤v_rr w.r.t. pressure using relaxed jacobi for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); if (bm->getRigidBodyObject()->isDynamic()) { std::vector bodyInContact = std::vector(); unsigned int numContacts = 1; @@ -250,8 +251,24 @@ void TimeStepWCSPH::computeRigidRigidAccels() { // beta_r_RJ Real relaxation = 0.5 / numContacts; + // source term don't change in WCSPH + computeV_s(); computeSourceTerm(); - for (unsigned int i = 0; i < 5; i++) { + + for (unsigned int i = 0; i < sim->getDynamicBoundarySimulator()->getMaxIteration(); i++) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Real artificialVolume = (bm->getRestDensity() * bm->getVolume(r)) / bm->getDensity(r); + const Vector3r a = - bm->getArtificialVolume(r) * bm->getPressureGrad(r); + bm->addForce(bm->getPosition(r), bm->getRigidBodyObject()->getMass() * a); + } + } + // update position and velocity using the current pressure + sim->getDynamicBoundarySimulator()->timeStepStrongCoupling(); + + Real densityErrorAvg = 0; computeRigidParticleDensity(); computeRigidParticlePressureGrad(); computeSourceTermRHS(); @@ -261,28 +278,25 @@ void TimeStepWCSPH::computeRigidRigidAccels() { // compute number of contacts #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - Real pressureNextIter = bm->getPressure(r) + relaxation / bm->getDiagonalElement(r) * (bm->getSourceTerm(r) - bm->getMinus_rho_div_v_rr(r)); + densityErrorAvg += bm->getDensity(r); + Real pressureNextIter = bm->getPressure(r) + relaxation / bm->getDiagonalElement(r) * (bm->getSourceTerm(r) - bm->getSourceTermRHS(r)); + bm->setLastPressure(r, bm->getPressure(r)); bm->setPressure(r, pressureNextIter); } } - } - computeRigidParticlePressureGrad(); + densityErrorAvg /= bm->numberOfParticles(); - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - Real artificialVolume = (bm->getRestDensity() * bm->getVolume(r)) / bm->getDensity(r); - const Vector3r a = -1 / bm->getDensity(r) * bm->getPressureGrad(r); - bm->addForce(bm->getPosition(r), bm->getRigidBodyObject()->getMass() * a); + // only particles int contact with other object ? + if ((bm->getRestDensity() - densityErrorAvg) / bm->getRestDensity() < 0.001) { + break; } } + } } } void TimeStepWCSPH::computeSourceTerm() { - computeV_s(); Simulation* sim = Simulation::getCurrent(); DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); TimeManager* tm = TimeManager::getCurrent(); @@ -324,13 +338,13 @@ void TimeStepWCSPH::computeDiagonalElement() { const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + for (unsigned int pointSetIndex_r = nFluids; pointSetIndex_r < sim->numberOfPointSets(); pointSetIndex_r++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_r)); DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); if (rb->isDynamic()) { #pragma omp parallel default(shared) { - #pragma omp for schedule(static) + #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { Matrix3r productMat_r; Vector3r pos_r = bm->getPosition(r); @@ -338,14 +352,14 @@ void TimeStepWCSPH::computeDiagonalElement() { pos_r.z(), 0, -pos_r.x(), -pos_r.y(), pos_r.x(), 0; - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - BoundaryModel_Akinci2012* bm_i = static_cast(sim->getBoundaryModelFromPointSet(pid)); + for (unsigned int pointSetIndex_i = nFluids; pointSetIndex_i < sim->numberOfPointSets(); pointSetIndex_i++) { + BoundaryModel_Akinci2012* bm_i = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_i)); DynamicRigidBody* rb_i = static_cast(bm_i->getRigidBodyObject()); Real diagonal = 0; // neighbors of r - for (unsigned int m = 0; m < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); m++) { + for (unsigned int m = 0; m < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_i, r); m++) { - const unsigned int i = sim->getNeighbor(boundaryPointSetIndex, pid, r, m); + const unsigned int i = sim->getNeighbor(pointSetIndex_r, pointSetIndex_i, r, m); Vector3r coeffSum_ik; Vector3r gradWri = sim->gradW(bm->getPosition(r) - bm_i->getPosition(i)); @@ -355,76 +369,75 @@ void TimeStepWCSPH::computeDiagonalElement() { pos_i.z(), 0, -pos_i.x(), -pos_i.y(), pos_i.x(), 0; - // neighbors of i - for (unsigned int pid2 = nFluids; pid2 < sim->numberOfPointSets(); pid2++) { - BoundaryModel_Akinci2012* bm_k = static_cast(sim->getBoundaryModelFromPointSet(pid2)); - for (unsigned int n = 0; n < sim->numberOfNeighbors(pid, pid2, i); n++) { - const unsigned int k = sim->getNeighbor(pid, pid2, i, n); - Vector3r coeffSum_kj; - - Vector3r pos_k = bm_k->getPosition(k); - Matrix3r productMat_k; - productMat_k << 0, -pos_k.z(), pos_k.y(), - pos_k.z(), 0, -pos_k.x(), - -pos_k.y(), pos_k.x(), 0; - Matrix3r K_ik = rb_i->getInvMass() * Matrix3r::Identity() - productMat_i * rb_i->getInertiaTensorInverseW() * productMat_k; - - // neighbors of k - for (unsigned int pid3 = nFluids; pid3 < sim->numberOfPointSets(); pid3++) { - BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pid3)); - for (unsigned int o = 0; o < sim->numberOfNeighbors(pid2, pid3, k); o++) { - const unsigned int j = sim->getNeighbor(pid2, pid3, k, o); - Vector3r gradWkj = sim->gradW(bm_k->getPosition(k) - bm_j->getPosition(j)); - if (pid2 == boundaryPointSetIndex && k == r) { - coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_k->getDensity(k) * bm_k->getDensity(k)) * gradWkj; - } - if (pid3 == boundaryPointSetIndex && j == r) { - coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_j->getDensity(j) * bm_j->getDensity(j)) * gradWkj; - } + // neighbors of i in the same rigid body, denoted as k + for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_i, pointSetIndex_i, i); n++) { + const unsigned int k = sim->getNeighbor(pointSetIndex_i, pointSetIndex_i, i, n); + Vector3r coeffSum_kj; + + Vector3r pos_k = bm_i->getPosition(k); + Matrix3r productMat_k; + productMat_k << 0, -pos_k.z(), pos_k.y(), + pos_k.z(), 0, -pos_k.x(), + -pos_k.y(), pos_k.x(), 0; + Matrix3r K_ik = rb_i->getInvMass() * Matrix3r::Identity() - productMat_i * rb_i->getInertiaTensorInverseW() * productMat_k; + + // neighbors of k in all bodies, denoted as j + for (unsigned int pointSetIndex_j = nFluids; pointSetIndex_j < sim->numberOfPointSets(); pointSetIndex_j++) { + BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_j)); + for (unsigned int o = 0; o < sim->numberOfNeighbors(pointSetIndex_i, pointSetIndex_j, k); o++) { + const unsigned int j = sim->getNeighbor(pointSetIndex_i, pointSetIndex_j, k, o); + Vector3r gradWkj = sim->gradW(bm_i->getPosition(k) - bm_j->getPosition(j)); + if (pointSetIndex_i == pointSetIndex_r && bm_i->getParticleID(k) == bm->getParticleID(r)) { + coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_i->getDensity(k) * bm_i->getDensity(k)) * gradWkj; + } + if (pointSetIndex_j == pointSetIndex_r && bm_j->getParticleID(j) == bm->getParticleID(r)) { + coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_j->getDensity(j) * bm_j->getDensity(j)) * gradWkj; } } - coeffSum_kj = bm_k->getArtificialVolume(k) * K_ik * bm_k->getDensity(k) * coeffSum_kj; - coeffSum_ik += coeffSum_kj; } + coeffSum_kj = bm_i->getArtificialVolume(k) * K_ik * bm_i->getDensity(k) * coeffSum_kj; + if (r == 0) { + std::cout << bm_i->getVolume(k) << std::endl; + } + coeffSum_ik += coeffSum_kj; } + coeffSum_ik *= dt; Vector3r coeffSum_rk; - // neighbors of r - for (unsigned int pid2 = nFluids; pid2 < sim->numberOfPointSets(); pid2++) { - BoundaryModel_Akinci2012* bm_k = static_cast(sim->getBoundaryModelFromPointSet(pid2)); - for (unsigned int n = 0; n < sim->numberOfNeighbors(boundaryPointSetIndex, pid2, r); n++) { - const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid2, r, n); - Vector3r coeffSum_kj; - - Vector3r pos_k = bm_k->getPosition(k); - Matrix3r productMat_k; - productMat_k << 0, -pos_k.z(), pos_k.y(), - pos_k.z(), 0, -pos_k.x(), - -pos_k.y(), pos_k.x(), 0; - Matrix3r K_rk = rb->getInvMass() * Matrix3r::Identity() - productMat_r * rb->getInertiaTensorInverseW() * productMat_k; - - //neighbors of k - for (unsigned int pid3 = nFluids; pid3 < sim->numberOfPointSets(); pid3++) { - BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pid3)); - for (unsigned int o = 0; o < sim->numberOfNeighbors(pid2, pid3, k); o++) { - const unsigned int j = sim->getNeighbor(pid2, pid3, k, o); - Vector3r gradWkj = sim->gradW(bm_k->getPosition(k) - bm_j->getPosition(j)); - if (pid2 == boundaryPointSetIndex && k == r) { - coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_k->getDensity(k) * bm_k->getDensity(k)) * gradWkj; - } - if (pid3 == boundaryPointSetIndex && j == r) { - coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_j->getDensity(j) * bm_j->getDensity(j)) * gradWkj; - } + // neighbors of r in the same rigid body, denoted as k + for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_r, r); n++) { + const unsigned int k = sim->getNeighbor(pointSetIndex_r, pointSetIndex_r, r, n); + Vector3r coeffSum_kj; + + Vector3r pos_k = bm->getPosition(k); + Matrix3r productMat_k; + productMat_k << 0, -pos_k.z(), pos_k.y(), + pos_k.z(), 0, -pos_k.x(), + -pos_k.y(), pos_k.x(), 0; + Matrix3r K_rk = rb->getInvMass() * Matrix3r::Identity() - productMat_r * rb->getInertiaTensorInverseW() * productMat_k; + + // neighbors of k in all bodies, denoted as j + for (unsigned int pointSetIndex_j = nFluids; pointSetIndex_j < sim->numberOfPointSets(); pointSetIndex_j++) { + BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_j)); + for (unsigned int o = 0; o < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_j, k); o++) { + const unsigned int j = sim->getNeighbor(pointSetIndex_r, pointSetIndex_j, k, o); + Vector3r gradWkj = sim->gradW(bm->getPosition(k) - bm_j->getPosition(j)); + if (bm->getParticleID(k) == bm->getParticleID(r)) { + coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm->getDensity(k) * bm->getDensity(k)) * gradWkj; + } + if (pointSetIndex_j == pointSetIndex_r && bm_j->getParticleID(j) == bm->getParticleID(r)) { + coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_j->getDensity(j) * bm_j->getDensity(j)) * gradWkj; } } - coeffSum_kj = bm_k->getArtificialVolume(k) * K_rk * bm_k->getDensity(k) * coeffSum_kj; - coeffSum_rk += coeffSum_kj; } + coeffSum_kj = bm->getArtificialVolume(k) * K_rk * bm->getDensity(k) * coeffSum_kj; + coeffSum_rk += coeffSum_kj; } + coeffSum_rk *= dt; - diagonal += bm_i->getArtificialVolume(i) * bm_i->getDensity(i) * (-coeffSum_ik + coeffSum_rk).dot(gradWri); + diagonal = bm_i->getArtificialVolume(i) * bm_i->getDensity(i) * (coeffSum_ik - coeffSum_rk).dot(gradWri); bm->getDiagonalElement(r) += diagonal; } } @@ -562,7 +575,7 @@ void TimeStepWCSPH::computeSourceTermRHS() { bm->setV_rr_body(v_rr_body); bm->setOmega_rr_body(omega_rr_body); } - // compute v_rr for all particles + // compute v_rr for all particles (predicted velocity) for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); @@ -596,7 +609,7 @@ void TimeStepWCSPH::computeSourceTermRHS() { } } minus_rho_div_v_rr = -minus_rho_div_v_rr; - bm->setMinus_rho_div_v_rr(r, minus_rho_div_v_rr); + bm->setSourceTermRHS(r, minus_rho_div_v_rr); } } } diff --git a/Simulator/DynamicBoundarySimulator.cpp b/Simulator/DynamicBoundarySimulator.cpp index 94c56efc..3e9f7fa7 100644 --- a/Simulator/DynamicBoundarySimulator.cpp +++ b/Simulator/DynamicBoundarySimulator.cpp @@ -204,7 +204,7 @@ void DynamicBoundarySimulator::timeStepStrongCoupling() { const unsigned int nObjects = sim->numberOfBoundaryModels(); #pragma omp parallel for for (int i = 0; i < nObjects; i++) { - BoundaryModel* bm = sim->getBoundaryModel(i); + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModel(i)); RigidBodyObject* rbo = bm->getRigidBodyObject(); if (rbo->isDynamic()) { DynamicRigidBody* drb = dynamic_cast(rbo); diff --git a/Simulator/SimulatorBase.cpp b/Simulator/SimulatorBase.cpp index fa1e9359..47ac395f 100644 --- a/Simulator/SimulatorBase.cpp +++ b/Simulator/SimulatorBase.cpp @@ -97,7 +97,7 @@ SimulatorBase::SimulatorBase() m_colorMapType.resize(1, 0); m_renderMinValue.resize(1, 0.0); m_renderMaxValue.resize(1, 5.0); - m_particleAttributes = "velocity"; + m_particleAttributes = "velocity;density"; m_timeStepCB = nullptr; m_resetCB = nullptr; m_updateGUI = false; From 8c9e2e8af1fecb357080c50ab7599a2fd24b63cf Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Mon, 8 May 2023 11:23:19 +0200 Subject: [PATCH 18/38] refactorized --- SPlisHSPlasH/CMakeLists.txt | 2 + SPlisHSPlasH/StrongCouplingBoundarySolver.cpp | 324 +++++++++++++++++ SPlisHSPlasH/StrongCouplingBoundarySolver.h | 26 ++ SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 339 +----------------- SPlisHSPlasH/WCSPH/TimeStepWCSPH.h | 7 - Simulator/DynamicBoundarySimulator.cpp | 3 +- 6 files changed, 365 insertions(+), 336 deletions(-) create mode 100644 SPlisHSPlasH/StrongCouplingBoundarySolver.cpp create mode 100644 SPlisHSPlasH/StrongCouplingBoundarySolver.h diff --git a/SPlisHSPlasH/CMakeLists.txt b/SPlisHSPlasH/CMakeLists.txt index 1a123ba3..a38ec96e 100644 --- a/SPlisHSPlasH/CMakeLists.txt +++ b/SPlisHSPlasH/CMakeLists.txt @@ -233,6 +233,8 @@ add_library(SPlisHSPlasH NonPressureForceBase.h XSPH.cpp XSPH.h + StrongCouplingBoundarySolver.cpp + StrongCouplingBoundarySolver.h ${WCSPH_HEADER_FILES} diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp new file mode 100644 index 00000000..b8f7fb98 --- /dev/null +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp @@ -0,0 +1,324 @@ +#include "SPlisHSPlasH/BoundaryModel_Akinci2012.h" +#include "StrongCouplingBoundarySolver.h" +#include "TimeManager.h" +#include "DynamicRigidBody.h" + +using namespace SPH; + +StrongCouplingBoundarySolver* StrongCouplingBoundarySolver::current = nullptr; + +void StrongCouplingBoundarySolver::computeSourceTerm() { + Simulation* sim = Simulation::getCurrent(); + DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + TimeManager* tm = TimeManager::getCurrent(); + const Real dt = tm->getTimeStepSize(); + const unsigned int nFluids = sim->numberOfFluidModels(); + + // compute source term s for all particles + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + if (bm->getRigidBodyObject()->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Real s = 0; + // iterate over all rigid bodies except bm, since the divergence of particles in the same rigid body should be 0. + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + if (boundaryPointSetIndex != pid) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + // sum up divergence of v_s + s += bm_neighbor->getArtificialVolume(k) * bm_neighbor->getDensity(k) * (bm_neighbor->getV_s(k) - bm->getV_s(r)).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); + } + } + } + s += (bm->getRestDensity() - bm->getDensity(r)) / dt; + bm->setSourceTerm(r, s); + } + } + } + } +} + +void StrongCouplingBoundarySolver::computeDiagonalElement() { + Simulation* sim = Simulation::getCurrent(); + DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + TimeManager* tm = TimeManager::getCurrent(); + const Real dt = tm->getTimeStepSize(); + const unsigned int nFluids = sim->numberOfFluidModels(); + + for (unsigned int pointSetIndex_r = nFluids; pointSetIndex_r < sim->numberOfPointSets(); pointSetIndex_r++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_r)); + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + if (rb->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Matrix3r productMat_r; + Vector3r pos_r = bm->getPosition(r); + productMat_r << 0, -pos_r.z(), pos_r.y(), + pos_r.z(), 0, -pos_r.x(), + -pos_r.y(), pos_r.x(), 0; + Real diagonal = 0; + for (unsigned int pointSetIndex_i = nFluids; pointSetIndex_i < sim->numberOfPointSets(); pointSetIndex_i++) { + BoundaryModel_Akinci2012* bm_i = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_i)); + DynamicRigidBody* rb_i = static_cast(bm_i->getRigidBodyObject()); + + // neighbors of r + for (unsigned int m = 0; m < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_i, r); m++) { + + const unsigned int i = sim->getNeighbor(pointSetIndex_r, pointSetIndex_i, r, m); + Vector3r coeffSum_ik; + + Vector3r gradWri = sim->gradW(bm->getPosition(r) - bm_i->getPosition(i)); + Matrix3r productMat_i; + Vector3r pos_i = bm_i->getPosition(i); + productMat_i << 0, -pos_i.z(), pos_i.y(), + pos_i.z(), 0, -pos_i.x(), + -pos_i.y(), pos_i.x(), 0; + + // neighbors of i in the same rigid body, denoted as k + for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_i, pointSetIndex_i, i); n++) { + const unsigned int k = sim->getNeighbor(pointSetIndex_i, pointSetIndex_i, i, n); + Vector3r coeffSum_kj; + + Vector3r pos_k = bm_i->getPosition(k); + Matrix3r productMat_k; + productMat_k << 0, -pos_k.z(), pos_k.y(), + pos_k.z(), 0, -pos_k.x(), + -pos_k.y(), pos_k.x(), 0; + Matrix3r K_ik = rb_i->getInvMass() * Matrix3r::Identity() - productMat_i * rb_i->getInertiaTensorInverseW() * productMat_k; + + // neighbors of k in all bodies, denoted as j + for (unsigned int pointSetIndex_j = nFluids; pointSetIndex_j < sim->numberOfPointSets(); pointSetIndex_j++) { + BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_j)); + for (unsigned int o = 0; o < sim->numberOfNeighbors(pointSetIndex_i, pointSetIndex_j, k); o++) { + const unsigned int j = sim->getNeighbor(pointSetIndex_i, pointSetIndex_j, k, o); + Vector3r gradWkj = sim->gradW(bm_i->getPosition(k) - bm_j->getPosition(j)); + if (pointSetIndex_i == pointSetIndex_r && bm_i->getParticleID(k) == bm->getParticleID(r)) { + coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_i->getDensity(k) * bm_i->getDensity(k)) * gradWkj; + } + if (pointSetIndex_j == pointSetIndex_r && bm_j->getParticleID(j) == bm->getParticleID(r)) { + coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_j->getDensity(j) * bm_j->getDensity(j)) * gradWkj; + } + } + } + coeffSum_kj = bm_i->getArtificialVolume(k) * K_ik * bm_i->getDensity(k) * coeffSum_kj; + coeffSum_ik += coeffSum_kj; + } + + coeffSum_ik *= dt; + + Vector3r coeffSum_rk; + // neighbors of r in the same rigid body, denoted as k + for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_r, r); n++) { + const unsigned int k = sim->getNeighbor(pointSetIndex_r, pointSetIndex_r, r, n); + Vector3r coeffSum_kj; + + Vector3r pos_k = bm->getPosition(k); + Matrix3r productMat_k; + productMat_k << 0, -pos_k.z(), pos_k.y(), + pos_k.z(), 0, -pos_k.x(), + -pos_k.y(), pos_k.x(), 0; + Matrix3r K_rk = rb->getInvMass() * Matrix3r::Identity() - productMat_r * rb->getInertiaTensorInverseW() * productMat_k; + + // neighbors of k in all bodies, denoted as j + for (unsigned int pointSetIndex_j = nFluids; pointSetIndex_j < sim->numberOfPointSets(); pointSetIndex_j++) { + BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_j)); + for (unsigned int o = 0; o < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_j, k); o++) { + const unsigned int j = sim->getNeighbor(pointSetIndex_r, pointSetIndex_j, k, o); + Vector3r gradWkj = sim->gradW(bm->getPosition(k) - bm_j->getPosition(j)); + if (bm->getParticleID(k) == bm->getParticleID(r)) { + coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm->getDensity(k) * bm->getDensity(k)) * gradWkj; + } + if (pointSetIndex_j == pointSetIndex_r && bm_j->getParticleID(j) == bm->getParticleID(r)) { + coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_j->getDensity(j) * bm_j->getDensity(j)) * gradWkj; + } + } + } + coeffSum_kj = bm->getArtificialVolume(k) * K_rk * bm->getDensity(k) * coeffSum_kj; + coeffSum_rk += coeffSum_kj; + } + + coeffSum_rk *= dt; + + diagonal += bm_i->getArtificialVolume(i) * bm_i->getDensity(i) * (coeffSum_ik - coeffSum_rk).dot(gradWri); + } + } + bm->setDiagonalElement(r, diagonal); + } + } + } + } +} + +void StrongCouplingBoundarySolver::computeDensityAndVolume() { + // Use dynamic boundary simulator and Akinci2012 + Simulation* sim = Simulation::getCurrent(); + DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + TimeManager* tm = TimeManager::getCurrent(); + const Real dt = tm->getTimeStepSize(); + const unsigned int nFluids = sim->numberOfFluidModels(); + + // Compute density and artificial volume for all particles + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + if (rb->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + // compute density + Real particleDensity = 0; + // iterate over all rigid bodies + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + particleDensity += bm->getRestDensity() * bm->getVolume(r) * sim->W(bm->getPosition(r) - bm_neighbor->getPosition(k)); + } + } + // 0.8 for compensation + bm->setDensity(r, particleDensity / 0.8); + bm->setArtificialVolume(r, bm->getRestDensity() * bm->getVolume(r) / bm->getDensity(r)); + } + } + } + } +} + +void StrongCouplingBoundarySolver::computePressureGrad() { + Simulation* sim = Simulation::getCurrent(); + DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + TimeManager* tm = TimeManager::getCurrent(); + const Real dt = tm->getTimeStepSize(); + const unsigned int nFluids = sim->numberOfFluidModels(); + + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + if (rb->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Vector3r pressureGrad_r = Vector3r().setZero(); + const Real density_r = bm->getDensity(r); + const Real pressure_r = bm->getPressure(r); + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + const Real density_k = bm_neighbor->getDensity(k); + const Real volume_k = bm_neighbor->getRestDensity() / density_k * bm_neighbor->getVolume(k); + const Real pressure_k = bm_neighbor->getPressure(k); + pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); + } + } + pressureGrad_r *= density_r; + bm->setPressureGrad(r, pressureGrad_r); + } + } + } + } + +} + +void StrongCouplingBoundarySolver::computeV_s() { + // Use dynamic boundary simulator and Akinci2012 + Simulation* sim = Simulation::getCurrent(); + DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + TimeManager* tm = TimeManager::getCurrent(); + const Real dt = tm->getTimeStepSize(); + const unsigned int nFluids = sim->numberOfFluidModels(); + + // Compute v_s for all particles + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + if (rb->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + // compute v_s + Vector3r gravForce = rb->getMass() * Vector3r(sim->getVecValue(Simulation::GRAVITATION)); + // the rb->getForce() contains only fluid-rigid forces + Vector3r F_R = rb->getForce() + gravForce; + bm->setV_s(r, rb->getVelocity() + dt * rb->getInvMass() * F_R + + (rb->getAngularVelocity() + rb->getInertiaTensorInverseW() * (dt * rb->getTorque() + dt * (rb->getInertiaTensorW() * rb->getAngularVelocity()).cross(rb->getAngularVelocity()))).cross(bm->getPosition(r))); + } + } + } + } +} + +void StrongCouplingBoundarySolver::computeSourceTermRHS() { + Simulation* sim = Simulation::getCurrent(); + DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + TimeManager* tm = TimeManager::getCurrent(); + const Real dt = tm->getTimeStepSize(); + const unsigned int nFluids = sim->numberOfFluidModels(); + + // compute v_rr and omega_rr for rigid body using the pressure gradient + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + Vector3r v_rr_body = Vector3r().setZero(); + Vector3r omega_rr_body = Vector3r().setZero(); + if (rb->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + v_rr_body += -dt * rb->getInvMass() * bm->getArtificialVolume(r) * bm->getPressureGrad(r); + omega_rr_body += -dt * rb->getInertiaTensorInverseW() * bm->getArtificialVolume(r) * bm->getPosition(r).cross(bm->getPressureGrad(r)); + } + } + } + bm->setV_rr_body(v_rr_body); + bm->setOmega_rr_body(omega_rr_body); + } + // compute v_rr for all particles (predicted velocity) + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + if (rb->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + bm->setV_rr(r, bm->getV_rr_body() + bm->getOmega_rr_body().cross(bm->getPosition(r))); + } + } + } + } + // compute the -rho * (div v_rr), which is the RHS to the source term + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Real minus_rho_div_v_rr = 0; + const Vector3r v_rr_r = bm->getV_rr(r); + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + const Real density_k = bm_neighbor->getDensity(k); + const Real volume_k = bm_neighbor->getArtificialVolume(k); + const Vector3r v_rr_k = bm_neighbor->getV_rr(k); + minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); + } + } + minus_rho_div_v_rr = -minus_rho_div_v_rr; + bm->setSourceTermRHS(r, minus_rho_div_v_rr); + } + } + } +} \ No newline at end of file diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.h b/SPlisHSPlasH/StrongCouplingBoundarySolver.h new file mode 100644 index 00000000..7d472568 --- /dev/null +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.h @@ -0,0 +1,26 @@ +#include "SPlisHSPlasH/Common.h" +#include "SPlisHSPlasH/TimeStep.h" +#include "SPlisHSPlasH/SPHKernels.h" + +namespace SPH { + class StrongCouplingBoundarySolver { + public: + ~StrongCouplingBoundarySolver(){ + current = nullptr; + } + static StrongCouplingBoundarySolver* getCurrent() { + if (current == nullptr) { + current = new StrongCouplingBoundarySolver(); + } + return current; + } + void computeDensityAndVolume(); + void computePressureGrad(); + void computeV_s(); + void computeSourceTermRHS(); + void computeSourceTerm(); + void computeDiagonalElement(); + private: + static StrongCouplingBoundarySolver* current; + }; +} \ No newline at end of file diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index 892d883a..04deab96 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -9,7 +9,8 @@ #include "SPlisHSPlasH/BoundaryModel_Koschier2017.h" #include "SPlisHSPlasH/BoundaryModel_Bender2019.h" #include "Simulator/DynamicBoundarySimulator.h" -#include +#include "SPlisHSPlasH/DynamicRigidBody.h" +#include "SPlisHSPlasH/StrongCouplingBoundarySolver.h" using namespace SPH; using namespace std; @@ -221,6 +222,7 @@ void TimeStepWCSPH::computeRigidRigidAccels() { TimeManager* tm = TimeManager::getCurrent(); const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); + StrongCouplingBoundarySolver* boundarySolver = StrongCouplingBoundarySolver::getCurrent(); // solve the equation s = -rho * div¡¤v_rr w.r.t. pressure using relaxed jacobi for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { @@ -252,10 +254,13 @@ void TimeStepWCSPH::computeRigidRigidAccels() { Real relaxation = 0.5 / numContacts; // source term don't change in WCSPH - computeV_s(); - computeSourceTerm(); + boundarySolver->computeV_s(); + boundarySolver->computeSourceTerm(); for (unsigned int i = 0; i < sim->getDynamicBoundarySimulator()->getMaxIteration(); i++) { + boundarySolver->computeDensityAndVolume(); + boundarySolver->computePressureGrad(); + #pragma omp parallel default(shared) { #pragma omp for schedule(static) @@ -269,10 +274,9 @@ void TimeStepWCSPH::computeRigidRigidAccels() { sim->getDynamicBoundarySimulator()->timeStepStrongCoupling(); Real densityErrorAvg = 0; - computeRigidParticleDensity(); - computeRigidParticlePressureGrad(); - computeSourceTermRHS(); - computeDiagonalElement(); + + boundarySolver->computeSourceTermRHS(); + boundarySolver->computeDiagonalElement(); #pragma omp parallel default(shared) { // compute number of contacts @@ -280,7 +284,6 @@ void TimeStepWCSPH::computeRigidRigidAccels() { for (int r = 0; r < bm->numberOfParticles(); r++) { densityErrorAvg += bm->getDensity(r); Real pressureNextIter = bm->getPressure(r) + relaxation / bm->getDiagonalElement(r) * (bm->getSourceTerm(r) - bm->getSourceTermRHS(r)); - bm->setLastPressure(r, bm->getPressure(r)); bm->setPressure(r, pressureNextIter); } } @@ -291,330 +294,10 @@ void TimeStepWCSPH::computeRigidRigidAccels() { break; } } - } } } -void TimeStepWCSPH::computeSourceTerm() { - Simulation* sim = Simulation::getCurrent(); - DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); - TimeManager* tm = TimeManager::getCurrent(); - const Real dt = tm->getTimeStepSize(); - const unsigned int nFluids = sim->numberOfFluidModels(); - - // compute source term s for all particles - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - if (bm->getRigidBodyObject()->isDynamic()) { - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - Real s = 0; - // iterate over all rigid bodies except bm, since the divergence of particles in the same rigid body should be 0. - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - if (boundaryPointSetIndex != pid) { - BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { - const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - // sum up divergence of v_s - s += bm_neighbor->getArtificialVolume(k) * bm_neighbor->getDensity(k) * (bm_neighbor->getV_s(k) - bm->getV_s(r)).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); - } - } - } - s += (bm->getRestDensity() - bm->getDensity(r)) / dt; - bm->setSourceTerm(r, s); - } - } - } - } -} - -void TimeStepWCSPH::computeDiagonalElement() { - Simulation* sim = Simulation::getCurrent(); - DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); - TimeManager* tm = TimeManager::getCurrent(); - const Real dt = tm->getTimeStepSize(); - const unsigned int nFluids = sim->numberOfFluidModels(); - - for (unsigned int pointSetIndex_r = nFluids; pointSetIndex_r < sim->numberOfPointSets(); pointSetIndex_r++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_r)); - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - if (rb->isDynamic()) { - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - Matrix3r productMat_r; - Vector3r pos_r = bm->getPosition(r); - productMat_r << 0, -pos_r.z(), pos_r.y(), - pos_r.z(), 0, -pos_r.x(), - -pos_r.y(), pos_r.x(), 0; - - for (unsigned int pointSetIndex_i = nFluids; pointSetIndex_i < sim->numberOfPointSets(); pointSetIndex_i++) { - BoundaryModel_Akinci2012* bm_i = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_i)); - DynamicRigidBody* rb_i = static_cast(bm_i->getRigidBodyObject()); - Real diagonal = 0; - // neighbors of r - for (unsigned int m = 0; m < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_i, r); m++) { - - const unsigned int i = sim->getNeighbor(pointSetIndex_r, pointSetIndex_i, r, m); - Vector3r coeffSum_ik; - - Vector3r gradWri = sim->gradW(bm->getPosition(r) - bm_i->getPosition(i)); - Matrix3r productMat_i; - Vector3r pos_i = bm_i->getPosition(i); - productMat_i << 0, -pos_i.z(), pos_i.y(), - pos_i.z(), 0, -pos_i.x(), - -pos_i.y(), pos_i.x(), 0; - - // neighbors of i in the same rigid body, denoted as k - for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_i, pointSetIndex_i, i); n++) { - const unsigned int k = sim->getNeighbor(pointSetIndex_i, pointSetIndex_i, i, n); - Vector3r coeffSum_kj; - - Vector3r pos_k = bm_i->getPosition(k); - Matrix3r productMat_k; - productMat_k << 0, -pos_k.z(), pos_k.y(), - pos_k.z(), 0, -pos_k.x(), - -pos_k.y(), pos_k.x(), 0; - Matrix3r K_ik = rb_i->getInvMass() * Matrix3r::Identity() - productMat_i * rb_i->getInertiaTensorInverseW() * productMat_k; - - // neighbors of k in all bodies, denoted as j - for (unsigned int pointSetIndex_j = nFluids; pointSetIndex_j < sim->numberOfPointSets(); pointSetIndex_j++) { - BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_j)); - for (unsigned int o = 0; o < sim->numberOfNeighbors(pointSetIndex_i, pointSetIndex_j, k); o++) { - const unsigned int j = sim->getNeighbor(pointSetIndex_i, pointSetIndex_j, k, o); - Vector3r gradWkj = sim->gradW(bm_i->getPosition(k) - bm_j->getPosition(j)); - if (pointSetIndex_i == pointSetIndex_r && bm_i->getParticleID(k) == bm->getParticleID(r)) { - coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_i->getDensity(k) * bm_i->getDensity(k)) * gradWkj; - } - if (pointSetIndex_j == pointSetIndex_r && bm_j->getParticleID(j) == bm->getParticleID(r)) { - coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_j->getDensity(j) * bm_j->getDensity(j)) * gradWkj; - } - } - } - coeffSum_kj = bm_i->getArtificialVolume(k) * K_ik * bm_i->getDensity(k) * coeffSum_kj; - if (r == 0) { - std::cout << bm_i->getVolume(k) << std::endl; - } - coeffSum_ik += coeffSum_kj; - } - - coeffSum_ik *= dt; - - Vector3r coeffSum_rk; - // neighbors of r in the same rigid body, denoted as k - for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_r, r); n++) { - const unsigned int k = sim->getNeighbor(pointSetIndex_r, pointSetIndex_r, r, n); - Vector3r coeffSum_kj; - - Vector3r pos_k = bm->getPosition(k); - Matrix3r productMat_k; - productMat_k << 0, -pos_k.z(), pos_k.y(), - pos_k.z(), 0, -pos_k.x(), - -pos_k.y(), pos_k.x(), 0; - Matrix3r K_rk = rb->getInvMass() * Matrix3r::Identity() - productMat_r * rb->getInertiaTensorInverseW() * productMat_k; - - // neighbors of k in all bodies, denoted as j - for (unsigned int pointSetIndex_j = nFluids; pointSetIndex_j < sim->numberOfPointSets(); pointSetIndex_j++) { - BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_j)); - for (unsigned int o = 0; o < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_j, k); o++) { - const unsigned int j = sim->getNeighbor(pointSetIndex_r, pointSetIndex_j, k, o); - Vector3r gradWkj = sim->gradW(bm->getPosition(k) - bm_j->getPosition(j)); - if (bm->getParticleID(k) == bm->getParticleID(r)) { - coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm->getDensity(k) * bm->getDensity(k)) * gradWkj; - } - if (pointSetIndex_j == pointSetIndex_r && bm_j->getParticleID(j) == bm->getParticleID(r)) { - coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_j->getDensity(j) * bm_j->getDensity(j)) * gradWkj; - } - } - } - coeffSum_kj = bm->getArtificialVolume(k) * K_rk * bm->getDensity(k) * coeffSum_kj; - coeffSum_rk += coeffSum_kj; - } - - coeffSum_rk *= dt; - - diagonal = bm_i->getArtificialVolume(i) * bm_i->getDensity(i) * (coeffSum_ik - coeffSum_rk).dot(gradWri); - bm->getDiagonalElement(r) += diagonal; - } - } - } - } - } - } -} - -void TimeStepWCSPH::computeRigidParticleDensity() { - // Use dynamic boundary simulator and Akinci2012 - Simulation* sim = Simulation::getCurrent(); - DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); - TimeManager* tm = TimeManager::getCurrent(); - const Real dt = tm->getTimeStepSize(); - const unsigned int nFluids = sim->numberOfFluidModels(); - - // Compute density, artificial volume, and v_s for all particles - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - if (rb->isDynamic()) { - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - // compute density - Real particleDensity = 0; - // iterate over all rigid bodies - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { - const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - particleDensity += bm->getRestDensity() * bm->getVolume(r) * sim->W(bm->getPosition(r) - bm_neighbor->getPosition(k)); - } - } - // 0.8 for compensation - bm->setDensity(r, particleDensity / 0.8); - bm->setArtificialVolume(r, bm->getRestDensity() * bm->getVolume(r) / bm->getDensity(r)); - } - } - } - } -} - -void TimeStepWCSPH::computeRigidParticlePressureGrad() { - Simulation* sim = Simulation::getCurrent(); - DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); - TimeManager* tm = TimeManager::getCurrent(); - const Real dt = tm->getTimeStepSize(); - const unsigned int nFluids = sim->numberOfFluidModels(); - - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - if (rb->isDynamic()) { - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - Vector3r pressureGrad_r = Vector3r().setZero(); - const Real density_r = bm->getDensity(r); - const Real pressure_r = bm->getPressure(r); - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { - const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - const Real density_k = bm_neighbor->getDensity(k); - const Real volume_k = bm_neighbor->getRestDensity() / density_k * bm_neighbor->getVolume(k); - const Real pressure_k = bm_neighbor->getPressure(k); - pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); - } - } - pressureGrad_r *= density_r; - bm->setPressureGrad(r, pressureGrad_r); - } - } - } - } - -} - -void TimeStepWCSPH::computeV_s() { - // Use dynamic boundary simulator and Akinci2012 - Simulation* sim = Simulation::getCurrent(); - DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); - TimeManager* tm = TimeManager::getCurrent(); - const Real dt = tm->getTimeStepSize(); - const unsigned int nFluids = sim->numberOfFluidModels(); - - // Compute v_s for all particles - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - if (rb->isDynamic()) { - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - // compute v_s - Vector3r gravForce = rb->getMass() * Vector3r(sim->getVecValue(Simulation::GRAVITATION)); - // the rb->getForce() contains only fluid-rigid forces - Vector3r F_R = rb->getForce() + gravForce; - bm->setV_s(r, rb->getVelocity() + dt * rb->getInvMass() * F_R + - (rb->getAngularVelocity() + rb->getInertiaTensorInverseW() * (dt * rb->getTorque() + dt * (rb->getInertiaTensorW() * rb->getAngularVelocity()).cross(rb->getAngularVelocity()))).cross(bm->getPosition(r))); - } - } - } - } -} - -void TimeStepWCSPH::computeSourceTermRHS() { - Simulation* sim = Simulation::getCurrent(); - DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); - TimeManager* tm = TimeManager::getCurrent(); - const Real dt = tm->getTimeStepSize(); - const unsigned int nFluids = sim->numberOfFluidModels(); - - // compute v_rr and omega_rr for rigid body using the pressure gradient - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - Vector3r v_rr_body = Vector3r().setZero(); - Vector3r omega_rr_body = Vector3r().setZero(); - if (rb->isDynamic()) { - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - v_rr_body += -dt * rb->getInvMass() * bm->getArtificialVolume(r) * bm->getPressureGrad(r); - omega_rr_body += -dt * rb->getInertiaTensorInverseW() * bm->getArtificialVolume(r) * bm->getPosition(r).cross(bm->getPressureGrad(r)); - } - } - } - bm->setV_rr_body(v_rr_body); - bm->setOmega_rr_body(omega_rr_body); - } - // compute v_rr for all particles (predicted velocity) - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - if (rb->isDynamic()) { - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - bm->setV_rr(r, bm->getV_rr_body() + bm->getOmega_rr_body().cross(bm->getPosition(r))); - } - } - } - } - // compute the -rho * (div v_rr), which is the RHS to the source term - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - Real minus_rho_div_v_rr = 0; - const Vector3r v_rr_r = bm->getV_rr(r); - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { - const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - const Real density_k = bm_neighbor->getDensity(k); - const Real volume_k = bm_neighbor->getArtificialVolume(k); - const Vector3r v_rr_k = bm_neighbor->getV_rr(k); - minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); - } - } - minus_rho_div_v_rr = -minus_rho_div_v_rr; - bm->setSourceTermRHS(r, minus_rho_div_v_rr); - } - } - } -} - void TimeStepWCSPH::performNeighborhoodSearch() { if (Simulation::getCurrent()->zSortEnabled()) diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h index 5c0373f0..e5253c90 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h @@ -36,13 +36,6 @@ namespace SPH virtual void initParameters(); void computeRigidRigidAccels(); - // for rigid-rigid forces - void computeRigidParticleDensity(); - void computeRigidParticlePressureGrad(); - void computeV_s(); - void computeSourceTermRHS(); - void computeSourceTerm(); - void computeDiagonalElement(); public: static int STIFFNESS; diff --git a/Simulator/DynamicBoundarySimulator.cpp b/Simulator/DynamicBoundarySimulator.cpp index 3e9f7fa7..9c46f130 100644 --- a/Simulator/DynamicBoundarySimulator.cpp +++ b/Simulator/DynamicBoundarySimulator.cpp @@ -10,6 +10,7 @@ #include "SPlisHSPlasH/TriangleMesh.h" #include "Simulator/SceneConfiguration.h" #include "SPlisHSPlasH/Utilities/MeshImport.h" +#include "SPlisHSPlasH/StrongCouplingBoundarySolver.h" using namespace std; using namespace SPH; @@ -22,7 +23,7 @@ DynamicBoundarySimulator::DynamicBoundarySimulator(SimulatorBase* base) { } DynamicBoundarySimulator::~DynamicBoundarySimulator() { - + delete StrongCouplingBoundarySolver::getCurrent(); } void DynamicBoundarySimulator::initBoundaryData() { From b8e054492a61b183a58541424316302c6962aff4 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Wed, 10 May 2023 17:53:10 +0200 Subject: [PATCH 19/38] refactorized --- SPlisHSPlasH/BoundaryModel_Akinci2012.cpp | 82 +--- SPlisHSPlasH/BoundaryModel_Akinci2012.h | 183 --------- SPlisHSPlasH/StrongCouplingBoundarySolver.cpp | 367 +++++++++++------- SPlisHSPlasH/StrongCouplingBoundarySolver.h | 195 +++++++++- SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 42 +- 5 files changed, 451 insertions(+), 418 deletions(-) diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp index e938e1b2..171a3495 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp @@ -14,18 +14,7 @@ BoundaryModel_Akinci2012::BoundaryModel_Akinci2012() : m_x0(), m_x(), m_v(), - m_V(), - m_density(), - m_pressureGrad(), - m_v_s(), - m_s(), - m_pressure(), - m_v_rr(), - m_minus_rho_div_v_rr(), - m_diagonalElement(), - m_artificialVolume(), - m_particleID(), - m_lastPressure() + m_V() { m_sorted = false; m_pointSetIndex = 0; @@ -34,7 +23,6 @@ BoundaryModel_Akinci2012::BoundaryModel_Akinci2012() : addField({ "position0", FieldType::Vector3, [&](const unsigned int i) -> Real* { return &getPosition0(i)[0]; } }); addField({ "velocity", FieldType::Vector3, [&](const unsigned int i) -> Real* { return &getVelocity(i)[0]; }, true }); addField({ "volume", FieldType::Scalar, [&](const unsigned int i) -> Real* { return &getVolume(i); }, true }); - addField({ "density", FieldType::Scalar, [&](const unsigned int i) -> Real* { return &getDensity(i); }, true }); } BoundaryModel_Akinci2012::~BoundaryModel_Akinci2012(void) @@ -43,17 +31,6 @@ BoundaryModel_Akinci2012::~BoundaryModel_Akinci2012(void) m_x.clear(); m_v.clear(); m_V.clear(); - m_density.clear(); - m_v_s.clear(); - m_s.clear(); - m_pressure.clear(); - m_v_rr.clear(); - m_minus_rho_div_v_rr.clear(); - m_diagonalElement.clear(); - m_pressureGrad.clear(); - m_artificialVolume.clear(); - m_particleID.clear(); - m_lastPressure.clear(); } void BoundaryModel_Akinci2012::reset() @@ -64,22 +41,10 @@ void BoundaryModel_Akinci2012::reset() // positions and velocities are already updated by updateBoundaryParticles if (!m_rigidBody->isDynamic() && !m_rigidBody->isAnimated()) { - // reset velocities, accelerations, densities and other fields for (int j = 0; j < (int)numberOfParticles(); j++) { m_x[j] = m_x0[j]; m_v[j].setZero(); - m_density[j] = m_restDensity; - m_v_s[j].setZero(); - m_s[j] = 0; - m_pressure[j] = 0; - m_v_rr[j].setZero(); - m_minus_rho_div_v_rr[j] = 0; - m_diagonalElement[j] = 0; - m_pressureGrad[j].setZero(); - m_artificialVolume[j] = 0; - m_particleID[j] = j; - m_lastPressure[j] = 0; } } } @@ -145,21 +110,6 @@ void BoundaryModel_Akinci2012::initModel(RigidBodyObject *rbo, const unsigned in m_x.resize(numBoundaryParticles); m_v.resize(numBoundaryParticles); m_V.resize(numBoundaryParticles); - m_density.resize(numBoundaryParticles); - m_v_s.resize(numBoundaryParticles); - m_s.resize(numBoundaryParticles); - m_pressure.resize(numBoundaryParticles); - m_v_rr.resize(numBoundaryParticles); - m_minus_rho_div_v_rr.resize(numBoundaryParticles); - m_diagonalElement.resize(numBoundaryParticles); - m_pressureGrad.resize(numBoundaryParticles); - m_artificialVolume.resize(numBoundaryParticles); - m_particleID.resize(numBoundaryParticles); - m_lastPressure.resize(numBoundaryParticles); - m_restDensity = 1; - m_v_rr_body = Vector3r().setZero(); - m_omega_rr_body = Vector3r().setZero(); - if (rbo->isDynamic()) { @@ -181,14 +131,6 @@ void BoundaryModel_Akinci2012::initModel(RigidBodyObject *rbo, const unsigned in m_x[i] = boundaryParticles[i]; m_v[i].setZero(); m_V[i] = 0.0; - m_density[i] = m_restDensity; - m_v_s[i].setZero(); - m_pressure[i] = 0; - m_v_rr[i].setZero(); - m_pressureGrad[i].setZero(); - m_artificialVolume[i] = 0.0; - m_particleID[i] = i; - m_lastPressure[i] = 0; } } m_rigidBody = rbo; @@ -212,17 +154,6 @@ void BoundaryModel_Akinci2012::performNeighborhoodSearchSort() d.sort_field(&m_x[0]); d.sort_field(&m_v[0]); d.sort_field(&m_V[0]); - d.sort_field(&m_density[0]); - d.sort_field(&m_v_s[0]); - d.sort_field(&m_s[0]); - d.sort_field(&m_pressure[0]); - d.sort_field(&m_v_rr[0]); - d.sort_field(&m_minus_rho_div_v_rr[0]); - d.sort_field(&m_diagonalElement[0]); - d.sort_field(&m_pressureGrad[0]); - d.sort_field(&m_artificialVolume[0]); - d.sort_field(&m_particleID[0]); - d.sort_field(&m_lastPressure[0]); m_sorted = true; } @@ -244,15 +175,4 @@ void SPH::BoundaryModel_Akinci2012::resize(const unsigned int numBoundaryParticl m_x.resize(numBoundaryParticles); m_v.resize(numBoundaryParticles); m_V.resize(numBoundaryParticles); - m_density.resize(numBoundaryParticles); - m_v_s.resize(numBoundaryParticles); - m_s.resize(numBoundaryParticles); - m_pressure.resize(numBoundaryParticles); - m_v_rr.resize(numBoundaryParticles); - m_minus_rho_div_v_rr.resize(numBoundaryParticles); - m_diagonalElement.resize(numBoundaryParticles); - m_pressureGrad.resize(numBoundaryParticles); - m_artificialVolume.resize(numBoundaryParticles); - m_particleID.resize(numBoundaryParticles); - m_lastPressure.resize(numBoundaryParticles); } diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.h b/SPlisHSPlasH/BoundaryModel_Akinci2012.h index 6dfc0a8a..a40e1bc6 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.h +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.h @@ -36,22 +36,6 @@ namespace SPH std::vector m_V; std::vector m_fields; - // values required for Gissler 2019 strong coupling based on Akinci 2012 - std::vector m_particleID; - std::vector m_density; - std::vector m_pressure; - std::vector m_lastPressure; - std::vector m_artificialVolume; - std::vector m_v_s; - std::vector m_s; // source term - std::vector m_pressureGrad; - std::vector m_v_rr; - std::vector m_minus_rho_div_v_rr; // RHS to the source term - std::vector m_diagonalElement; // diagonal element for jacobi iteration - Real m_restDensity; - Vector3r m_v_rr_body; - Vector3r m_omega_rr_body; - public: void addField(const FieldDescription& field); const std::vector& getFields() {return m_fields;} @@ -76,89 +60,6 @@ namespace SPH void initModel(RigidBodyObject *rbo, const unsigned int numBoundaryParticles, Vector3r *boundaryParticles); - FORCE_INLINE const unsigned int& getParticleID(const Real& index) const { - return m_particleID[index]; - } - - FORCE_INLINE unsigned int& getParticleID(const Real& index) { - return m_particleID[index]; - } - - FORCE_INLINE void setParticleID(const Real& index, const Real& value) { - m_particleID[index] = value; - } - - FORCE_INLINE const Real& getDensity(const Real& index) const { - return m_density[index]; - } - - FORCE_INLINE Real& getDensity(const Real& index) { - return m_density[index]; - } - - FORCE_INLINE void setDensity(const Real& index, const Real& value) { - m_density[index] = value; - } - - FORCE_INLINE const Real& getPressure(const Real& index) const { - return m_pressure[index]; - } - - FORCE_INLINE Real& getPressure(const Real& index) { - return m_pressure[index]; - } - - FORCE_INLINE void setPressure(const Real& index, const Real& value) { - m_pressure[index] = value; - } - - FORCE_INLINE const Real& getLastPressure(const Real& index) const { - return m_lastPressure[index]; - } - - FORCE_INLINE Real& getLastPressure(const Real& index) { - return m_lastPressure[index]; - } - - FORCE_INLINE void setLastPressure(const Real& index, const Real& value) { - m_lastPressure[index] = value; - } - - FORCE_INLINE const Real& getRestDensity() const { - return m_restDensity; - } - - FORCE_INLINE Real& getRestDensity() { - return m_restDensity; - } - - FORCE_INLINE void setRestDensity(const Real& value) { - m_restDensity = value; - } - - FORCE_INLINE const Vector3r& getV_rr_body() const { - return m_v_rr_body; - } - - FORCE_INLINE Vector3r& getV_rr_body() { - return m_v_rr_body; - } - - FORCE_INLINE void setV_rr_body(const Vector3r& value) { - m_v_rr_body = value; - } - - FORCE_INLINE const Vector3r& getOmega_rr_body() const { - return m_omega_rr_body; - } - - FORCE_INLINE Vector3r& getOmega_rr_body() { - return m_omega_rr_body; - } - - FORCE_INLINE void setOmega_rr_body(const Vector3r& value) { - m_omega_rr_body = value; - } FORCE_INLINE Vector3r &getPosition0(const unsigned int i) { @@ -205,78 +106,6 @@ namespace SPH m_v[i] = vel; } - FORCE_INLINE Vector3r& getV_s(const unsigned int i) { - return m_v_s[i]; - } - - FORCE_INLINE const Vector3r& getV_s(const unsigned int i) const { - return m_v_s[i]; - } - - FORCE_INLINE void setV_s(const unsigned int i, const Vector3r& value) { - m_v_s[i] = value; - } - - FORCE_INLINE Vector3r& getV_rr(const unsigned int i) { - return m_v_rr[i]; - } - - FORCE_INLINE const Vector3r& getV_rr(const unsigned int i) const { - return m_v_rr[i]; - } - - FORCE_INLINE void setV_rr(const unsigned int i, const Vector3r& value) { - m_v_rr[i] = value; - } - - FORCE_INLINE Vector3r& getPressureGrad(const unsigned int i) { - return m_pressureGrad[i]; - } - - FORCE_INLINE const Vector3r& getPressureGrad(const unsigned int i) const { - return m_pressureGrad[i]; - } - - FORCE_INLINE void setPressureGrad(const unsigned int i, const Vector3r& value) { - m_pressureGrad[i] = value; - } - - FORCE_INLINE Real& getSourceTermRHS(const unsigned int i) { - return m_minus_rho_div_v_rr[i]; - } - - FORCE_INLINE const Real& getSourceTermRHS(const unsigned int i) const { - return m_minus_rho_div_v_rr[i]; - } - - FORCE_INLINE void setSourceTermRHS(const unsigned int i, const Real& value) { - m_minus_rho_div_v_rr[i] = value; - } - - FORCE_INLINE Real& getDiagonalElement(const unsigned int i) { - return m_diagonalElement[i]; - } - - FORCE_INLINE const Real& getDiagonalElement(const unsigned int i) const { - return m_diagonalElement[i]; - } - - FORCE_INLINE void setDiagonalElement(const unsigned int i, const Real& value) { - m_diagonalElement[i] = value; - } - - FORCE_INLINE Real& getSourceTerm(const unsigned int i) { - return m_s[i]; - } - - FORCE_INLINE const Real& getSourceTerm(const unsigned int i) const { - return m_s[i]; - } - - FORCE_INLINE void setSourceTerm(const unsigned int i, const Real& value) { - m_s[i] = value; - } - FORCE_INLINE const Real& getVolume(const unsigned int i) const { return m_V[i]; @@ -291,18 +120,6 @@ namespace SPH { m_V[i] = val; } - - FORCE_INLINE const Real& getArtificialVolume(const unsigned int i) const { - return m_artificialVolume[i]; - } - - FORCE_INLINE Real& getArtificialVolume(const unsigned int i) { - return m_artificialVolume[i]; - } - - FORCE_INLINE void setArtificialVolume(const unsigned int i, const Real& val) { - m_artificialVolume[i] = val; - } }; } diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp index b8f7fb98..caccded1 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp @@ -7,6 +7,107 @@ using namespace SPH; StrongCouplingBoundarySolver* StrongCouplingBoundarySolver::current = nullptr; +StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : + m_density(), + m_pressureGrad(), + m_v_s(), + m_s(), + m_pressure(), + m_v_rr(), + m_minus_rho_div_v_rr(), + m_diagonalElement(), + m_artificialVolume(), + m_particleID(), + m_lastPressure() +{ + Simulation* sim = Simulation::getCurrent(); + const unsigned int nBoundaries = sim->numberOfBoundaryModels(); + + m_density.resize(nBoundaries); + m_v_s.resize(nBoundaries); + m_s.resize(nBoundaries); + m_pressure.resize(nBoundaries); + m_v_rr.resize(nBoundaries); + m_minus_rho_div_v_rr.resize(nBoundaries); + m_diagonalElement.resize(nBoundaries); + m_pressureGrad.resize(nBoundaries); + m_artificialVolume.resize(nBoundaries); + m_lastPressure.resize(nBoundaries); + m_restDensity.resize(nBoundaries, 1); + m_v_rr_body.resize(nBoundaries, Vector3r::Zero()); + m_omega_rr_body.resize(nBoundaries, Vector3r::Zero()); + + for (unsigned int i = 0; i < nBoundaries; i++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModel(i)); + + m_density[i].resize(bm->numberOfParticles(), m_restDensity[i]); + m_v_s[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_s[i].resize(bm->numberOfParticles(), 0); + m_pressure[i].resize(bm->numberOfParticles(), 0); + m_v_rr[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_minus_rho_div_v_rr[i].resize(bm->numberOfParticles(), 0); + m_diagonalElement[i].resize(bm->numberOfParticles(), 0); + m_pressureGrad[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_artificialVolume[i].resize(bm->numberOfParticles(), 0); + m_lastPressure[i].resize(bm->numberOfParticles(), 0); + } +} + +StrongCouplingBoundarySolver::~StrongCouplingBoundarySolver() { + current = nullptr; + for (unsigned int i = 0; i < Simulation::getCurrent()->numberOfBoundaryModels(); i++) { + m_density[i].clear(); + m_v_s[i].clear(); + m_s[i].clear(); + m_pressure[i].clear(); + m_v_rr[i].clear(); + m_minus_rho_div_v_rr[i].clear(); + m_diagonalElement[i].clear(); + m_pressureGrad[i].clear(); + m_artificialVolume[i].clear(); + m_lastPressure[i].clear(); + } + m_density.clear(); + m_v_s.clear(); + m_s.clear(); + m_pressure.clear(); + m_v_rr.clear(); + m_minus_rho_div_v_rr.clear(); + m_diagonalElement.clear(); + m_pressureGrad.clear(); + m_artificialVolume.clear(); + m_lastPressure.clear(); +} + +void StrongCouplingBoundarySolver::computeV_s() { + // Use dynamic boundary simulator and Akinci2012 + Simulation* sim = Simulation::getCurrent(); + DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + TimeManager* tm = TimeManager::getCurrent(); + const Real dt = tm->getTimeStepSize(); + const unsigned int nFluids = sim->numberOfFluidModels(); + + // Compute v_s for all particles + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + if (rb->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + // compute v_s + Vector3r gravForce = rb->getMass() * Vector3r(sim->getVecValue(Simulation::GRAVITATION)); + // the rb->getForce() contains only fluid-rigid forces + Vector3r F_R = rb->getForce() + gravForce; + setV_s(boundaryPointSetIndex - nFluids, r, rb->getVelocity() + dt * rb->getInvMass() * F_R + + (rb->getAngularVelocity() + rb->getInertiaTensorInverseW() * (dt * rb->getTorque() + dt * (rb->getInertiaTensorW() * rb->getAngularVelocity()).cross(rb->getAngularVelocity()))).cross(bm->getPosition(r))); + } + } + } + } +} + void StrongCouplingBoundarySolver::computeSourceTerm() { Simulation* sim = Simulation::getCurrent(); DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); @@ -17,6 +118,7 @@ void StrongCouplingBoundarySolver::computeSourceTerm() { // compute source term s for all particles for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + int bmIndex = boundaryPointSetIndex - nFluids; if (bm->getRigidBodyObject()->isDynamic()) { #pragma omp parallel default(shared) { @@ -27,15 +129,16 @@ void StrongCouplingBoundarySolver::computeSourceTerm() { for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { if (boundaryPointSetIndex != pid) { BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + int neighborIndex = pid - nFluids; for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); // sum up divergence of v_s - s += bm_neighbor->getArtificialVolume(k) * bm_neighbor->getDensity(k) * (bm_neighbor->getV_s(k) - bm->getV_s(r)).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); + s += getArtificialVolume(neighborIndex, k) * getDensity(neighborIndex, k) * (getV_s(neighborIndex, k) - getV_s(bmIndex, r)).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); } } } - s += (bm->getRestDensity() - bm->getDensity(r)) / dt; - bm->setSourceTerm(r, s); + s += (getRestDensity(bmIndex) - getDensity(bmIndex, r)) / dt; + setSourceTerm(bmIndex, r, s); } } } @@ -48,107 +151,122 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { TimeManager* tm = TimeManager::getCurrent(); const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); - for (unsigned int pointSetIndex_r = nFluids; pointSetIndex_r < sim->numberOfPointSets(); pointSetIndex_r++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_r)); - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + BoundaryModel_Akinci2012* bm_r = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_r)); + int indexR = pointSetIndex_r - nFluids; + DynamicRigidBody* rb = static_cast(bm_r->getRigidBodyObject()); if (rb->isDynamic()) { #pragma omp parallel default(shared) { #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - Matrix3r productMat_r; - Vector3r pos_r = bm->getPosition(r); + for (int r = 0; r < bm_r->numberOfParticles(); r++) { + Matrix3r productMat_r = Matrix3r().setZero(); + Vector3r pos_r = bm_r->getPosition(r); productMat_r << 0, -pos_r.z(), pos_r.y(), pos_r.z(), 0, -pos_r.x(), -pos_r.y(), pos_r.x(), 0; Real diagonal = 0; for (unsigned int pointSetIndex_i = nFluids; pointSetIndex_i < sim->numberOfPointSets(); pointSetIndex_i++) { BoundaryModel_Akinci2012* bm_i = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_i)); + int indexI = pointSetIndex_i - nFluids; DynamicRigidBody* rb_i = static_cast(bm_i->getRigidBodyObject()); - // neighbors of r - for (unsigned int m = 0; m < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_i, r); m++) { - - const unsigned int i = sim->getNeighbor(pointSetIndex_r, pointSetIndex_i, r, m); - Vector3r coeffSum_ik; + // neighbors of r in other rigid bodies + if (pointSetIndex_i != pointSetIndex_r) { + for (unsigned int m = 0; m < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_i, r); m++) { + const unsigned int i = sim->getNeighbor(pointSetIndex_r, pointSetIndex_i, r, m); + Vector3r coeffSum_ik = Vector3r().setZero(); - Vector3r gradWri = sim->gradW(bm->getPosition(r) - bm_i->getPosition(i)); - Matrix3r productMat_i; - Vector3r pos_i = bm_i->getPosition(i); - productMat_i << 0, -pos_i.z(), pos_i.y(), - pos_i.z(), 0, -pos_i.x(), - -pos_i.y(), pos_i.x(), 0; + Vector3r gradWri = sim->gradW(bm_r->getPosition(r) - bm_i->getPosition(i)); + Matrix3r productMat_i = Matrix3r().setZero(); + Vector3r pos_i = bm_i->getPosition(i); + productMat_i << 0, -pos_i.z(), pos_i.y(), + pos_i.z(), 0, -pos_i.x(), + -pos_i.y(), pos_i.x(), 0; - // neighbors of i in the same rigid body, denoted as k - for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_i, pointSetIndex_i, i); n++) { - const unsigned int k = sim->getNeighbor(pointSetIndex_i, pointSetIndex_i, i, n); - Vector3r coeffSum_kj; + // neighbors of i in the same rigid body, denoted as k (k cannot be r) + for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_i, pointSetIndex_i, i); n++) { + const unsigned int k = sim->getNeighbor(pointSetIndex_i, pointSetIndex_i, i, n); + Vector3r coeffSum_kj = Vector3r().setZero(); - Vector3r pos_k = bm_i->getPosition(k); - Matrix3r productMat_k; - productMat_k << 0, -pos_k.z(), pos_k.y(), - pos_k.z(), 0, -pos_k.x(), - -pos_k.y(), pos_k.x(), 0; - Matrix3r K_ik = rb_i->getInvMass() * Matrix3r::Identity() - productMat_i * rb_i->getInertiaTensorInverseW() * productMat_k; + Vector3r pos_k = bm_i->getPosition(k); + Matrix3r productMat_k = Matrix3r().setZero(); + productMat_k << 0, -pos_k.z(), pos_k.y(), + pos_k.z(), 0, -pos_k.x(), + -pos_k.y(), pos_k.x(), 0; + Real invMass = 0; + if (rb_i->isDynamic()) { + invMass = rb_i->getInvMass(); + } else { + invMass = 1; + } + Matrix3r K_ik = invMass * Matrix3r::Identity() - productMat_i * rb_i->getInertiaTensorInverseW() * productMat_k; - // neighbors of k in all bodies, denoted as j - for (unsigned int pointSetIndex_j = nFluids; pointSetIndex_j < sim->numberOfPointSets(); pointSetIndex_j++) { - BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_j)); - for (unsigned int o = 0; o < sim->numberOfNeighbors(pointSetIndex_i, pointSetIndex_j, k); o++) { - const unsigned int j = sim->getNeighbor(pointSetIndex_i, pointSetIndex_j, k, o); - Vector3r gradWkj = sim->gradW(bm_i->getPosition(k) - bm_j->getPosition(j)); - if (pointSetIndex_i == pointSetIndex_r && bm_i->getParticleID(k) == bm->getParticleID(r)) { - coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_i->getDensity(k) * bm_i->getDensity(k)) * gradWkj; - } - if (pointSetIndex_j == pointSetIndex_r && bm_j->getParticleID(j) == bm->getParticleID(r)) { - coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_j->getDensity(j) * bm_j->getDensity(j)) * gradWkj; + // neighbors of k in all bodies, denoted as j + for (unsigned int pointSetIndex_j = nFluids; pointSetIndex_j < sim->numberOfPointSets(); pointSetIndex_j++) { + BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_j)); + for (unsigned int o = 0; o < sim->numberOfNeighbors(pointSetIndex_i, pointSetIndex_j, k); o++) { + const unsigned int j = sim->getNeighbor(pointSetIndex_i, pointSetIndex_j, k, o); + int indexJ = pointSetIndex_j - nFluids; + Vector3r gradWkj = sim->gradW(bm_i->getPosition(k) - bm_j->getPosition(j)); + //if (pointSetIndex_i == pointSetIndex_r && bm_i->getParticleID(k) == bm->getParticleID(r)) { + // coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_i->getDensity(k) * bm_i->getDensity(k)) * gradWkj; + //} + if (pointSetIndex_j == pointSetIndex_r && j == r) { + coeffSum_kj += getArtificialVolume(indexJ, j) * getDensity(indexJ, j) / (getDensity(indexJ, j) * getDensity(indexJ, j)) * gradWkj; + } } } + if (coeffSum_kj != Vector3r().setZero()) { + coeffSum_kj = getArtificialVolume(indexI, k) * K_ik * getDensity(indexI, k) * coeffSum_kj; + coeffSum_ik += coeffSum_kj; + + } } - coeffSum_kj = bm_i->getArtificialVolume(k) * K_ik * bm_i->getDensity(k) * coeffSum_kj; - coeffSum_ik += coeffSum_kj; - } - coeffSum_ik *= dt; + coeffSum_ik *= dt; - Vector3r coeffSum_rk; - // neighbors of r in the same rigid body, denoted as k - for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_r, r); n++) { - const unsigned int k = sim->getNeighbor(pointSetIndex_r, pointSetIndex_r, r, n); - Vector3r coeffSum_kj; + Vector3r coeffSum_rk = Vector3r().setZero(); + // neighbors of r in the same rigid body, denoted as k + for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_r, r); n++) { + const unsigned int k = sim->getNeighbor(pointSetIndex_r, pointSetIndex_r, r, n); + Vector3r coeffSum_kj = Vector3r().setZero(); - Vector3r pos_k = bm->getPosition(k); - Matrix3r productMat_k; - productMat_k << 0, -pos_k.z(), pos_k.y(), - pos_k.z(), 0, -pos_k.x(), - -pos_k.y(), pos_k.x(), 0; - Matrix3r K_rk = rb->getInvMass() * Matrix3r::Identity() - productMat_r * rb->getInertiaTensorInverseW() * productMat_k; + Vector3r pos_k = bm_r->getPosition(k); + Matrix3r productMat_k = Matrix3r().setZero(); + productMat_k << 0, -pos_k.z(), pos_k.y(), + pos_k.z(), 0, -pos_k.x(), + -pos_k.y(), pos_k.x(), 0; + Matrix3r K_rk = rb->getInvMass() * Matrix3r::Identity() - productMat_r * rb->getInertiaTensorInverseW() * productMat_k; - // neighbors of k in all bodies, denoted as j - for (unsigned int pointSetIndex_j = nFluids; pointSetIndex_j < sim->numberOfPointSets(); pointSetIndex_j++) { - BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_j)); - for (unsigned int o = 0; o < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_j, k); o++) { - const unsigned int j = sim->getNeighbor(pointSetIndex_r, pointSetIndex_j, k, o); - Vector3r gradWkj = sim->gradW(bm->getPosition(k) - bm_j->getPosition(j)); - if (bm->getParticleID(k) == bm->getParticleID(r)) { - coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm->getDensity(k) * bm->getDensity(k)) * gradWkj; - } - if (pointSetIndex_j == pointSetIndex_r && bm_j->getParticleID(j) == bm->getParticleID(r)) { - coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_j->getDensity(j) * bm_j->getDensity(j)) * gradWkj; + // neighbors of k in all bodies, denoted as j + for (unsigned int pointSetIndex_j = nFluids; pointSetIndex_j < sim->numberOfPointSets(); pointSetIndex_j++) { + BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_j)); + int indexJ = pointSetIndex_j - nFluids; + for (unsigned int o = 0; o < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_j, k); o++) { + const unsigned int j = sim->getNeighbor(pointSetIndex_r, pointSetIndex_j, k, o); + Vector3r gradWkj = sim->gradW(bm_r->getPosition(k) - bm_j->getPosition(j)); + if (k == r) { + coeffSum_kj += getArtificialVolume(indexJ, j) * getDensity(indexJ, j) / (getDensity(indexR, k) * getDensity(indexR, k)) * gradWkj; + } + + if (pointSetIndex_j == pointSetIndex_r && j == r) { + coeffSum_kj += getArtificialVolume(indexJ, j) * getDensity(indexJ, j) / (getDensity(indexJ, j) * getDensity(indexJ, j)) * gradWkj; + } } } + if (coeffSum_kj != Vector3r().setZero()) { + coeffSum_kj = getArtificialVolume(indexR, k) * K_rk * getDensity(indexR, k) * coeffSum_kj; + coeffSum_rk += coeffSum_kj; + } } - coeffSum_kj = bm->getArtificialVolume(k) * K_rk * bm->getDensity(k) * coeffSum_kj; - coeffSum_rk += coeffSum_kj; - } - - coeffSum_rk *= dt; - diagonal += bm_i->getArtificialVolume(i) * bm_i->getDensity(i) * (coeffSum_ik - coeffSum_rk).dot(gradWri); - } + coeffSum_rk *= dt; + diagonal += getArtificialVolume(indexI, i) * getDensity(indexI, i) * (coeffSum_ik - coeffSum_rk).dot(gradWri); + } + } } - bm->setDiagonalElement(r, diagonal); + setDiagonalElement(indexR, r, diagonal); } } } @@ -166,12 +284,13 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { // Compute density and artificial volume for all particles for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + int bmIndex = boundaryPointSetIndex - nFluids; DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - if (rb->isDynamic()) { - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + if (rb->isDynamic()) { // compute density Real particleDensity = 0; // iterate over all rigid bodies @@ -179,15 +298,18 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - particleDensity += bm->getRestDensity() * bm->getVolume(r) * sim->W(bm->getPosition(r) - bm_neighbor->getPosition(k)); + particleDensity += getRestDensity(bmIndex) * bm->getVolume(r) * sim->W(bm->getPosition(r) - bm_neighbor->getPosition(k)); } } // 0.8 for compensation - bm->setDensity(r, particleDensity / 0.8); - bm->setArtificialVolume(r, bm->getRestDensity() * bm->getVolume(r) / bm->getDensity(r)); + setDensity(bmIndex, r, particleDensity / 0.8); + setArtificialVolume(bmIndex, r, getRestDensity(bmIndex) * bm->getVolume(r) / getDensity(bmIndex, r)); + } else { + setArtificialVolume(bmIndex, r, bm->getVolume(r)); } } } + } } @@ -200,6 +322,7 @@ void StrongCouplingBoundarySolver::computePressureGrad() { for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + int bmIndex = boundaryPointSetIndex - nFluids; DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); if (rb->isDynamic()) { #pragma omp parallel default(shared) @@ -207,50 +330,21 @@ void StrongCouplingBoundarySolver::computePressureGrad() { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { Vector3r pressureGrad_r = Vector3r().setZero(); - const Real density_r = bm->getDensity(r); - const Real pressure_r = bm->getPressure(r); + const Real density_r = getDensity(bmIndex, r); + const Real pressure_r = getPressure(bmIndex, r); for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + int neighborIndex = pid - nFluids; for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - const Real density_k = bm_neighbor->getDensity(k); - const Real volume_k = bm_neighbor->getRestDensity() / density_k * bm_neighbor->getVolume(k); - const Real pressure_k = bm_neighbor->getPressure(k); + const Real density_k = getDensity(neighborIndex, k); + const Real volume_k = getArtificialVolume(neighborIndex, k); + const Real pressure_k = getPressure(neighborIndex, k); pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); } } pressureGrad_r *= density_r; - bm->setPressureGrad(r, pressureGrad_r); - } - } - } - } - -} - -void StrongCouplingBoundarySolver::computeV_s() { - // Use dynamic boundary simulator and Akinci2012 - Simulation* sim = Simulation::getCurrent(); - DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); - TimeManager* tm = TimeManager::getCurrent(); - const Real dt = tm->getTimeStepSize(); - const unsigned int nFluids = sim->numberOfFluidModels(); - - // Compute v_s for all particles - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - if (rb->isDynamic()) { - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - // compute v_s - Vector3r gravForce = rb->getMass() * Vector3r(sim->getVecValue(Simulation::GRAVITATION)); - // the rb->getForce() contains only fluid-rigid forces - Vector3r F_R = rb->getForce() + gravForce; - bm->setV_s(r, rb->getVelocity() + dt * rb->getInvMass() * F_R + - (rb->getAngularVelocity() + rb->getInertiaTensorInverseW() * (dt * rb->getTorque() + dt * (rb->getInertiaTensorW() * rb->getAngularVelocity()).cross(rb->getAngularVelocity()))).cross(bm->getPosition(r))); + setPressureGrad(bmIndex, r, pressureGrad_r); } } } @@ -267,6 +361,7 @@ void StrongCouplingBoundarySolver::computeSourceTermRHS() { // compute v_rr and omega_rr for rigid body using the pressure gradient for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + int bmIndex = boundaryPointSetIndex - nFluids; DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); Vector3r v_rr_body = Vector3r().setZero(); Vector3r omega_rr_body = Vector3r().setZero(); @@ -275,24 +370,25 @@ void StrongCouplingBoundarySolver::computeSourceTermRHS() { { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - v_rr_body += -dt * rb->getInvMass() * bm->getArtificialVolume(r) * bm->getPressureGrad(r); - omega_rr_body += -dt * rb->getInertiaTensorInverseW() * bm->getArtificialVolume(r) * bm->getPosition(r).cross(bm->getPressureGrad(r)); + v_rr_body += -dt * rb->getInvMass() * getArtificialVolume(bmIndex, r) * getPressureGrad(bmIndex, r); + omega_rr_body += -dt * rb->getInertiaTensorInverseW() * getArtificialVolume(bmIndex, r) * bm->getPosition(r).cross(getPressureGrad(bmIndex, r)); } } } - bm->setV_rr_body(v_rr_body); - bm->setOmega_rr_body(omega_rr_body); + setV_rr_body(bmIndex, v_rr_body); + setOmega_rr_body(bmIndex, omega_rr_body); } // compute v_rr for all particles (predicted velocity) for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + int bmIndex = boundaryPointSetIndex - nFluids; DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); if (rb->isDynamic()) { #pragma omp parallel default(shared) { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - bm->setV_rr(r, bm->getV_rr_body() + bm->getOmega_rr_body().cross(bm->getPosition(r))); + setV_rr(bmIndex, r, getV_rr_body(bmIndex) + getOmega_rr_body(bmIndex).cross(bm->getPosition(r))); } } } @@ -300,24 +396,29 @@ void StrongCouplingBoundarySolver::computeSourceTermRHS() { // compute the -rho * (div v_rr), which is the RHS to the source term for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + int bmIndex = boundaryPointSetIndex - nFluids; #pragma omp parallel default(shared) { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { Real minus_rho_div_v_rr = 0; - const Vector3r v_rr_r = bm->getV_rr(r); + const Vector3r v_rr_r = getV_rr(bmIndex, r); for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { - const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - const Real density_k = bm_neighbor->getDensity(k); - const Real volume_k = bm_neighbor->getArtificialVolume(k); - const Vector3r v_rr_k = bm_neighbor->getV_rr(k); - minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); + // divergence of particles in the same body should be 0; + if (boundaryPointSetIndex != pid) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + int neighborIndex = pid - nFluids; + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + const Real density_k = getDensity(neighborIndex, k); + const Real volume_k = getArtificialVolume(neighborIndex, k); + const Vector3r v_rr_k = getV_rr(neighborIndex, k); + minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); + } } } minus_rho_div_v_rr = -minus_rho_div_v_rr; - bm->setSourceTermRHS(r, minus_rho_div_v_rr); + setSourceTermRHS(bmIndex, r, minus_rho_div_v_rr); } } } diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.h b/SPlisHSPlasH/StrongCouplingBoundarySolver.h index 7d472568..31673e38 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.h +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.h @@ -4,10 +4,28 @@ namespace SPH { class StrongCouplingBoundarySolver { + private: + // values required for Gissler 2019 strong coupling based on Akinci 2012 + std::vector> m_particleID; + std::vector> m_density; + std::vector> m_pressure; + std::vector> m_lastPressure; + std::vector> m_artificialVolume; + std::vector> m_v_s; + std::vector> m_s; // source term + std::vector> m_pressureGrad; + std::vector> m_v_rr; + std::vector> m_minus_rho_div_v_rr; // RHS to the source term + std::vector> m_diagonalElement; // diagonal element for jacobi iteration + std::vector m_restDensity; + std::vector m_v_rr_body; + std::vector m_omega_rr_body; + + static StrongCouplingBoundarySolver* current; + public: - ~StrongCouplingBoundarySolver(){ - current = nullptr; - } + StrongCouplingBoundarySolver(); + ~StrongCouplingBoundarySolver(); static StrongCouplingBoundarySolver* getCurrent() { if (current == nullptr) { current = new StrongCouplingBoundarySolver(); @@ -20,7 +38,174 @@ namespace SPH { void computeSourceTermRHS(); void computeSourceTerm(); void computeDiagonalElement(); - private: - static StrongCouplingBoundarySolver* current; + + + FORCE_INLINE const unsigned int& getParticleID(const Real& rigidBodyIndex, Real& index) const { + return m_particleID[rigidBodyIndex][index]; + } + + FORCE_INLINE unsigned int& getParticleID(const Real& rigidBodyIndex, const Real& index) { + return m_particleID[rigidBodyIndex][index]; + } + + FORCE_INLINE void setParticleID(const Real& rigidBodyIndex, const Real& index, const Real& value) { + m_particleID[rigidBodyIndex][index] = value; + } + + FORCE_INLINE const Real& getDensity(const Real& rigidBodyIndex, const Real& index) const { + return m_density[rigidBodyIndex][index]; + } + + FORCE_INLINE Real& getDensity(const Real& rigidBodyIndex, const Real& index) { + return m_density[rigidBodyIndex][index]; + } + + FORCE_INLINE void setDensity(const Real& rigidBodyIndex, const Real& index, const Real& value) { + m_density[rigidBodyIndex][index] = value; + } + + FORCE_INLINE const Real& getPressure(const Real& rigidBodyIndex, const Real& index) const { + return m_pressure[rigidBodyIndex][index]; + } + + FORCE_INLINE Real& getPressure(const Real& rigidBodyIndex, const Real& index) { + return m_pressure[rigidBodyIndex][index]; + } + + FORCE_INLINE void setPressure(const Real& rigidBodyIndex, const Real& index, const Real& value) { + m_pressure[rigidBodyIndex][index] = value; + } + + FORCE_INLINE const Real& getLastPressure(const Real& rigidBodyIndex, const Real& index) const { + return m_lastPressure[rigidBodyIndex][index]; + } + + FORCE_INLINE Real& getLastPressure(const Real& rigidBodyIndex, const Real& index) { + return m_lastPressure[rigidBodyIndex][index]; + } + + FORCE_INLINE void setLastPressure(const Real& rigidBodyIndex, const Real& index, const Real& value) { + m_lastPressure[rigidBodyIndex][index] = value; + } + + FORCE_INLINE const Real& getRestDensity(const Real& rigidBodyIndex) const { + return m_restDensity[rigidBodyIndex]; + } + + FORCE_INLINE Real& getRestDensity(const Real& rigidBodyIndex) { + return m_restDensity[rigidBodyIndex]; + } + + FORCE_INLINE void setRestDensity(const Real& rigidBodyIndex, const Real& value) { + m_restDensity[rigidBodyIndex] = value; + } + + FORCE_INLINE const Vector3r& getV_rr_body(const Real& rigidBodyIndex) const { + return m_v_rr_body[rigidBodyIndex]; + } + + FORCE_INLINE Vector3r& getV_rr_body(const Real& rigidBodyIndex) { + return m_v_rr_body[rigidBodyIndex]; + } + + FORCE_INLINE void setV_rr_body(const Real& rigidBodyIndex, const Vector3r& value) { + m_v_rr_body[rigidBodyIndex] = value; + } + + FORCE_INLINE const Vector3r& getOmega_rr_body(const Real& rigidBodyIndex) const { + return m_omega_rr_body[rigidBodyIndex]; + } + + FORCE_INLINE Vector3r& getOmega_rr_body(const Real& rigidBodyIndex) { + return m_omega_rr_body[rigidBodyIndex]; + } + + FORCE_INLINE void setOmega_rr_body(const Real& rigidBodyIndex, const Vector3r& value) { + m_omega_rr_body[rigidBodyIndex] = value; + } + + FORCE_INLINE Vector3r& getV_s(const Real& rigidBodyIndex, const unsigned int i) { + return m_v_s[rigidBodyIndex][i]; + } + + FORCE_INLINE const Vector3r& getV_s(const Real& rigidBodyIndex, const unsigned int i) const { + return m_v_s[rigidBodyIndex][i]; + } + + FORCE_INLINE void setV_s(const Real& rigidBodyIndex, const unsigned int i, const Vector3r& value) { + m_v_s[rigidBodyIndex][i] = value; + } + + FORCE_INLINE Vector3r& getV_rr(const Real& rigidBodyIndex, const unsigned int i) { + return m_v_rr[rigidBodyIndex][i]; + } + + FORCE_INLINE const Vector3r& getV_rr(const Real& rigidBodyIndex, const unsigned int i) const { + return m_v_rr[rigidBodyIndex][i]; + } + + FORCE_INLINE void setV_rr(const Real& rigidBodyIndex, const unsigned int i, const Vector3r& value) { + m_v_rr[rigidBodyIndex][i] = value; + } + + FORCE_INLINE Vector3r& getPressureGrad(const Real& rigidBodyIndex, const unsigned int i) { + return m_pressureGrad[rigidBodyIndex][i]; + } + + FORCE_INLINE const Vector3r& getPressureGrad(const Real& rigidBodyIndex, const unsigned int i) const { + return m_pressureGrad[rigidBodyIndex][i]; + } + + FORCE_INLINE void setPressureGrad(const Real& rigidBodyIndex, const unsigned int i, const Vector3r& value) { + m_pressureGrad[rigidBodyIndex][i] = value; + } + + FORCE_INLINE Real& getSourceTermRHS(const Real& rigidBodyIndex, const unsigned int i) { + return m_minus_rho_div_v_rr[rigidBodyIndex][i]; + } + + FORCE_INLINE const Real& getSourceTermRHS(const Real& rigidBodyIndex, const unsigned int i) const { + return m_minus_rho_div_v_rr[rigidBodyIndex][i]; + } + + FORCE_INLINE void setSourceTermRHS(const Real& rigidBodyIndex, const unsigned int i, const Real& value) { + m_minus_rho_div_v_rr[rigidBodyIndex][i] = value; + } + + FORCE_INLINE Real& getDiagonalElement(const Real& rigidBodyIndex, const unsigned int i) { + return m_diagonalElement[rigidBodyIndex][i]; + } + + FORCE_INLINE const Real& getDiagonalElement(const Real& rigidBodyIndex, const unsigned int i) const { + return m_diagonalElement[rigidBodyIndex][i]; + } + + FORCE_INLINE void setDiagonalElement(const Real& rigidBodyIndex, const unsigned int i, const Real& value) { + m_diagonalElement[rigidBodyIndex][i] = value; + } + + FORCE_INLINE Real& getSourceTerm(const Real& rigidBodyIndex, const unsigned int i) { + return m_s[rigidBodyIndex][i]; + } + + FORCE_INLINE const Real& getSourceTerm(const Real& rigidBodyIndex, const unsigned int i) const { + return m_s[rigidBodyIndex][i]; + } + + FORCE_INLINE void setSourceTerm(const Real& rigidBodyIndex, const unsigned int i, const Real& value) { + m_s[rigidBodyIndex][i] = value; + } + + FORCE_INLINE const Real& getArtificialVolume(const Real& rigidBodyIndex, const unsigned int i) const { + return m_artificialVolume[rigidBodyIndex][i]; + } + + FORCE_INLINE Real& getArtificialVolume(const Real& rigidBodyIndex, const unsigned int i) { + return m_artificialVolume[rigidBodyIndex][i]; + } + + FORCE_INLINE void setArtificialVolume(const Real& rigidBodyIndex, const unsigned int i, const Real& val) { + m_artificialVolume[rigidBodyIndex][i] = val; + } }; } \ No newline at end of file diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index 04deab96..660997ae 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -222,11 +222,12 @@ void TimeStepWCSPH::computeRigidRigidAccels() { TimeManager* tm = TimeManager::getCurrent(); const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); - StrongCouplingBoundarySolver* boundarySolver = StrongCouplingBoundarySolver::getCurrent(); + StrongCouplingBoundarySolver* bs = StrongCouplingBoundarySolver::getCurrent(); // solve the equation s = -rho * div¡¤v_rr w.r.t. pressure using relaxed jacobi for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + int bmIndex = boundaryPointSetIndex - nFluids; DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); if (bm->getRigidBodyObject()->isDynamic()) { std::vector bodyInContact = std::vector(); @@ -254,43 +255,52 @@ void TimeStepWCSPH::computeRigidRigidAccels() { Real relaxation = 0.5 / numContacts; // source term don't change in WCSPH - boundarySolver->computeV_s(); - boundarySolver->computeSourceTerm(); - for (unsigned int i = 0; i < sim->getDynamicBoundarySimulator()->getMaxIteration(); i++) { - boundarySolver->computeDensityAndVolume(); - boundarySolver->computePressureGrad(); + + for (unsigned int i = 0; i < 10; i++) { + + bs->computeDensityAndVolume(); + bs->computeV_s(); + bs->computeSourceTerm(); #pragma omp parallel default(shared) { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - Real artificialVolume = (bm->getRestDensity() * bm->getVolume(r)) / bm->getDensity(r); - const Vector3r a = - bm->getArtificialVolume(r) * bm->getPressureGrad(r); + const Vector3r a = - bs->getArtificialVolume(bmIndex, r) * bs->getPressureGrad(bmIndex, r); bm->addForce(bm->getPosition(r), bm->getRigidBodyObject()->getMass() * a); } } // update position and velocity using the current pressure - sim->getDynamicBoundarySimulator()->timeStepStrongCoupling(); + //sim->getDynamicBoundarySimulator()->timeStepStrongCoupling(); - Real densityErrorAvg = 0; + bs->computePressureGrad(); + bs->computeSourceTermRHS(); + bs->computeDiagonalElement(); - boundarySolver->computeSourceTermRHS(); - boundarySolver->computeDiagonalElement(); + Real densityErrorAvg = 0; #pragma omp parallel default(shared) { // compute number of contacts #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - densityErrorAvg += bm->getDensity(r); - Real pressureNextIter = bm->getPressure(r) + relaxation / bm->getDiagonalElement(r) * (bm->getSourceTerm(r) - bm->getSourceTermRHS(r)); - bm->setPressure(r, pressureNextIter); + if (bs->getDiagonalElement(bmIndex, r) != 0) { + densityErrorAvg += bs->getDensity(bmIndex, r); + Real pressureNextIter = bs->getPressure(bmIndex, r) + relaxation / bs->getDiagonalElement(bmIndex, r) * (bs->getSourceTerm(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r)); + //if (i == 1) { + // std::cout << bs->getDensity(bmIndex, r) << std::endl;; + //} + bs->setPressure(bmIndex, r, pressureNextIter); + + } else { + bs->setPressure(bmIndex, r, 0); + } } } densityErrorAvg /= bm->numberOfParticles(); // only particles int contact with other object ? - if ((bm->getRestDensity() - densityErrorAvg) / bm->getRestDensity() < 0.001) { + if ((bs->getRestDensity(bmIndex) - densityErrorAvg) / bs->getRestDensity(bmIndex) < 0.001) { break; } } From 54d6e2af68190c589cff379c00c317c73d6079d5 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Fri, 12 May 2023 13:00:11 +0200 Subject: [PATCH 20/38] bug fix --- SPlisHSPlasH/StrongCouplingBoundarySolver.cpp | 174 ++++++++++++------ SPlisHSPlasH/StrongCouplingBoundarySolver.h | 28 +-- SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 5 +- 3 files changed, 135 insertions(+), 72 deletions(-) diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp index caccded1..dd4baaa4 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp @@ -17,8 +17,8 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_minus_rho_div_v_rr(), m_diagonalElement(), m_artificialVolume(), - m_particleID(), - m_lastPressure() + m_lastPressure(), + m_predictVelocity() { Simulation* sim = Simulation::getCurrent(); const unsigned int nBoundaries = sim->numberOfBoundaryModels(); @@ -33,6 +33,7 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_pressureGrad.resize(nBoundaries); m_artificialVolume.resize(nBoundaries); m_lastPressure.resize(nBoundaries); + m_predictVelocity.resize(nBoundaries); m_restDensity.resize(nBoundaries, 1); m_v_rr_body.resize(nBoundaries, Vector3r::Zero()); m_omega_rr_body.resize(nBoundaries, Vector3r::Zero()); @@ -50,7 +51,11 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_pressureGrad[i].resize(bm->numberOfParticles(), Vector3r::Zero()); m_artificialVolume[i].resize(bm->numberOfParticles(), 0); m_lastPressure[i].resize(bm->numberOfParticles(), 0); + m_predictVelocity[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + + bm->addField({ "density", FieldType::Scalar, [this, i](const unsigned int j) -> Real* { return &getDensity(i, j); } }); } + } StrongCouplingBoundarySolver::~StrongCouplingBoundarySolver() { @@ -66,6 +71,7 @@ StrongCouplingBoundarySolver::~StrongCouplingBoundarySolver() { m_pressureGrad[i].clear(); m_artificialVolume[i].clear(); m_lastPressure[i].clear(); + m_predictVelocity[i].clear(); } m_density.clear(); m_v_s.clear(); @@ -77,6 +83,7 @@ StrongCouplingBoundarySolver::~StrongCouplingBoundarySolver() { m_pressureGrad.clear(); m_artificialVolume.clear(); m_lastPressure.clear(); + m_predictVelocity.clear(); } void StrongCouplingBoundarySolver::computeV_s() { @@ -163,15 +170,15 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { Matrix3r productMat_r = Matrix3r().setZero(); Vector3r pos_r = bm_r->getPosition(r); productMat_r << 0, -pos_r.z(), pos_r.y(), - pos_r.z(), 0, -pos_r.x(), - -pos_r.y(), pos_r.x(), 0; + pos_r.z(), 0, -pos_r.x(), + -pos_r.y(), pos_r.x(), 0; Real diagonal = 0; for (unsigned int pointSetIndex_i = nFluids; pointSetIndex_i < sim->numberOfPointSets(); pointSetIndex_i++) { BoundaryModel_Akinci2012* bm_i = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_i)); int indexI = pointSetIndex_i - nFluids; DynamicRigidBody* rb_i = static_cast(bm_i->getRigidBodyObject()); - // neighbors of r in other rigid bodies + // neighbors of r in other rigid bodies, denoted as i if (pointSetIndex_i != pointSetIndex_r) { for (unsigned int m = 0; m < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_i, r); m++) { const unsigned int i = sim->getNeighbor(pointSetIndex_r, pointSetIndex_i, r, m); @@ -181,8 +188,8 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { Matrix3r productMat_i = Matrix3r().setZero(); Vector3r pos_i = bm_i->getPosition(i); productMat_i << 0, -pos_i.z(), pos_i.y(), - pos_i.z(), 0, -pos_i.x(), - -pos_i.y(), pos_i.x(), 0; + pos_i.z(), 0, -pos_i.x(), + -pos_i.y(), pos_i.x(), 0; // neighbors of i in the same rigid body, denoted as k (k cannot be r) for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_i, pointSetIndex_i, i); n++) { @@ -192,8 +199,8 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { Vector3r pos_k = bm_i->getPosition(k); Matrix3r productMat_k = Matrix3r().setZero(); productMat_k << 0, -pos_k.z(), pos_k.y(), - pos_k.z(), 0, -pos_k.x(), - -pos_k.y(), pos_k.x(), 0; + pos_k.z(), 0, -pos_k.x(), + -pos_k.y(), pos_k.x(), 0; Real invMass = 0; if (rb_i->isDynamic()) { invMass = rb_i->getInvMass(); @@ -202,71 +209,94 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { } Matrix3r K_ik = invMass * Matrix3r::Identity() - productMat_i * rb_i->getInertiaTensorInverseW() * productMat_k; - // neighbors of k in all bodies, denoted as j - for (unsigned int pointSetIndex_j = nFluids; pointSetIndex_j < sim->numberOfPointSets(); pointSetIndex_j++) { - BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_j)); - for (unsigned int o = 0; o < sim->numberOfNeighbors(pointSetIndex_i, pointSetIndex_j, k); o++) { - const unsigned int j = sim->getNeighbor(pointSetIndex_i, pointSetIndex_j, k, o); - int indexJ = pointSetIndex_j - nFluids; - Vector3r gradWkj = sim->gradW(bm_i->getPosition(k) - bm_j->getPosition(j)); - //if (pointSetIndex_i == pointSetIndex_r && bm_i->getParticleID(k) == bm->getParticleID(r)) { - // coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_i->getDensity(k) * bm_i->getDensity(k)) * gradWkj; - //} - if (pointSetIndex_j == pointSetIndex_r && j == r) { - coeffSum_kj += getArtificialVolume(indexJ, j) * getDensity(indexJ, j) / (getDensity(indexJ, j) * getDensity(indexJ, j)) * gradWkj; - } - } - } - if (coeffSum_kj != Vector3r().setZero()) { - coeffSum_kj = getArtificialVolume(indexI, k) * K_ik * getDensity(indexI, k) * coeffSum_kj; - coeffSum_ik += coeffSum_kj; + // neighbors of k in all bodies, denoted as j (loop can be optimized?) + //for (unsigned int pointSetIndex_j = nFluids; pointSetIndex_j < sim->numberOfPointSets(); pointSetIndex_j++) { + // BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_j)); + // for (unsigned int o = 0; o < sim->numberOfNeighbors(pointSetIndex_i, pointSetIndex_j, k); o++) { + // const unsigned int j = sim->getNeighbor(pointSetIndex_i, pointSetIndex_j, k, o); + // int indexJ = pointSetIndex_j - nFluids; + // Vector3r gradWkj = sim->gradW(bm_i->getPosition(k) - bm_j->getPosition(j)); + // //if (pointSetIndex_i == pointSetIndex_r && bm_i->getParticleID(k) == bm->getParticleID(r)) { + // // coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_i->getDensity(k) * bm_i->getDensity(k)) * gradWkj; + // //} + // if (pointSetIndex_j == pointSetIndex_r && j == r) { + // coeffSum_kj += getArtificialVolume(indexJ, j) * getDensity(indexJ, j) / (getDensity(indexJ, j) * getDensity(indexJ, j)) * gradWkj; + // } + // } + //} - } + //if (coeffSum_kj != Vector3r().setZero()) { + // coeffSum_kj = getArtificialVolume(indexI, k) * K_ik * getDensity(indexI, k) * coeffSum_kj; + // coeffSum_ik += coeffSum_kj; + //} + Vector3r gradWkr = sim->gradW(bm_i->getPosition(k) - bm_r->getPosition(r)); + coeffSum_ik += getArtificialVolume(indexI, k) * K_ik * getDensity(indexI, k) * getArtificialVolume(indexR, r) * getDensity(indexR, r) / (getDensity(indexR, r) * getDensity(indexR, r)) * gradWkr; } - coeffSum_ik *= dt; Vector3r coeffSum_rk = Vector3r().setZero(); - // neighbors of r in the same rigid body, denoted as k + // neighbors of r in the same rigid body, denoted as k, k != r for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_r, r); n++) { const unsigned int k = sim->getNeighbor(pointSetIndex_r, pointSetIndex_r, r, n); - Vector3r coeffSum_kj = Vector3r().setZero(); Vector3r pos_k = bm_r->getPosition(k); Matrix3r productMat_k = Matrix3r().setZero(); productMat_k << 0, -pos_k.z(), pos_k.y(), - pos_k.z(), 0, -pos_k.x(), - -pos_k.y(), pos_k.x(), 0; + pos_k.z(), 0, -pos_k.x(), + -pos_k.y(), pos_k.x(), 0; Matrix3r K_rk = rb->getInvMass() * Matrix3r::Identity() - productMat_r * rb->getInertiaTensorInverseW() * productMat_k; // neighbors of k in all bodies, denoted as j - for (unsigned int pointSetIndex_j = nFluids; pointSetIndex_j < sim->numberOfPointSets(); pointSetIndex_j++) { - BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_j)); - int indexJ = pointSetIndex_j - nFluids; - for (unsigned int o = 0; o < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_j, k); o++) { - const unsigned int j = sim->getNeighbor(pointSetIndex_r, pointSetIndex_j, k, o); - Vector3r gradWkj = sim->gradW(bm_r->getPosition(k) - bm_j->getPosition(j)); - if (k == r) { - coeffSum_kj += getArtificialVolume(indexJ, j) * getDensity(indexJ, j) / (getDensity(indexR, k) * getDensity(indexR, k)) * gradWkj; - } - - if (pointSetIndex_j == pointSetIndex_r && j == r) { - coeffSum_kj += getArtificialVolume(indexJ, j) * getDensity(indexJ, j) / (getDensity(indexJ, j) * getDensity(indexJ, j)) * gradWkj; - } - } - } - if (coeffSum_kj != Vector3r().setZero()) { - coeffSum_kj = getArtificialVolume(indexR, k) * K_rk * getDensity(indexR, k) * coeffSum_kj; - coeffSum_rk += coeffSum_kj; + //for (unsigned int pointSetIndex_j = nFluids; pointSetIndex_j < sim->numberOfPointSets(); pointSetIndex_j++) { + // BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_j)); + // int indexJ = pointSetIndex_j - nFluids; + // for (unsigned int o = 0; o < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_j, k); o++) { + // const unsigned int j = sim->getNeighbor(pointSetIndex_r, pointSetIndex_j, k, o); + // Vector3r gradWkj = sim->gradW(bm_r->getPosition(k) - bm_j->getPosition(j)); + // if (k == r) { + // coeffSum_kj += getArtificialVolume(indexJ, j) * getDensity(indexJ, j) / (getDensity(indexR, k) * getDensity(indexR, k)) * gradWkj; + // } + + // if (pointSetIndex_j == pointSetIndex_r && j == r) { + // coeffSum_kj += getArtificialVolume(indexJ, j) * getDensity(indexJ, j) / (getDensity(indexJ, j) * getDensity(indexJ, j)) * gradWkj; + // } + // } + //} + Vector3r gradWkr = sim->gradW(bm_r->getPosition(k) - bm_r->getPosition(r)); + + coeffSum_rk += getArtificialVolume(indexR, k) * K_rk * getDensity(indexR, k) * getArtificialVolume(indexR, r) * getDensity(indexR, r) / (getDensity(indexR, r) * getDensity(indexR, r)) * gradWkr; + + //if (coeffSum_kj != Vector3r().setZero()) { + // coeffSum_kj = getArtificialVolume(indexR, k) * K_rk * getDensity(indexR, k) * coeffSum_kj; + // coeffSum_rk += coeffSum_kj; + //} + } + + Vector3r coeffSum_rj = Vector3r().setZero(); + // k = r, for all neighbors of r in all bodies, denoted as j + for (unsigned int pointSetIndex_j = nFluids; pointSetIndex_j < sim->numberOfPointSets(); pointSetIndex_j++) { + BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_j)); + int indexJ = pointSetIndex_j - nFluids; + for (unsigned int o = 0; o < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_j, r); o++) { + const unsigned int j = sim->getNeighbor(pointSetIndex_r, pointSetIndex_j, r, o); + Vector3r gradWrj = sim->gradW(bm_r->getPosition(r) - bm_j->getPosition(j)); + coeffSum_rj += getArtificialVolume(indexJ, j) * getDensity(indexJ, j) / (getDensity(indexR, r) * getDensity(indexR, r)) * gradWrj; } } + + Matrix3r K_rr = rb->getInvMass() * Matrix3r::Identity() - productMat_r * rb->getInertiaTensorInverseW() * productMat_r; + + coeffSum_rj = getArtificialVolume(indexR, r) * K_rr * getDensity(indexR, r) * coeffSum_rj; + coeffSum_rk += coeffSum_rj; coeffSum_rk *= dt; diagonal += getArtificialVolume(indexI, i) * getDensity(indexI, i) * (coeffSum_ik - coeffSum_rk).dot(gradWri); + } } } setDiagonalElement(indexR, r, diagonal); + //std::cout << getDiagonalElement(indexR, r) << std::endl; } } } @@ -291,8 +321,8 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { if (rb->isDynamic()) { - // compute density - Real particleDensity = 0; + // compute density for particle r + Real particleDensity = getRestDensity(bmIndex) * bm->getVolume(r) * sim->W_zero(); // iterate over all rigid bodies for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); @@ -301,9 +331,12 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { particleDensity += getRestDensity(bmIndex) * bm->getVolume(r) * sim->W(bm->getPosition(r) - bm_neighbor->getPosition(k)); } } - // 0.8 for compensation - setDensity(bmIndex, r, particleDensity / 0.8); - setArtificialVolume(bmIndex, r, getRestDensity(bmIndex) * bm->getVolume(r) / getDensity(bmIndex, r)); + setDensity(bmIndex, r, particleDensity); + if (getDensity(bmIndex, r) > getRestDensity(bmIndex)) { + setArtificialVolume(bmIndex, r, getRestDensity(bmIndex) * bm->getVolume(r) / getDensity(bmIndex, r)); + }else{ + setArtificialVolume(bmIndex, r, bm->getVolume(r)); + } } else { setArtificialVolume(bmIndex, r, bm->getVolume(r)); } @@ -329,6 +362,7 @@ void StrongCouplingBoundarySolver::computePressureGrad() { { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { + // pressure gradient for particle r Vector3r pressureGrad_r = Vector3r().setZero(); const Real density_r = getDensity(bmIndex, r); const Real pressure_r = getPressure(bmIndex, r); @@ -378,7 +412,7 @@ void StrongCouplingBoundarySolver::computeSourceTermRHS() { setV_rr_body(bmIndex, v_rr_body); setOmega_rr_body(bmIndex, omega_rr_body); } - // compute v_rr for all particles (predicted velocity) + // compute v_rr and predicted velocity (v_rr+v_s) for all particles for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); int bmIndex = boundaryPointSetIndex - nFluids; @@ -389,6 +423,7 @@ void StrongCouplingBoundarySolver::computeSourceTermRHS() { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { setV_rr(bmIndex, r, getV_rr_body(bmIndex) + getOmega_rr_body(bmIndex).cross(bm->getPosition(r))); + setPredictVelocity(bmIndex, r, getV_rr(bmIndex, r) + getV_s(bmIndex, r)); } } } @@ -422,4 +457,29 @@ void StrongCouplingBoundarySolver::computeSourceTermRHS() { } } } +} + +void SPH::StrongCouplingBoundarySolver::performNeighborhoodSearchSort() { + Simulation* sim = Simulation::getCurrent(); + const unsigned int nModels = sim->numberOfBoundaryModels(); + + for (unsigned int i = 0; i < nModels; i++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModel(i)); + + const unsigned int numPart = bm->numberOfParticles(); + if (numPart != 0) { + auto const& d = sim->getNeighborhoodSearch()->point_set(bm->getPointSetIndex()); + d.sort_field(&m_density[i][0]); + d.sort_field(&m_v_s[i][0]); + d.sort_field(&m_s[i][0]); + d.sort_field(&m_pressure[i][0]); + d.sort_field(&m_v_rr[i][0]); + d.sort_field(&m_minus_rho_div_v_rr[i][0]); + d.sort_field(&m_diagonalElement[i][0]); + d.sort_field(&m_pressureGrad[i][0]); + d.sort_field(&m_artificialVolume[i][0]); + d.sort_field(&m_lastPressure[i][0]); + d.sort_field(&m_predictVelocity[i][0]); + } + } } \ No newline at end of file diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.h b/SPlisHSPlasH/StrongCouplingBoundarySolver.h index 31673e38..52da4ba9 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.h +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.h @@ -6,7 +6,6 @@ namespace SPH { class StrongCouplingBoundarySolver { private: // values required for Gissler 2019 strong coupling based on Akinci 2012 - std::vector> m_particleID; std::vector> m_density; std::vector> m_pressure; std::vector> m_lastPressure; @@ -15,6 +14,7 @@ namespace SPH { std::vector> m_s; // source term std::vector> m_pressureGrad; std::vector> m_v_rr; + std::vector> m_predictVelocity; std::vector> m_minus_rho_div_v_rr; // RHS to the source term std::vector> m_diagonalElement; // diagonal element for jacobi iteration std::vector m_restDensity; @@ -38,19 +38,7 @@ namespace SPH { void computeSourceTermRHS(); void computeSourceTerm(); void computeDiagonalElement(); - - - FORCE_INLINE const unsigned int& getParticleID(const Real& rigidBodyIndex, Real& index) const { - return m_particleID[rigidBodyIndex][index]; - } - - FORCE_INLINE unsigned int& getParticleID(const Real& rigidBodyIndex, const Real& index) { - return m_particleID[rigidBodyIndex][index]; - } - - FORCE_INLINE void setParticleID(const Real& rigidBodyIndex, const Real& index, const Real& value) { - m_particleID[rigidBodyIndex][index] = value; - } + void performNeighborhoodSearchSort(); FORCE_INLINE const Real& getDensity(const Real& rigidBodyIndex, const Real& index) const { return m_density[rigidBodyIndex][index]; @@ -148,6 +136,18 @@ namespace SPH { m_v_rr[rigidBodyIndex][i] = value; } + FORCE_INLINE Vector3r& getPredictVelocity(const Real& rigidBodyIndex, const unsigned int i) { + return m_predictVelocity[rigidBodyIndex][i]; + } + + FORCE_INLINE const Vector3r& getPredictVelocity(const Real& rigidBodyIndex, const unsigned int i) const { + return m_predictVelocity[rigidBodyIndex][i]; + } + + FORCE_INLINE void setPredictVelocity(const Real& rigidBodyIndex, const unsigned int i, const Vector3r& value) { + m_predictVelocity[rigidBodyIndex][i] = value; + } + FORCE_INLINE Vector3r& getPressureGrad(const Real& rigidBodyIndex, const unsigned int i) { return m_pressureGrad[rigidBodyIndex][i]; } diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index 660997ae..78a81127 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -287,9 +287,11 @@ void TimeStepWCSPH::computeRigidRigidAccels() { if (bs->getDiagonalElement(bmIndex, r) != 0) { densityErrorAvg += bs->getDensity(bmIndex, r); Real pressureNextIter = bs->getPressure(bmIndex, r) + relaxation / bs->getDiagonalElement(bmIndex, r) * (bs->getSourceTerm(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r)); - //if (i == 1) { + //std::cout << pressureNextIter << std::endl; + //if (i == 0) { // std::cout << bs->getDensity(bmIndex, r) << std::endl;; //} + bs->setLastPressure(bmIndex, r, bs->getPressure(bmIndex, r)); bs->setPressure(bmIndex, r, pressureNextIter); } else { @@ -315,6 +317,7 @@ void TimeStepWCSPH::performNeighborhoodSearch() if (m_counter % 500 == 0) { Simulation::getCurrent()->performNeighborhoodSearchSort(); + StrongCouplingBoundarySolver::getCurrent()->performNeighborhoodSearchSort(); m_simulationData.performNeighborhoodSearchSort(); } m_counter++; From 457ffa01c0803e1b5358fdcd22e2489e725349a1 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Wed, 24 May 2023 15:27:33 +0200 Subject: [PATCH 21/38] to debug --- SPlisHSPlasH/DynamicRigidBody.h | 17 +- SPlisHSPlasH/Simulation.cpp | 6 +- SPlisHSPlasH/StrongCouplingBoundarySolver.cpp | 392 +++++++++--------- SPlisHSPlasH/StrongCouplingBoundarySolver.h | 67 +++ SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 34 +- Simulator/SimulatorBase.cpp | 2 +- 6 files changed, 296 insertions(+), 222 deletions(-) diff --git a/SPlisHSPlasH/DynamicRigidBody.h b/SPlisHSPlasH/DynamicRigidBody.h index 667e5cfe..8f0f3275 100644 --- a/SPlisHSPlasH/DynamicRigidBody.h +++ b/SPlisHSPlasH/DynamicRigidBody.h @@ -15,8 +15,7 @@ namespace SPH { class DynamicRigidBody : public RigidBodyObject { // Some fields are from PBD::RigidBody private: - // Boundary Particles - + bool m_isDynamic; Real m_density; @@ -173,12 +172,9 @@ namespace SPH { // Determine mass and inertia tensor void determineMassProperties(const Real density, bool isDynamic, const Vector3r scale) { + m_isDynamic = isDynamic; // for now only consider cubiod which is scaled from a unit cube - if (isDynamic) { - setMass(density * scale.x() * scale.y() * scale.z()); - } else { - setMass(0.0); - } + setMass(density * scale.x() * scale.y() * scale.z()); Vector3r value = m_mass * Vector3r((scale.y() * scale.y() + scale.z() * scale.z()) / 12, (scale.x() * scale.x() + scale.z() * scale.z()) / 12, (scale.x() * scale.x() + scale.z() * scale.z()) / 12); m_inertiaTensor = value; m_inertiaTensorInverse = Vector3r(static_cast(1.0) / value[0], static_cast(1.0) / value[1], static_cast(1.0) / value[2]); @@ -540,7 +536,7 @@ namespace SPH { virtual bool isDynamic() const { - return m_mass != 0.0; + return m_isDynamic; } virtual Real const getMass() const { @@ -564,6 +560,11 @@ namespace SPH { virtual Vector3r const& getVelocity() const { return m_v; } + + FORCE_INLINE Vector3r& getVelocity() { + return m_v; + } + virtual void setVelocity(const Vector3r& v) { if (m_isAnimated) m_v = v; } diff --git a/SPlisHSPlasH/Simulation.cpp b/SPlisHSPlasH/Simulation.cpp index c59298e4..0d40ad35 100644 --- a/SPlisHSPlasH/Simulation.cpp +++ b/SPlisHSPlasH/Simulation.cpp @@ -13,6 +13,7 @@ #include "BoundaryModel_Akinci2012.h" #include "BoundaryModel_Bender2019.h" #include "BoundaryModel_Koschier2017.h" +#include "StrongCouplingBoundarySolver.h" using namespace SPH; @@ -508,8 +509,11 @@ void Simulation::reset() for (unsigned int i = 0; i < numberOfBoundaryModels(); i++) getBoundaryModel(i)->reset(); - if (getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { updateBoundaryVolume(); + StrongCouplingBoundarySolver::getCurrent()->reset(); + } + if (m_timeStep) m_timeStep->reset(); diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp index dd4baaa4..7579839b 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp @@ -14,11 +14,18 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_s(), m_pressure(), m_v_rr(), + m_v_b(), + m_grad_p_b(), m_minus_rho_div_v_rr(), m_diagonalElement(), m_artificialVolume(), m_lastPressure(), - m_predictVelocity() + m_predictVelocity(), + m_predictPosition(), + m_v_rr_body(), + m_omega_rr_body(), + m_v_b_body(), + m_omega_b_body() { Simulation* sim = Simulation::getCurrent(); const unsigned int nBoundaries = sim->numberOfBoundaryModels(); @@ -28,15 +35,20 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_s.resize(nBoundaries); m_pressure.resize(nBoundaries); m_v_rr.resize(nBoundaries); + m_v_b.resize(nBoundaries); m_minus_rho_div_v_rr.resize(nBoundaries); m_diagonalElement.resize(nBoundaries); m_pressureGrad.resize(nBoundaries); + m_grad_p_b.resize(nBoundaries); m_artificialVolume.resize(nBoundaries); m_lastPressure.resize(nBoundaries); m_predictVelocity.resize(nBoundaries); - m_restDensity.resize(nBoundaries, 1); + m_predictPosition.resize(nBoundaries); + m_restDensity.resize(nBoundaries, 1000); m_v_rr_body.resize(nBoundaries, Vector3r::Zero()); m_omega_rr_body.resize(nBoundaries, Vector3r::Zero()); + m_v_b_body.resize(nBoundaries, Vector3r::Zero()); + m_omega_b_body.resize(nBoundaries, Vector3r::Zero()); for (unsigned int i = 0; i < nBoundaries; i++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModel(i)); @@ -46,18 +58,70 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_s[i].resize(bm->numberOfParticles(), 0); m_pressure[i].resize(bm->numberOfParticles(), 0); m_v_rr[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_v_b[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_grad_p_b[i].resize(bm->numberOfParticles(), Vector3r::Zero()); m_minus_rho_div_v_rr[i].resize(bm->numberOfParticles(), 0); m_diagonalElement[i].resize(bm->numberOfParticles(), 0); m_pressureGrad[i].resize(bm->numberOfParticles(), Vector3r::Zero()); m_artificialVolume[i].resize(bm->numberOfParticles(), 0); m_lastPressure[i].resize(bm->numberOfParticles(), 0); m_predictVelocity[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_predictPosition[i].resize(bm->numberOfParticles(), Vector3r::Zero()); bm->addField({ "density", FieldType::Scalar, [this, i](const unsigned int j) -> Real* { return &getDensity(i, j); } }); + bm->addField({ "sourceTerm", FieldType::Scalar, [this, i](const unsigned int j)->Real* {return &getSourceTerm(i,j); } }); + bm->addField({ "v_s", FieldType::Vector3, [this,i](const unsigned int j)->Vector3r* {return &getV_s(i,j); } }); + bm->addField({ "v_rr", FieldType::Vector3, [this,i](const unsigned int j)->Vector3r* {return &getV_rr(i,j); } }); + bm->addField({ "pressure", FieldType::Scalar,[this,i](const unsigned int j)->Real* {return &getPressure(i,j); } }); + bm->addField({ "rigidbodyVelocity", FieldType::Vector3,[bm](const unsigned int j)->Vector3r* {return &(static_cast(bm->getRigidBodyObject())->getVelocity()); } }); } } +void SPH::StrongCouplingBoundarySolver::reset() { + Simulation* sim = Simulation::getCurrent(); + const unsigned int nBoundaries = sim->numberOfBoundaryModels(); + + m_density.resize(nBoundaries); + m_v_s.resize(nBoundaries); + m_s.resize(nBoundaries); + m_pressure.resize(nBoundaries); + m_v_rr.resize(nBoundaries); + m_v_b.resize(nBoundaries); + m_grad_p_b.resize(nBoundaries); + m_minus_rho_div_v_rr.resize(nBoundaries); + m_diagonalElement.resize(nBoundaries); + m_pressureGrad.resize(nBoundaries); + m_artificialVolume.resize(nBoundaries); + m_lastPressure.resize(nBoundaries); + m_predictVelocity.resize(nBoundaries); + m_predictPosition.resize(nBoundaries); + m_restDensity.resize(nBoundaries, 1); + m_v_rr_body.resize(nBoundaries, Vector3r::Zero()); + m_omega_rr_body.resize(nBoundaries, Vector3r::Zero()); + m_v_b_body.resize(nBoundaries, Vector3r::Zero()); + m_omega_b_body.resize(nBoundaries, Vector3r::Zero()); + + for (unsigned int i = 0; i < nBoundaries; i++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModel(i)); + + m_density[i].resize(bm->numberOfParticles(), m_restDensity[i]); + m_v_s[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_s[i].resize(bm->numberOfParticles(), 0); + m_pressure[i].resize(bm->numberOfParticles(), 0); + m_v_rr[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_v_b[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_grad_p_b[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_minus_rho_div_v_rr[i].resize(bm->numberOfParticles(), 0); + m_diagonalElement[i].resize(bm->numberOfParticles(), 0); + m_pressureGrad[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_artificialVolume[i].resize(bm->numberOfParticles(), 0); + m_lastPressure[i].resize(bm->numberOfParticles(), 0); + m_predictVelocity[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_predictPosition[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + } +} + StrongCouplingBoundarySolver::~StrongCouplingBoundarySolver() { current = nullptr; for (unsigned int i = 0; i < Simulation::getCurrent()->numberOfBoundaryModels(); i++) { @@ -66,24 +130,63 @@ StrongCouplingBoundarySolver::~StrongCouplingBoundarySolver() { m_s[i].clear(); m_pressure[i].clear(); m_v_rr[i].clear(); + m_v_b[i].clear(); + m_grad_p_b[i].clear(); m_minus_rho_div_v_rr[i].clear(); m_diagonalElement[i].clear(); m_pressureGrad[i].clear(); m_artificialVolume[i].clear(); m_lastPressure[i].clear(); m_predictVelocity[i].clear(); + m_predictPosition[i].clear(); } m_density.clear(); m_v_s.clear(); m_s.clear(); m_pressure.clear(); m_v_rr.clear(); + m_v_b.clear(); + m_grad_p_b.clear(); m_minus_rho_div_v_rr.clear(); m_diagonalElement.clear(); m_pressureGrad.clear(); m_artificialVolume.clear(); m_lastPressure.clear(); m_predictVelocity.clear(); + m_predictPosition.clear(); + m_v_rr_body.clear(); + m_omega_rr_body.clear(); + m_v_b_body.clear(); + m_omega_b_body.clear(); +} + + +void SPH::StrongCouplingBoundarySolver::performNeighborhoodSearchSort() { + Simulation* sim = Simulation::getCurrent(); + const unsigned int nModels = sim->numberOfBoundaryModels(); + + for (unsigned int i = 0; i < nModels; i++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModel(i)); + + const unsigned int numPart = bm->numberOfParticles(); + if (numPart != 0) { + auto const& d = sim->getNeighborhoodSearch()->point_set(bm->getPointSetIndex()); + d.sort_field(&m_density[i][0]); + d.sort_field(&m_v_s[i][0]); + d.sort_field(&m_s[i][0]); + d.sort_field(&m_pressure[i][0]); + d.sort_field(&m_v_rr[i][0]); + d.sort_field(&m_v_b[i][0]); + d.sort_field(&m_minus_rho_div_v_rr[i][0]); + d.sort_field(&m_diagonalElement[i][0]); + d.sort_field(&m_pressureGrad[i][0]); + d.sort_field(&m_artificialVolume[i][0]); + d.sort_field(&m_lastPressure[i][0]); + d.sort_field(&m_predictVelocity[i][0]); + d.sort_field(&m_predictPosition[i][0]); + d.sort_field(&m_grad_p_b[i][0]); + } + } } void StrongCouplingBoundarySolver::computeV_s() { @@ -108,7 +211,7 @@ void StrongCouplingBoundarySolver::computeV_s() { // the rb->getForce() contains only fluid-rigid forces Vector3r F_R = rb->getForce() + gravForce; setV_s(boundaryPointSetIndex - nFluids, r, rb->getVelocity() + dt * rb->getInvMass() * F_R + - (rb->getAngularVelocity() + rb->getInertiaTensorInverseW() * (dt * rb->getTorque() + dt * (rb->getInertiaTensorW() * rb->getAngularVelocity()).cross(rb->getAngularVelocity()))).cross(bm->getPosition(r))); + (rb->getAngularVelocity() + rb->getInertiaTensorInverseW() * (dt * rb->getTorque() + dt * (rb->getInertiaTensorW() * rb->getAngularVelocity()).cross(rb->getAngularVelocity()))).cross(bm->getPosition(r) - rb->getPosition())); } } } @@ -122,6 +225,8 @@ void StrongCouplingBoundarySolver::computeSourceTerm() { const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); + computeV_s(); + // compute source term s for all particles for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); @@ -160,143 +265,73 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { const unsigned int nFluids = sim->numberOfFluidModels(); for (unsigned int pointSetIndex_r = nFluids; pointSetIndex_r < sim->numberOfPointSets(); pointSetIndex_r++) { BoundaryModel_Akinci2012* bm_r = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_r)); - int indexR = pointSetIndex_r - nFluids; + int index_r = pointSetIndex_r - nFluids; DynamicRigidBody* rb = static_cast(bm_r->getRigidBodyObject()); + getV_b_body(index_r) = Vector3r::Zero(); + getOmega_b_body(index_r) = Vector3r::Zero(); if (rb->isDynamic()) { #pragma omp parallel default(shared) { #pragma omp for schedule(static) for (int r = 0; r < bm_r->numberOfParticles(); r++) { - Matrix3r productMat_r = Matrix3r().setZero(); - Vector3r pos_r = bm_r->getPosition(r); - productMat_r << 0, -pos_r.z(), pos_r.y(), - pos_r.z(), 0, -pos_r.x(), - -pos_r.y(), pos_r.x(), 0; - Real diagonal = 0; - for (unsigned int pointSetIndex_i = nFluids; pointSetIndex_i < sim->numberOfPointSets(); pointSetIndex_i++) { - BoundaryModel_Akinci2012* bm_i = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_i)); - int indexI = pointSetIndex_i - nFluids; - DynamicRigidBody* rb_i = static_cast(bm_i->getRigidBodyObject()); - - // neighbors of r in other rigid bodies, denoted as i - if (pointSetIndex_i != pointSetIndex_r) { - for (unsigned int m = 0; m < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_i, r); m++) { - const unsigned int i = sim->getNeighbor(pointSetIndex_r, pointSetIndex_i, r, m); - Vector3r coeffSum_ik = Vector3r().setZero(); - - Vector3r gradWri = sim->gradW(bm_r->getPosition(r) - bm_i->getPosition(i)); - Matrix3r productMat_i = Matrix3r().setZero(); - Vector3r pos_i = bm_i->getPosition(i); - productMat_i << 0, -pos_i.z(), pos_i.y(), - pos_i.z(), 0, -pos_i.x(), - -pos_i.y(), pos_i.x(), 0; - - // neighbors of i in the same rigid body, denoted as k (k cannot be r) - for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_i, pointSetIndex_i, i); n++) { - const unsigned int k = sim->getNeighbor(pointSetIndex_i, pointSetIndex_i, i, n); - Vector3r coeffSum_kj = Vector3r().setZero(); - - Vector3r pos_k = bm_i->getPosition(k); - Matrix3r productMat_k = Matrix3r().setZero(); - productMat_k << 0, -pos_k.z(), pos_k.y(), - pos_k.z(), 0, -pos_k.x(), - -pos_k.y(), pos_k.x(), 0; - Real invMass = 0; - if (rb_i->isDynamic()) { - invMass = rb_i->getInvMass(); - } else { - invMass = 1; - } - Matrix3r K_ik = invMass * Matrix3r::Identity() - productMat_i * rb_i->getInertiaTensorInverseW() * productMat_k; - - // neighbors of k in all bodies, denoted as j (loop can be optimized?) - //for (unsigned int pointSetIndex_j = nFluids; pointSetIndex_j < sim->numberOfPointSets(); pointSetIndex_j++) { - // BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_j)); - // for (unsigned int o = 0; o < sim->numberOfNeighbors(pointSetIndex_i, pointSetIndex_j, k); o++) { - // const unsigned int j = sim->getNeighbor(pointSetIndex_i, pointSetIndex_j, k, o); - // int indexJ = pointSetIndex_j - nFluids; - // Vector3r gradWkj = sim->gradW(bm_i->getPosition(k) - bm_j->getPosition(j)); - // //if (pointSetIndex_i == pointSetIndex_r && bm_i->getParticleID(k) == bm->getParticleID(r)) { - // // coeffSum_kj += bm_j->getArtificialVolume(j) * bm_j->getDensity(j) / (bm_i->getDensity(k) * bm_i->getDensity(k)) * gradWkj; - // //} - // if (pointSetIndex_j == pointSetIndex_r && j == r) { - // coeffSum_kj += getArtificialVolume(indexJ, j) * getDensity(indexJ, j) / (getDensity(indexJ, j) * getDensity(indexJ, j)) * gradWkj; - // } - // } - //} - - //if (coeffSum_kj != Vector3r().setZero()) { - // coeffSum_kj = getArtificialVolume(indexI, k) * K_ik * getDensity(indexI, k) * coeffSum_kj; - // coeffSum_ik += coeffSum_kj; - //} - Vector3r gradWkr = sim->gradW(bm_i->getPosition(k) - bm_r->getPosition(r)); - coeffSum_ik += getArtificialVolume(indexI, k) * K_ik * getDensity(indexI, k) * getArtificialVolume(indexR, r) * getDensity(indexR, r) / (getDensity(indexR, r) * getDensity(indexR, r)) * gradWkr; - } - coeffSum_ik *= dt; - - Vector3r coeffSum_rk = Vector3r().setZero(); - // neighbors of r in the same rigid body, denoted as k, k != r - for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_r, r); n++) { - const unsigned int k = sim->getNeighbor(pointSetIndex_r, pointSetIndex_r, r, n); - - Vector3r pos_k = bm_r->getPosition(k); - Matrix3r productMat_k = Matrix3r().setZero(); - productMat_k << 0, -pos_k.z(), pos_k.y(), - pos_k.z(), 0, -pos_k.x(), - -pos_k.y(), pos_k.x(), 0; - Matrix3r K_rk = rb->getInvMass() * Matrix3r::Identity() - productMat_r * rb->getInertiaTensorInverseW() * productMat_k; - - // neighbors of k in all bodies, denoted as j - //for (unsigned int pointSetIndex_j = nFluids; pointSetIndex_j < sim->numberOfPointSets(); pointSetIndex_j++) { - // BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_j)); - // int indexJ = pointSetIndex_j - nFluids; - // for (unsigned int o = 0; o < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_j, k); o++) { - // const unsigned int j = sim->getNeighbor(pointSetIndex_r, pointSetIndex_j, k, o); - // Vector3r gradWkj = sim->gradW(bm_r->getPosition(k) - bm_j->getPosition(j)); - // if (k == r) { - // coeffSum_kj += getArtificialVolume(indexJ, j) * getDensity(indexJ, j) / (getDensity(indexR, k) * getDensity(indexR, k)) * gradWkj; - // } - - // if (pointSetIndex_j == pointSetIndex_r && j == r) { - // coeffSum_kj += getArtificialVolume(indexJ, j) * getDensity(indexJ, j) / (getDensity(indexJ, j) * getDensity(indexJ, j)) * gradWkj; - // } - // } - //} - Vector3r gradWkr = sim->gradW(bm_r->getPosition(k) - bm_r->getPosition(r)); - - coeffSum_rk += getArtificialVolume(indexR, k) * K_rk * getDensity(indexR, k) * getArtificialVolume(indexR, r) * getDensity(indexR, r) / (getDensity(indexR, r) * getDensity(indexR, r)) * gradWkr; - - //if (coeffSum_kj != Vector3r().setZero()) { - // coeffSum_kj = getArtificialVolume(indexR, k) * K_rk * getDensity(indexR, k) * coeffSum_kj; - // coeffSum_rk += coeffSum_kj; - //} - } - - Vector3r coeffSum_rj = Vector3r().setZero(); - // k = r, for all neighbors of r in all bodies, denoted as j - for (unsigned int pointSetIndex_j = nFluids; pointSetIndex_j < sim->numberOfPointSets(); pointSetIndex_j++) { - BoundaryModel_Akinci2012* bm_j = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_j)); - int indexJ = pointSetIndex_j - nFluids; - for (unsigned int o = 0; o < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_j, r); o++) { - const unsigned int j = sim->getNeighbor(pointSetIndex_r, pointSetIndex_j, r, o); - Vector3r gradWrj = sim->gradW(bm_r->getPosition(r) - bm_j->getPosition(j)); - coeffSum_rj += getArtificialVolume(indexJ, j) * getDensity(indexJ, j) / (getDensity(indexR, r) * getDensity(indexR, r)) * gradWrj; - } - } - - - Matrix3r K_rr = rb->getInvMass() * Matrix3r::Identity() - productMat_r * rb->getInertiaTensorInverseW() * productMat_r; - - coeffSum_rj = getArtificialVolume(indexR, r) * K_rr * getDensity(indexR, r) * coeffSum_rj; - coeffSum_rk += coeffSum_rj; - coeffSum_rk *= dt; - diagonal += getArtificialVolume(indexI, i) * getDensity(indexI, i) * (coeffSum_ik - coeffSum_rk).dot(gradWri); + Vector3r pos_r = bm_r->getPosition(r) - rb->getPosition(); + Vector3r grad_p_b = Vector3r::Zero(); + const Real density_r2 = getDensity(index_r, r) * getDensity(index_r, r); + // rk are neighboring rigid particles of r of other rigid bodies k + for (unsigned int pointSetIndex_rk = nFluids; pointSetIndex_rk < sim->numberOfPointSets(); pointSetIndex_rk++) { + if (pointSetIndex_rk != pointSetIndex_r) { + BoundaryModel_Akinci2012* bm_rk = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_rk)); + int index_rk = pointSetIndex_rk - nFluids; + DynamicRigidBody* rb_rk = static_cast(bm_rk->getRigidBodyObject()); + for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_rk, r); n++) { + const unsigned int rk = sim->getNeighbor(pointSetIndex_r, pointSetIndex_rk, r, n); + grad_p_b += getArtificialVolume(index_rk, rk) * getDensity(index_rk, rk) / density_r2 * sim->gradW(bm_r->getPosition(r) - bm_rk->getPosition(rk)); + } + } + } + grad_p_b *= getDensity(index_r, r); + setGrad_p_b(index_r, r, grad_p_b); + getV_b_body(index_r) += -dt * rb->getInvMass() * getArtificialVolume(index_r, r) * grad_p_b; + getOmega_b_body(index_r) += -dt * rb->getInertiaTensorInverseW() * getArtificialVolume(index_r, r) * pos_r.cross(grad_p_b); + //////// + } + } + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm_r->numberOfParticles(); r++) { + Vector3r pos_r = bm_r->getPosition(r) - rb->getPosition(); + const Real density_r2 = getDensity(index_r, r) * getDensity(index_r, r); + setV_b(index_r, r, getV_b_body(index_r) + getOmega_b_body(index_r).cross(pos_r)); + Real b_r = 0; + for (unsigned int pointSetIndex_rk = nFluids; pointSetIndex_rk < sim->numberOfPointSets(); pointSetIndex_rk++) { + if (pointSetIndex_rk != pointSetIndex_r) { + Vector3r v_b_k_body = Vector3r::Zero(); + Vector3r omega_b_k_body = Vector3r::Zero(); + BoundaryModel_Akinci2012* bm_rk = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_rk)); + int index_rk = pointSetIndex_rk - nFluids; + DynamicRigidBody* rb_rk = static_cast(bm_rk->getRigidBodyObject()); + for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_rk, r); n++) { + const unsigned int rk = sim->getNeighbor(pointSetIndex_r, pointSetIndex_rk, r, n); + Vector3r pos_rk = bm_rk->getPosition(rk) - rb_rk->getPosition(); + Vector3r grad_p_b_rkr = getDensity(index_rk, rk) * getArtificialVolume(index_r, r) * getDensity(index_r, r) / density_r2 * sim->gradW(bm_rk->getPosition(rk) - bm_r->getPosition(r)); + v_b_k_body += -dt * rb_rk->getInvMass() * getArtificialVolume(index_rk, rk) * grad_p_b_rkr; + omega_b_k_body += -dt * rb_rk->getInertiaTensorInverseW() * getArtificialVolume(index_rk, rk) * pos_rk.cross(grad_p_b_rkr); } - } + // divergence + Real sum_rk = 0; + for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_rk, r); n++) { + const unsigned int rk = sim->getNeighbor(pointSetIndex_r, pointSetIndex_rk, r, n); + Vector3r pos_rk = bm_rk->getPosition(rk) - rb_rk->getPosition(); + Vector3r v_b_rk = v_b_k_body + omega_b_k_body.cross(pos_rk); + sum_rk += getArtificialVolume(index_rk, rk) * getDensity(index_rk, rk) * (v_b_rk - getV_b(index_r, r)).dot(sim->gradW(bm_r->getPosition(r) - bm_rk->getPosition(rk))); + } + b_r += sum_rk; + } } - setDiagonalElement(indexR, r, diagonal); - //std::cout << getDiagonalElement(indexR, r) << std::endl; + b_r = -b_r; + setDiagonalElement(index_r, r, b_r > 0 ? b_r : 0); } } } @@ -304,7 +339,6 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { } void StrongCouplingBoundarySolver::computeDensityAndVolume() { - // Use dynamic boundary simulator and Akinci2012 Simulation* sim = Simulation::getCurrent(); DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); TimeManager* tm = TimeManager::getCurrent(); @@ -342,7 +376,6 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { } } } - } } @@ -367,14 +400,16 @@ void StrongCouplingBoundarySolver::computePressureGrad() { const Real density_r = getDensity(bmIndex, r); const Real pressure_r = getPressure(bmIndex, r); for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - int neighborIndex = pid - nFluids; - for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { - const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - const Real density_k = getDensity(neighborIndex, k); - const Real volume_k = getArtificialVolume(neighborIndex, k); - const Real pressure_k = getPressure(neighborIndex, k); - pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); + if (pid != boundaryPointSetIndex) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + int neighborIndex = pid - nFluids; + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + const Real density_k = getDensity(neighborIndex, k); + const Real volume_k = getArtificialVolume(neighborIndex, k); + const Real pressure_k = getPressure(neighborIndex, k); + pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); + } } } pressureGrad_r *= density_r; @@ -392,6 +427,7 @@ void StrongCouplingBoundarySolver::computeSourceTermRHS() { const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); + computePressureGrad(); // compute v_rr and omega_rr for rigid body using the pressure gradient for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); @@ -405,7 +441,7 @@ void StrongCouplingBoundarySolver::computeSourceTermRHS() { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { v_rr_body += -dt * rb->getInvMass() * getArtificialVolume(bmIndex, r) * getPressureGrad(bmIndex, r); - omega_rr_body += -dt * rb->getInertiaTensorInverseW() * getArtificialVolume(bmIndex, r) * bm->getPosition(r).cross(getPressureGrad(bmIndex, r)); + omega_rr_body += -dt * rb->getInertiaTensorInverseW() * getArtificialVolume(bmIndex, r) * (bm->getPosition(r) - rb->getPosition()).cross(getPressureGrad(bmIndex, r)); } } } @@ -422,8 +458,11 @@ void StrongCouplingBoundarySolver::computeSourceTermRHS() { { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - setV_rr(bmIndex, r, getV_rr_body(bmIndex) + getOmega_rr_body(bmIndex).cross(bm->getPosition(r))); + setV_rr(bmIndex, r, getV_rr_body(bmIndex) + getOmega_rr_body(bmIndex).cross(bm->getPosition(r) - rb->getPosition())); setPredictVelocity(bmIndex, r, getV_rr(bmIndex, r) + getV_s(bmIndex, r)); + + //////// + } } } @@ -432,54 +471,31 @@ void StrongCouplingBoundarySolver::computeSourceTermRHS() { for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); int bmIndex = boundaryPointSetIndex - nFluids; - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - Real minus_rho_div_v_rr = 0; - const Vector3r v_rr_r = getV_rr(bmIndex, r); - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - // divergence of particles in the same body should be 0; - if (boundaryPointSetIndex != pid) { - BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - int neighborIndex = pid - nFluids; - for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { - const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - const Real density_k = getDensity(neighborIndex, k); - const Real volume_k = getArtificialVolume(neighborIndex, k); - const Vector3r v_rr_k = getV_rr(neighborIndex, k); - minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); + if (bm->getRigidBodyObject()->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Real minus_rho_div_v_rr = 0; + const Vector3r v_rr_r = getV_rr(bmIndex, r); + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + // divergence of particles in the same body should be 0; + if (boundaryPointSetIndex != pid) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + int neighborIndex = pid - nFluids; + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + const Real density_k = getDensity(neighborIndex, k); + const Real volume_k = getArtificialVolume(neighborIndex, k); + const Vector3r v_rr_k = getV_rr(neighborIndex, k); + minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); + } } } + minus_rho_div_v_rr = -minus_rho_div_v_rr; + setSourceTermRHS(bmIndex, r, minus_rho_div_v_rr); } - minus_rho_div_v_rr = -minus_rho_div_v_rr; - setSourceTermRHS(bmIndex, r, minus_rho_div_v_rr); } - } + } } } - -void SPH::StrongCouplingBoundarySolver::performNeighborhoodSearchSort() { - Simulation* sim = Simulation::getCurrent(); - const unsigned int nModels = sim->numberOfBoundaryModels(); - - for (unsigned int i = 0; i < nModels; i++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModel(i)); - - const unsigned int numPart = bm->numberOfParticles(); - if (numPart != 0) { - auto const& d = sim->getNeighborhoodSearch()->point_set(bm->getPointSetIndex()); - d.sort_field(&m_density[i][0]); - d.sort_field(&m_v_s[i][0]); - d.sort_field(&m_s[i][0]); - d.sort_field(&m_pressure[i][0]); - d.sort_field(&m_v_rr[i][0]); - d.sort_field(&m_minus_rho_div_v_rr[i][0]); - d.sort_field(&m_diagonalElement[i][0]); - d.sort_field(&m_pressureGrad[i][0]); - d.sort_field(&m_artificialVolume[i][0]); - d.sort_field(&m_lastPressure[i][0]); - d.sort_field(&m_predictVelocity[i][0]); - } - } -} \ No newline at end of file diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.h b/SPlisHSPlasH/StrongCouplingBoundarySolver.h index 52da4ba9..5ca1ba16 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.h +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.h @@ -14,12 +14,17 @@ namespace SPH { std::vector> m_s; // source term std::vector> m_pressureGrad; std::vector> m_v_rr; + std::vector> m_v_b; + std::vector> m_grad_p_b; std::vector> m_predictVelocity; + std::vector> m_predictPosition; std::vector> m_minus_rho_div_v_rr; // RHS to the source term std::vector> m_diagonalElement; // diagonal element for jacobi iteration std::vector m_restDensity; std::vector m_v_rr_body; std::vector m_omega_rr_body; + std::vector m_v_b_body; + std::vector m_omega_b_body; static StrongCouplingBoundarySolver* current; @@ -32,12 +37,14 @@ namespace SPH { } return current; } + void reset(); void computeDensityAndVolume(); void computePressureGrad(); void computeV_s(); void computeSourceTermRHS(); void computeSourceTerm(); void computeDiagonalElement(); + void computeFriction(); void performNeighborhoodSearchSort(); FORCE_INLINE const Real& getDensity(const Real& rigidBodyIndex, const Real& index) const { @@ -100,6 +107,18 @@ namespace SPH { m_v_rr_body[rigidBodyIndex] = value; } + FORCE_INLINE const Vector3r& getV_b_body(const Real& rigidBodyIndex) const { + return m_v_b_body[rigidBodyIndex]; + } + + FORCE_INLINE Vector3r& getV_b_body(const Real& rigidBodyIndex) { + return m_v_b_body[rigidBodyIndex]; + } + + FORCE_INLINE void setV_b_body(const Real& rigidBodyIndex, const Vector3r& value) { + m_v_b_body[rigidBodyIndex] = value; + } + FORCE_INLINE const Vector3r& getOmega_rr_body(const Real& rigidBodyIndex) const { return m_omega_rr_body[rigidBodyIndex]; } @@ -111,6 +130,18 @@ namespace SPH { FORCE_INLINE void setOmega_rr_body(const Real& rigidBodyIndex, const Vector3r& value) { m_omega_rr_body[rigidBodyIndex] = value; } + + FORCE_INLINE const Vector3r& getOmega_b_body(const Real& rigidBodyIndex) const { + return m_omega_b_body[rigidBodyIndex]; + } + + FORCE_INLINE Vector3r& getOmega_b_body(const Real& rigidBodyIndex) { + return m_omega_b_body[rigidBodyIndex]; + } + + FORCE_INLINE void setOmega_b_body(const Real& rigidBodyIndex, const Vector3r& value) { + m_omega_b_body[rigidBodyIndex] = value; + } FORCE_INLINE Vector3r& getV_s(const Real& rigidBodyIndex, const unsigned int i) { return m_v_s[rigidBodyIndex][i]; @@ -136,6 +167,30 @@ namespace SPH { m_v_rr[rigidBodyIndex][i] = value; } + FORCE_INLINE Vector3r& getV_b(const Real& rigidBodyIndex, const unsigned int i) { + return m_v_b[rigidBodyIndex][i]; + } + + FORCE_INLINE const Vector3r& getV_b(const Real& rigidBodyIndex, const unsigned int i) const { + return m_v_b[rigidBodyIndex][i]; + } + + FORCE_INLINE void setV_b(const Real& rigidBodyIndex, const unsigned int i, const Vector3r& value) { + m_v_b[rigidBodyIndex][i] = value; + } + + FORCE_INLINE Vector3r& getGrad_p_b(const Real& rigidBodyIndex, const unsigned int i) { + return m_grad_p_b[rigidBodyIndex][i]; + } + + FORCE_INLINE const Vector3r& getGrad_p_b(const Real& rigidBodyIndex, const unsigned int i) const { + return m_grad_p_b[rigidBodyIndex][i]; + } + + FORCE_INLINE void setGrad_p_b(const Real& rigidBodyIndex, const unsigned int i, const Vector3r& value) { + m_grad_p_b[rigidBodyIndex][i] = value; + } + FORCE_INLINE Vector3r& getPredictVelocity(const Real& rigidBodyIndex, const unsigned int i) { return m_predictVelocity[rigidBodyIndex][i]; } @@ -148,6 +203,18 @@ namespace SPH { m_predictVelocity[rigidBodyIndex][i] = value; } + FORCE_INLINE Vector3r& getPredictPosition(const Real& rigidBodyIndex, const unsigned int i) { + return m_predictPosition[rigidBodyIndex][i]; + } + + FORCE_INLINE const Vector3r& getPredictPosition(const Real& rigidBodyIndex, const unsigned int i) const { + return m_predictPosition[rigidBodyIndex][i]; + } + + FORCE_INLINE void setPredictPosition(const Real& rigidBodyIndex, const unsigned int i, const Vector3r& value) { + m_predictPosition[rigidBodyIndex][i] = value; + } + FORCE_INLINE Vector3r& getPressureGrad(const Real& rigidBodyIndex, const unsigned int i) { return m_pressureGrad[rigidBodyIndex][i]; } diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index 78a81127..fa42b8a5 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -254,46 +254,24 @@ void TimeStepWCSPH::computeRigidRigidAccels() { // beta_r_RJ Real relaxation = 0.5 / numContacts; - // source term don't change in WCSPH - - - for (unsigned int i = 0; i < 10; i++) { + for (unsigned int i = 0; i < 1; i++) { bs->computeDensityAndVolume(); - bs->computeV_s(); bs->computeSourceTerm(); - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - const Vector3r a = - bs->getArtificialVolume(bmIndex, r) * bs->getPressureGrad(bmIndex, r); - bm->addForce(bm->getPosition(r), bm->getRigidBodyObject()->getMass() * a); - } - } - // update position and velocity using the current pressure - //sim->getDynamicBoundarySimulator()->timeStepStrongCoupling(); - - bs->computePressureGrad(); bs->computeSourceTermRHS(); bs->computeDiagonalElement(); Real densityErrorAvg = 0; #pragma omp parallel default(shared) { - // compute number of contacts #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { if (bs->getDiagonalElement(bmIndex, r) != 0) { densityErrorAvg += bs->getDensity(bmIndex, r); Real pressureNextIter = bs->getPressure(bmIndex, r) + relaxation / bs->getDiagonalElement(bmIndex, r) * (bs->getSourceTerm(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r)); - //std::cout << pressureNextIter << std::endl; - //if (i == 0) { - // std::cout << bs->getDensity(bmIndex, r) << std::endl;; - //} bs->setLastPressure(bmIndex, r, bs->getPressure(bmIndex, r)); bs->setPressure(bmIndex, r, pressureNextIter); - } else { bs->setPressure(bmIndex, r, 0); } @@ -301,11 +279,19 @@ void TimeStepWCSPH::computeRigidRigidAccels() { } densityErrorAvg /= bm->numberOfParticles(); - // only particles int contact with other object ? + // only particles in contact with other object ? if ((bs->getRestDensity(bmIndex) - densityErrorAvg) / bs->getRestDensity(bmIndex) < 0.001) { break; } } + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + const Vector3r a = -bs->getArtificialVolume(bmIndex, r) * bs->getPressureGrad(bmIndex, r); + bm->addForce(bm->getPosition(r), bs->getArtificialVolume(bmIndex, r) * bs->getDensity(bmIndex, r) * a); + } + } } } } diff --git a/Simulator/SimulatorBase.cpp b/Simulator/SimulatorBase.cpp index 47ac395f..046df908 100644 --- a/Simulator/SimulatorBase.cpp +++ b/Simulator/SimulatorBase.cpp @@ -97,7 +97,7 @@ SimulatorBase::SimulatorBase() m_colorMapType.resize(1, 0); m_renderMinValue.resize(1, 0.0); m_renderMaxValue.resize(1, 5.0); - m_particleAttributes = "velocity;density"; + m_particleAttributes = "velocity;density;sourceTerm;v_s;v_rr;pressure;rigidbodyVelocity"; m_timeStepCB = nullptr; m_resetCB = nullptr; m_updateGUI = false; From ea19f5a9711ed51d97001a12f877a8bfa6105a84 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Fri, 26 May 2023 19:11:36 +0200 Subject: [PATCH 22/38] diagonal element fix --- SPlisHSPlasH/DynamicRigidBody.h | 8 + SPlisHSPlasH/StrongCouplingBoundarySolver.cpp | 253 +++++++++--------- SPlisHSPlasH/StrongCouplingBoundarySolver.h | 130 ++++----- SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 41 ++- 4 files changed, 232 insertions(+), 200 deletions(-) diff --git a/SPlisHSPlasH/DynamicRigidBody.h b/SPlisHSPlasH/DynamicRigidBody.h index 8f0f3275..0e8c0ca5 100644 --- a/SPlisHSPlasH/DynamicRigidBody.h +++ b/SPlisHSPlasH/DynamicRigidBody.h @@ -112,6 +112,13 @@ namespace SPH { m_v0.setZero(); m_a.setZero(); m_force.setZero(); + //if (position.x() > 0) { + // m_v0 = Vector3r(-1, 0, 0); + // m_v = m_v0; + //} else { + // m_v0 = Vector3r(1, 0, 0); + // m_v = m_v0; + //} m_q = rotation; m_q0 = rotation; @@ -143,6 +150,7 @@ namespace SPH { m_omega = m_omega0; getAcceleration().setZero(); + getForce().setZero(); getTorque().setZero(); rotationUpdated(); diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp index 7579839b..f6d602ed 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp @@ -52,7 +52,6 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : for (unsigned int i = 0; i < nBoundaries; i++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModel(i)); - m_density[i].resize(bm->numberOfParticles(), m_restDensity[i]); m_v_s[i].resize(bm->numberOfParticles(), Vector3r::Zero()); m_s[i].resize(bm->numberOfParticles(), 0); @@ -68,12 +67,13 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_predictVelocity[i].resize(bm->numberOfParticles(), Vector3r::Zero()); m_predictPosition[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - bm->addField({ "density", FieldType::Scalar, [this, i](const unsigned int j) -> Real* { return &getDensity(i, j); } }); - bm->addField({ "sourceTerm", FieldType::Scalar, [this, i](const unsigned int j)->Real* {return &getSourceTerm(i,j); } }); + bm->addField({ "density", FieldType::Scalar, [this, i](const unsigned int j) -> double* { return &getDensity(i, j); } }); + bm->addField({ "sourceTerm", FieldType::Scalar, [this, i](const unsigned int j)->double* {return &getSourceTerm(i,j); } }); bm->addField({ "v_s", FieldType::Vector3, [this,i](const unsigned int j)->Vector3r* {return &getV_s(i,j); } }); bm->addField({ "v_rr", FieldType::Vector3, [this,i](const unsigned int j)->Vector3r* {return &getV_rr(i,j); } }); - bm->addField({ "pressure", FieldType::Scalar,[this,i](const unsigned int j)->Real* {return &getPressure(i,j); } }); + bm->addField({ "pressure", FieldType::Scalar,[this,i](const unsigned int j)->double* {return &getPressure(i,j); } }); bm->addField({ "rigidbodyVelocity", FieldType::Vector3,[bm](const unsigned int j)->Vector3r* {return &(static_cast(bm->getRigidBodyObject())->getVelocity()); } }); + bm->addField({ "v_rr_body", FieldType::Vector3,[this,i](const unsigned int j)->Vector3r* {return &getV_rr_body(i); } }); } } @@ -82,43 +82,24 @@ void SPH::StrongCouplingBoundarySolver::reset() { Simulation* sim = Simulation::getCurrent(); const unsigned int nBoundaries = sim->numberOfBoundaryModels(); - m_density.resize(nBoundaries); - m_v_s.resize(nBoundaries); - m_s.resize(nBoundaries); - m_pressure.resize(nBoundaries); - m_v_rr.resize(nBoundaries); - m_v_b.resize(nBoundaries); - m_grad_p_b.resize(nBoundaries); - m_minus_rho_div_v_rr.resize(nBoundaries); - m_diagonalElement.resize(nBoundaries); - m_pressureGrad.resize(nBoundaries); - m_artificialVolume.resize(nBoundaries); - m_lastPressure.resize(nBoundaries); - m_predictVelocity.resize(nBoundaries); - m_predictPosition.resize(nBoundaries); - m_restDensity.resize(nBoundaries, 1); - m_v_rr_body.resize(nBoundaries, Vector3r::Zero()); - m_omega_rr_body.resize(nBoundaries, Vector3r::Zero()); - m_v_b_body.resize(nBoundaries, Vector3r::Zero()); - m_omega_b_body.resize(nBoundaries, Vector3r::Zero()); - for (unsigned int i = 0; i < nBoundaries; i++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModel(i)); - - m_density[i].resize(bm->numberOfParticles(), m_restDensity[i]); - m_v_s[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - m_s[i].resize(bm->numberOfParticles(), 0); - m_pressure[i].resize(bm->numberOfParticles(), 0); - m_v_rr[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - m_v_b[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - m_grad_p_b[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - m_minus_rho_div_v_rr[i].resize(bm->numberOfParticles(), 0); - m_diagonalElement[i].resize(bm->numberOfParticles(), 0); - m_pressureGrad[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - m_artificialVolume[i].resize(bm->numberOfParticles(), 0); - m_lastPressure[i].resize(bm->numberOfParticles(), 0); - m_predictVelocity[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - m_predictPosition[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + for (int j = 0; j < bm->numberOfParticles(); j++) { + m_density[i][j] = m_restDensity[i]; + m_v_s[i][j] = Vector3r::Zero(); + m_s[i][j] = 0; + m_pressure[i][j] = 0; + m_v_rr[i][j] = Vector3r::Zero(); + m_v_b[i][j] = Vector3r::Zero(); + m_grad_p_b[i][j] = Vector3r::Zero(); + m_minus_rho_div_v_rr[i][j] = 0; + m_diagonalElement[i][j] = 0; + m_pressureGrad[i][j] = Vector3r::Zero(); + m_artificialVolume[i][j] = 0; + m_lastPressure[i][j] = 0; + m_predictVelocity[i][j] = Vector3r::Zero(); + m_predictPosition[i][j] = Vector3r::Zero(); + } } } @@ -189,6 +170,47 @@ void SPH::StrongCouplingBoundarySolver::performNeighborhoodSearchSort() { } } +void StrongCouplingBoundarySolver::computeDensityAndVolume() { + Simulation* sim = Simulation::getCurrent(); + DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + TimeManager* tm = TimeManager::getCurrent(); + const Real dt = tm->getTimeStepSize(); + const unsigned int nFluids = sim->numberOfFluidModels(); + + // Compute density and artificial volume for all particles + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + int bmIndex = boundaryPointSetIndex - nFluids; + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + if (rb->isDynamic()) { + // compute density for particle r + Real particleDensity = getRestDensity(bmIndex) * bm->getVolume(r) * sim->W_zero(); + // iterate over all rigid bodies + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + particleDensity += getRestDensity(bmIndex) * bm->getVolume(r) * sim->W(bm->getPosition(r) - bm_neighbor->getPosition(k)); + } + } + setDensity(bmIndex, r, particleDensity); + if (getDensity(bmIndex, r) > getRestDensity(bmIndex)) { + setArtificialVolume(bmIndex, r, getRestDensity(bmIndex) * bm->getVolume(r) / getDensity(bmIndex, r)); + } else { + setArtificialVolume(bmIndex, r, bm->getVolume(r)); + } + } else { + setArtificialVolume(bmIndex, r, bm->getVolume(r)); + } + } + } + } +} + void StrongCouplingBoundarySolver::computeV_s() { // Use dynamic boundary simulator and Akinci2012 Simulation* sim = Simulation::getCurrent(); @@ -206,12 +228,13 @@ void StrongCouplingBoundarySolver::computeV_s() { { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { + Vector3r pos = bm->getPosition(r) - rb->getPosition(); // compute v_s Vector3r gravForce = rb->getMass() * Vector3r(sim->getVecValue(Simulation::GRAVITATION)); // the rb->getForce() contains only fluid-rigid forces Vector3r F_R = rb->getForce() + gravForce; setV_s(boundaryPointSetIndex - nFluids, r, rb->getVelocity() + dt * rb->getInvMass() * F_R + - (rb->getAngularVelocity() + rb->getInertiaTensorInverseW() * (dt * rb->getTorque() + dt * (rb->getInertiaTensorW() * rb->getAngularVelocity()).cross(rb->getAngularVelocity()))).cross(bm->getPosition(r) - rb->getPosition())); + (rb->getAngularVelocity() + rb->getInertiaTensorInverseW() * (dt * rb->getTorque() + dt * (rb->getInertiaTensorW() * rb->getAngularVelocity()).cross(rb->getAngularVelocity()))).cross(pos)); } } } @@ -267,8 +290,6 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { BoundaryModel_Akinci2012* bm_r = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_r)); int index_r = pointSetIndex_r - nFluids; DynamicRigidBody* rb = static_cast(bm_r->getRigidBodyObject()); - getV_b_body(index_r) = Vector3r::Zero(); - getOmega_b_body(index_r) = Vector3r::Zero(); if (rb->isDynamic()) { #pragma omp parallel default(shared) { @@ -290,21 +311,11 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { } } grad_p_b *= getDensity(index_r, r); - setGrad_p_b(index_r, r, grad_p_b); - getV_b_body(index_r) += -dt * rb->getInvMass() * getArtificialVolume(index_r, r) * grad_p_b; - getOmega_b_body(index_r) += -dt * rb->getInertiaTensorInverseW() * getArtificialVolume(index_r, r) * pos_r.cross(grad_p_b); - - //////// - } - } - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm_r->numberOfParticles(); r++) { - Vector3r pos_r = bm_r->getPosition(r) - rb->getPosition(); - const Real density_r2 = getDensity(index_r, r) * getDensity(index_r, r); - setV_b(index_r, r, getV_b_body(index_r) + getOmega_b_body(index_r).cross(pos_r)); + Vector3r v_b = -dt * rb->getInvMass() * getArtificialVolume(index_r, r) * grad_p_b; + Vector3r omega_b = -dt * rb->getInertiaTensorInverseW() * getArtificialVolume(index_r, r) * pos_r.cross(grad_p_b); + Vector3r v_b_r = v_b + omega_b.cross(pos_r); Real b_r = 0; + // for all neighboring rigid bodies for (unsigned int pointSetIndex_rk = nFluids; pointSetIndex_rk < sim->numberOfPointSets(); pointSetIndex_rk++) { if (pointSetIndex_rk != pointSetIndex_r) { Vector3r v_b_k_body = Vector3r::Zero(); @@ -325,54 +336,14 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { const unsigned int rk = sim->getNeighbor(pointSetIndex_r, pointSetIndex_rk, r, n); Vector3r pos_rk = bm_rk->getPosition(rk) - rb_rk->getPosition(); Vector3r v_b_rk = v_b_k_body + omega_b_k_body.cross(pos_rk); - sum_rk += getArtificialVolume(index_rk, rk) * getDensity(index_rk, rk) * (v_b_rk - getV_b(index_r, r)).dot(sim->gradW(bm_r->getPosition(r) - bm_rk->getPosition(rk))); + sum_rk += getArtificialVolume(index_rk, rk) * getDensity(index_rk, rk) * (v_b_rk - v_b_r).dot(sim->gradW(bm_r->getPosition(r) - bm_rk->getPosition(rk))); } b_r += sum_rk; } } b_r = -b_r; - setDiagonalElement(index_r, r, b_r > 0 ? b_r : 0); - } - } - } - } -} - -void StrongCouplingBoundarySolver::computeDensityAndVolume() { - Simulation* sim = Simulation::getCurrent(); - DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); - TimeManager* tm = TimeManager::getCurrent(); - const Real dt = tm->getTimeStepSize(); - const unsigned int nFluids = sim->numberOfFluidModels(); - - // Compute density and artificial volume for all particles - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - int bmIndex = boundaryPointSetIndex - nFluids; - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - if (rb->isDynamic()) { - // compute density for particle r - Real particleDensity = getRestDensity(bmIndex) * bm->getVolume(r) * sim->W_zero(); - // iterate over all rigid bodies - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { - const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - particleDensity += getRestDensity(bmIndex) * bm->getVolume(r) * sim->W(bm->getPosition(r) - bm_neighbor->getPosition(k)); - } - } - setDensity(bmIndex, r, particleDensity); - if (getDensity(bmIndex, r) > getRestDensity(bmIndex)) { - setArtificialVolume(bmIndex, r, getRestDensity(bmIndex) * bm->getVolume(r) / getDensity(bmIndex, r)); - }else{ - setArtificialVolume(bmIndex, r, bm->getVolume(r)); - } - } else { - setArtificialVolume(bmIndex, r, bm->getVolume(r)); + //setDiagonalElement(index_r, r, b_r > 0 ? b_r : 0); + setDiagonalElement(index_r, r, b_r); } } } @@ -407,6 +378,7 @@ void StrongCouplingBoundarySolver::computePressureGrad() { const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); const Real density_k = getDensity(neighborIndex, k); const Real volume_k = getArtificialVolume(neighborIndex, k); + //const Real pressure_k = bm_neighbor->getRigidBodyObject()->isDynamic() ? getPressure(neighborIndex, k) : pressure_r; const Real pressure_k = getPressure(neighborIndex, k); pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); } @@ -427,8 +399,9 @@ void StrongCouplingBoundarySolver::computeSourceTermRHS() { const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); - computePressureGrad(); - // compute v_rr and omega_rr for rigid body using the pressure gradient + //computePressureGrad(); + // + // compute pressure gradient, v_rr and omega_rr for rigid body for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); int bmIndex = boundaryPointSetIndex - nFluids; @@ -440,8 +413,28 @@ void StrongCouplingBoundarySolver::computeSourceTermRHS() { { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { + Vector3r pressureGrad_r = Vector3r::Zero(); + const Real density_r = getDensity(bmIndex, r); + const Real pressure_r = getPressure(bmIndex, r); + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + if (pid != boundaryPointSetIndex) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + int neighborIndex = pid - nFluids; + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + const Real density_k = getDensity(neighborIndex, k); + const Real volume_k = getArtificialVolume(neighborIndex, k); + const Real pressure_k = getPressure(neighborIndex, k); + pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); + } + } + } + pressureGrad_r *= density_r; + setPressureGrad(bmIndex, r, pressureGrad_r); + v_rr_body += -dt * rb->getInvMass() * getArtificialVolume(bmIndex, r) * getPressureGrad(bmIndex, r); - omega_rr_body += -dt * rb->getInertiaTensorInverseW() * getArtificialVolume(bmIndex, r) * (bm->getPosition(r) - rb->getPosition()).cross(getPressureGrad(bmIndex, r)); + Vector3r pos = bm->getPosition(r) - rb->getPosition(); + omega_rr_body += -dt * rb->getInertiaTensorInverseW() * getArtificialVolume(bmIndex, r) * pos.cross(getPressureGrad(bmIndex, r)); } } } @@ -458,24 +451,10 @@ void StrongCouplingBoundarySolver::computeSourceTermRHS() { { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - setV_rr(bmIndex, r, getV_rr_body(bmIndex) + getOmega_rr_body(bmIndex).cross(bm->getPosition(r) - rb->getPosition())); - setPredictVelocity(bmIndex, r, getV_rr(bmIndex, r) + getV_s(bmIndex, r)); + Vector3r pos = bm->getPosition(r) - rb->getPosition(); + setV_rr(bmIndex, r, getV_rr_body(bmIndex) + getOmega_rr_body(bmIndex).cross(pos)); + setPredictVelocity(bmIndex, r, getV_rr(bmIndex, r) + getV_s(bmIndex, r)); - //////// - - } - } - } - } - // compute the -rho * (div v_rr), which is the RHS to the source term - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - int bmIndex = boundaryPointSetIndex - nFluids; - if (bm->getRigidBodyObject()->isDynamic()) { - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { Real minus_rho_div_v_rr = 0; const Vector3r v_rr_r = getV_rr(bmIndex, r); for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { @@ -487,7 +466,8 @@ void StrongCouplingBoundarySolver::computeSourceTermRHS() { const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); const Real density_k = getDensity(neighborIndex, k); const Real volume_k = getArtificialVolume(neighborIndex, k); - const Vector3r v_rr_k = getV_rr(neighborIndex, k); + //const Vector3r v_rr_k = getV_rr_body(pid - nFluids) + getOmega_rr_body(pid - nFluids).cross(bm_neighbor->getPosition(k) - bm_neighbor->getRigidBodyObject()->getPosition()); + const Vector3r v_rr_k = getV_rr(pid - nFluids, k); minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); } } @@ -496,6 +476,37 @@ void StrongCouplingBoundarySolver::computeSourceTermRHS() { setSourceTermRHS(bmIndex, r, minus_rho_div_v_rr); } } - } + } } + // compute the -rho * (div v_rr), which is the RHS to the source term + //for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + // BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + // int bmIndex = boundaryPointSetIndex - nFluids; + // if (bm->getRigidBodyObject()->isDynamic()) { + // #pragma omp parallel default(shared) + // { + // #pragma omp for schedule(static) + // for (int r = 0; r < bm->numberOfParticles(); r++) { + // Real minus_rho_div_v_rr = 0; + // const Vector3r v_rr_r = getV_rr(bmIndex, r); + // for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + // // divergence of particles in the same body should be 0; + // if (boundaryPointSetIndex != pid) { + // BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + // int neighborIndex = pid - nFluids; + // for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + // const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + // const Real density_k = getDensity(neighborIndex, k); + // const Real volume_k = getArtificialVolume(neighborIndex, k); + // const Vector3r v_rr_k = getV_rr(neighborIndex, k); + // minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); + // } + // } + // } + // minus_rho_div_v_rr = -minus_rho_div_v_rr; + // setSourceTermRHS(bmIndex, r, minus_rho_div_v_rr); + // } + // } + // } + //} } diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.h b/SPlisHSPlasH/StrongCouplingBoundarySolver.h index 5ca1ba16..c6fdc3e9 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.h +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.h @@ -6,21 +6,21 @@ namespace SPH { class StrongCouplingBoundarySolver { private: // values required for Gissler 2019 strong coupling based on Akinci 2012 - std::vector> m_density; - std::vector> m_pressure; - std::vector> m_lastPressure; - std::vector> m_artificialVolume; + std::vector> m_density; + std::vector> m_pressure; + std::vector> m_lastPressure; + std::vector> m_artificialVolume; std::vector> m_v_s; - std::vector> m_s; // source term + std::vector> m_s; // source term std::vector> m_pressureGrad; std::vector> m_v_rr; std::vector> m_v_b; std::vector> m_grad_p_b; std::vector> m_predictVelocity; std::vector> m_predictPosition; - std::vector> m_minus_rho_div_v_rr; // RHS to the source term - std::vector> m_diagonalElement; // diagonal element for jacobi iteration - std::vector m_restDensity; + std::vector> m_minus_rho_div_v_rr; // RHS to the source term + std::vector> m_diagonalElement; // diagonal element for jacobi iteration + std::vector m_restDensity; std::vector m_v_rr_body; std::vector m_omega_rr_body; std::vector m_v_b_body; @@ -47,231 +47,231 @@ namespace SPH { void computeFriction(); void performNeighborhoodSearchSort(); - FORCE_INLINE const Real& getDensity(const Real& rigidBodyIndex, const Real& index) const { + FORCE_INLINE const double& getDensity(const unsigned int& rigidBodyIndex, const unsigned int& index) const { return m_density[rigidBodyIndex][index]; } - FORCE_INLINE Real& getDensity(const Real& rigidBodyIndex, const Real& index) { + FORCE_INLINE double& getDensity(const unsigned int& rigidBodyIndex, const unsigned int& index) { return m_density[rigidBodyIndex][index]; } - FORCE_INLINE void setDensity(const Real& rigidBodyIndex, const Real& index, const Real& value) { + FORCE_INLINE void setDensity(const unsigned int& rigidBodyIndex, const unsigned int& index, const double& value) { m_density[rigidBodyIndex][index] = value; } - FORCE_INLINE const Real& getPressure(const Real& rigidBodyIndex, const Real& index) const { + FORCE_INLINE const double& getPressure(const unsigned int& rigidBodyIndex, const unsigned int& index) const { return m_pressure[rigidBodyIndex][index]; } - FORCE_INLINE Real& getPressure(const Real& rigidBodyIndex, const Real& index) { + FORCE_INLINE double& getPressure(const unsigned int& rigidBodyIndex, const unsigned int& index) { return m_pressure[rigidBodyIndex][index]; } - FORCE_INLINE void setPressure(const Real& rigidBodyIndex, const Real& index, const Real& value) { + FORCE_INLINE void setPressure(const unsigned int& rigidBodyIndex, const unsigned int& index, const double& value) { m_pressure[rigidBodyIndex][index] = value; } - FORCE_INLINE const Real& getLastPressure(const Real& rigidBodyIndex, const Real& index) const { + FORCE_INLINE const double& getLastPressure(const unsigned int& rigidBodyIndex, const unsigned int& index) const { return m_lastPressure[rigidBodyIndex][index]; } - FORCE_INLINE Real& getLastPressure(const Real& rigidBodyIndex, const Real& index) { + FORCE_INLINE double& getLastPressure(const unsigned int& rigidBodyIndex, const unsigned int& index) { return m_lastPressure[rigidBodyIndex][index]; } - FORCE_INLINE void setLastPressure(const Real& rigidBodyIndex, const Real& index, const Real& value) { + FORCE_INLINE void setLastPressure(const unsigned int& rigidBodyIndex, const unsigned int& index, const double& value) { m_lastPressure[rigidBodyIndex][index] = value; } - FORCE_INLINE const Real& getRestDensity(const Real& rigidBodyIndex) const { + FORCE_INLINE const double& getRestDensity(const unsigned int& rigidBodyIndex) const { return m_restDensity[rigidBodyIndex]; } - FORCE_INLINE Real& getRestDensity(const Real& rigidBodyIndex) { + FORCE_INLINE double& getRestDensity(const unsigned int& rigidBodyIndex) { return m_restDensity[rigidBodyIndex]; } - FORCE_INLINE void setRestDensity(const Real& rigidBodyIndex, const Real& value) { + FORCE_INLINE void setRestDensity(const unsigned int& rigidBodyIndex, const double& value) { m_restDensity[rigidBodyIndex] = value; } - FORCE_INLINE const Vector3r& getV_rr_body(const Real& rigidBodyIndex) const { + FORCE_INLINE const Vector3r& getV_rr_body(const unsigned int& rigidBodyIndex) const { return m_v_rr_body[rigidBodyIndex]; } - FORCE_INLINE Vector3r& getV_rr_body(const Real& rigidBodyIndex) { + FORCE_INLINE Vector3r& getV_rr_body(const unsigned int& rigidBodyIndex) { return m_v_rr_body[rigidBodyIndex]; } - FORCE_INLINE void setV_rr_body(const Real& rigidBodyIndex, const Vector3r& value) { + FORCE_INLINE void setV_rr_body(const unsigned int& rigidBodyIndex, const Vector3r& value) { m_v_rr_body[rigidBodyIndex] = value; } - FORCE_INLINE const Vector3r& getV_b_body(const Real& rigidBodyIndex) const { + FORCE_INLINE const Vector3r& getV_b_body(const unsigned int& rigidBodyIndex) const { return m_v_b_body[rigidBodyIndex]; } - FORCE_INLINE Vector3r& getV_b_body(const Real& rigidBodyIndex) { + FORCE_INLINE Vector3r& getV_b_body(const unsigned int& rigidBodyIndex) { return m_v_b_body[rigidBodyIndex]; } - FORCE_INLINE void setV_b_body(const Real& rigidBodyIndex, const Vector3r& value) { + FORCE_INLINE void setV_b_body(const unsigned int& rigidBodyIndex, const Vector3r& value) { m_v_b_body[rigidBodyIndex] = value; } - FORCE_INLINE const Vector3r& getOmega_rr_body(const Real& rigidBodyIndex) const { + FORCE_INLINE const Vector3r& getOmega_rr_body(const unsigned int& rigidBodyIndex) const { return m_omega_rr_body[rigidBodyIndex]; } - FORCE_INLINE Vector3r& getOmega_rr_body(const Real& rigidBodyIndex) { + FORCE_INLINE Vector3r& getOmega_rr_body(const unsigned int& rigidBodyIndex) { return m_omega_rr_body[rigidBodyIndex]; } - FORCE_INLINE void setOmega_rr_body(const Real& rigidBodyIndex, const Vector3r& value) { + FORCE_INLINE void setOmega_rr_body(const unsigned int& rigidBodyIndex, const Vector3r& value) { m_omega_rr_body[rigidBodyIndex] = value; } - FORCE_INLINE const Vector3r& getOmega_b_body(const Real& rigidBodyIndex) const { + FORCE_INLINE const Vector3r& getOmega_b_body(const unsigned int& rigidBodyIndex) const { return m_omega_b_body[rigidBodyIndex]; } - FORCE_INLINE Vector3r& getOmega_b_body(const Real& rigidBodyIndex) { + FORCE_INLINE Vector3r& getOmega_b_body(const unsigned int& rigidBodyIndex) { return m_omega_b_body[rigidBodyIndex]; } - FORCE_INLINE void setOmega_b_body(const Real& rigidBodyIndex, const Vector3r& value) { + FORCE_INLINE void setOmega_b_body(const unsigned int& rigidBodyIndex, const Vector3r& value) { m_omega_b_body[rigidBodyIndex] = value; } - FORCE_INLINE Vector3r& getV_s(const Real& rigidBodyIndex, const unsigned int i) { + FORCE_INLINE Vector3r& getV_s(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_v_s[rigidBodyIndex][i]; } - FORCE_INLINE const Vector3r& getV_s(const Real& rigidBodyIndex, const unsigned int i) const { + FORCE_INLINE const Vector3r& getV_s(const unsigned int& rigidBodyIndex, const unsigned int i) const { return m_v_s[rigidBodyIndex][i]; } - FORCE_INLINE void setV_s(const Real& rigidBodyIndex, const unsigned int i, const Vector3r& value) { + FORCE_INLINE void setV_s(const unsigned int& rigidBodyIndex, const unsigned int i, const Vector3r& value) { m_v_s[rigidBodyIndex][i] = value; } - FORCE_INLINE Vector3r& getV_rr(const Real& rigidBodyIndex, const unsigned int i) { + FORCE_INLINE Vector3r& getV_rr(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_v_rr[rigidBodyIndex][i]; } - FORCE_INLINE const Vector3r& getV_rr(const Real& rigidBodyIndex, const unsigned int i) const { + FORCE_INLINE const Vector3r& getV_rr(const unsigned int& rigidBodyIndex, const unsigned int i) const { return m_v_rr[rigidBodyIndex][i]; } - FORCE_INLINE void setV_rr(const Real& rigidBodyIndex, const unsigned int i, const Vector3r& value) { + FORCE_INLINE void setV_rr(const unsigned int& rigidBodyIndex, const unsigned int i, const Vector3r& value) { m_v_rr[rigidBodyIndex][i] = value; } - FORCE_INLINE Vector3r& getV_b(const Real& rigidBodyIndex, const unsigned int i) { + FORCE_INLINE Vector3r& getV_b(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_v_b[rigidBodyIndex][i]; } - FORCE_INLINE const Vector3r& getV_b(const Real& rigidBodyIndex, const unsigned int i) const { + FORCE_INLINE const Vector3r& getV_b(const unsigned int& rigidBodyIndex, const unsigned int i) const { return m_v_b[rigidBodyIndex][i]; } - FORCE_INLINE void setV_b(const Real& rigidBodyIndex, const unsigned int i, const Vector3r& value) { + FORCE_INLINE void setV_b(const unsigned int& rigidBodyIndex, const unsigned int i, const Vector3r& value) { m_v_b[rigidBodyIndex][i] = value; } - FORCE_INLINE Vector3r& getGrad_p_b(const Real& rigidBodyIndex, const unsigned int i) { + FORCE_INLINE Vector3r& getGrad_p_b(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_grad_p_b[rigidBodyIndex][i]; } - FORCE_INLINE const Vector3r& getGrad_p_b(const Real& rigidBodyIndex, const unsigned int i) const { + FORCE_INLINE const Vector3r& getGrad_p_b(const unsigned int& rigidBodyIndex, const unsigned int i) const { return m_grad_p_b[rigidBodyIndex][i]; } - FORCE_INLINE void setGrad_p_b(const Real& rigidBodyIndex, const unsigned int i, const Vector3r& value) { + FORCE_INLINE void setGrad_p_b(const unsigned int& rigidBodyIndex, const unsigned int i, const Vector3r& value) { m_grad_p_b[rigidBodyIndex][i] = value; } - FORCE_INLINE Vector3r& getPredictVelocity(const Real& rigidBodyIndex, const unsigned int i) { + FORCE_INLINE Vector3r& getPredictVelocity(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_predictVelocity[rigidBodyIndex][i]; } - FORCE_INLINE const Vector3r& getPredictVelocity(const Real& rigidBodyIndex, const unsigned int i) const { + FORCE_INLINE const Vector3r& getPredictVelocity(const unsigned int& rigidBodyIndex, const unsigned int i) const { return m_predictVelocity[rigidBodyIndex][i]; } - FORCE_INLINE void setPredictVelocity(const Real& rigidBodyIndex, const unsigned int i, const Vector3r& value) { + FORCE_INLINE void setPredictVelocity(const unsigned int& rigidBodyIndex, const unsigned int i, const Vector3r& value) { m_predictVelocity[rigidBodyIndex][i] = value; } - FORCE_INLINE Vector3r& getPredictPosition(const Real& rigidBodyIndex, const unsigned int i) { + FORCE_INLINE Vector3r& getPredictPosition(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_predictPosition[rigidBodyIndex][i]; } - FORCE_INLINE const Vector3r& getPredictPosition(const Real& rigidBodyIndex, const unsigned int i) const { + FORCE_INLINE const Vector3r& getPredictPosition(const unsigned int& rigidBodyIndex, const unsigned int i) const { return m_predictPosition[rigidBodyIndex][i]; } - FORCE_INLINE void setPredictPosition(const Real& rigidBodyIndex, const unsigned int i, const Vector3r& value) { + FORCE_INLINE void setPredictPosition(const unsigned int& rigidBodyIndex, const unsigned int i, const Vector3r& value) { m_predictPosition[rigidBodyIndex][i] = value; } - FORCE_INLINE Vector3r& getPressureGrad(const Real& rigidBodyIndex, const unsigned int i) { + FORCE_INLINE Vector3r& getPressureGrad(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_pressureGrad[rigidBodyIndex][i]; } - FORCE_INLINE const Vector3r& getPressureGrad(const Real& rigidBodyIndex, const unsigned int i) const { + FORCE_INLINE const Vector3r& getPressureGrad(const unsigned int& rigidBodyIndex, const unsigned int i) const { return m_pressureGrad[rigidBodyIndex][i]; } - FORCE_INLINE void setPressureGrad(const Real& rigidBodyIndex, const unsigned int i, const Vector3r& value) { + FORCE_INLINE void setPressureGrad(const unsigned int& rigidBodyIndex, const unsigned int i, const Vector3r& value) { m_pressureGrad[rigidBodyIndex][i] = value; } - FORCE_INLINE Real& getSourceTermRHS(const Real& rigidBodyIndex, const unsigned int i) { + FORCE_INLINE double& getSourceTermRHS(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_minus_rho_div_v_rr[rigidBodyIndex][i]; } - FORCE_INLINE const Real& getSourceTermRHS(const Real& rigidBodyIndex, const unsigned int i) const { + FORCE_INLINE const double& getSourceTermRHS(const unsigned int& rigidBodyIndex, const unsigned int i) const { return m_minus_rho_div_v_rr[rigidBodyIndex][i]; } - FORCE_INLINE void setSourceTermRHS(const Real& rigidBodyIndex, const unsigned int i, const Real& value) { + FORCE_INLINE void setSourceTermRHS(const unsigned int& rigidBodyIndex, const unsigned int i, const double& value) { m_minus_rho_div_v_rr[rigidBodyIndex][i] = value; } - FORCE_INLINE Real& getDiagonalElement(const Real& rigidBodyIndex, const unsigned int i) { + FORCE_INLINE double& getDiagonalElement(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_diagonalElement[rigidBodyIndex][i]; } - FORCE_INLINE const Real& getDiagonalElement(const Real& rigidBodyIndex, const unsigned int i) const { + FORCE_INLINE const double& getDiagonalElement(const unsigned int& rigidBodyIndex, const unsigned int i) const { return m_diagonalElement[rigidBodyIndex][i]; } - FORCE_INLINE void setDiagonalElement(const Real& rigidBodyIndex, const unsigned int i, const Real& value) { + FORCE_INLINE void setDiagonalElement(const unsigned int& rigidBodyIndex, const unsigned int i, const double& value) { m_diagonalElement[rigidBodyIndex][i] = value; } - FORCE_INLINE Real& getSourceTerm(const Real& rigidBodyIndex, const unsigned int i) { + FORCE_INLINE double& getSourceTerm(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_s[rigidBodyIndex][i]; } - FORCE_INLINE const Real& getSourceTerm(const Real& rigidBodyIndex, const unsigned int i) const { + FORCE_INLINE const double& getSourceTerm(const unsigned int& rigidBodyIndex, const unsigned int i) const { return m_s[rigidBodyIndex][i]; } - FORCE_INLINE void setSourceTerm(const Real& rigidBodyIndex, const unsigned int i, const Real& value) { + FORCE_INLINE void setSourceTerm(const unsigned int& rigidBodyIndex, const unsigned int i, const double& value) { m_s[rigidBodyIndex][i] = value; } - FORCE_INLINE const Real& getArtificialVolume(const Real& rigidBodyIndex, const unsigned int i) const { + FORCE_INLINE const double& getArtificialVolume(const unsigned int& rigidBodyIndex, const unsigned int i) const { return m_artificialVolume[rigidBodyIndex][i]; } - FORCE_INLINE Real& getArtificialVolume(const Real& rigidBodyIndex, const unsigned int i) { + FORCE_INLINE double& getArtificialVolume(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_artificialVolume[rigidBodyIndex][i]; } - FORCE_INLINE void setArtificialVolume(const Real& rigidBodyIndex, const unsigned int i, const Real& val) { + FORCE_INLINE void setArtificialVolume(const unsigned int& rigidBodyIndex, const unsigned int i, const double& val) { m_artificialVolume[rigidBodyIndex][i] = val; } }; diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index fa42b8a5..190eca0d 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -253,43 +253,56 @@ void TimeStepWCSPH::computeRigidRigidAccels() { } // beta_r_RJ Real relaxation = 0.5 / numContacts; - - for (unsigned int i = 0; i < 1; i++) { - - bs->computeDensityAndVolume(); - bs->computeSourceTerm(); + bs->computeDensityAndVolume(); + bs->computeSourceTerm(); + bs->computeDiagonalElement(); + for (unsigned int i = 0; i < 20; i++) { bs->computeSourceTermRHS(); - bs->computeDiagonalElement(); Real densityErrorAvg = 0; + int numParticles = 0; #pragma omp parallel default(shared) { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - if (bs->getDiagonalElement(bmIndex, r) != 0) { + if (std::abs(bs->getDiagonalElement(bmIndex, r)) != 0) { + numParticles++; densityErrorAvg += bs->getDensity(bmIndex, r); + Real pressureNextIter = bs->getPressure(bmIndex, r) + relaxation / bs->getDiagonalElement(bmIndex, r) * (bs->getSourceTerm(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r)); + //pressureNextIter = std::max(pressureNextIter, 0.f); + //std::cout << (bs->getSourceTerm(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r)) << std::endl; + bs->setLastPressure(bmIndex, r, bs->getPressure(bmIndex, r)); - bs->setPressure(bmIndex, r, pressureNextIter); + bs->setPressure(bmIndex, r, pressureNextIter > 0 ? pressureNextIter : 0); + } else { bs->setPressure(bmIndex, r, 0); } } } - densityErrorAvg /= bm->numberOfParticles(); + //std::cout << std::endl; + densityErrorAvg /= numParticles; // only particles in contact with other object ? - if ((bs->getRestDensity(bmIndex) - densityErrorAvg) / bs->getRestDensity(bmIndex) < 0.001) { - break; - } + //if (std::abs((bs->getRestDensity(bmIndex) - densityErrorAvg) / bs->getRestDensity(bmIndex)) < 0.001) { + // std::cout << (bs->getRestDensity(bmIndex) - densityErrorAvg) << std::endl; + // break; + //} } + //std::cout << "-------------------" << std::endl; #pragma omp parallel default(shared) { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - const Vector3r a = -bs->getArtificialVolume(bmIndex, r) * bs->getPressureGrad(bmIndex, r); - bm->addForce(bm->getPosition(r), bs->getArtificialVolume(bmIndex, r) * bs->getDensity(bmIndex, r) * a); + const Vector3r f = -bs->getArtificialVolume(bmIndex, r) * bs->getPressureGrad(bmIndex, r); + if(bm->numberOfParticles() == 1) { + bm->addForce(rb->getPosition(), f); + } else { + bm->addForce(bm->getPosition(r), f); + } + bs->getPressure(bmIndex, r) = 0; } } } From ce4f1f9e2da7d51b784ffa4cca77d90da18ac8ed Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Tue, 30 May 2023 21:03:56 +0200 Subject: [PATCH 23/38] looks like correct --- SPlisHSPlasH/BoundaryModel_Akinci2012.cpp | 3 +- SPlisHSPlasH/DynamicRigidBody.h | 7 - SPlisHSPlasH/StrongCouplingBoundarySolver.cpp | 92 +++++--- SPlisHSPlasH/StrongCouplingBoundarySolver.h | 78 ++++--- SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 221 ++++++++++++++---- 5 files changed, 276 insertions(+), 125 deletions(-) diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp index 171a3495..1285b141 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp @@ -97,8 +97,7 @@ void BoundaryModel_Akinci2012::computeBoundaryVolume() delta += sim->W(getPosition(i) - bm_neighbor->getPosition(neighborIndex)); } } - const Real gamma = static_cast(1.0); - const Real volume = gamma / delta; + const Real volume = static_cast(1.0) / delta; m_V[i] = volume; } } diff --git a/SPlisHSPlasH/DynamicRigidBody.h b/SPlisHSPlasH/DynamicRigidBody.h index 0e8c0ca5..d2c40845 100644 --- a/SPlisHSPlasH/DynamicRigidBody.h +++ b/SPlisHSPlasH/DynamicRigidBody.h @@ -112,13 +112,6 @@ namespace SPH { m_v0.setZero(); m_a.setZero(); m_force.setZero(); - //if (position.x() > 0) { - // m_v0 = Vector3r(-1, 0, 0); - // m_v = m_v0; - //} else { - // m_v0 = Vector3r(1, 0, 0); - // m_v = m_v0; - //} m_q = rotation; m_q0 = rotation; diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp index f6d602ed..ef365e68 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp @@ -16,6 +16,7 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_v_rr(), m_v_b(), m_grad_p_b(), + m_minus_rho_div_v_s(), m_minus_rho_div_v_rr(), m_diagonalElement(), m_artificialVolume(), @@ -36,6 +37,7 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_pressure.resize(nBoundaries); m_v_rr.resize(nBoundaries); m_v_b.resize(nBoundaries); + m_minus_rho_div_v_s.resize(nBoundaries); m_minus_rho_div_v_rr.resize(nBoundaries); m_diagonalElement.resize(nBoundaries); m_pressureGrad.resize(nBoundaries); @@ -44,7 +46,7 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_lastPressure.resize(nBoundaries); m_predictVelocity.resize(nBoundaries); m_predictPosition.resize(nBoundaries); - m_restDensity.resize(nBoundaries, 1000); + m_restDensity.resize(nBoundaries, 1000.0); m_v_rr_body.resize(nBoundaries, Vector3r::Zero()); m_omega_rr_body.resize(nBoundaries, Vector3r::Zero()); m_v_b_body.resize(nBoundaries, Vector3r::Zero()); @@ -54,24 +56,25 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModel(i)); m_density[i].resize(bm->numberOfParticles(), m_restDensity[i]); m_v_s[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - m_s[i].resize(bm->numberOfParticles(), 0); - m_pressure[i].resize(bm->numberOfParticles(), 0); + m_s[i].resize(bm->numberOfParticles(), 0.0); + m_pressure[i].resize(bm->numberOfParticles(), 0.0); m_v_rr[i].resize(bm->numberOfParticles(), Vector3r::Zero()); m_v_b[i].resize(bm->numberOfParticles(), Vector3r::Zero()); m_grad_p_b[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - m_minus_rho_div_v_rr[i].resize(bm->numberOfParticles(), 0); - m_diagonalElement[i].resize(bm->numberOfParticles(), 0); + m_minus_rho_div_v_s[i].resize(bm->numberOfParticles(), 0.0); + m_minus_rho_div_v_rr[i].resize(bm->numberOfParticles(), 0.0); + m_diagonalElement[i].resize(bm->numberOfParticles(), 0.0); m_pressureGrad[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - m_artificialVolume[i].resize(bm->numberOfParticles(), 0); - m_lastPressure[i].resize(bm->numberOfParticles(), 0); + m_artificialVolume[i].resize(bm->numberOfParticles(), 0.0); + m_lastPressure[i].resize(bm->numberOfParticles(), 0.0); m_predictVelocity[i].resize(bm->numberOfParticles(), Vector3r::Zero()); m_predictPosition[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - bm->addField({ "density", FieldType::Scalar, [this, i](const unsigned int j) -> double* { return &getDensity(i, j); } }); - bm->addField({ "sourceTerm", FieldType::Scalar, [this, i](const unsigned int j)->double* {return &getSourceTerm(i,j); } }); + bm->addField({ "density", FieldType::Scalar, [this, i](const unsigned int j) -> Real* { return &getDensity(i, j); } }); + bm->addField({ "sourceTerm", FieldType::Scalar, [this, i](const unsigned int j)->Real* {return &getSourceTerm(i,j); } }); bm->addField({ "v_s", FieldType::Vector3, [this,i](const unsigned int j)->Vector3r* {return &getV_s(i,j); } }); bm->addField({ "v_rr", FieldType::Vector3, [this,i](const unsigned int j)->Vector3r* {return &getV_rr(i,j); } }); - bm->addField({ "pressure", FieldType::Scalar,[this,i](const unsigned int j)->double* {return &getPressure(i,j); } }); + bm->addField({ "pressure", FieldType::Scalar,[this,i](const unsigned int j)->Real* {return &getPressure(i,j); } }); bm->addField({ "rigidbodyVelocity", FieldType::Vector3,[bm](const unsigned int j)->Vector3r* {return &(static_cast(bm->getRigidBodyObject())->getVelocity()); } }); bm->addField({ "v_rr_body", FieldType::Vector3,[this,i](const unsigned int j)->Vector3r* {return &getV_rr_body(i); } }); } @@ -87,16 +90,17 @@ void SPH::StrongCouplingBoundarySolver::reset() { for (int j = 0; j < bm->numberOfParticles(); j++) { m_density[i][j] = m_restDensity[i]; m_v_s[i][j] = Vector3r::Zero(); - m_s[i][j] = 0; - m_pressure[i][j] = 0; + m_s[i][j] = 0.0; + m_pressure[i][j] = 0.0; m_v_rr[i][j] = Vector3r::Zero(); m_v_b[i][j] = Vector3r::Zero(); m_grad_p_b[i][j] = Vector3r::Zero(); - m_minus_rho_div_v_rr[i][j] = 0; - m_diagonalElement[i][j] = 0; + m_minus_rho_div_v_s[i][j] = 0.0; + m_minus_rho_div_v_rr[i][j] = 0.0; + m_diagonalElement[i][j] = 0.0; m_pressureGrad[i][j] = Vector3r::Zero(); - m_artificialVolume[i][j] = 0; - m_lastPressure[i][j] = 0; + m_artificialVolume[i][j] = 0.0; + m_lastPressure[i][j] = 0.0; m_predictVelocity[i][j] = Vector3r::Zero(); m_predictPosition[i][j] = Vector3r::Zero(); } @@ -113,6 +117,7 @@ StrongCouplingBoundarySolver::~StrongCouplingBoundarySolver() { m_v_rr[i].clear(); m_v_b[i].clear(); m_grad_p_b[i].clear(); + m_minus_rho_div_v_s[i].clear(); m_minus_rho_div_v_rr[i].clear(); m_diagonalElement[i].clear(); m_pressureGrad[i].clear(); @@ -128,6 +133,7 @@ StrongCouplingBoundarySolver::~StrongCouplingBoundarySolver() { m_v_rr.clear(); m_v_b.clear(); m_grad_p_b.clear(); + m_minus_rho_div_v_s.clear(); m_minus_rho_div_v_rr.clear(); m_diagonalElement.clear(); m_pressureGrad.clear(); @@ -186,7 +192,7 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - if (rb->isDynamic()) { + //if (rb->isDynamic()) { // compute density for particle r Real particleDensity = getRestDensity(bmIndex) * bm->getVolume(r) * sim->W_zero(); // iterate over all rigid bodies @@ -197,15 +203,18 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { particleDensity += getRestDensity(bmIndex) * bm->getVolume(r) * sim->W(bm->getPosition(r) - bm_neighbor->getPosition(k)); } } - setDensity(bmIndex, r, particleDensity); + setDensity(bmIndex, r, std::max(particleDensity, getRestDensity(bmIndex))); + //gamma = 0.7, see the paper + const Real gamma = static_cast(0.7); if (getDensity(bmIndex, r) > getRestDensity(bmIndex)) { - setArtificialVolume(bmIndex, r, getRestDensity(bmIndex) * bm->getVolume(r) / getDensity(bmIndex, r)); + + setArtificialVolume(bmIndex, r, gamma * getRestDensity(bmIndex) * bm->getVolume(r) / getDensity(bmIndex, r)); } else { - setArtificialVolume(bmIndex, r, bm->getVolume(r)); + setArtificialVolume(bmIndex, r, gamma * bm->getVolume(r)); } - } else { - setArtificialVolume(bmIndex, r, bm->getVolume(r)); - } + //} else { + // setArtificialVolume(bmIndex, r, bm->getVolume(r)); + //} } } } @@ -259,7 +268,7 @@ void StrongCouplingBoundarySolver::computeSourceTerm() { { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - Real s = 0; + Real rho_div_v_s = 0; // iterate over all rigid bodies except bm, since the divergence of particles in the same rigid body should be 0. for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { if (boundaryPointSetIndex != pid) { @@ -268,12 +277,13 @@ void StrongCouplingBoundarySolver::computeSourceTerm() { for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); // sum up divergence of v_s - s += getArtificialVolume(neighborIndex, k) * getDensity(neighborIndex, k) * (getV_s(neighborIndex, k) - getV_s(bmIndex, r)).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); + rho_div_v_s += getArtificialVolume(neighborIndex, k) * getDensity(neighborIndex, k) * (getV_s(neighborIndex, k) - getV_s(bmIndex, r)).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); } } } - s += (getRestDensity(bmIndex) - getDensity(bmIndex, r)) / dt; + Real s = (getRestDensity(bmIndex) - getDensity(bmIndex, r)) / dt + rho_div_v_s; setSourceTerm(bmIndex, r, s); + setMinus_rho_div_v_s(bmIndex, r, -rho_div_v_s); } } } @@ -296,6 +306,9 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { #pragma omp for schedule(static) for (int r = 0; r < bm_r->numberOfParticles(); r++) { Vector3r pos_r = bm_r->getPosition(r) - rb->getPosition(); + if (bm_r->numberOfParticles() == 1) { + pos_r.setZero(); + } Vector3r grad_p_b = Vector3r::Zero(); const Real density_r2 = getDensity(index_r, r) * getDensity(index_r, r); // rk are neighboring rigid particles of r of other rigid bodies k @@ -398,20 +411,23 @@ void StrongCouplingBoundarySolver::computeSourceTermRHS() { TimeManager* tm = TimeManager::getCurrent(); const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); - - //computePressureGrad(); - // + Vector3r tvrr; + Vector3r tomega; // compute pressure gradient, v_rr and omega_rr for rigid body for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); int bmIndex = boundaryPointSetIndex - nFluids; DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - Vector3r v_rr_body = Vector3r().setZero(); - Vector3r omega_rr_body = Vector3r().setZero(); + Real vx = 0; + Real vy = 0; + Real vz = 0; + Real omegax = 0; + Real omegay = 0; + Real omegaz = 0; if (rb->isDynamic()) { #pragma omp parallel default(shared) { - #pragma omp for schedule(static) + #pragma omp for schedule(static) reduction(+:vx) reduction(+:vy) reduction(+:vz) reduction(+:omegax) reduction(+:omegay) reduction(+:omegaz) for (int r = 0; r < bm->numberOfParticles(); r++) { Vector3r pressureGrad_r = Vector3r::Zero(); const Real density_r = getDensity(bmIndex, r); @@ -432,12 +448,20 @@ void StrongCouplingBoundarySolver::computeSourceTermRHS() { pressureGrad_r *= density_r; setPressureGrad(bmIndex, r, pressureGrad_r); - v_rr_body += -dt * rb->getInvMass() * getArtificialVolume(bmIndex, r) * getPressureGrad(bmIndex, r); + Vector3r v_rr_body_tmp = -dt * rb->getInvMass() * getArtificialVolume(bmIndex, r) * getPressureGrad(bmIndex, r); + vx += v_rr_body_tmp.x(); + vy += v_rr_body_tmp.y(); + vz += v_rr_body_tmp.z(); Vector3r pos = bm->getPosition(r) - rb->getPosition(); - omega_rr_body += -dt * rb->getInertiaTensorInverseW() * getArtificialVolume(bmIndex, r) * pos.cross(getPressureGrad(bmIndex, r)); + Vector3r omega_rr_body_tmp = -dt * rb->getInertiaTensorInverseW() * getArtificialVolume(bmIndex, r) * pos.cross(getPressureGrad(bmIndex, r)); + omegax += omega_rr_body_tmp.x(); + omegay += omega_rr_body_tmp.y(); + omegaz += omega_rr_body_tmp.z(); } } } + Vector3r v_rr_body = Vector3r(vx, vy, vz); + Vector3r omega_rr_body = Vector3r(omegax, omegay, omegaz); setV_rr_body(bmIndex, v_rr_body); setOmega_rr_body(bmIndex, omega_rr_body); } diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.h b/SPlisHSPlasH/StrongCouplingBoundarySolver.h index c6fdc3e9..fb719063 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.h +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.h @@ -6,21 +6,22 @@ namespace SPH { class StrongCouplingBoundarySolver { private: // values required for Gissler 2019 strong coupling based on Akinci 2012 - std::vector> m_density; - std::vector> m_pressure; - std::vector> m_lastPressure; - std::vector> m_artificialVolume; + std::vector> m_density; + std::vector> m_pressure; + std::vector> m_lastPressure; + std::vector> m_artificialVolume; std::vector> m_v_s; - std::vector> m_s; // source term + std::vector> m_s; // source term std::vector> m_pressureGrad; std::vector> m_v_rr; std::vector> m_v_b; std::vector> m_grad_p_b; std::vector> m_predictVelocity; std::vector> m_predictPosition; - std::vector> m_minus_rho_div_v_rr; // RHS to the source term - std::vector> m_diagonalElement; // diagonal element for jacobi iteration - std::vector m_restDensity; + std::vector> m_minus_rho_div_v_s; + std::vector> m_minus_rho_div_v_rr; // RHS to the source term + std::vector> m_diagonalElement; // diagonal element for jacobi iteration + std::vector m_restDensity; std::vector m_v_rr_body; std::vector m_omega_rr_body; std::vector m_v_b_body; @@ -47,51 +48,51 @@ namespace SPH { void computeFriction(); void performNeighborhoodSearchSort(); - FORCE_INLINE const double& getDensity(const unsigned int& rigidBodyIndex, const unsigned int& index) const { + FORCE_INLINE const Real& getDensity(const unsigned int& rigidBodyIndex, const unsigned int& index) const { return m_density[rigidBodyIndex][index]; } - FORCE_INLINE double& getDensity(const unsigned int& rigidBodyIndex, const unsigned int& index) { + FORCE_INLINE Real& getDensity(const unsigned int& rigidBodyIndex, const unsigned int& index) { return m_density[rigidBodyIndex][index]; } - FORCE_INLINE void setDensity(const unsigned int& rigidBodyIndex, const unsigned int& index, const double& value) { + FORCE_INLINE void setDensity(const unsigned int& rigidBodyIndex, const unsigned int& index, const Real& value) { m_density[rigidBodyIndex][index] = value; } - FORCE_INLINE const double& getPressure(const unsigned int& rigidBodyIndex, const unsigned int& index) const { + FORCE_INLINE const Real& getPressure(const unsigned int& rigidBodyIndex, const unsigned int& index) const { return m_pressure[rigidBodyIndex][index]; } - FORCE_INLINE double& getPressure(const unsigned int& rigidBodyIndex, const unsigned int& index) { + FORCE_INLINE Real& getPressure(const unsigned int& rigidBodyIndex, const unsigned int& index) { return m_pressure[rigidBodyIndex][index]; } - FORCE_INLINE void setPressure(const unsigned int& rigidBodyIndex, const unsigned int& index, const double& value) { + FORCE_INLINE void setPressure(const unsigned int& rigidBodyIndex, const unsigned int& index, const Real& value) { m_pressure[rigidBodyIndex][index] = value; } - FORCE_INLINE const double& getLastPressure(const unsigned int& rigidBodyIndex, const unsigned int& index) const { + FORCE_INLINE const Real& getLastPressure(const unsigned int& rigidBodyIndex, const unsigned int& index) const { return m_lastPressure[rigidBodyIndex][index]; } - FORCE_INLINE double& getLastPressure(const unsigned int& rigidBodyIndex, const unsigned int& index) { + FORCE_INLINE Real& getLastPressure(const unsigned int& rigidBodyIndex, const unsigned int& index) { return m_lastPressure[rigidBodyIndex][index]; } - FORCE_INLINE void setLastPressure(const unsigned int& rigidBodyIndex, const unsigned int& index, const double& value) { + FORCE_INLINE void setLastPressure(const unsigned int& rigidBodyIndex, const unsigned int& index, const Real& value) { m_lastPressure[rigidBodyIndex][index] = value; } - FORCE_INLINE const double& getRestDensity(const unsigned int& rigidBodyIndex) const { + FORCE_INLINE const Real& getRestDensity(const unsigned int& rigidBodyIndex) const { return m_restDensity[rigidBodyIndex]; } - FORCE_INLINE double& getRestDensity(const unsigned int& rigidBodyIndex) { + FORCE_INLINE Real& getRestDensity(const unsigned int& rigidBodyIndex) { return m_restDensity[rigidBodyIndex]; } - FORCE_INLINE void setRestDensity(const unsigned int& rigidBodyIndex, const double& value) { + FORCE_INLINE void setRestDensity(const unsigned int& rigidBodyIndex, const Real& value) { m_restDensity[rigidBodyIndex] = value; } @@ -155,6 +156,7 @@ namespace SPH { m_v_s[rigidBodyIndex][i] = value; } + FORCE_INLINE Vector3r& getV_rr(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_v_rr[rigidBodyIndex][i]; } @@ -227,51 +229,63 @@ namespace SPH { m_pressureGrad[rigidBodyIndex][i] = value; } - FORCE_INLINE double& getSourceTermRHS(const unsigned int& rigidBodyIndex, const unsigned int i) { + FORCE_INLINE Real& getMinus_rho_div_v_s(const unsigned int& rigidBodyIndex, const unsigned int i) { + return m_minus_rho_div_v_s[rigidBodyIndex][i]; + } + + FORCE_INLINE const Real& getMinus_rho_div_v_s(const unsigned int& rigidBodyIndex, const unsigned int i) const { + return m_minus_rho_div_v_s[rigidBodyIndex][i]; + } + + FORCE_INLINE void setMinus_rho_div_v_s(const unsigned int& rigidBodyIndex, const unsigned int i, const Real& value) { + m_minus_rho_div_v_s[rigidBodyIndex][i] = value; + } + + FORCE_INLINE Real& getSourceTermRHS(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_minus_rho_div_v_rr[rigidBodyIndex][i]; } - FORCE_INLINE const double& getSourceTermRHS(const unsigned int& rigidBodyIndex, const unsigned int i) const { + FORCE_INLINE const Real& getSourceTermRHS(const unsigned int& rigidBodyIndex, const unsigned int i) const { return m_minus_rho_div_v_rr[rigidBodyIndex][i]; } - FORCE_INLINE void setSourceTermRHS(const unsigned int& rigidBodyIndex, const unsigned int i, const double& value) { + FORCE_INLINE void setSourceTermRHS(const unsigned int& rigidBodyIndex, const unsigned int i, const Real& value) { m_minus_rho_div_v_rr[rigidBodyIndex][i] = value; } - FORCE_INLINE double& getDiagonalElement(const unsigned int& rigidBodyIndex, const unsigned int i) { + FORCE_INLINE Real& getDiagonalElement(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_diagonalElement[rigidBodyIndex][i]; } - FORCE_INLINE const double& getDiagonalElement(const unsigned int& rigidBodyIndex, const unsigned int i) const { + FORCE_INLINE const Real& getDiagonalElement(const unsigned int& rigidBodyIndex, const unsigned int i) const { return m_diagonalElement[rigidBodyIndex][i]; } - FORCE_INLINE void setDiagonalElement(const unsigned int& rigidBodyIndex, const unsigned int i, const double& value) { + FORCE_INLINE void setDiagonalElement(const unsigned int& rigidBodyIndex, const unsigned int i, const Real& value) { m_diagonalElement[rigidBodyIndex][i] = value; } - FORCE_INLINE double& getSourceTerm(const unsigned int& rigidBodyIndex, const unsigned int i) { + FORCE_INLINE Real& getSourceTerm(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_s[rigidBodyIndex][i]; } - FORCE_INLINE const double& getSourceTerm(const unsigned int& rigidBodyIndex, const unsigned int i) const { + FORCE_INLINE const Real& getSourceTerm(const unsigned int& rigidBodyIndex, const unsigned int i) const { return m_s[rigidBodyIndex][i]; } - FORCE_INLINE void setSourceTerm(const unsigned int& rigidBodyIndex, const unsigned int i, const double& value) { + FORCE_INLINE void setSourceTerm(const unsigned int& rigidBodyIndex, const unsigned int i, const Real& value) { m_s[rigidBodyIndex][i] = value; } - FORCE_INLINE const double& getArtificialVolume(const unsigned int& rigidBodyIndex, const unsigned int i) const { + FORCE_INLINE const Real& getArtificialVolume(const unsigned int& rigidBodyIndex, const unsigned int i) const { return m_artificialVolume[rigidBodyIndex][i]; } - FORCE_INLINE double& getArtificialVolume(const unsigned int& rigidBodyIndex, const unsigned int i) { + FORCE_INLINE Real& getArtificialVolume(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_artificialVolume[rigidBodyIndex][i]; } - FORCE_INLINE void setArtificialVolume(const unsigned int& rigidBodyIndex, const unsigned int i, const double& val) { + FORCE_INLINE void setArtificialVolume(const unsigned int& rigidBodyIndex, const unsigned int i, const Real& val) { m_artificialVolume[rigidBodyIndex][i] = val; } }; diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index 190eca0d..649e130c 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -224,89 +224,210 @@ void TimeStepWCSPH::computeRigidRigidAccels() { const unsigned int nFluids = sim->numberOfFluidModels(); StrongCouplingBoundarySolver* bs = StrongCouplingBoundarySolver::getCurrent(); - // solve the equation s = -rho * div¡¤v_rr w.r.t. pressure using relaxed jacobi + bs->computeDensityAndVolume(); + + // compute density deviation + int particleInContact = 0; for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); int bmIndex = boundaryPointSetIndex - nFluids; - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); if (bm->getRigidBodyObject()->isDynamic()) { - std::vector bodyInContact = std::vector(); - unsigned int numContacts = 1; - //#pragma omp parallel default(shared) + #pragma omp parallel default(shared) { - // compute number of contacts - //#pragma omp for schedule(static) + #pragma omp for schedule(static) reduction(+:particleInContact) for (int r = 0; r < bm->numberOfParticles(); r++) { for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - if (boundaryPointSetIndex != pid) { - BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - if (sim->numberOfNeighbors(boundaryPointSetIndex, pid, r) > 0 && std::find(bodyInContact.begin(), bodyInContact.end(), pid) == bodyInContact.end()) { - bodyInContact.push_back(pid); + if (pid != boundaryPointSetIndex) { + if (sim->numberOfNeighbors(boundaryPointSetIndex, pid, r) > 0) { + particleInContact++; + break; } } } } } - numContacts = bodyInContact.size(); - if (numContacts == 0) { - continue; - } - // beta_r_RJ - Real relaxation = 0.5 / numContacts; - bs->computeDensityAndVolume(); - bs->computeSourceTerm(); - bs->computeDiagonalElement(); - for (unsigned int i = 0; i < 20; i++) { - - bs->computeSourceTermRHS(); + } + } + if (particleInContact == 0) { + return; + } + //std::cout << particleInContact << std::endl; + Real avgDensityDeviation = 1.0; + bs->computeDiagonalElement(); + bs->computeSourceTerm(); + int iterations = 0; + // while density deviation too large + while ((avgDensityDeviation > 0.0025 && iterations < 100) || iterations < 20) { + bs->computeSourceTermRHS(); + avgDensityDeviation = 0; + // update pressure + + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + int bmIndex = boundaryPointSetIndex - nFluids; + if (bm->getRigidBodyObject()->isDynamic()) { + int numContactsBody = 0; + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) reduction(+:numContactsBody) + for (int r = 0; r < bm->numberOfParticles(); r++) { + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + if (pid != boundaryPointSetIndex) { + if (sim->numberOfNeighbors(boundaryPointSetIndex, pid, r) > 0) { + numContactsBody++; + break; + } + } + } + } + } + if (numContactsBody == 0) { + continue; + } + // beta_r_RJ + Real relaxation = 0.5 / numContactsBody; - Real densityErrorAvg = 0; - int numParticles = 0; #pragma omp parallel default(shared) { - #pragma omp for schedule(static) + #pragma omp for schedule(static) reduction(+:avgDensityDeviation) for (int r = 0; r < bm->numberOfParticles(); r++) { - if (std::abs(bs->getDiagonalElement(bmIndex, r)) != 0) { - numParticles++; - densityErrorAvg += bs->getDensity(bmIndex, r); - + if (bs->getDensity(bmIndex, r) - bs->getRestDensity(bmIndex) > 1e-9 && std::abs(bs->getDiagonalElement(bmIndex, r)) > 1e-9) { Real pressureNextIter = bs->getPressure(bmIndex, r) + relaxation / bs->getDiagonalElement(bmIndex, r) * (bs->getSourceTerm(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r)); - //pressureNextIter = std::max(pressureNextIter, 0.f); - //std::cout << (bs->getSourceTerm(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r)) << std::endl; - - bs->setLastPressure(bmIndex, r, bs->getPressure(bmIndex, r)); bs->setPressure(bmIndex, r, pressureNextIter > 0 ? pressureNextIter : 0); - + avgDensityDeviation -= (bs->getSourceTerm(bmIndex, r) - bs->getMinus_rho_div_v_s(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r)) * dt; } else { bs->setPressure(bmIndex, r, 0); } } } - //std::cout << std::endl; - densityErrorAvg /= numParticles; - - // only particles in contact with other object ? - //if (std::abs((bs->getRestDensity(bmIndex) - densityErrorAvg) / bs->getRestDensity(bmIndex)) < 0.001) { - // std::cout << (bs->getRestDensity(bmIndex) - densityErrorAvg) << std::endl; - // break; - //} - } - //std::cout << "-------------------" << std::endl; + } + } + if (particleInContact == 0) { + return; + } + avgDensityDeviation /= particleInContact; + avgDensityDeviation /= bs->getRestDensity(0); + avgDensityDeviation = std::abs(avgDensityDeviation); + std::cout << avgDensityDeviation << std::endl; + iterations++; + } + std::cout << "------------------------------" << std::endl; + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + int bmIndex = boundaryPointSetIndex - nFluids; + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + if (rb->isDynamic()) { #pragma omp parallel default(shared) { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { const Vector3r f = -bs->getArtificialVolume(bmIndex, r) * bs->getPressureGrad(bmIndex, r); - if(bm->numberOfParticles() == 1) { - bm->addForce(rb->getPosition(), f); - } else { - bm->addForce(bm->getPosition(r), f); + if (f != Vector3r::Zero()) { + if (bm->numberOfParticles() == 1) { + bm->addForce(rb->getPosition(), f); + } else { + bm->addForce(bm->getPosition(r), f); + } } - bs->getPressure(bmIndex, r) = 0; + bs->setPressure(bmIndex, r, 0); } } } } + + // solve the equation s = -rho * div¡¤v_rr w.r.t. pressure using relaxed jacobi + + + //for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + // BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + // int bmIndex = boundaryPointSetIndex - nFluids; + // DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + // unsigned int numContacts = 0; + // if (bm->getRigidBodyObject()->isDynamic()) { + // bs->computeDensityAndVolume(); + // // number of contacts + // #pragma omp parallel default(shared) + // { + // #pragma omp for schedule(static) reduction(+:numContacts) + // for (int r = 0; r < bm->numberOfParticles(); r++) { + // for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + // if (pid != boundaryPointSetIndex) { + // if (sim->numberOfNeighbors(boundaryPointSetIndex, pid, r) > 0) { + // numContacts++; + // } + // } + // } + // } + // } + // if(numContacts == 0){ + // return; + // } + // // beta_r_RJ + // Real relaxation = 0.5/numContacts; + // //std::cout << numContacts << std::endl; + // bs->computeSourceTerm(); + // bs->computeDiagonalElement(); + // Real densityDeviationAvg = 1; + // unsigned int numParticles = 0; + // unsigned int i = 0; + + // while (densityDeviationAvg > 0.002) { + // densityDeviationAvg = 0.0; + // numParticles = 0; + // bs->computeSourceTermRHS(); + // #pragma omp parallel default(shared) + // { + // #pragma omp for schedule(static) reduction(+:numParticles) reduction(+:densityDeviationAvg) + // for (int r = 0; r < bm->numberOfParticles(); r++) { + // if (bs->getDensity(bmIndex,r) - bs->getRestDensity(bmIndex) > 1e-9 && std::abs(bs->getDiagonalElement(bmIndex, r)) > 1e-9) { + // numParticles++; + // Real pressureNextIter = bs->getPressure(bmIndex, r) + relaxation / bs->getDiagonalElement(bmIndex, r) * (bs->getSourceTerm(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r)); + // //if (r == 105) { + // // //if (bs->getSourceTerm(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r) > 0) { + // // // std::cout << bs->getSourceTerm(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r) << std::endl; + // // // std::cout << bs->getSourceTermRHS(bmIndex, r) << std::endl; + // // // std::cout << pressureNextIter << std::endl << std::endl; + // // //} + // // std::cout << bs->getSourceTerm(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r) << std::endl; + // // //std::cout << bs->getDiagonalElement(bmIndex, r) << std::endl; + // // //std::cout << bs->getPressure(bmIndex, r) << std::endl; + // // //pressureNextIter = 1.46289e+07; + // //} + // bs->setPressure(bmIndex, r, std::max(pressureNextIter, static_cast(0))); + // densityDeviationAvg -= (bs->getMinus_rho_div_v_s(bmIndex, r) + bs->getSourceTermRHS(bmIndex, r)) * dt; + // } else { + // bs->setPressure(bmIndex, r, 0); + // } + // } + // } + // if (numParticles == 0 || densityDeviationAvg < 0) { + // break; + // } + // densityDeviationAvg /= numParticles; + // densityDeviationAvg /= bs->getRestDensity(bmIndex); + // //std::cout << numParticles << std::endl; + // ////densityErrorAvg /= numParticles; + // std::cout << densityDeviationAvg << std::endl; + // i++; + // } + // std::cout << "-------------------" << std::endl; + // #pragma omp parallel default(shared) + // { + // #pragma omp for schedule(static) + // for (int r = 0; r < bm->numberOfParticles(); r++) { + // if (bs->getPressureGrad(bmIndex, r) != Vector3r::Zero()) { + // const Vector3r f = -bs->getArtificialVolume(bmIndex, r) * bs->getPressureGrad(bmIndex, r); + // if (bm->numberOfParticles() == 1) { + // bm->addForce(rb->getPosition(), f); + // } else { + // bm->addForce(bm->getPosition(r), f); + // } + // bs->setPressure(bmIndex, r, 0); + // } + // } + // } + // } + //} } void TimeStepWCSPH::performNeighborhoodSearch() From bb0239ceaeba3cc25a52f27942396ea250378e60 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Wed, 31 May 2023 18:11:01 +0200 Subject: [PATCH 24/38] refactoring and UI update --- SPlisHSPlasH/DynamicRigidBody.h | 14 +- SPlisHSPlasH/StrongCouplingBoundarySolver.cpp | 273 +++++++++--------- SPlisHSPlasH/StrongCouplingBoundarySolver.h | 113 +++----- .../Utilities/SceneParameterObjects.cpp | 10 + .../Utilities/SceneParameterObjects.h | 11 +- SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 27 +- Simulator/DynamicBoundarySimulator.cpp | 3 +- Simulator/DynamicBoundarySimulator.h | 13 +- Simulator/GUI/imgui/Simulator_GUI_imgui.cpp | 33 ++- 9 files changed, 247 insertions(+), 250 deletions(-) diff --git a/SPlisHSPlasH/DynamicRigidBody.h b/SPlisHSPlasH/DynamicRigidBody.h index d2c40845..83a4d7c6 100644 --- a/SPlisHSPlasH/DynamicRigidBody.h +++ b/SPlisHSPlasH/DynamicRigidBody.h @@ -8,10 +8,7 @@ #include "Simulation.h" namespace SPH { - /** \brief This class stores the information of a dynamic rigid body which - * is used for the strong coupling method introduced in - * Interlinked SPH Pressure Solvers for Strong Fluid-Rigid Coupling. Gissler et al. https://doi.org/10.1145/3284980 - */ + class DynamicRigidBody : public RigidBodyObject { // Some fields are from PBD::RigidBody private: @@ -99,7 +96,7 @@ namespace SPH { } void initBody(const Real density, const bool isDynamic, const Vector3r &position, const Quaternionr &rotation, - const Vector3r &scale) + const Vector3r &scale, const Vector3r &velocity, const Real &friction) { m_density = density; m_scale = scale; @@ -108,8 +105,9 @@ namespace SPH { m_x0 = position; m_lastX = position; m_oldX = position; - m_v.setZero(); - m_v0.setZero(); + + m_v0 = velocity; + m_v = m_v0; m_a.setZero(); m_force.setZero(); @@ -124,7 +122,7 @@ namespace SPH { m_torque.setZero(); //m_restitutionCoeff = static_cast(0.6); - m_frictionCoeff = static_cast(0.2); + m_frictionCoeff = friction; updateMeshTransformation(); } diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp index ef365e68..da5e744a 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp @@ -14,8 +14,6 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_s(), m_pressure(), m_v_rr(), - m_v_b(), - m_grad_p_b(), m_minus_rho_div_v_s(), m_minus_rho_div_v_rr(), m_diagonalElement(), @@ -24,43 +22,39 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_predictVelocity(), m_predictPosition(), m_v_rr_body(), - m_omega_rr_body(), - m_v_b_body(), - m_omega_b_body() + m_omega_rr_body() { + m_maxIterations = 100; + m_minIterations = 20; + m_maxDensityDeviation = 0.001; + Simulation* sim = Simulation::getCurrent(); const unsigned int nBoundaries = sim->numberOfBoundaryModels(); + m_restDensity = 1000; m_density.resize(nBoundaries); m_v_s.resize(nBoundaries); m_s.resize(nBoundaries); m_pressure.resize(nBoundaries); m_v_rr.resize(nBoundaries); - m_v_b.resize(nBoundaries); m_minus_rho_div_v_s.resize(nBoundaries); m_minus_rho_div_v_rr.resize(nBoundaries); m_diagonalElement.resize(nBoundaries); m_pressureGrad.resize(nBoundaries); - m_grad_p_b.resize(nBoundaries); m_artificialVolume.resize(nBoundaries); m_lastPressure.resize(nBoundaries); m_predictVelocity.resize(nBoundaries); m_predictPosition.resize(nBoundaries); - m_restDensity.resize(nBoundaries, 1000.0); m_v_rr_body.resize(nBoundaries, Vector3r::Zero()); m_omega_rr_body.resize(nBoundaries, Vector3r::Zero()); - m_v_b_body.resize(nBoundaries, Vector3r::Zero()); - m_omega_b_body.resize(nBoundaries, Vector3r::Zero()); for (unsigned int i = 0; i < nBoundaries; i++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModel(i)); - m_density[i].resize(bm->numberOfParticles(), m_restDensity[i]); + m_density[i].resize(bm->numberOfParticles(), m_restDensity); m_v_s[i].resize(bm->numberOfParticles(), Vector3r::Zero()); m_s[i].resize(bm->numberOfParticles(), 0.0); m_pressure[i].resize(bm->numberOfParticles(), 0.0); m_v_rr[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - m_v_b[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - m_grad_p_b[i].resize(bm->numberOfParticles(), Vector3r::Zero()); m_minus_rho_div_v_s[i].resize(bm->numberOfParticles(), 0.0); m_minus_rho_div_v_rr[i].resize(bm->numberOfParticles(), 0.0); m_diagonalElement[i].resize(bm->numberOfParticles(), 0.0); @@ -88,13 +82,10 @@ void SPH::StrongCouplingBoundarySolver::reset() { for (unsigned int i = 0; i < nBoundaries; i++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModel(i)); for (int j = 0; j < bm->numberOfParticles(); j++) { - m_density[i][j] = m_restDensity[i]; m_v_s[i][j] = Vector3r::Zero(); m_s[i][j] = 0.0; m_pressure[i][j] = 0.0; m_v_rr[i][j] = Vector3r::Zero(); - m_v_b[i][j] = Vector3r::Zero(); - m_grad_p_b[i][j] = Vector3r::Zero(); m_minus_rho_div_v_s[i][j] = 0.0; m_minus_rho_div_v_rr[i][j] = 0.0; m_diagonalElement[i][j] = 0.0; @@ -115,8 +106,6 @@ StrongCouplingBoundarySolver::~StrongCouplingBoundarySolver() { m_s[i].clear(); m_pressure[i].clear(); m_v_rr[i].clear(); - m_v_b[i].clear(); - m_grad_p_b[i].clear(); m_minus_rho_div_v_s[i].clear(); m_minus_rho_div_v_rr[i].clear(); m_diagonalElement[i].clear(); @@ -131,8 +120,6 @@ StrongCouplingBoundarySolver::~StrongCouplingBoundarySolver() { m_s.clear(); m_pressure.clear(); m_v_rr.clear(); - m_v_b.clear(); - m_grad_p_b.clear(); m_minus_rho_div_v_s.clear(); m_minus_rho_div_v_rr.clear(); m_diagonalElement.clear(); @@ -143,12 +130,20 @@ StrongCouplingBoundarySolver::~StrongCouplingBoundarySolver() { m_predictPosition.clear(); m_v_rr_body.clear(); m_omega_rr_body.clear(); - m_v_b_body.clear(); - m_omega_b_body.clear(); } +StrongCouplingBoundarySolver* StrongCouplingBoundarySolver::getCurrent() { + if (current == nullptr) { + current = new StrongCouplingBoundarySolver(); + } else { + if (Simulation::getCurrent()->numberOfBoundaryModels() != current->m_density.size()) { + current = new StrongCouplingBoundarySolver(); + } + } + return current; +} -void SPH::StrongCouplingBoundarySolver::performNeighborhoodSearchSort() { +void StrongCouplingBoundarySolver::performNeighborhoodSearchSort() { Simulation* sim = Simulation::getCurrent(); const unsigned int nModels = sim->numberOfBoundaryModels(); @@ -163,7 +158,6 @@ void SPH::StrongCouplingBoundarySolver::performNeighborhoodSearchSort() { d.sort_field(&m_s[i][0]); d.sort_field(&m_pressure[i][0]); d.sort_field(&m_v_rr[i][0]); - d.sort_field(&m_v_b[i][0]); d.sort_field(&m_minus_rho_div_v_rr[i][0]); d.sort_field(&m_diagonalElement[i][0]); d.sort_field(&m_pressureGrad[i][0]); @@ -171,14 +165,12 @@ void SPH::StrongCouplingBoundarySolver::performNeighborhoodSearchSort() { d.sort_field(&m_lastPressure[i][0]); d.sort_field(&m_predictVelocity[i][0]); d.sort_field(&m_predictPosition[i][0]); - d.sort_field(&m_grad_p_b[i][0]); } } } void StrongCouplingBoundarySolver::computeDensityAndVolume() { Simulation* sim = Simulation::getCurrent(); - DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); TimeManager* tm = TimeManager::getCurrent(); const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); @@ -194,21 +186,21 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { for (int r = 0; r < bm->numberOfParticles(); r++) { //if (rb->isDynamic()) { // compute density for particle r - Real particleDensity = getRestDensity(bmIndex) * bm->getVolume(r) * sim->W_zero(); + Real particleDensity = getRestDensity() * bm->getVolume(r) * sim->W_zero(); // iterate over all rigid bodies for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - particleDensity += getRestDensity(bmIndex) * bm->getVolume(r) * sim->W(bm->getPosition(r) - bm_neighbor->getPosition(k)); + particleDensity += getRestDensity() * bm->getVolume(r) * sim->W(bm->getPosition(r) - bm_neighbor->getPosition(k)); } } - setDensity(bmIndex, r, std::max(particleDensity, getRestDensity(bmIndex))); + setDensity(bmIndex, r, std::max(particleDensity, getRestDensity())); //gamma = 0.7, see the paper const Real gamma = static_cast(0.7); - if (getDensity(bmIndex, r) > getRestDensity(bmIndex)) { + if (getDensity(bmIndex, r) > getRestDensity()) { - setArtificialVolume(bmIndex, r, gamma * getRestDensity(bmIndex) * bm->getVolume(r) / getDensity(bmIndex, r)); + setArtificialVolume(bmIndex, r, gamma * getRestDensity() * bm->getVolume(r) / getDensity(bmIndex, r)); } else { setArtificialVolume(bmIndex, r, gamma * bm->getVolume(r)); } @@ -223,7 +215,6 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { void StrongCouplingBoundarySolver::computeV_s() { // Use dynamic boundary simulator and Akinci2012 Simulation* sim = Simulation::getCurrent(); - DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); TimeManager* tm = TimeManager::getCurrent(); const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); @@ -252,7 +243,6 @@ void StrongCouplingBoundarySolver::computeV_s() { void StrongCouplingBoundarySolver::computeSourceTerm() { Simulation* sim = Simulation::getCurrent(); - DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); TimeManager* tm = TimeManager::getCurrent(); const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); @@ -281,7 +271,7 @@ void StrongCouplingBoundarySolver::computeSourceTerm() { } } } - Real s = (getRestDensity(bmIndex) - getDensity(bmIndex, r)) / dt + rho_div_v_s; + Real s = (getRestDensity() - getDensity(bmIndex, r)) / dt + rho_div_v_s; setSourceTerm(bmIndex, r, s); setMinus_rho_div_v_s(bmIndex, r, -rho_div_v_s); } @@ -292,7 +282,6 @@ void StrongCouplingBoundarySolver::computeSourceTerm() { void StrongCouplingBoundarySolver::computeDiagonalElement() { Simulation* sim = Simulation::getCurrent(); - DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); TimeManager* tm = TimeManager::getCurrent(); const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); @@ -407,130 +396,130 @@ void StrongCouplingBoundarySolver::computePressureGrad() { void StrongCouplingBoundarySolver::computeSourceTermRHS() { Simulation* sim = Simulation::getCurrent(); - DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + const unsigned int nFluids = sim->numberOfFluidModels(); + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + computeSourceTermRHSForBody(boundaryPointSetIndex); + } +} + +void SPH::StrongCouplingBoundarySolver::computeSourceTermRHSForBody(const unsigned int& boundaryPointSetIndex) { + Simulation* sim = Simulation::getCurrent(); TimeManager* tm = TimeManager::getCurrent(); const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); - Vector3r tvrr; - Vector3r tomega; + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + // compute pressure gradient, v_rr and omega_rr for rigid body - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - int bmIndex = boundaryPointSetIndex - nFluids; - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - Real vx = 0; - Real vy = 0; - Real vz = 0; - Real omegax = 0; - Real omegay = 0; - Real omegaz = 0; - if (rb->isDynamic()) { - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) reduction(+:vx) reduction(+:vy) reduction(+:vz) reduction(+:omegax) reduction(+:omegay) reduction(+:omegaz) - for (int r = 0; r < bm->numberOfParticles(); r++) { - Vector3r pressureGrad_r = Vector3r::Zero(); - const Real density_r = getDensity(bmIndex, r); - const Real pressure_r = getPressure(bmIndex, r); - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - if (pid != boundaryPointSetIndex) { - BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - int neighborIndex = pid - nFluids; - for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { - const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - const Real density_k = getDensity(neighborIndex, k); - const Real volume_k = getArtificialVolume(neighborIndex, k); - const Real pressure_k = getPressure(neighborIndex, k); - pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); - } + int bmIndex = boundaryPointSetIndex - nFluids; + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + Real vx = 0; + Real vy = 0; + Real vz = 0; + Real omegax = 0; + Real omegay = 0; + Real omegaz = 0; + if (rb->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) reduction(+:vx) reduction(+:vy) reduction(+:vz) reduction(+:omegax) reduction(+:omegay) reduction(+:omegaz) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Vector3r pressureGrad_r = Vector3r::Zero(); + const Real density_r = getDensity(bmIndex, r); + const Real pressure_r = getPressure(bmIndex, r); + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + if (pid != boundaryPointSetIndex) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + int neighborIndex = pid - nFluids; + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + const Real density_k = getDensity(neighborIndex, k); + const Real volume_k = getArtificialVolume(neighborIndex, k); + const Real pressure_k = getPressure(neighborIndex, k); + pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); } } - pressureGrad_r *= density_r; - setPressureGrad(bmIndex, r, pressureGrad_r); - - Vector3r v_rr_body_tmp = -dt * rb->getInvMass() * getArtificialVolume(bmIndex, r) * getPressureGrad(bmIndex, r); - vx += v_rr_body_tmp.x(); - vy += v_rr_body_tmp.y(); - vz += v_rr_body_tmp.z(); - Vector3r pos = bm->getPosition(r) - rb->getPosition(); - Vector3r omega_rr_body_tmp = -dt * rb->getInertiaTensorInverseW() * getArtificialVolume(bmIndex, r) * pos.cross(getPressureGrad(bmIndex, r)); - omegax += omega_rr_body_tmp.x(); - omegay += omega_rr_body_tmp.y(); - omegaz += omega_rr_body_tmp.z(); } + pressureGrad_r *= density_r; + setPressureGrad(bmIndex, r, pressureGrad_r); + + Vector3r v_rr_body_tmp = -dt * rb->getInvMass() * getArtificialVolume(bmIndex, r) * getPressureGrad(bmIndex, r); + vx += v_rr_body_tmp.x(); + vy += v_rr_body_tmp.y(); + vz += v_rr_body_tmp.z(); + Vector3r pos = bm->getPosition(r) - rb->getPosition(); + Vector3r omega_rr_body_tmp = -dt * rb->getInertiaTensorInverseW() * getArtificialVolume(bmIndex, r) * pos.cross(getPressureGrad(bmIndex, r)); + omegax += omega_rr_body_tmp.x(); + omegay += omega_rr_body_tmp.y(); + omegaz += omega_rr_body_tmp.z(); } } - Vector3r v_rr_body = Vector3r(vx, vy, vz); - Vector3r omega_rr_body = Vector3r(omegax, omegay, omegaz); - setV_rr_body(bmIndex, v_rr_body); - setOmega_rr_body(bmIndex, omega_rr_body); } + Vector3r v_rr_body = Vector3r(vx, vy, vz); + Vector3r omega_rr_body = Vector3r(omegax, omegay, omegaz); + setV_rr_body(bmIndex, v_rr_body); + setOmega_rr_body(bmIndex, omega_rr_body); + // compute v_rr and predicted velocity (v_rr+v_s) for all particles - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - int bmIndex = boundaryPointSetIndex - nFluids; - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - if (rb->isDynamic()) { - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - Vector3r pos = bm->getPosition(r) - rb->getPosition(); - setV_rr(bmIndex, r, getV_rr_body(bmIndex) + getOmega_rr_body(bmIndex).cross(pos)); - setPredictVelocity(bmIndex, r, getV_rr(bmIndex, r) + getV_s(bmIndex, r)); + if (rb->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + Vector3r pos = bm->getPosition(r) - rb->getPosition(); + setV_rr(bmIndex, r, getV_rr_body(bmIndex) + getOmega_rr_body(bmIndex).cross(pos)); + setPredictVelocity(bmIndex, r, getV_rr(bmIndex, r) + getV_s(bmIndex, r)); - Real minus_rho_div_v_rr = 0; - const Vector3r v_rr_r = getV_rr(bmIndex, r); - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - // divergence of particles in the same body should be 0; - if (boundaryPointSetIndex != pid) { - BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - int neighborIndex = pid - nFluids; - for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { - const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - const Real density_k = getDensity(neighborIndex, k); - const Real volume_k = getArtificialVolume(neighborIndex, k); - //const Vector3r v_rr_k = getV_rr_body(pid - nFluids) + getOmega_rr_body(pid - nFluids).cross(bm_neighbor->getPosition(k) - bm_neighbor->getRigidBodyObject()->getPosition()); - const Vector3r v_rr_k = getV_rr(pid - nFluids, k); - minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); - } + Real minus_rho_div_v_rr = 0; + const Vector3r v_rr_r = getV_rr(bmIndex, r); + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + // divergence of particles in the same body should be 0; + if (boundaryPointSetIndex != pid) { + BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + int neighborIndex = pid - nFluids; + for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + const Real density_k = getDensity(neighborIndex, k); + const Real volume_k = getArtificialVolume(neighborIndex, k); + //const Vector3r v_rr_k = getV_rr_body(pid - nFluids) + getOmega_rr_body(pid - nFluids).cross(bm_neighbor->getPosition(k) - bm_neighbor->getRigidBodyObject()->getPosition()); + const Vector3r v_rr_k = getV_rr(pid - nFluids, k); + minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); } } - minus_rho_div_v_rr = -minus_rho_div_v_rr; - setSourceTermRHS(bmIndex, r, minus_rho_div_v_rr); } + minus_rho_div_v_rr = -minus_rho_div_v_rr; + setSourceTermRHS(bmIndex, r, minus_rho_div_v_rr); } } } // compute the -rho * (div v_rr), which is the RHS to the source term - //for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - // BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - // int bmIndex = boundaryPointSetIndex - nFluids; - // if (bm->getRigidBodyObject()->isDynamic()) { - // #pragma omp parallel default(shared) - // { - // #pragma omp for schedule(static) - // for (int r = 0; r < bm->numberOfParticles(); r++) { - // Real minus_rho_div_v_rr = 0; - // const Vector3r v_rr_r = getV_rr(bmIndex, r); - // for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - // // divergence of particles in the same body should be 0; - // if (boundaryPointSetIndex != pid) { - // BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - // int neighborIndex = pid - nFluids; - // for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { - // const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - // const Real density_k = getDensity(neighborIndex, k); - // const Real volume_k = getArtificialVolume(neighborIndex, k); - // const Vector3r v_rr_k = getV_rr(neighborIndex, k); - // minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); - // } - // } - // } - // minus_rho_div_v_rr = -minus_rho_div_v_rr; - // setSourceTermRHS(bmIndex, r, minus_rho_div_v_rr); - // } - // } - // } - //} +//for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { +// BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); +// int bmIndex = boundaryPointSetIndex - nFluids; +// if (bm->getRigidBodyObject()->isDynamic()) { +// #pragma omp parallel default(shared) + // { +// #pragma omp for schedule(static) + // for (int r = 0; r < bm->numberOfParticles(); r++) { + // Real minus_rho_div_v_rr = 0; + // const Vector3r v_rr_r = getV_rr(bmIndex, r); + // for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + // // divergence of particles in the same body should be 0; + // if (boundaryPointSetIndex != pid) { + // BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); + // int neighborIndex = pid - nFluids; + // for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { + // const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); + // const Real density_k = getDensity(neighborIndex, k); + // const Real volume_k = getArtificialVolume(neighborIndex, k); + // const Vector3r v_rr_k = getV_rr(neighborIndex, k); + // minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); + // } + // } + // } + // minus_rho_div_v_rr = -minus_rho_div_v_rr; + // setSourceTermRHS(bmIndex, r, minus_rho_div_v_rr); + // } + // } + // } + //} } diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.h b/SPlisHSPlasH/StrongCouplingBoundarySolver.h index fb719063..36601b8b 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.h +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.h @@ -2,10 +2,16 @@ #include "SPlisHSPlasH/TimeStep.h" #include "SPlisHSPlasH/SPHKernels.h" + namespace SPH { + /** \brief This class stores the information of a dynamic rigid body which + * is used for the strong coupling method introduced in + * Interlinked SPH Pressure Solvers for Strong Fluid-Rigid Coupling. Gissler et al. https://doi.org/10.1145/3284980 + */ class StrongCouplingBoundarySolver { private: // values required for Gissler 2019 strong coupling based on Akinci 2012 + Real m_restDensity; std::vector> m_density; std::vector> m_pressure; std::vector> m_lastPressure; @@ -14,35 +20,30 @@ namespace SPH { std::vector> m_s; // source term std::vector> m_pressureGrad; std::vector> m_v_rr; - std::vector> m_v_b; - std::vector> m_grad_p_b; std::vector> m_predictVelocity; std::vector> m_predictPosition; std::vector> m_minus_rho_div_v_s; std::vector> m_minus_rho_div_v_rr; // RHS to the source term std::vector> m_diagonalElement; // diagonal element for jacobi iteration - std::vector m_restDensity; std::vector m_v_rr_body; std::vector m_omega_rr_body; - std::vector m_v_b_body; - std::vector m_omega_b_body; static StrongCouplingBoundarySolver* current; + unsigned int m_maxIterations; + unsigned int m_minIterations; + Real m_maxDensityDeviation; + public: StrongCouplingBoundarySolver(); ~StrongCouplingBoundarySolver(); - static StrongCouplingBoundarySolver* getCurrent() { - if (current == nullptr) { - current = new StrongCouplingBoundarySolver(); - } - return current; - } + static StrongCouplingBoundarySolver* getCurrent(); void reset(); void computeDensityAndVolume(); void computePressureGrad(); void computeV_s(); void computeSourceTermRHS(); + void computeSourceTermRHSForBody(const unsigned int& boundaryPointSetIndex); void computeSourceTerm(); void computeDiagonalElement(); void computeFriction(); @@ -84,16 +85,16 @@ namespace SPH { m_lastPressure[rigidBodyIndex][index] = value; } - FORCE_INLINE const Real& getRestDensity(const unsigned int& rigidBodyIndex) const { - return m_restDensity[rigidBodyIndex]; + FORCE_INLINE const Real& getRestDensity() const { + return m_restDensity; } - FORCE_INLINE Real& getRestDensity(const unsigned int& rigidBodyIndex) { - return m_restDensity[rigidBodyIndex]; + FORCE_INLINE Real& getRestDensity() { + return m_restDensity; } - FORCE_INLINE void setRestDensity(const unsigned int& rigidBodyIndex, const Real& value) { - m_restDensity[rigidBodyIndex] = value; + FORCE_INLINE void setRestDensity(const Real& value) { + m_restDensity = value; } FORCE_INLINE const Vector3r& getV_rr_body(const unsigned int& rigidBodyIndex) const { @@ -108,18 +109,6 @@ namespace SPH { m_v_rr_body[rigidBodyIndex] = value; } - FORCE_INLINE const Vector3r& getV_b_body(const unsigned int& rigidBodyIndex) const { - return m_v_b_body[rigidBodyIndex]; - } - - FORCE_INLINE Vector3r& getV_b_body(const unsigned int& rigidBodyIndex) { - return m_v_b_body[rigidBodyIndex]; - } - - FORCE_INLINE void setV_b_body(const unsigned int& rigidBodyIndex, const Vector3r& value) { - m_v_b_body[rigidBodyIndex] = value; - } - FORCE_INLINE const Vector3r& getOmega_rr_body(const unsigned int& rigidBodyIndex) const { return m_omega_rr_body[rigidBodyIndex]; } @@ -131,18 +120,6 @@ namespace SPH { FORCE_INLINE void setOmega_rr_body(const unsigned int& rigidBodyIndex, const Vector3r& value) { m_omega_rr_body[rigidBodyIndex] = value; } - - FORCE_INLINE const Vector3r& getOmega_b_body(const unsigned int& rigidBodyIndex) const { - return m_omega_b_body[rigidBodyIndex]; - } - - FORCE_INLINE Vector3r& getOmega_b_body(const unsigned int& rigidBodyIndex) { - return m_omega_b_body[rigidBodyIndex]; - } - - FORCE_INLINE void setOmega_b_body(const unsigned int& rigidBodyIndex, const Vector3r& value) { - m_omega_b_body[rigidBodyIndex] = value; - } FORCE_INLINE Vector3r& getV_s(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_v_s[rigidBodyIndex][i]; @@ -169,30 +146,6 @@ namespace SPH { m_v_rr[rigidBodyIndex][i] = value; } - FORCE_INLINE Vector3r& getV_b(const unsigned int& rigidBodyIndex, const unsigned int i) { - return m_v_b[rigidBodyIndex][i]; - } - - FORCE_INLINE const Vector3r& getV_b(const unsigned int& rigidBodyIndex, const unsigned int i) const { - return m_v_b[rigidBodyIndex][i]; - } - - FORCE_INLINE void setV_b(const unsigned int& rigidBodyIndex, const unsigned int i, const Vector3r& value) { - m_v_b[rigidBodyIndex][i] = value; - } - - FORCE_INLINE Vector3r& getGrad_p_b(const unsigned int& rigidBodyIndex, const unsigned int i) { - return m_grad_p_b[rigidBodyIndex][i]; - } - - FORCE_INLINE const Vector3r& getGrad_p_b(const unsigned int& rigidBodyIndex, const unsigned int i) const { - return m_grad_p_b[rigidBodyIndex][i]; - } - - FORCE_INLINE void setGrad_p_b(const unsigned int& rigidBodyIndex, const unsigned int i, const Vector3r& value) { - m_grad_p_b[rigidBodyIndex][i] = value; - } - FORCE_INLINE Vector3r& getPredictVelocity(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_predictVelocity[rigidBodyIndex][i]; } @@ -288,5 +241,35 @@ namespace SPH { FORCE_INLINE void setArtificialVolume(const unsigned int& rigidBodyIndex, const unsigned int i, const Real& val) { m_artificialVolume[rigidBodyIndex][i] = val; } + + FORCE_INLINE const unsigned int& getMaxIterations() const { + return m_maxIterations; + } + FORCE_INLINE unsigned int& getMaxIterations() { + return m_maxIterations; + } + FORCE_INLINE void setMaxIterations(const unsigned int& value) { + m_maxIterations = value; + } + + FORCE_INLINE const unsigned int& getMinIterations() const { + return m_minIterations; + } + FORCE_INLINE unsigned int& getMinIterations() { + return m_minIterations; + } + FORCE_INLINE void setMinIterations(const unsigned int& value) { + m_minIterations = value; + } + + FORCE_INLINE const Real& getMaxDensityDeviation() const { + return m_maxDensityDeviation; + } + FORCE_INLINE Real& getMaxDensityDeviation() { + return m_maxDensityDeviation; + } + FORCE_INLINE void setMaxDensityDeviation(const Real& value) { + m_maxDensityDeviation = value; + } }; } \ No newline at end of file diff --git a/SPlisHSPlasH/Utilities/SceneParameterObjects.cpp b/SPlisHSPlasH/Utilities/SceneParameterObjects.cpp index e00c1683..ac05a172 100644 --- a/SPlisHSPlasH/Utilities/SceneParameterObjects.cpp +++ b/SPlisHSPlasH/Utilities/SceneParameterObjects.cpp @@ -319,6 +319,8 @@ int BoundaryParameterObject::BOUNDARY_MAP_RESOLUTION = -1; int BoundaryParameterObject::BOUNDARY_SAMPLING_MODE = -1; int BoundaryParameterObject::BOUNDARY_IS_ANIMATED = -1; int BoundaryParameterObject::BOUNDARY_DENSITY = -1; +int BoundaryParameterObject::BOUNDARY_VELOCITY = -1; +int BoundaryParameterObject::BOUNDARY_FRICTION = -1; void BoundaryParameterObject::initParameters() { @@ -385,4 +387,12 @@ void BoundaryParameterObject::initParameters() BOUNDARY_DENSITY = createNumericParameter("density", "Density", &density); setGroup(BOUNDARY_DENSITY, "Boundary"); setDescription(BOUNDARY_DENSITY, "Density of the rigid body."); + + BOUNDARY_FRICTION = createNumericParameter("friction", "Friction", &friction); + setGroup(BOUNDARY_FRICTION, "Boundary"); + setDescription(BOUNDARY_FRICTION, "Friction of the rigid body."); + + BOUNDARY_VELOCITY = createVectorParameter("velocity", "Velocity", 3u, velocity.data()); + setGroup(BOUNDARY_VELOCITY, "Boundary"); + setDescription(BOUNDARY_VELOCITY, "Velocity of the rigid body after loading."); } \ No newline at end of file diff --git a/SPlisHSPlasH/Utilities/SceneParameterObjects.h b/SPlisHSPlasH/Utilities/SceneParameterObjects.h index 34736c46..e7f20707 100644 --- a/SPlisHSPlasH/Utilities/SceneParameterObjects.h +++ b/SPlisHSPlasH/Utilities/SceneParameterObjects.h @@ -322,9 +322,11 @@ namespace Utilities std::string meshFile; Vector3r translation; Vector3r axis; + Vector3r velocity; Real angle; Vector3r scale; Real density; + Real friction; bool dynamic; bool isWall; Eigen::Matrix color; @@ -342,11 +344,13 @@ namespace Utilities meshFile = ""; translation = Vector3r::Zero(); axis = Vector3r(1, 0, 0); + velocity = Vector3r::Zero(); angle = 0.0; density = 1000.0; scale = Vector3r::Ones(); dynamic = false; isWall = false; + friction = 0.0; color = Eigen::Vector4f(1.0f, 0.0f, 0.0f, 0.0f); samplingMode = 0; isAnimated = false; @@ -359,16 +363,19 @@ namespace Utilities BoundaryParameterObject(std::string samplesFile_, std::string meshFile_, Vector3r translation_, Vector3r axis_, Real angle_, Vector3r scale_, bool dynamic_, bool isWall_, Eigen::Matrix color_, std::string mapFile_, bool mapInvert_, - Real mapThickness_, Eigen::Matrix mapResolution_, unsigned int samplingMode_, bool isAnimated_, Real density_ = 1000.0) + Real mapThickness_, Eigen::Matrix mapResolution_, unsigned int samplingMode_, bool isAnimated_, + Vector3r velocity_, Real friction_, Real density_ = 1000.0) { samplesFile = samplesFile_; meshFile = meshFile_; translation = translation_; axis = axis_; angle = angle_; + velocity = velocity_; scale = scale_; density = density_; dynamic = dynamic_; + friction = friction_; isWall = isWall_; color = color_; samplingMode = samplingMode_; @@ -396,6 +403,8 @@ namespace Utilities static int BOUNDARY_SAMPLING_MODE; static int BOUNDARY_IS_ANIMATED; static int BOUNDARY_DENSITY; + static int BOUNDARY_VELOCITY; + static int BOUNDARY_FRICTION; virtual void initParameters(); }; diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index 649e130c..593c5cbb 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -144,7 +144,7 @@ void TimeStepWCSPH::step() sim->animateParticles(); // Only for strong coupling method with BoundaryModel_Akinci2012 - if (sim->getDynamicBoundarySimulator() != nullptr) { + if (sim->getDynamicBoundarySimulator() != nullptr && sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { sim->getDynamicBoundarySimulator()->timeStepStrongCoupling(); } @@ -218,7 +218,6 @@ void TimeStepWCSPH::computePressureAccels(const unsigned int fluidModelIndex) { void TimeStepWCSPH::computeRigidRigidAccels() { Simulation* sim = Simulation::getCurrent(); - DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); TimeManager* tm = TimeManager::getCurrent(); const Real dt = tm->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); @@ -257,8 +256,8 @@ void TimeStepWCSPH::computeRigidRigidAccels() { bs->computeSourceTerm(); int iterations = 0; // while density deviation too large - while ((avgDensityDeviation > 0.0025 && iterations < 100) || iterations < 20) { - bs->computeSourceTermRHS(); + while ((avgDensityDeviation >bs->getMaxDensityDeviation() && iterations < bs->getMaxIterations()) || iterations < bs->getMinIterations()) { + //bs->computeSourceTermRHS(); avgDensityDeviation = 0; // update pressure @@ -266,6 +265,9 @@ void TimeStepWCSPH::computeRigidRigidAccels() { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); int bmIndex = boundaryPointSetIndex - nFluids; if (bm->getRigidBodyObject()->isDynamic()) { + + bs->computeSourceTermRHSForBody(boundaryPointSetIndex); + int numContactsBody = 0; #pragma omp parallel default(shared) { @@ -291,12 +293,12 @@ void TimeStepWCSPH::computeRigidRigidAccels() { { #pragma omp for schedule(static) reduction(+:avgDensityDeviation) for (int r = 0; r < bm->numberOfParticles(); r++) { - if (bs->getDensity(bmIndex, r) - bs->getRestDensity(bmIndex) > 1e-9 && std::abs(bs->getDiagonalElement(bmIndex, r)) > 1e-9) { + if (bs->getDensity(bmIndex, r) - bs->getRestDensity() > 1e-9 && std::abs(bs->getDiagonalElement(bmIndex, r)) > 1e-9) { Real pressureNextIter = bs->getPressure(bmIndex, r) + relaxation / bs->getDiagonalElement(bmIndex, r) * (bs->getSourceTerm(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r)); - bs->setPressure(bmIndex, r, pressureNextIter > 0 ? pressureNextIter : 0); + bs->setPressure(bmIndex, r, std::max(pressureNextIter, static_cast(0.0))); avgDensityDeviation -= (bs->getSourceTerm(bmIndex, r) - bs->getMinus_rho_div_v_s(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r)) * dt; } else { - bs->setPressure(bmIndex, r, 0); + bs->setPressure(bmIndex, r, static_cast(0.0)); } } } @@ -306,7 +308,7 @@ void TimeStepWCSPH::computeRigidRigidAccels() { return; } avgDensityDeviation /= particleInContact; - avgDensityDeviation /= bs->getRestDensity(0); + avgDensityDeviation /= bs->getRestDensity(); avgDensityDeviation = std::abs(avgDensityDeviation); std::cout << avgDensityDeviation << std::endl; iterations++; @@ -323,13 +325,9 @@ void TimeStepWCSPH::computeRigidRigidAccels() { for (int r = 0; r < bm->numberOfParticles(); r++) { const Vector3r f = -bs->getArtificialVolume(bmIndex, r) * bs->getPressureGrad(bmIndex, r); if (f != Vector3r::Zero()) { - if (bm->numberOfParticles() == 1) { - bm->addForce(rb->getPosition(), f); - } else { - bm->addForce(bm->getPosition(r), f); - } + bm->addForce(bm->getPosition(r), f); } - bs->setPressure(bmIndex, r, 0); + bs->setPressure(bmIndex, r, static_cast(0.0)); } } } @@ -337,7 +335,6 @@ void TimeStepWCSPH::computeRigidRigidAccels() { // solve the equation s = -rho * div¡¤v_rr w.r.t. pressure using relaxed jacobi - //for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { // BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); // int bmIndex = boundaryPointSetIndex - nFluids; diff --git a/Simulator/DynamicBoundarySimulator.cpp b/Simulator/DynamicBoundarySimulator.cpp index 9c46f130..497a1437 100644 --- a/Simulator/DynamicBoundarySimulator.cpp +++ b/Simulator/DynamicBoundarySimulator.cpp @@ -131,7 +131,8 @@ void DynamicBoundarySimulator::initBoundaryData() { Matrix3r rot = AngleAxisr(scene.boundaryModels[i]->angle, scene.boundaryModels[i]->axis).toRotationMatrix(); Quaternionr q(rot); - rb->initBody(scene.boundaryModels[i]->density, scene.boundaryModels[i]->dynamic, scene.boundaryModels[i]->translation, q, scene.boundaryModels[i]->scale); + rb->initBody(scene.boundaryModels[i]->density, scene.boundaryModels[i]->dynamic, scene.boundaryModels[i]->translation, q, + scene.boundaryModels[i]->scale, scene.boundaryModels[i]->velocity, scene.boundaryModels[i]->friction); if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { BoundaryModel_Akinci2012* bm = new BoundaryModel_Akinci2012(); diff --git a/Simulator/DynamicBoundarySimulator.h b/Simulator/DynamicBoundarySimulator.h index 034a31ec..f537363e 100644 --- a/Simulator/DynamicBoundarySimulator.h +++ b/Simulator/DynamicBoundarySimulator.h @@ -5,11 +5,11 @@ namespace SPH { class SimulatorBase; class TriangleMesh; - // This class is used for the strong coupling method. See DynamicRigidBody. class DynamicBoundarySimulator : public BoundarySimulator { private: Real m_dampingCoeff = 0.0; - Real m_maxIteration = 10; + + protected: SimulatorBase* m_base; @@ -39,15 +39,6 @@ namespace SPH { m_dampingCoeff = value; } - FORCE_INLINE const Real& getMaxIteration() const { - return m_maxIteration; - } - FORCE_INLINE Real& getMaxIteration() { - return m_maxIteration; - } - FORCE_INLINE void setMaxIteration(const Real& value) { - m_maxIteration = value; - } }; } diff --git a/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp b/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp index fabec000..1d2d820d 100644 --- a/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp +++ b/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp @@ -15,6 +15,7 @@ #include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_opengl3.h" #include "Simulator/DynamicBoundarySimulator.h" +#include "SPlisHSPlasH/StrongCouplingBoundarySolver.h" #define GLFW_INCLUDE_NONE #include @@ -503,7 +504,7 @@ void Simulator_GUI_imgui::initSimulationParameterGUI() } if (!m_simulatorBase->isStaticScene()) { - DynamicBoundarySimulator* simulator = sim->getDynamicBoundarySimulator(); + DynamicBoundarySimulator* simulator = sim->getDynamicBoundarySimulator(); // Fields for all boundary models { imguiParameters::imguiNumericParameter* damping = new imguiParameters::imguiNumericParameter(); @@ -513,12 +514,30 @@ void Simulator_GUI_imgui::initSimulationParameterGUI() damping->setFct = [simulator](Real v) {simulator->setDampingCoeff(v); }; imguiParameters::addParam("Boundary Model", "General", damping); - imguiParameters::imguiNumericParameter* maxIteration = new imguiParameters::imguiNumericParameter; - maxIteration->description = "max iteration to solve the strong coupling method"; - maxIteration->label = "Max Iterations"; - maxIteration->getFct = [simulator]()->int {return simulator->getMaxIteration(); }; - maxIteration->setFct = [simulator](int v) {simulator->setMaxIteration(v); }; - imguiParameters::addParam("Boundary Model", "General", maxIteration); + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { + StrongCouplingBoundarySolver* bs = StrongCouplingBoundarySolver::getCurrent(); + + imguiParameters::imguiNumericParameter* maxIteration = new imguiParameters::imguiNumericParameter; + maxIteration->description = "max iteration to solve the strong coupling method"; + maxIteration->label = "Max Iterations"; + maxIteration->getFct = [bs]()->unsigned int {return bs->getMaxIterations(); }; + maxIteration->setFct = [bs](unsigned int v) {bs->setMaxIterations(v); }; + imguiParameters::addParam("Boundary Model", "General", maxIteration); + + imguiParameters::imguiNumericParameter* minIteration = new imguiParameters::imguiNumericParameter; + minIteration->description = "min iteration to solve the strong coupling method"; + minIteration->label = "min Iterations"; + minIteration->getFct = [bs]()->unsigned int {return bs->getMinIterations(); }; + minIteration->setFct = [bs](unsigned int v) {bs->setMinIterations(v); }; + imguiParameters::addParam("Boundary Model", "General", minIteration); + + imguiParameters::imguiNumericParameter* maxDensityDeviation = new imguiParameters::imguiNumericParameter; + maxDensityDeviation->description = "max density deviation in % to solve the strong coupling method"; + maxDensityDeviation->label = "max density deviation (%)"; + maxDensityDeviation->getFct = [bs]()->Real {return bs->getMaxDensityDeviation() * 100; }; + maxDensityDeviation->setFct = [bs](Real v) {bs->setMaxDensityDeviation(v / 100); }; + imguiParameters::addParam("Boundary Model", "General", maxDensityDeviation); + } } // Enum for all boundary models From 6e01275ae7a9f4bb1e0f6a88fbf069e944d0f912 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Sat, 3 Jun 2023 21:39:18 +0200 Subject: [PATCH 25/38] moved pressure solve iterations to boundary solver --- SPlisHSPlasH/StrongCouplingBoundarySolver.cpp | 175 ++++++++++++--- SPlisHSPlasH/StrongCouplingBoundarySolver.h | 23 +- SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 204 +----------------- SPlisHSPlasH/WCSPH/TimeStepWCSPH.h | 2 +- 4 files changed, 174 insertions(+), 230 deletions(-) diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp index da5e744a..4f2bb676 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp @@ -22,7 +22,8 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_predictVelocity(), m_predictPosition(), m_v_rr_body(), - m_omega_rr_body() + m_omega_rr_body(), + m_bodyContacts() { m_maxIterations = 100; m_minIterations = 20; @@ -47,6 +48,7 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_predictPosition.resize(nBoundaries); m_v_rr_body.resize(nBoundaries, Vector3r::Zero()); m_omega_rr_body.resize(nBoundaries, Vector3r::Zero()); + m_bodyContacts.resize(nBoundaries, 0); for (unsigned int i = 0; i < nBoundaries; i++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModel(i)); @@ -75,6 +77,48 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : } + +void SPH::StrongCouplingBoundarySolver::resize(unsigned int size) { + Simulation* sim = Simulation::getCurrent(); + const unsigned int nBoundaries = sim->numberOfBoundaryModels(); + + m_restDensity = 1000; + m_density.resize(nBoundaries); + m_v_s.resize(nBoundaries); + m_s.resize(nBoundaries); + m_pressure.resize(nBoundaries); + m_v_rr.resize(nBoundaries); + m_minus_rho_div_v_s.resize(nBoundaries); + m_minus_rho_div_v_rr.resize(nBoundaries); + m_diagonalElement.resize(nBoundaries); + m_pressureGrad.resize(nBoundaries); + m_artificialVolume.resize(nBoundaries); + m_lastPressure.resize(nBoundaries); + m_predictVelocity.resize(nBoundaries); + m_predictPosition.resize(nBoundaries); + m_v_rr_body.resize(nBoundaries, Vector3r::Zero()); + m_omega_rr_body.resize(nBoundaries, Vector3r::Zero()); + m_bodyContacts.resize(nBoundaries, 0); + + for (unsigned int i = 0; i < nBoundaries; i++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModel(i)); + m_density[i].resize(bm->numberOfParticles(), m_restDensity); + m_v_s[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_s[i].resize(bm->numberOfParticles(), 0.0); + m_pressure[i].resize(bm->numberOfParticles(), 0.0); + m_v_rr[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_minus_rho_div_v_s[i].resize(bm->numberOfParticles(), 0.0); + m_minus_rho_div_v_rr[i].resize(bm->numberOfParticles(), 0.0); + m_diagonalElement[i].resize(bm->numberOfParticles(), 0.0); + m_pressureGrad[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_artificialVolume[i].resize(bm->numberOfParticles(), 0.0); + m_lastPressure[i].resize(bm->numberOfParticles(), 0.0); + m_predictVelocity[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_predictPosition[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + } +} + + void SPH::StrongCouplingBoundarySolver::reset() { Simulation* sim = Simulation::getCurrent(); const unsigned int nBoundaries = sim->numberOfBoundaryModels(); @@ -95,6 +139,9 @@ void SPH::StrongCouplingBoundarySolver::reset() { m_predictVelocity[i][j] = Vector3r::Zero(); m_predictPosition[i][j] = Vector3r::Zero(); } + m_v_rr_body[i] = Vector3r::Zero(); + m_omega_rr_body[i] = Vector3r::Zero(); + m_bodyContacts[i] = 0; } } @@ -130,6 +177,7 @@ StrongCouplingBoundarySolver::~StrongCouplingBoundarySolver() { m_predictPosition.clear(); m_v_rr_body.clear(); m_omega_rr_body.clear(); + m_bodyContacts.clear(); } StrongCouplingBoundarySolver* StrongCouplingBoundarySolver::getCurrent() { @@ -137,7 +185,7 @@ StrongCouplingBoundarySolver* StrongCouplingBoundarySolver::getCurrent() { current = new StrongCouplingBoundarySolver(); } else { if (Simulation::getCurrent()->numberOfBoundaryModels() != current->m_density.size()) { - current = new StrongCouplingBoundarySolver(); + current->resize(Simulation::getCurrent()->numberOfBoundaryModels()); } } return current; @@ -169,6 +217,36 @@ void StrongCouplingBoundarySolver::performNeighborhoodSearchSort() { } } +void StrongCouplingBoundarySolver::computeContacts() { + Simulation* sim = Simulation::getCurrent(); + const unsigned int nFluids = sim->numberOfFluidModels(); + m_contactsAllBodies = 0; + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + unsigned int contacts = 0; + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + int bmIndex = boundaryPointSetIndex - nFluids; + if (bm->getRigidBodyObject()->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) reduction(+:contacts) + for (int r = 0; r < bm->numberOfParticles(); r++) { + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + if (pid != boundaryPointSetIndex) { + if (sim->numberOfNeighbors(boundaryPointSetIndex, pid, r) > 0) { + contacts++; + break; + } + } + } + } + } + } + m_bodyContacts[bmIndex] = contacts; + m_contactsAllBodies += contacts; + } +} + + void StrongCouplingBoundarySolver::computeDensityAndVolume() { Simulation* sim = Simulation::getCurrent(); TimeManager* tm = TimeManager::getCurrent(); @@ -469,7 +547,7 @@ void SPH::StrongCouplingBoundarySolver::computeSourceTermRHSForBody(const unsign setV_rr(bmIndex, r, getV_rr_body(bmIndex) + getOmega_rr_body(bmIndex).cross(pos)); setPredictVelocity(bmIndex, r, getV_rr(bmIndex, r) + getV_s(bmIndex, r)); - Real minus_rho_div_v_rr = 0; + Real minus_rho_div_v_rr = 0.0; const Vector3r v_rr_r = getV_rr(bmIndex, r); for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { // divergence of particles in the same body should be 0; @@ -480,7 +558,6 @@ void SPH::StrongCouplingBoundarySolver::computeSourceTermRHSForBody(const unsign const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); const Real density_k = getDensity(neighborIndex, k); const Real volume_k = getArtificialVolume(neighborIndex, k); - //const Vector3r v_rr_k = getV_rr_body(pid - nFluids) + getOmega_rr_body(pid - nFluids).cross(bm_neighbor->getPosition(k) - bm_neighbor->getRigidBodyObject()->getPosition()); const Vector3r v_rr_k = getV_rr(pid - nFluids, k); minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); } @@ -491,35 +568,63 @@ void SPH::StrongCouplingBoundarySolver::computeSourceTermRHSForBody(const unsign } } } - // compute the -rho * (div v_rr), which is the RHS to the source term -//for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { -// BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); -// int bmIndex = boundaryPointSetIndex - nFluids; -// if (bm->getRigidBodyObject()->isDynamic()) { -// #pragma omp parallel default(shared) - // { -// #pragma omp for schedule(static) - // for (int r = 0; r < bm->numberOfParticles(); r++) { - // Real minus_rho_div_v_rr = 0; - // const Vector3r v_rr_r = getV_rr(bmIndex, r); - // for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - // // divergence of particles in the same body should be 0; - // if (boundaryPointSetIndex != pid) { - // BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - // int neighborIndex = pid - nFluids; - // for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { - // const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - // const Real density_k = getDensity(neighborIndex, k); - // const Real volume_k = getArtificialVolume(neighborIndex, k); - // const Vector3r v_rr_k = getV_rr(neighborIndex, k); - // minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); - // } - // } - // } - // minus_rho_div_v_rr = -minus_rho_div_v_rr; - // setSourceTermRHS(bmIndex, r, minus_rho_div_v_rr); - // } - // } - // } - //} +} + + +void StrongCouplingBoundarySolver::pressureSolveIteration(Real& avgDensityDeviation) { + Simulation* sim = Simulation::getCurrent(); + const Real dt = TimeManager::getCurrent()->getTimeStepSize(); + const unsigned int nFluids = sim->numberOfFluidModels(); + Real avgDensityDev = 0.0; + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + int bmIndex = boundaryPointSetIndex - nFluids; + if (bm->getRigidBodyObject()->isDynamic()) { + int numContactsBody = getBodyContacts(bmIndex); + computeSourceTermRHSForBody(boundaryPointSetIndex); + // beta_r_RJ + Real relaxation = 0.5 / numContactsBody; + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) reduction(+:avgDensityDev) + for (int r = 0; r < bm->numberOfParticles(); r++) { + if (std::abs(getDiagonalElement(bmIndex, r)) > 1e-10) { + Real pressureNextIter = getPressure(bmIndex, r) + relaxation / getDiagonalElement(bmIndex, r) * (getSourceTerm(bmIndex, r) - getSourceTermRHS(bmIndex, r)); + setPressure(bmIndex, r, std::max(pressureNextIter, static_cast(0.0))); + avgDensityDev -= (getSourceTerm(bmIndex, r) - getMinus_rho_div_v_s(bmIndex, r) - getSourceTermRHS(bmIndex, r)) * dt; + } else { + setPressure(bmIndex, r, static_cast(0.0)); + } + } + } + } + } + avgDensityDev /= m_contactsAllBodies; + avgDensityDev /= getRestDensity(); + avgDensityDeviation = std::abs(avgDensityDev); +} + +void StrongCouplingBoundarySolver::applyForce() { + Simulation* sim = Simulation::getCurrent(); + const Real dt = TimeManager::getCurrent()->getTimeStepSize(); + const unsigned int nFluids = sim->numberOfFluidModels(); + + for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + int bmIndex = boundaryPointSetIndex - nFluids; + DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + if (rb->isDynamic()) { + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int r = 0; r < bm->numberOfParticles(); r++) { + const Vector3r f = -getArtificialVolume(bmIndex, r) * getPressureGrad(bmIndex, r); + if (f != Vector3r::Zero()) { + bm->addForce(bm->getPosition(r), f); + } + setPressure(bmIndex, r, static_cast(0.0)); + } + } + } + } } diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.h b/SPlisHSPlasH/StrongCouplingBoundarySolver.h index 36601b8b..b9c7a572 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.h +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.h @@ -27,6 +27,8 @@ namespace SPH { std::vector> m_diagonalElement; // diagonal element for jacobi iteration std::vector m_v_rr_body; std::vector m_omega_rr_body; + std::vector m_bodyContacts; + unsigned int m_contactsAllBodies; static StrongCouplingBoundarySolver* current; @@ -39,6 +41,8 @@ namespace SPH { ~StrongCouplingBoundarySolver(); static StrongCouplingBoundarySolver* getCurrent(); void reset(); + void resize(unsigned int size); + void computeContacts(); void computeDensityAndVolume(); void computePressureGrad(); void computeV_s(); @@ -47,6 +51,8 @@ namespace SPH { void computeSourceTerm(); void computeDiagonalElement(); void computeFriction(); + void pressureSolveIteration(Real& avgDensityDeviation); + void applyForce(); void performNeighborhoodSearchSort(); FORCE_INLINE const Real& getDensity(const unsigned int& rigidBodyIndex, const unsigned int& index) const { @@ -133,7 +139,6 @@ namespace SPH { m_v_s[rigidBodyIndex][i] = value; } - FORCE_INLINE Vector3r& getV_rr(const unsigned int& rigidBodyIndex, const unsigned int i) { return m_v_rr[rigidBodyIndex][i]; } @@ -242,6 +247,22 @@ namespace SPH { m_artificialVolume[rigidBodyIndex][i] = val; } + FORCE_INLINE const unsigned int& getBodyContacts(const unsigned int& rigidBodyIndex) const { + return m_bodyContacts[rigidBodyIndex]; + } + + FORCE_INLINE unsigned int& getBodyContacts(const unsigned int& rigidBodyIndex) { + return m_bodyContacts[rigidBodyIndex]; + } + + FORCE_INLINE void setBodyContacts(const unsigned int& rigidBodyIndex, const unsigned int& value) { + m_bodyContacts[rigidBodyIndex] = value; + } + + FORCE_INLINE unsigned int getAllContacts() { + return m_contactsAllBodies; + } + FORCE_INLINE const unsigned int& getMaxIterations() const { return m_maxIterations; } diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index 593c5cbb..bd3e7904 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -114,7 +114,7 @@ void TimeStepWCSPH::step() // TODO: rigid-rigid contact forces if (sim->getDynamicBoundarySimulator() != nullptr && sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { - computeRigidRigidAccels(); + solveRigidRigidContacts(); } sim->updateTimeStepSize(); @@ -216,215 +216,33 @@ void TimeStepWCSPH::computePressureAccels(const unsigned int fluidModelIndex) { } } -void TimeStepWCSPH::computeRigidRigidAccels() { +void TimeStepWCSPH::solveRigidRigidContacts() { Simulation* sim = Simulation::getCurrent(); - TimeManager* tm = TimeManager::getCurrent(); - const Real dt = tm->getTimeStepSize(); + const Real dt = TimeManager::getCurrent()->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); StrongCouplingBoundarySolver* bs = StrongCouplingBoundarySolver::getCurrent(); bs->computeDensityAndVolume(); - // compute density deviation - int particleInContact = 0; - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - int bmIndex = boundaryPointSetIndex - nFluids; - if (bm->getRigidBodyObject()->isDynamic()) { - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) reduction(+:particleInContact) - for (int r = 0; r < bm->numberOfParticles(); r++) { - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - if (pid != boundaryPointSetIndex) { - if (sim->numberOfNeighbors(boundaryPointSetIndex, pid, r) > 0) { - particleInContact++; - break; - } - } - } - } - } - } - } - if (particleInContact == 0) { + // check whehter there is any collisions + bs->computeContacts(); + if (bs->getAllContacts() == 0) { return; } - //std::cout << particleInContact << std::endl; - Real avgDensityDeviation = 1.0; bs->computeDiagonalElement(); bs->computeSourceTerm(); + Real avgDensityDeviation = 1.0; int iterations = 0; // while density deviation too large - while ((avgDensityDeviation >bs->getMaxDensityDeviation() && iterations < bs->getMaxIterations()) || iterations < bs->getMinIterations()) { - //bs->computeSourceTermRHS(); - avgDensityDeviation = 0; - // update pressure - - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - int bmIndex = boundaryPointSetIndex - nFluids; - if (bm->getRigidBodyObject()->isDynamic()) { - - bs->computeSourceTermRHSForBody(boundaryPointSetIndex); - - int numContactsBody = 0; - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) reduction(+:numContactsBody) - for (int r = 0; r < bm->numberOfParticles(); r++) { - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - if (pid != boundaryPointSetIndex) { - if (sim->numberOfNeighbors(boundaryPointSetIndex, pid, r) > 0) { - numContactsBody++; - break; - } - } - } - } - } - if (numContactsBody == 0) { - continue; - } - // beta_r_RJ - Real relaxation = 0.5 / numContactsBody; - - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) reduction(+:avgDensityDeviation) - for (int r = 0; r < bm->numberOfParticles(); r++) { - if (bs->getDensity(bmIndex, r) - bs->getRestDensity() > 1e-9 && std::abs(bs->getDiagonalElement(bmIndex, r)) > 1e-9) { - Real pressureNextIter = bs->getPressure(bmIndex, r) + relaxation / bs->getDiagonalElement(bmIndex, r) * (bs->getSourceTerm(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r)); - bs->setPressure(bmIndex, r, std::max(pressureNextIter, static_cast(0.0))); - avgDensityDeviation -= (bs->getSourceTerm(bmIndex, r) - bs->getMinus_rho_div_v_s(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r)) * dt; - } else { - bs->setPressure(bmIndex, r, static_cast(0.0)); - } - } - } - } - } - if (particleInContact == 0) { - return; - } - avgDensityDeviation /= particleInContact; - avgDensityDeviation /= bs->getRestDensity(); - avgDensityDeviation = std::abs(avgDensityDeviation); + while ((avgDensityDeviation > bs->getMaxDensityDeviation() && iterations < bs->getMaxIterations()) || iterations < bs->getMinIterations()) { + avgDensityDeviation = 0.0; + bs->pressureSolveIteration(avgDensityDeviation); std::cout << avgDensityDeviation << std::endl; iterations++; } std::cout << "------------------------------" << std::endl; - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - int bmIndex = boundaryPointSetIndex - nFluids; - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - if (rb->isDynamic()) { - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - const Vector3r f = -bs->getArtificialVolume(bmIndex, r) * bs->getPressureGrad(bmIndex, r); - if (f != Vector3r::Zero()) { - bm->addForce(bm->getPosition(r), f); - } - bs->setPressure(bmIndex, r, static_cast(0.0)); - } - } - } - } + bs->applyForce(); - // solve the equation s = -rho * div¡¤v_rr w.r.t. pressure using relaxed jacobi - - //for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - // BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - // int bmIndex = boundaryPointSetIndex - nFluids; - // DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - // unsigned int numContacts = 0; - // if (bm->getRigidBodyObject()->isDynamic()) { - // bs->computeDensityAndVolume(); - // // number of contacts - // #pragma omp parallel default(shared) - // { - // #pragma omp for schedule(static) reduction(+:numContacts) - // for (int r = 0; r < bm->numberOfParticles(); r++) { - // for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - // if (pid != boundaryPointSetIndex) { - // if (sim->numberOfNeighbors(boundaryPointSetIndex, pid, r) > 0) { - // numContacts++; - // } - // } - // } - // } - // } - // if(numContacts == 0){ - // return; - // } - // // beta_r_RJ - // Real relaxation = 0.5/numContacts; - // //std::cout << numContacts << std::endl; - // bs->computeSourceTerm(); - // bs->computeDiagonalElement(); - // Real densityDeviationAvg = 1; - // unsigned int numParticles = 0; - // unsigned int i = 0; - - // while (densityDeviationAvg > 0.002) { - // densityDeviationAvg = 0.0; - // numParticles = 0; - // bs->computeSourceTermRHS(); - // #pragma omp parallel default(shared) - // { - // #pragma omp for schedule(static) reduction(+:numParticles) reduction(+:densityDeviationAvg) - // for (int r = 0; r < bm->numberOfParticles(); r++) { - // if (bs->getDensity(bmIndex,r) - bs->getRestDensity(bmIndex) > 1e-9 && std::abs(bs->getDiagonalElement(bmIndex, r)) > 1e-9) { - // numParticles++; - // Real pressureNextIter = bs->getPressure(bmIndex, r) + relaxation / bs->getDiagonalElement(bmIndex, r) * (bs->getSourceTerm(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r)); - // //if (r == 105) { - // // //if (bs->getSourceTerm(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r) > 0) { - // // // std::cout << bs->getSourceTerm(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r) << std::endl; - // // // std::cout << bs->getSourceTermRHS(bmIndex, r) << std::endl; - // // // std::cout << pressureNextIter << std::endl << std::endl; - // // //} - // // std::cout << bs->getSourceTerm(bmIndex, r) - bs->getSourceTermRHS(bmIndex, r) << std::endl; - // // //std::cout << bs->getDiagonalElement(bmIndex, r) << std::endl; - // // //std::cout << bs->getPressure(bmIndex, r) << std::endl; - // // //pressureNextIter = 1.46289e+07; - // //} - // bs->setPressure(bmIndex, r, std::max(pressureNextIter, static_cast(0))); - // densityDeviationAvg -= (bs->getMinus_rho_div_v_s(bmIndex, r) + bs->getSourceTermRHS(bmIndex, r)) * dt; - // } else { - // bs->setPressure(bmIndex, r, 0); - // } - // } - // } - // if (numParticles == 0 || densityDeviationAvg < 0) { - // break; - // } - // densityDeviationAvg /= numParticles; - // densityDeviationAvg /= bs->getRestDensity(bmIndex); - // //std::cout << numParticles << std::endl; - // ////densityErrorAvg /= numParticles; - // std::cout << densityDeviationAvg << std::endl; - // i++; - // } - // std::cout << "-------------------" << std::endl; - // #pragma omp parallel default(shared) - // { - // #pragma omp for schedule(static) - // for (int r = 0; r < bm->numberOfParticles(); r++) { - // if (bs->getPressureGrad(bmIndex, r) != Vector3r::Zero()) { - // const Vector3r f = -bs->getArtificialVolume(bmIndex, r) * bs->getPressureGrad(bmIndex, r); - // if (bm->numberOfParticles() == 1) { - // bm->addForce(rb->getPosition(), f); - // } else { - // bm->addForce(bm->getPosition(r), f); - // } - // bs->setPressure(bmIndex, r, 0); - // } - // } - // } - // } - //} } void TimeStepWCSPH::performNeighborhoodSearch() diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h index e5253c90..d1cfdd81 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.h @@ -35,7 +35,7 @@ namespace SPH virtual void emittedParticles(FluidModel *model, const unsigned int startIndex); virtual void initParameters(); - void computeRigidRigidAccels(); + void solveRigidRigidContacts(); public: static int STIFFNESS; From 0377a9abff5be34401b6640648bdca21e4cb8d91 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Wed, 7 Jun 2023 09:44:21 +0200 Subject: [PATCH 26/38] test scene file --- SPlisHSPlasH/StrongCouplingBoundarySolver.cpp | 49 +------ SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 1 - data/Scenes/Cubes.json | 91 ++++++++++++ data/Scenes/CubesTwo.json | 110 ++++++++++++++ data/Scenes/DamBreakWithCubes.json | 136 ++++++++++++++++++ 5 files changed, 339 insertions(+), 48 deletions(-) create mode 100644 data/Scenes/Cubes.json create mode 100644 data/Scenes/CubesTwo.json create mode 100644 data/Scenes/DamBreakWithCubes.json diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp index 4f2bb676..e5a41e42 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp @@ -276,8 +276,7 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { setDensity(bmIndex, r, std::max(particleDensity, getRestDensity())); //gamma = 0.7, see the paper const Real gamma = static_cast(0.7); - if (getDensity(bmIndex, r) > getRestDensity()) { - + if (getDensity(bmIndex, r) > getRestDensity()) { setArtificialVolume(bmIndex, r, gamma * getRestDensity() * bm->getVolume(r) / getDensity(bmIndex, r)); } else { setArtificialVolume(bmIndex, r, gamma * bm->getVolume(r)); @@ -351,6 +350,7 @@ void StrongCouplingBoundarySolver::computeSourceTerm() { } Real s = (getRestDensity() - getDensity(bmIndex, r)) / dt + rho_div_v_s; setSourceTerm(bmIndex, r, s); + // used to computed the density deviation setMinus_rho_div_v_s(bmIndex, r, -rho_div_v_s); } } @@ -373,9 +373,6 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { #pragma omp for schedule(static) for (int r = 0; r < bm_r->numberOfParticles(); r++) { Vector3r pos_r = bm_r->getPosition(r) - rb->getPosition(); - if (bm_r->numberOfParticles() == 1) { - pos_r.setZero(); - } Vector3r grad_p_b = Vector3r::Zero(); const Real density_r2 = getDensity(index_r, r) * getDensity(index_r, r); // rk are neighboring rigid particles of r of other rigid bodies k @@ -430,48 +427,6 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { } } -void StrongCouplingBoundarySolver::computePressureGrad() { - Simulation* sim = Simulation::getCurrent(); - DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); - TimeManager* tm = TimeManager::getCurrent(); - const Real dt = tm->getTimeStepSize(); - const unsigned int nFluids = sim->numberOfFluidModels(); - - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - int bmIndex = boundaryPointSetIndex - nFluids; - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - if (rb->isDynamic()) { - #pragma omp parallel default(shared) - { - #pragma omp for schedule(static) - for (int r = 0; r < bm->numberOfParticles(); r++) { - // pressure gradient for particle r - Vector3r pressureGrad_r = Vector3r().setZero(); - const Real density_r = getDensity(bmIndex, r); - const Real pressure_r = getPressure(bmIndex, r); - for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { - if (pid != boundaryPointSetIndex) { - BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); - int neighborIndex = pid - nFluids; - for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { - const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - const Real density_k = getDensity(neighborIndex, k); - const Real volume_k = getArtificialVolume(neighborIndex, k); - //const Real pressure_k = bm_neighbor->getRigidBodyObject()->isDynamic() ? getPressure(neighborIndex, k) : pressure_r; - const Real pressure_k = getPressure(neighborIndex, k); - pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); - } - } - } - pressureGrad_r *= density_r; - setPressureGrad(bmIndex, r, pressureGrad_r); - } - } - } - } -} - void StrongCouplingBoundarySolver::computeSourceTermRHS() { Simulation* sim = Simulation::getCurrent(); const unsigned int nFluids = sim->numberOfFluidModels(); diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index bd3e7904..50b8d4aa 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -112,7 +112,6 @@ void TimeStepWCSPH::step() computePressureAccels(fluidModelIndex); } - // TODO: rigid-rigid contact forces if (sim->getDynamicBoundarySimulator() != nullptr && sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { solveRigidRigidContacts(); } diff --git a/data/Scenes/Cubes.json b/data/Scenes/Cubes.json new file mode 100644 index 00000000..39f3096a --- /dev/null +++ b/data/Scenes/Cubes.json @@ -0,0 +1,91 @@ +{ + "Configuration": + { + "particleRadius": 0.025, + "numberOfStepsPerRenderUpdate": 2, + "density0": 1000, + "simulationMethod": 0, + "gravitation": [0,-9.81,0], + "cflMethod": 1, + "cflFactor": 0.5, + "cflMaxTimeStepSize": 0.005, + "maxIterations": 100, + "maxError": 0.05, + "maxIterationsV": 100, + "maxErrorV": 0.1, + "stiffness": 50000, + "exponent": 7, + "velocityUpdateMethod": 0, + "enableDivergenceSolver": true, + "boundaryHandlingMethod": 0 + }, + "Simulation": + { + "timeStepSize": 0.005, + "maxIter" : 5, + "maxIterVel" : 5, + "velocityUpdateMethod" : 0, + "contactTolerance": 0.06, + "tetModelSimulationMethod": 2, + "triangleModelSimulationMethod": 2, + "triangleModelBendingMethod": 2, + "contactStiffnessRigidBody" : 1.0, + "contactStiffnessParticleRigidBody": 100.0, + "cloth_stiffness": 1.0, + "cloth_bendingStiffness": 0.005, + "cloth_xxStiffness": 1.0, + "cloth_yyStiffness": 1.0, + "cloth_xyStiffness": 1.0, + "cloth_xyPoissonRatio": 0.3, + "cloth_yxPoissonRatio": 0.3, + "cloth_normalizeStretch": 0, + "cloth_normalizeShear": 0, + "solid_stiffness": 1.0, + "solid_poissonRatio": 0.2, + "solid_normalizeStretch": 0, + "solid_normalizeShear": 0 + }, + "RigidBodies": [ + { + "id": 1, + "geometryFile": "../models/UnitBox.obj", + "translation": [0,4,0], + "rotationAxis": [1, 0, 0], + "rotationAngle": 0, + "scale": [3.1, 8, 1.6], + "color": [0.1, 0.4, 0.6, 1.0], + "isDynamic": false, + "isWall": true, + "restitution" : 0.6, + "friction" : 0.0, + "collisionObjectType": 2, + "collisionObjectScale": [3.1, 8, 1.6], + "invertSDF": true, + "mapInvert": true, + "mapThickness": 0.0, + "mapResolution": [30,40,15] + }, + { + "id": 2, + "geometryFile": "../models/UnitBox.obj", + "isDynamic": 1, + "density": 400, + "translation": [0,2,0], + "rotationAxis": [1, 0, 0], + "rotationAngle": 0, + "scale": [0.4, 0.4, 0.4], + "velocity": [0,0,0], + "restitution" : 0.6, + "friction" : 0.2, + "color": [0.3, 0.5, 0.8, 1.0], + "collisionObjectType": 2, + "collisionObjectScale": [0.4, 0.4, 0.4], + "mapInvert": false, + "mapThickness": 0.0, + "mapResolution": [20,20,20] + } + ] +} + + + diff --git a/data/Scenes/CubesTwo.json b/data/Scenes/CubesTwo.json new file mode 100644 index 00000000..4224bb3e --- /dev/null +++ b/data/Scenes/CubesTwo.json @@ -0,0 +1,110 @@ +{ + "Configuration": + { + "particleRadius": 0.025, + "numberOfStepsPerRenderUpdate": 2, + "density0": 1000, + "simulationMethod": 0, + "gravitation": [0,-9.81,0], + "cflMethod": 1, + "cflFactor": 0.5, + "cflMaxTimeStepSize": 0.005, + "maxIterations": 100, + "maxError": 0.05, + "maxIterationsV": 100, + "maxErrorV": 0.1, + "stiffness": 50000, + "exponent": 7, + "velocityUpdateMethod": 0, + "enableDivergenceSolver": true, + "boundaryHandlingMethod": 0 + }, + "Simulation": + { + "timeStepSize": 0.005, + "maxIter" : 5, + "maxIterVel" : 5, + "velocityUpdateMethod" : 0, + "contactTolerance": 0.06, + "tetModelSimulationMethod": 2, + "triangleModelSimulationMethod": 2, + "triangleModelBendingMethod": 2, + "contactStiffnessRigidBody" : 1.0, + "contactStiffnessParticleRigidBody": 100.0, + "cloth_stiffness": 1.0, + "cloth_bendingStiffness": 0.005, + "cloth_xxStiffness": 1.0, + "cloth_yyStiffness": 1.0, + "cloth_xyStiffness": 1.0, + "cloth_xyPoissonRatio": 0.3, + "cloth_yxPoissonRatio": 0.3, + "cloth_normalizeStretch": 0, + "cloth_normalizeShear": 0, + "solid_stiffness": 1.0, + "solid_poissonRatio": 0.2, + "solid_normalizeStretch": 0, + "solid_normalizeShear": 0 + }, + "RigidBodies": [ + { + "id": 1, + "geometryFile": "../models/UnitBox.obj", + "translation": [0,4,0], + "rotationAxis": [1, 0, 0], + "rotationAngle": 0, + "scale": [3.1, 8, 1.6], + "color": [0.1, 0.4, 0.6, 1.0], + "isDynamic": false, + "isWall": true, + "restitution" : 0.6, + "friction" : 0.0, + "collisionObjectType": 2, + "collisionObjectScale": [3.1, 8, 1.6], + "invertSDF": true, + "mapInvert": true, + "mapThickness": 0.0, + "mapResolution": [30,40,15] + }, + { + "id": 2, + "geometryFile": "../models/UnitBox.obj", + "isDynamic": 1, + "density": 400, + "translation": [-1,2.0,0], + "rotationAxis": [1, 0, 0], + "rotationAngle": 0.0, + "scale": [0.2, 0.4, 0.4], + "velocity": [3,0,0], + "restitution" : 0.6, + "friction" : 0.2, + "color": [0.3, 0.5, 0.8, 1.0], + "collisionObjectType": 2, + "collisionObjectScale": [0.4, 0.4, 0.4], + "mapInvert": false, + "mapThickness": 0.0, + "mapResolution": [20,20,20] + }, + { + "id": 3, + "geometryFile": "../models/UnitBox.obj", + "isDynamic": 1, + "density": 400, + "translation": [1,2.0,0], + "rotationAxis": [1, 0, 0], + "rotationAngle": 0.0, + "scale": [0.1, 0.1, 0.1], + "velocity": [-3,0,0], + "restitution" : 0.6, + "friction" : 0.2, + "color": [0.3, 0.5, 0.8, 1.0], + "collisionObjectType": 2, + "collisionObjectScale": [0.4, 0.4, 0.4], + "mapInvert": false, + "mapThickness": 0.0, + "mapResolution": [20,20,20] + } + ] +} + + + diff --git a/data/Scenes/DamBreakWithCubes.json b/data/Scenes/DamBreakWithCubes.json new file mode 100644 index 00000000..5d351658 --- /dev/null +++ b/data/Scenes/DamBreakWithCubes.json @@ -0,0 +1,136 @@ +{ + "Configuration": + { + "particleRadius": 0.025, + "numberOfStepsPerRenderUpdate": 2, + "density0": 1000, + "simulationMethod": 4, + "gravitation": [0,-9.81,0], + "cflMethod": 1, + "cflFactor": 0.5, + "cflMaxTimeStepSize": 0.005, + "maxIterations": 100, + "maxError": 0.05, + "maxIterationsV": 100, + "maxErrorV": 0.1, + "stiffness": 50000, + "exponent": 7, + "velocityUpdateMethod": 0, + "enableDivergenceSolver": true, + "boundaryHandlingMethod": 0 + }, + "Simulation": + { + "timeStepSize": 0.005, + "maxIter" : 5, + "maxIterVel" : 5, + "velocityUpdateMethod" : 0, + "contactTolerance": 0.06, + "tetModelSimulationMethod": 2, + "triangleModelSimulationMethod": 2, + "triangleModelBendingMethod": 2, + "contactStiffnessRigidBody" : 1.0, + "contactStiffnessParticleRigidBody": 100.0, + "cloth_stiffness": 1.0, + "cloth_bendingStiffness": 0.005, + "cloth_xxStiffness": 1.0, + "cloth_yyStiffness": 1.0, + "cloth_xyStiffness": 1.0, + "cloth_xyPoissonRatio": 0.3, + "cloth_yxPoissonRatio": 0.3, + "cloth_normalizeStretch": 0, + "cloth_normalizeShear": 0, + "solid_stiffness": 1.0, + "solid_poissonRatio": 0.2, + "solid_normalizeStretch": 0, + "solid_normalizeShear": 0 + }, + "RigidBodies": [ + { + "id": 1, + "geometryFile": "../models/UnitBox.obj", + "translation": [0,4,0], + "rotationAxis": [1, 0, 0], + "rotationAngle": 0, + "scale": [3.1, 8, 1.6], + "color": [0.1, 0.4, 0.6, 1.0], + "isDynamic": false, + "isWall": true, + "restitution" : 0.6, + "friction" : 0.0, + "collisionObjectType": 2, + "collisionObjectScale": [3.1, 8, 1.6], + "invertSDF": true, + "mapInvert": true, + "mapThickness": 0.0, + "mapResolution": [30,40,15] + }, + { + "id": 2, + "geometryFile": "../models/UnitBox.obj", + "isDynamic": 1, + "density": 400, + "translation": [0.1,2.0,0], + "rotationAxis": [1, 0, 0], + "rotationAngle": 0.0, + "scale": [0.4, 0.4, 0.4], + "velocity": [0,0,0], + "restitution" : 0.6, + "friction" : 0.2, + "color": [0.3, 0.5, 0.8, 1.0], + "collisionObjectType": 2, + "collisionObjectScale": [0.4, 0.4, 0.4], + "mapInvert": false, + "mapThickness": 0.0, + "mapResolution": [20,20,20] + }, + { + "id": 3, + "geometryFile": "../models/UnitBox.obj", + "isDynamic": 1, + "density": 700, + "translation": [-0.2, 3, 0], + "rotationAxis": [1, 1, 1], + "rotationAngle": 0.5, + "scale": [0.1, 0.5, 0.1], + "restitution" : 0.6, + "friction" : 0.2, + "color": [1.0, 1.0, 1.0, 1.0], + "collisionObjectType": 2, + "collisionObjectScale": [0.1, 0.5, 0.1], + "mapInvert": false, + "mapThickness": 0.0, + "mapResolution": [20,20,20] + }, + { + "id": 4, + "geometryFile": "../models/UnitBox.obj", + "isDynamic": 1, + "density": 100, + "translation": [0.4,1.0,0.0], + "rotationAxis": [0, 0, 1], + "rotationAngle": 1.0, + "scale": [0.2, 0.2, 0.2], + "restitution" : 0.6, + "friction" : 0.2, + "color": [0.5, 0.2, 0.6, 1.0], + "collisionObjectType": 2, + "collisionObjectScale": [0.2, 0.2, 0.2], + "mapInvert": false, + "mapThickness": 0.0, + "mapResolution": [20,20,20] + } + ], + "FluidBlocks": [ + { + "denseMode": 0, + "start": [-0.75, 0.0, -0.75], + "end": [0.75, 1.5, 0.75], + "translation": [-0.75, 0.0, 0.0], + "scale": [1,1,1] + } + ] +} + + + From 008b2e9157795c190ac7cbf048fd02150cfdbd12 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Thu, 15 Jun 2023 17:40:55 +0200 Subject: [PATCH 27/38] added enum BoundaryHandlingMethod::Gissler2019, integration in IISPH --- SPlisHSPlasH/Drag/DragForce_Gissler2017.cpp | 2 +- SPlisHSPlasH/DynamicRigidBody.h | 2 +- SPlisHSPlasH/Emitter.cpp | 4 +- SPlisHSPlasH/IISPH/SimulationDataIISPH.cpp | 5 + SPlisHSPlasH/IISPH/SimulationDataIISPH.h | 14 ++ SPlisHSPlasH/IISPH/TimeStepIISPH.cpp | 150 +++++++++++++++++- SPlisHSPlasH/IISPH/TimeStepIISPH.h | 1 + SPlisHSPlasH/PBF/TimeStepPBF.cpp | 6 +- SPlisHSPlasH/Simulation.cpp | 8 +- SPlisHSPlasH/Simulation.h | 3 +- SPlisHSPlasH/StrongCouplingBoundarySolver.cpp | 77 ++++----- SPlisHSPlasH/StrongCouplingBoundarySolver.h | 32 ++-- .../SurfaceTension_Akinci2013.cpp | 2 +- .../SurfaceTension_Becker2007.cpp | 2 +- .../SurfaceTension/SurfaceTension_He2014.cpp | 4 +- SPlisHSPlasH/TimeStep.cpp | 2 +- SPlisHSPlasH/Utilities/SceneLoader.cpp | 3 + SPlisHSPlasH/Utilities/SceneLoader.h | 1 + .../Viscosity/Viscosity_Bender2017.cpp | 2 +- SPlisHSPlasH/Viscosity/Viscosity_Peer2015.cpp | 2 +- SPlisHSPlasH/Viscosity/Viscosity_Peer2016.cpp | 2 +- SPlisHSPlasH/Viscosity/Viscosity_Standard.cpp | 2 +- .../Viscosity/Viscosity_Takahashi2015.cpp | 2 +- .../Viscosity/Viscosity_Weiler2018.cpp | 12 +- .../Vorticity/MicropolarModel_Bender2017.cpp | 2 +- SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 23 +-- SPlisHSPlasH/XSPH.cpp | 2 +- Simulator/DynamicBoundarySimulator.cpp | 63 +++----- Simulator/DynamicBoundarySimulator.h | 1 - Simulator/GUI/imgui/Simulator_GUI_imgui.cpp | 18 +-- Simulator/SimulatorBase.cpp | 18 ++- Simulator/SimulatorBase.h | 2 + Simulator/main.cpp | 13 +- data/Scenes/Cubes.json | 8 +- data/Scenes/CubesTwo.json | 11 +- data/Scenes/DamBreakModel.json | 2 +- data/Scenes/DamBreakWithCubes.json | 4 +- data/Scenes/DamBreakWithObjects.json | 2 +- data/Scenes/DoubleDamBreakWithSphere.json | 2 +- 39 files changed, 331 insertions(+), 180 deletions(-) diff --git a/SPlisHSPlasH/Drag/DragForce_Gissler2017.cpp b/SPlisHSPlasH/Drag/DragForce_Gissler2017.cpp index 5d8ce94e..59d2e2a3 100644 --- a/SPlisHSPlasH/Drag/DragForce_Gissler2017.cpp +++ b/SPlisHSPlasH/Drag/DragForce_Gissler2017.cpp @@ -106,7 +106,7 @@ void DragForce_Gissler2017::step() for (unsigned int pid = 0; pid < nFluids; pid++) numNeighbors += sim->numberOfNeighbors(fluidModelIndex, pid, i); - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) numNeighbors += sim->numberOfNeighbors(fluidModelIndex, pid, i); diff --git a/SPlisHSPlasH/DynamicRigidBody.h b/SPlisHSPlasH/DynamicRigidBody.h index 83a4d7c6..f74ce645 100644 --- a/SPlisHSPlasH/DynamicRigidBody.h +++ b/SPlisHSPlasH/DynamicRigidBody.h @@ -174,7 +174,7 @@ namespace SPH { m_isDynamic = isDynamic; // for now only consider cubiod which is scaled from a unit cube setMass(density * scale.x() * scale.y() * scale.z()); - Vector3r value = m_mass * Vector3r((scale.y() * scale.y() + scale.z() * scale.z()) / 12, (scale.x() * scale.x() + scale.z() * scale.z()) / 12, (scale.x() * scale.x() + scale.z() * scale.z()) / 12); + Vector3r value = m_mass * Vector3r((scale.y() * scale.y() + scale.z() * scale.z()) / 12, (scale.x() * scale.x() + scale.z() * scale.z()) / 12, (scale.x() * scale.x() + scale.y() * scale.y()) / 12); m_inertiaTensor = value; m_inertiaTensorInverse = Vector3r(static_cast(1.0) / value[0], static_cast(1.0) / value[1], static_cast(1.0) / value[2]); } diff --git a/SPlisHSPlasH/Emitter.cpp b/SPlisHSPlasH/Emitter.cpp index 9726e58f..131674e3 100644 --- a/SPlisHSPlasH/Emitter.cpp +++ b/SPlisHSPlasH/Emitter.cpp @@ -48,7 +48,7 @@ Vector3r Emitter::getSize(const Real width, const Real height, const int type) Vector3r size; if (type == 0) { - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { size = { 2 * supportRadius, @@ -67,7 +67,7 @@ Vector3r Emitter::getSize(const Real width, const Real height, const int type) } else { - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { // height and radius of cylinder const Real h = 2 * supportRadius; diff --git a/SPlisHSPlasH/IISPH/SimulationDataIISPH.cpp b/SPlisHSPlasH/IISPH/SimulationDataIISPH.cpp index d9c40995..e2e26ee7 100644 --- a/SPlisHSPlasH/IISPH/SimulationDataIISPH.cpp +++ b/SPlisHSPlasH/IISPH/SimulationDataIISPH.cpp @@ -25,6 +25,7 @@ void SimulationDataIISPH::init() m_pressure.resize(nModels); m_lastPressure.resize(nModels); m_pressureAccel.resize(nModels); + m_density_adv_no_boundary.resize(nModels); for (unsigned int i = 0; i < nModels; i++) { FluidModel *fm = sim->getFluidModel(i); @@ -35,6 +36,7 @@ void SimulationDataIISPH::init() m_pressure[i].resize(fm->numParticles(), 0.0); m_lastPressure[i].resize(fm->numParticles(), 0.0); m_pressureAccel[i].resize(fm->numParticles(), Vector3r::Zero()); + m_density_adv_no_boundary[i].resize(fm->numParticles(), 0.0); } } @@ -52,6 +54,7 @@ void SimulationDataIISPH::cleanup() m_pressure[i].clear(); m_lastPressure[i].clear(); m_pressureAccel[i].clear(); + m_density_adv_no_boundary[i].clear(); } m_aii.clear(); m_dii.clear(); @@ -60,6 +63,7 @@ void SimulationDataIISPH::cleanup() m_pressure.clear(); m_lastPressure.clear(); m_pressureAccel.clear(); + m_density_adv_no_boundary.clear(); } void SimulationDataIISPH::reset() @@ -96,6 +100,7 @@ void SimulationDataIISPH::performNeighborhoodSearchSort() d.sort_field(&m_pressure[i][0]); d.sort_field(&m_lastPressure[i][0]); d.sort_field(&m_pressureAccel[i][0]); + d.sort_field(&m_density_adv_no_boundary[i][0]); } } } diff --git a/SPlisHSPlasH/IISPH/SimulationDataIISPH.h b/SPlisHSPlasH/IISPH/SimulationDataIISPH.h index f3aaef9c..636b1256 100644 --- a/SPlisHSPlasH/IISPH/SimulationDataIISPH.h +++ b/SPlisHSPlasH/IISPH/SimulationDataIISPH.h @@ -24,6 +24,8 @@ namespace SPH std::vector> m_dii; std::vector> m_dij_pj; std::vector> m_density_adv; + // for Gissler2019 strong coupling + std::vector> m_density_adv_no_boundary; std::vector> m_pressure; std::vector> m_lastPressure; std::vector> m_pressureAccel; @@ -108,6 +110,18 @@ namespace SPH m_density_adv[fluidIndex][i] = d; } + FORCE_INLINE const Real getDensityAdvNoBoundary(const unsigned int fluidIndex, const unsigned int i) const { + return m_density_adv_no_boundary[fluidIndex][i]; + } + + FORCE_INLINE Real& getDensityAdvNoBoundary(const unsigned int fluidIndex, const unsigned int i) { + return m_density_adv_no_boundary[fluidIndex][i]; + } + + FORCE_INLINE void setDensityAdvNoBoundary(const unsigned int fluidIndex, const unsigned int i, const Real d) { + m_density_adv_no_boundary[fluidIndex][i] = d; + } + FORCE_INLINE const Real getPressure(const unsigned int fluidIndex, const unsigned int i) const { return m_pressure[fluidIndex][i]; diff --git a/SPlisHSPlasH/IISPH/TimeStepIISPH.cpp b/SPlisHSPlasH/IISPH/TimeStepIISPH.cpp index 55bf8d2c..eb37fcbd 100644 --- a/SPlisHSPlasH/IISPH/TimeStepIISPH.cpp +++ b/SPlisHSPlasH/IISPH/TimeStepIISPH.cpp @@ -9,7 +9,9 @@ #include "SPlisHSPlasH/BoundaryModel_Akinci2012.h" #include "SPlisHSPlasH/BoundaryModel_Koschier2017.h" #include "SPlisHSPlasH/BoundaryModel_Bender2019.h" - +#include "SPlisHSPlasH/StrongCouplingBoundarySolver.h" +#include "Simulator/DynamicBoundarySimulator.h" +#include "SPlisHSPlasH/DynamicRigidBody.h" using namespace SPH; using namespace std; @@ -87,12 +89,20 @@ void TimeStepIISPH::step() STOP_TIMING_AVG; START_TIMING("pressureSolve"); - pressureSolve(); + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { + pressureSolveStrongCoupling(); + } else { + pressureSolve(); + } STOP_TIMING_AVG; for (unsigned int fluidModelIndex = 0; fluidModelIndex < nModels; fluidModelIndex++) integration(fluidModelIndex); + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { + StrongCouplingBoundarySolver::getCurrent()->applyForce(); + } + sim->emitParticles(); sim->animateParticles(); @@ -151,7 +161,7 @@ void TimeStepIISPH::predictAdvection(const unsigned int fluidModelIndex) ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( dii -= bm_neighbor->getVolume(neighborIndex) / density2 * sim->gradW(xi - xj); @@ -202,7 +212,7 @@ void TimeStepIISPH::predictAdvection(const unsigned int fluidModelIndex) densityAdv += h*bm_neighbor->getVolume(neighborIndex) * (vi - vj).dot(sim->gradW(xi - xj)); ); } - else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) { forall_density_maps( Vector3r vj; @@ -217,6 +227,11 @@ void TimeStepIISPH::predictAdvection(const unsigned int fluidModelIndex) bm_neighbor->getPointVelocity(xj, vj); densityAdv += h*Vj * (vi - vj).dot(sim->gradW(xi - xj)); ); + } + else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) + { + // for strong coupling, the density advection due to boundary particles are computed in pressure solve iterations. + m_simulationData.getDensityAdvNoBoundary(fluidModelIndex, i) = densityAdv; } const Real &pressure = m_simulationData.getPressure(fluidModelIndex, i); @@ -245,7 +260,7 @@ void TimeStepIISPH::predictAdvection(const unsigned int fluidModelIndex) ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( const Vector3r kernel = sim->gradW(xi - xj); @@ -302,6 +317,127 @@ void TimeStepIISPH::pressureSolve() INCREASE_COUNTER("IISPH - iterations", static_cast(m_iterations)); } +void TimeStepIISPH::pressureSolveStrongCoupling() { + Simulation* sim = Simulation::getCurrent(); + const unsigned int nFluids = sim->numberOfFluidModels(); + StrongCouplingBoundarySolver* bs = StrongCouplingBoundarySolver::getCurrent(); + const Real dt = TimeManager::getCurrent()->getTimeStepSize(); + Real avg_density_err = 0; + Real avg_density_err_rigid = 0; + m_iterations = 0; + bool chk = false; + + bs->computeContacts(); + bool anyRigidContact = bs->getAllContacts() != 0; + if (anyRigidContact) { + bs->computeDensityAndVolume(); + } + bool rigidSolverConverged = false; + + while ((!chk || !rigidSolverConverged || (m_iterations < m_minIterations)) && (m_iterations < m_maxIterations)) { + chk = true; + rigidSolverConverged = true; + + // fluid-rigid forces + for (unsigned int fluidModelIndex = 0; fluidModelIndex < nFluids; fluidModelIndex++) { + FluidModel* model = sim->getFluidModel(fluidModelIndex); + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int i = 0; i < (int)model->numActiveParticles(); i++) { + const Real density0 = model->getDensity0(); + const Real density_i = model->getDensity(i) / density0; + const Real density2 = density_i * density_i; + const Real dpi = m_simulationData.getPressure(fluidModelIndex, i) / density2; + const Vector3r& xi = model->getPosition(i); + const Vector3r& vi = model->getVelocity(i); + + Vector3r& ai = m_simulationData.getPressureAccel(fluidModelIndex, i); + ai.setZero(); + + // fluid pressure + forall_fluid_neighbors( + const Real density_j = fm_neighbor->getDensity(neighborIndex) / fm_neighbor->getDensity0(); + const Real densityj2 = density_j * density_j; + const Real dpj = m_simulationData.getPressure(pid, neighborIndex) / densityj2; + ai -= fm_neighbor->getVolume(neighborIndex) * (dpi + fm_neighbor->getDensity0() / density0 * dpj) * sim->gradW(xi - xj); + ); + + // fluid-rigid + forall_boundary_neighbors( + const Vector3r a = bm_neighbor->getVolume(neighborIndex) * dpi * sim->gradW(xi - xj); + ai -= a; + bm_neighbor->addForce(xj, model->getMass(i) * a); + ); + } + } + } + + // apply force and torque for computing predicted velocity + sim->getDynamicBoundarySimulator()->updateBoundaryForces(); + + if (anyRigidContact) { + bs->computeSourceTerm(); + bs->computeDiagonalElement(); + avg_density_err_rigid = 0.0; + bs->pressureSolveIteration(avg_density_err_rigid); + if (avg_density_err_rigid > bs->getMaxDensityDeviation()) { + rigidSolverConverged = false; + } + } else { + // compute the predicted velocity and position without rigid-rigid contacts + bs->computeV_s(); + } + + // clear force and torque used to computed predicted velocity + for (int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)->getRigidBodyObject())->clearForceAndTorque(); + } + + // predict density advection using the predicted velocity of fluid and rigid velocities + for (unsigned int fluidModelIndex = 0; fluidModelIndex < nFluids; fluidModelIndex++) { + FluidModel* model = sim->getFluidModel(fluidModelIndex); + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int i = 0; i < (int)model->numActiveParticles(); i++) { + const Vector3r& xi = model->getPosition(i); + const Vector3r& vi = model->getVelocity(i); + const Vector3r& ai = m_simulationData.getPressureAccel(fluidModelIndex, i); + const Vector3r predictedV = vi + ai * dt; + + Real densityAdv = m_simulationData.getDensityAdvNoBoundary(fluidModelIndex, i); + + // density advection considering rigid bodies + forall_boundary_neighbors( + densityAdv += dt * bm_neighbor->getVolume(neighborIndex) * (predictedV - bs->getPredictedVelocity(pid - nFluids, neighborIndex)).dot(sim->gradW(xi - xj)); + ); + m_simulationData.getDensityAdv(fluidModelIndex, i) = densityAdv; + } + } + } + + for (unsigned int i = 0; i < nFluids; i++) { + FluidModel* model = sim->getFluidModel(i); + const Real density0 = model->getDensity0(); + + avg_density_err = 0.0; + pressureSolveIteration(i, avg_density_err); + + // Maximal allowed density fluctuation + const Real eta = m_maxError * static_cast(0.01) * density0; // maxError is given in percent + chk = chk && (avg_density_err <= eta); + } + + m_iterations++; + } + + if (anyRigidContact) { + bs->applyForce(); + } + INCREASE_COUNTER("IISPH - iterations", static_cast(m_iterations)); +} + void TimeStepIISPH::pressureSolveIteration(const unsigned int fluidModelIndex, Real &avg_density_err) { Simulation *sim = Simulation::getCurrent(); @@ -377,7 +513,7 @@ void TimeStepIISPH::pressureSolveIteration(const unsigned int fluidModelIndex, R ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( sum += bm_neighbor->getVolume(neighborIndex) * m_simulationData.getDij_pj(fluidModelIndex, i).dot(sim->gradW(xi - xj)); @@ -492,7 +628,7 @@ void TimeStepIISPH::computePressureAccels(const unsigned int fluidModelIndex) ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( const Vector3r a = bm_neighbor->getVolume(neighborIndex) * dpi * sim->gradW(xi - xj); diff --git a/SPlisHSPlasH/IISPH/TimeStepIISPH.h b/SPlisHSPlasH/IISPH/TimeStepIISPH.h index 77b40292..43779e86 100644 --- a/SPlisHSPlasH/IISPH/TimeStepIISPH.h +++ b/SPlisHSPlasH/IISPH/TimeStepIISPH.h @@ -24,6 +24,7 @@ namespace SPH void predictAdvection(const unsigned int fluidModelIndex); void pressureSolve(); + void pressureSolveStrongCoupling(); void pressureSolveIteration(const unsigned int fluidModelIndex, Real &avg_density_err); void integration(const unsigned int fluidModelIndex); diff --git a/SPlisHSPlasH/PBF/TimeStepPBF.cpp b/SPlisHSPlasH/PBF/TimeStepPBF.cpp index eafb0553..860f5a9e 100644 --- a/SPlisHSPlasH/PBF/TimeStepPBF.cpp +++ b/SPlisHSPlasH/PBF/TimeStepPBF.cpp @@ -251,7 +251,7 @@ void TimeStepPBF::pressureSolveIteration(const unsigned int fluidModelIndex, Rea density += rho; ); } - else // Bender2019 + else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Bender2019) { forall_volume_maps( density += Vj * sim->W(xi - xj); @@ -297,7 +297,7 @@ void TimeStepPBF::pressureSolveIteration(const unsigned int fluidModelIndex, Rea gradC_i -= gradRho; ); } - else // Bender2019 + else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Bender2019) { forall_volume_maps( const Vector3r gradC_j = -Vj * sim->gradW(xi - xj); @@ -360,7 +360,7 @@ void TimeStepPBF::pressureSolveIteration(const unsigned int fluidModelIndex, Rea bm_neighbor->addForce(xj, model->getMass(i) * dx * invH2); ); } - else // Bender2019 + else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Bender2019) { forall_volume_maps( const Vector3r gradC_j = -Vj * sim->gradW(xi - xj); diff --git a/SPlisHSPlasH/Simulation.cpp b/SPlisHSPlasH/Simulation.cpp index 0d40ad35..36a630b8 100644 --- a/SPlisHSPlasH/Simulation.cpp +++ b/SPlisHSPlasH/Simulation.cpp @@ -60,6 +60,7 @@ int Simulation::BOUNDARY_HANDLING_METHOD = -1; int Simulation::ENUM_AKINCI2012 = -1; int Simulation::ENUM_KOSCHIER2017 = -1; int Simulation::ENUM_BENDER2019 = -1; +int Simulation::ENUM_GISSLER2019 = -1; Simulation::Simulation () @@ -266,6 +267,7 @@ void Simulation::initParameters() enumParam->addEnumValue("Akinci et al. 2012", ENUM_AKINCI2012); enumParam->addEnumValue("Koschier and Bender 2017", ENUM_KOSCHIER2017); enumParam->addEnumValue("Bender et al. 2019", ENUM_BENDER2019); + enumParam->addEnumValue("Gissler et al. 2019", ENUM_GISSLER2019); enumParam->setReadOnly(true); } @@ -381,7 +383,7 @@ void Simulation::setKernel(int val) m_kernelFct = WendlandQuinticC2Kernel2D::W; } } - if (getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) updateBoundaryVolume(); } @@ -430,7 +432,7 @@ void Simulation::updateTimeStepSizeCFL() } // boundary particles - if (getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { for (unsigned int i = 0; i < numberOfBoundaryModels(); i++) { @@ -509,7 +511,7 @@ void Simulation::reset() for (unsigned int i = 0; i < numberOfBoundaryModels(); i++) getBoundaryModel(i)->reset(); - if (getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { + if (getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { updateBoundaryVolume(); StrongCouplingBoundarySolver::getCurrent()->reset(); } diff --git a/SPlisHSPlasH/Simulation.h b/SPlisHSPlasH/Simulation.h index 62123a2c..67ddcff4 100644 --- a/SPlisHSPlasH/Simulation.h +++ b/SPlisHSPlasH/Simulation.h @@ -170,7 +170,7 @@ namespace SPH { class DynamicBoundarySimulator; enum class SimulationMethods { WCSPH = 0, PCISPH, PBF, IISPH, DFSPH, PF, ICSPH, NumSimulationMethods }; - enum class BoundaryHandlingMethods { Akinci2012 = 0, Koschier2017, Bender2019, NumSimulationMethods }; + enum class BoundaryHandlingMethods { Akinci2012 = 0, Koschier2017, Bender2019, Gissler2019, NumSimulationMethods }; /** \brief Class to manage the current simulation time and the time step size. * This class is a singleton. @@ -222,6 +222,7 @@ namespace SPH static int ENUM_AKINCI2012; static int ENUM_KOSCHIER2017; static int ENUM_BENDER2019; + static int ENUM_GISSLER2019; typedef PrecomputedKernel PrecomputedCubicKernel; diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp index e5a41e42..9b767215 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp @@ -2,6 +2,7 @@ #include "StrongCouplingBoundarySolver.h" #include "TimeManager.h" #include "DynamicRigidBody.h" +#include "Simulator/DynamicBoundarySimulator.h" using namespace SPH; @@ -19,20 +20,20 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_diagonalElement(), m_artificialVolume(), m_lastPressure(), - m_predictVelocity(), - m_predictPosition(), + m_predictedVelocity(), + m_predictedPosition(), m_v_rr_body(), m_omega_rr_body(), m_bodyContacts() { m_maxIterations = 100; - m_minIterations = 20; + m_minIterations = 2; m_maxDensityDeviation = 0.001; Simulation* sim = Simulation::getCurrent(); const unsigned int nBoundaries = sim->numberOfBoundaryModels(); - m_restDensity = 1000; + m_restDensity = 1; m_density.resize(nBoundaries); m_v_s.resize(nBoundaries); m_s.resize(nBoundaries); @@ -44,11 +45,12 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_pressureGrad.resize(nBoundaries); m_artificialVolume.resize(nBoundaries); m_lastPressure.resize(nBoundaries); - m_predictVelocity.resize(nBoundaries); - m_predictPosition.resize(nBoundaries); + m_predictedVelocity.resize(nBoundaries); + m_predictedPosition.resize(nBoundaries); m_v_rr_body.resize(nBoundaries, Vector3r::Zero()); m_omega_rr_body.resize(nBoundaries, Vector3r::Zero()); m_bodyContacts.resize(nBoundaries, 0); + m_contactsAllBodies = 0; for (unsigned int i = 0; i < nBoundaries; i++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModel(i)); @@ -63,8 +65,8 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_pressureGrad[i].resize(bm->numberOfParticles(), Vector3r::Zero()); m_artificialVolume[i].resize(bm->numberOfParticles(), 0.0); m_lastPressure[i].resize(bm->numberOfParticles(), 0.0); - m_predictVelocity[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - m_predictPosition[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_predictedVelocity[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_predictedPosition[i].resize(bm->numberOfParticles(), Vector3r::Zero()); bm->addField({ "density", FieldType::Scalar, [this, i](const unsigned int j) -> Real* { return &getDensity(i, j); } }); bm->addField({ "sourceTerm", FieldType::Scalar, [this, i](const unsigned int j)->Real* {return &getSourceTerm(i,j); } }); @@ -94,8 +96,8 @@ void SPH::StrongCouplingBoundarySolver::resize(unsigned int size) { m_pressureGrad.resize(nBoundaries); m_artificialVolume.resize(nBoundaries); m_lastPressure.resize(nBoundaries); - m_predictVelocity.resize(nBoundaries); - m_predictPosition.resize(nBoundaries); + m_predictedVelocity.resize(nBoundaries); + m_predictedPosition.resize(nBoundaries); m_v_rr_body.resize(nBoundaries, Vector3r::Zero()); m_omega_rr_body.resize(nBoundaries, Vector3r::Zero()); m_bodyContacts.resize(nBoundaries, 0); @@ -113,8 +115,8 @@ void SPH::StrongCouplingBoundarySolver::resize(unsigned int size) { m_pressureGrad[i].resize(bm->numberOfParticles(), Vector3r::Zero()); m_artificialVolume[i].resize(bm->numberOfParticles(), 0.0); m_lastPressure[i].resize(bm->numberOfParticles(), 0.0); - m_predictVelocity[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - m_predictPosition[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_predictedVelocity[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + m_predictedPosition[i].resize(bm->numberOfParticles(), Vector3r::Zero()); } } @@ -136,8 +138,8 @@ void SPH::StrongCouplingBoundarySolver::reset() { m_pressureGrad[i][j] = Vector3r::Zero(); m_artificialVolume[i][j] = 0.0; m_lastPressure[i][j] = 0.0; - m_predictVelocity[i][j] = Vector3r::Zero(); - m_predictPosition[i][j] = Vector3r::Zero(); + m_predictedVelocity[i][j] = Vector3r::Zero(); + m_predictedPosition[i][j] = Vector3r::Zero(); } m_v_rr_body[i] = Vector3r::Zero(); m_omega_rr_body[i] = Vector3r::Zero(); @@ -159,8 +161,8 @@ StrongCouplingBoundarySolver::~StrongCouplingBoundarySolver() { m_pressureGrad[i].clear(); m_artificialVolume[i].clear(); m_lastPressure[i].clear(); - m_predictVelocity[i].clear(); - m_predictPosition[i].clear(); + m_predictedVelocity[i].clear(); + m_predictedPosition[i].clear(); } m_density.clear(); m_v_s.clear(); @@ -173,8 +175,8 @@ StrongCouplingBoundarySolver::~StrongCouplingBoundarySolver() { m_pressureGrad.clear(); m_artificialVolume.clear(); m_lastPressure.clear(); - m_predictVelocity.clear(); - m_predictPosition.clear(); + m_predictedVelocity.clear(); + m_predictedPosition.clear(); m_v_rr_body.clear(); m_omega_rr_body.clear(); m_bodyContacts.clear(); @@ -211,8 +213,8 @@ void StrongCouplingBoundarySolver::performNeighborhoodSearchSort() { d.sort_field(&m_pressureGrad[i][0]); d.sort_field(&m_artificialVolume[i][0]); d.sort_field(&m_lastPressure[i][0]); - d.sort_field(&m_predictVelocity[i][0]); - d.sort_field(&m_predictPosition[i][0]); + d.sort_field(&m_predictedVelocity[i][0]); + d.sort_field(&m_predictedPosition[i][0]); } } } @@ -262,7 +264,7 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - //if (rb->isDynamic()) { + if (rb->isDynamic()) { // compute density for particle r Real particleDensity = getRestDensity() * bm->getVolume(r) * sim->W_zero(); // iterate over all rigid bodies @@ -281,16 +283,15 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { } else { setArtificialVolume(bmIndex, r, gamma * bm->getVolume(r)); } - //} else { - // setArtificialVolume(bmIndex, r, bm->getVolume(r)); - //} + } else { + setArtificialVolume(bmIndex, r, bm->getVolume(r)); + } } } } } void StrongCouplingBoundarySolver::computeV_s() { - // Use dynamic boundary simulator and Akinci2012 Simulation* sim = Simulation::getCurrent(); TimeManager* tm = TimeManager::getCurrent(); const Real dt = tm->getTimeStepSize(); @@ -300,6 +301,9 @@ void StrongCouplingBoundarySolver::computeV_s() { for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + Vector3r gravForce = rb->getMass() * Vector3r(sim->getVecValue(Simulation::GRAVITATION)); + // the rb->getForce() contains only fluid-rigid forces + Vector3r F_R = rb->getForce() + gravForce; if (rb->isDynamic()) { #pragma omp parallel default(shared) { @@ -307,11 +311,12 @@ void StrongCouplingBoundarySolver::computeV_s() { for (int r = 0; r < bm->numberOfParticles(); r++) { Vector3r pos = bm->getPosition(r) - rb->getPosition(); // compute v_s - Vector3r gravForce = rb->getMass() * Vector3r(sim->getVecValue(Simulation::GRAVITATION)); - // the rb->getForce() contains only fluid-rigid forces - Vector3r F_R = rb->getForce() + gravForce; setV_s(boundaryPointSetIndex - nFluids, r, rb->getVelocity() + dt * rb->getInvMass() * F_R + (rb->getAngularVelocity() + rb->getInertiaTensorInverseW() * (dt * rb->getTorque() + dt * (rb->getInertiaTensorW() * rb->getAngularVelocity()).cross(rb->getAngularVelocity()))).cross(pos)); + // compute the predicted velocity first here, since for cases without rigid-rigid contacts, the computeSourceTermRHS will not be called and V_rr is 0 + // but we still need the predicted velocity for fluid-rigid strong coupling + setPredictedVelocity(boundaryPointSetIndex - nFluids, r, getV_s(boundaryPointSetIndex - nFluids, r)); + setPredictedPosition(boundaryPointSetIndex - nFluids, r, bm->getPosition(r) + (bm->getVelocity(r) + getV_s(boundaryPointSetIndex - nFluids, r)) / 2 * dt); } } } @@ -419,7 +424,7 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { } } b_r = -b_r; - //setDiagonalElement(index_r, r, b_r > 0 ? b_r : 0); + //setDiagonalElement(index_r, r, b_r < 0 ? b_r : 0); setDiagonalElement(index_r, r, b_r); } } @@ -442,7 +447,7 @@ void SPH::StrongCouplingBoundarySolver::computeSourceTermRHSForBody(const unsign const unsigned int nFluids = sim->numberOfFluidModels(); BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - // compute pressure gradient, v_rr and omega_rr for rigid body + // compute pressure gradient, v_rr and omega_rr for rigid bodies int bmIndex = boundaryPointSetIndex - nFluids; DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); Real vx = 0; @@ -500,7 +505,8 @@ void SPH::StrongCouplingBoundarySolver::computeSourceTermRHSForBody(const unsign for (int r = 0; r < bm->numberOfParticles(); r++) { Vector3r pos = bm->getPosition(r) - rb->getPosition(); setV_rr(bmIndex, r, getV_rr_body(bmIndex) + getOmega_rr_body(bmIndex).cross(pos)); - setPredictVelocity(bmIndex, r, getV_rr(bmIndex, r) + getV_s(bmIndex, r)); + setPredictedVelocity(bmIndex, r, getV_rr(bmIndex, r) + getV_s(bmIndex, r)); + setPredictedPosition(bmIndex, r, bm->getPosition(r) + (bm->getVelocity(r) + getPredictedVelocity(bmIndex, r)) / 2 * dt); Real minus_rho_div_v_rr = 0.0; const Vector3r v_rr_r = getV_rr(bmIndex, r); @@ -561,9 +567,7 @@ void StrongCouplingBoundarySolver::pressureSolveIteration(Real& avgDensityDeviat void StrongCouplingBoundarySolver::applyForce() { Simulation* sim = Simulation::getCurrent(); - const Real dt = TimeManager::getCurrent()->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); - for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); int bmIndex = boundaryPointSetIndex - nFluids; @@ -571,13 +575,12 @@ void StrongCouplingBoundarySolver::applyForce() { if (rb->isDynamic()) { #pragma omp parallel default(shared) { - #pragma omp for schedule(static) + #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { const Vector3r f = -getArtificialVolume(bmIndex, r) * getPressureGrad(bmIndex, r); - if (f != Vector3r::Zero()) { - bm->addForce(bm->getPosition(r), f); - } + bm->addForce(bm->getPosition(r), f); setPressure(bmIndex, r, static_cast(0.0)); + setPressureGrad(bmIndex, r, Vector3r::Zero()); } } } diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.h b/SPlisHSPlasH/StrongCouplingBoundarySolver.h index b9c7a572..37e4e8d0 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.h +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.h @@ -20,8 +20,8 @@ namespace SPH { std::vector> m_s; // source term std::vector> m_pressureGrad; std::vector> m_v_rr; - std::vector> m_predictVelocity; - std::vector> m_predictPosition; + std::vector> m_predictedVelocity; + std::vector> m_predictedPosition; std::vector> m_minus_rho_div_v_s; std::vector> m_minus_rho_div_v_rr; // RHS to the source term std::vector> m_diagonalElement; // diagonal element for jacobi iteration @@ -32,8 +32,10 @@ namespace SPH { static StrongCouplingBoundarySolver* current; + // only used in WCSPH unsigned int m_maxIterations; unsigned int m_minIterations; + Real m_maxDensityDeviation; public: @@ -44,13 +46,11 @@ namespace SPH { void resize(unsigned int size); void computeContacts(); void computeDensityAndVolume(); - void computePressureGrad(); void computeV_s(); void computeSourceTermRHS(); void computeSourceTermRHSForBody(const unsigned int& boundaryPointSetIndex); void computeSourceTerm(); void computeDiagonalElement(); - void computeFriction(); void pressureSolveIteration(Real& avgDensityDeviation); void applyForce(); void performNeighborhoodSearchSort(); @@ -151,28 +151,28 @@ namespace SPH { m_v_rr[rigidBodyIndex][i] = value; } - FORCE_INLINE Vector3r& getPredictVelocity(const unsigned int& rigidBodyIndex, const unsigned int i) { - return m_predictVelocity[rigidBodyIndex][i]; + FORCE_INLINE Vector3r& getPredictedVelocity(const unsigned int& rigidBodyIndex, const unsigned int i) { + return m_predictedVelocity[rigidBodyIndex][i]; } - FORCE_INLINE const Vector3r& getPredictVelocity(const unsigned int& rigidBodyIndex, const unsigned int i) const { - return m_predictVelocity[rigidBodyIndex][i]; + FORCE_INLINE const Vector3r& getPredictedVelocity(const unsigned int& rigidBodyIndex, const unsigned int i) const { + return m_predictedVelocity[rigidBodyIndex][i]; } - FORCE_INLINE void setPredictVelocity(const unsigned int& rigidBodyIndex, const unsigned int i, const Vector3r& value) { - m_predictVelocity[rigidBodyIndex][i] = value; + FORCE_INLINE void setPredictedVelocity(const unsigned int& rigidBodyIndex, const unsigned int i, const Vector3r& value) { + m_predictedVelocity[rigidBodyIndex][i] = value; } - FORCE_INLINE Vector3r& getPredictPosition(const unsigned int& rigidBodyIndex, const unsigned int i) { - return m_predictPosition[rigidBodyIndex][i]; + FORCE_INLINE Vector3r& getPredictedPosition(const unsigned int& rigidBodyIndex, const unsigned int i) { + return m_predictedPosition[rigidBodyIndex][i]; } - FORCE_INLINE const Vector3r& getPredictPosition(const unsigned int& rigidBodyIndex, const unsigned int i) const { - return m_predictPosition[rigidBodyIndex][i]; + FORCE_INLINE const Vector3r& getPredictedPosition(const unsigned int& rigidBodyIndex, const unsigned int i) const { + return m_predictedPosition[rigidBodyIndex][i]; } - FORCE_INLINE void setPredictPosition(const unsigned int& rigidBodyIndex, const unsigned int i, const Vector3r& value) { - m_predictPosition[rigidBodyIndex][i] = value; + FORCE_INLINE void setPredictedPosition(const unsigned int& rigidBodyIndex, const unsigned int i, const Vector3r& value) { + m_predictedPosition[rigidBodyIndex][i] = value; } FORCE_INLINE Vector3r& getPressureGrad(const unsigned int& rigidBodyIndex, const unsigned int i) { diff --git a/SPlisHSPlasH/SurfaceTension/SurfaceTension_Akinci2013.cpp b/SPlisHSPlasH/SurfaceTension/SurfaceTension_Akinci2013.cpp index 867919c5..d531679a 100644 --- a/SPlisHSPlasH/SurfaceTension/SurfaceTension_Akinci2013.cpp +++ b/SPlisHSPlasH/SurfaceTension/SurfaceTension_Akinci2013.cpp @@ -109,7 +109,7 @@ void SurfaceTension_Akinci2013::step() ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { forall_boundary_neighbors( // adhesion force diff --git a/SPlisHSPlasH/SurfaceTension/SurfaceTension_Becker2007.cpp b/SPlisHSPlasH/SurfaceTension/SurfaceTension_Becker2007.cpp index 303d556d..326d4742 100644 --- a/SPlisHSPlasH/SurfaceTension/SurfaceTension_Becker2007.cpp +++ b/SPlisHSPlasH/SurfaceTension/SurfaceTension_Becker2007.cpp @@ -56,7 +56,7 @@ void SurfaceTension_Becker2007::step() ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( const Vector3r xixj = xi - xj; diff --git a/SPlisHSPlasH/SurfaceTension/SurfaceTension_He2014.cpp b/SPlisHSPlasH/SurfaceTension/SurfaceTension_He2014.cpp index e9187385..01142b24 100644 --- a/SPlisHSPlasH/SurfaceTension/SurfaceTension_He2014.cpp +++ b/SPlisHSPlasH/SurfaceTension/SurfaceTension_He2014.cpp @@ -63,7 +63,7 @@ void SurfaceTension_He2014::step() ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( ci += bm_neighbor->getVolume(neighborIndex) * sim->W(xi - xj); @@ -132,7 +132,7 @@ void SurfaceTension_He2014::step() ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( const Vector3r a = factorb*bm_neighbor->getVolume(neighborIndex) * gradC2_i * sim->gradW(xi - xj); diff --git a/SPlisHSPlasH/TimeStep.cpp b/SPlisHSPlasH/TimeStep.cpp index e4353878..b65e27ed 100644 --- a/SPlisHSPlasH/TimeStep.cpp +++ b/SPlisHSPlasH/TimeStep.cpp @@ -113,7 +113,7 @@ void TimeStep::computeDensities(const unsigned int fluidModelIndex) ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors_avx( const Scalarf8 V_avx = convert_zero(&sim->getNeighborList(fluidModelIndex, pid, i)[j], &bm_neighbor->getVolume(0), count); diff --git a/SPlisHSPlasH/Utilities/SceneLoader.cpp b/SPlisHSPlasH/Utilities/SceneLoader.cpp index d1c55150..b9b31bb0 100644 --- a/SPlisHSPlasH/Utilities/SceneLoader.cpp +++ b/SPlisHSPlasH/Utilities/SceneLoader.cpp @@ -44,6 +44,9 @@ void SceneLoader::readScene(const char *fileName, Scene &scene) scene.sim2D = false; readValue(config["sim2D"], scene.sim2D); + + scene.boundaryHandlingMethod = 0; + readValue(config["boundaryHandlingMethod"], scene.boundaryHandlingMethod); } ////////////////////////////////////////////////////////////////////////// diff --git a/SPlisHSPlasH/Utilities/SceneLoader.h b/SPlisHSPlasH/Utilities/SceneLoader.h index a404bd9e..9cceb17c 100644 --- a/SPlisHSPlasH/Utilities/SceneLoader.h +++ b/SPlisHSPlasH/Utilities/SceneLoader.h @@ -30,6 +30,7 @@ namespace Utilities std::vector materials; Real particleRadius; bool sim2D; + int boundaryHandlingMethod; }; nlohmann::json& getJSONData() { return m_jsonData; }; diff --git a/SPlisHSPlasH/Viscosity/Viscosity_Bender2017.cpp b/SPlisHSPlasH/Viscosity/Viscosity_Bender2017.cpp index 22ad1954..a78c2fb7 100644 --- a/SPlisHSPlasH/Viscosity/Viscosity_Bender2017.cpp +++ b/SPlisHSPlasH/Viscosity/Viscosity_Bender2017.cpp @@ -201,7 +201,7 @@ void Viscosity_Bender2017::step() ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( const Vector3r &vj = bm_neighbor->getVelocity(neighborIndex); diff --git a/SPlisHSPlasH/Viscosity/Viscosity_Peer2015.cpp b/SPlisHSPlasH/Viscosity/Viscosity_Peer2015.cpp index fb51e952..ca098070 100644 --- a/SPlisHSPlasH/Viscosity/Viscosity_Peer2015.cpp +++ b/SPlisHSPlasH/Viscosity/Viscosity_Peer2015.cpp @@ -89,7 +89,7 @@ void Viscosity_Peer2015::computeDensities() ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( // Boundary: Akinci2012 diff --git a/SPlisHSPlasH/Viscosity/Viscosity_Peer2016.cpp b/SPlisHSPlasH/Viscosity/Viscosity_Peer2016.cpp index 64665ac7..96647c58 100644 --- a/SPlisHSPlasH/Viscosity/Viscosity_Peer2016.cpp +++ b/SPlisHSPlasH/Viscosity/Viscosity_Peer2016.cpp @@ -114,7 +114,7 @@ void Viscosity_Peer2016::computeDensities() ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( // Boundary: Akinci2012 diff --git a/SPlisHSPlasH/Viscosity/Viscosity_Standard.cpp b/SPlisHSPlasH/Viscosity/Viscosity_Standard.cpp index f91671ff..1fec59e1 100644 --- a/SPlisHSPlasH/Viscosity/Viscosity_Standard.cpp +++ b/SPlisHSPlasH/Viscosity/Viscosity_Standard.cpp @@ -94,7 +94,7 @@ void Viscosity_Standard::step() ////////////////////////////////////////////////////////////////////////// if (m_boundaryViscosity != 0.0) { - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors_avx( const Vector3f8 vj_avx = convertVec_zero(&sim->getNeighborList(fluidModelIndex, pid, i)[j], &bm_neighbor->getVelocity(0), count); diff --git a/SPlisHSPlasH/Viscosity/Viscosity_Takahashi2015.cpp b/SPlisHSPlasH/Viscosity/Viscosity_Takahashi2015.cpp index 9a72f5e5..3b9425e8 100644 --- a/SPlisHSPlasH/Viscosity/Viscosity_Takahashi2015.cpp +++ b/SPlisHSPlasH/Viscosity/Viscosity_Takahashi2015.cpp @@ -214,7 +214,7 @@ void Viscosity_Takahashi2015::step() ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( const Vector3r &vj = bm_neighbor->getVelocity(neighborIndex); diff --git a/SPlisHSPlasH/Viscosity/Viscosity_Weiler2018.cpp b/SPlisHSPlasH/Viscosity/Viscosity_Weiler2018.cpp index 56469502..83279e03 100644 --- a/SPlisHSPlasH/Viscosity/Viscosity_Weiler2018.cpp +++ b/SPlisHSPlasH/Viscosity/Viscosity_Weiler2018.cpp @@ -130,7 +130,7 @@ void Viscosity_Weiler2018::matrixVecProd(const Real* vec, Real *result, void *us ////////////////////////////////////////////////////////////////////////// if (mub != 0.0) { - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors_avx( const Vector3f8 vj_avx = convertVec_zero(&sim->getNeighborList(fluidModelIndex, pid, i)[j], &bm_neighbor->getVelocity(0), count); @@ -492,7 +492,7 @@ void Viscosity_Weiler2018::diagonalMatrixElement(const unsigned int i, Matrix3r ////////////////////////////////////////////////////////////////////////// if (mub != 0.0) { - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors_avx( const Vector3f8 xixj = xi_avx - xj_avx; @@ -636,7 +636,7 @@ void Viscosity_Weiler2018::diagonalMatrixElement(const unsigned int i, Matrix3r ////////////////////////////////////////////////////////////////////////// if (mub != 0.0) { - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( const Vector3r xixj = xi - xj; @@ -779,7 +779,7 @@ void Viscosity_Weiler2018::diagonalMatrixElement(const unsigned int i, Vector3r ////////////////////////////////////////////////////////////////////////// if (mub != 0.0) { - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( const Vector3r xixj = xi - xj; @@ -954,7 +954,7 @@ void Viscosity_Weiler2018::applyForces(const VectorXr &x) ////////////////////////////////////////////////////////////////////////// if (mub != 0.0) { - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( const Vector3r &vj = bm_neighbor->getVelocity(neighborIndex); @@ -1118,7 +1118,7 @@ void Viscosity_Weiler2018::computeRHS(VectorXr &b, VectorXr &g) ////////////////////////////////////////////////////////////////////////// if (mub != 0.0) { - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( const Vector3r &vj = bm_neighbor->getVelocity(neighborIndex); diff --git a/SPlisHSPlasH/Vorticity/MicropolarModel_Bender2017.cpp b/SPlisHSPlasH/Vorticity/MicropolarModel_Bender2017.cpp index 52f60465..c6919f25 100644 --- a/SPlisHSPlasH/Vorticity/MicropolarModel_Bender2017.cpp +++ b/SPlisHSPlasH/Vorticity/MicropolarModel_Bender2017.cpp @@ -135,7 +135,7 @@ void MicropolarModel_Bender2017::step() ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors_avx( const Vector3f8 vj_avx = convertVec_zero(&sim->getNeighborList(fluidModelIndex, pid, i)[j], &bm_neighbor->getVelocity(0), count); diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index 50b8d4aa..3e1ca7c2 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -93,6 +93,7 @@ void TimeStepWCSPH::step() } sim->computeNonPressureForces(); + sim->updateTimeStepSize(); for (unsigned int fluidModelIndex = 0; fluidModelIndex < nModels; fluidModelIndex++) { @@ -112,12 +113,10 @@ void TimeStepWCSPH::step() computePressureAccels(fluidModelIndex); } - if (sim->getDynamicBoundarySimulator() != nullptr && sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { + if (sim->getDynamicBoundarySimulator() != nullptr && sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { solveRigidRigidContacts(); } - sim->updateTimeStepSize(); - for (unsigned int fluidModelIndex = 0; fluidModelIndex < nModels; fluidModelIndex++) { FluidModel *model = sim->getFluidModel(fluidModelIndex); @@ -142,11 +141,6 @@ void TimeStepWCSPH::step() sim->emitParticles(); sim->animateParticles(); - // Only for strong coupling method with BoundaryModel_Akinci2012 - if (sim->getDynamicBoundarySimulator() != nullptr && sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { - sim->getDynamicBoundarySimulator()->timeStepStrongCoupling(); - } - // Compute new time tm->setTime(tm->getTime() + h); } @@ -192,7 +186,7 @@ void TimeStepWCSPH::computePressureAccels(const unsigned int fluidModelIndex) { // Boundary ////////////////////////////////////////////////////////////////////////// const Real dpj = m_simulationData.getPressure(fluidModelIndex, i) / (density0 * density0); - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( const Vector3r a = density0 * bm_neighbor->getVolume(neighborIndex) * (dpi + dpj) * sim->gradW(xi - xj); ai -= a; @@ -220,14 +214,14 @@ void TimeStepWCSPH::solveRigidRigidContacts() { const Real dt = TimeManager::getCurrent()->getTimeStepSize(); const unsigned int nFluids = sim->numberOfFluidModels(); StrongCouplingBoundarySolver* bs = StrongCouplingBoundarySolver::getCurrent(); - - bs->computeDensityAndVolume(); - + sim->getDynamicBoundarySimulator()->updateBoundaryForces(); // check whehter there is any collisions bs->computeContacts(); if (bs->getAllContacts() == 0) { return; } + + bs->computeDensityAndVolume(); bs->computeDiagonalElement(); bs->computeSourceTerm(); Real avgDensityDeviation = 1.0; @@ -236,12 +230,11 @@ void TimeStepWCSPH::solveRigidRigidContacts() { while ((avgDensityDeviation > bs->getMaxDensityDeviation() && iterations < bs->getMaxIterations()) || iterations < bs->getMinIterations()) { avgDensityDeviation = 0.0; bs->pressureSolveIteration(avgDensityDeviation); - std::cout << avgDensityDeviation << std::endl; + //std::cout << avgDensityDeviation << std::endl; iterations++; } - std::cout << "------------------------------" << std::endl; + //std::cout << "------------------------------" << std::endl; bs->applyForce(); - } void TimeStepWCSPH::performNeighborhoodSearch() diff --git a/SPlisHSPlasH/XSPH.cpp b/SPlisHSPlasH/XSPH.cpp index 1559161d..98e6f253 100644 --- a/SPlisHSPlasH/XSPH.cpp +++ b/SPlisHSPlasH/XSPH.cpp @@ -98,7 +98,7 @@ void XSPH::step() ////////////////////////////////////////////////////////////////////////// if (m_boundaryCoefficient != 0.0) { - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( const Vector3r &vj = bm_neighbor->getVelocity(neighborIndex); diff --git a/Simulator/DynamicBoundarySimulator.cpp b/Simulator/DynamicBoundarySimulator.cpp index 497a1437..943eb20f 100644 --- a/Simulator/DynamicBoundarySimulator.cpp +++ b/Simulator/DynamicBoundarySimulator.cpp @@ -58,7 +58,7 @@ void DynamicBoundarySimulator::initBoundaryData() { MeshImport::importMesh(meshFileName, geo, Vector3r::Zero(), Matrix3r::Identity(), scene.boundaryModels[i]->scale); std::vector boundaryParticles; - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { // if a samples file is given, use this one if (scene.boundaryModels[i]->samplesFile != "") { string particleFileName = scene_path + "/" + scene.boundaryModels[i]->samplesFile; @@ -134,7 +134,7 @@ void DynamicBoundarySimulator::initBoundaryData() { rb->initBody(scene.boundaryModels[i]->density, scene.boundaryModels[i]->dynamic, scene.boundaryModels[i]->translation, q, scene.boundaryModels[i]->scale, scene.boundaryModels[i]->velocity, scene.boundaryModels[i]->friction); - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { BoundaryModel_Akinci2012* bm = new BoundaryModel_Akinci2012(); bm->initModel(rb, static_cast(boundaryParticles.size()), &boundaryParticles[0]); sim->addBoundaryModel(bm); @@ -161,7 +161,7 @@ void DynamicBoundarySimulator::initBoundaryData() { void DynamicBoundarySimulator::deferredInit() { Simulation* sim = Simulation::getCurrent(); sim->performNeighborhoodSearchSort(); - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { m_base->updateBoundaryParticles(true); Simulation::getCurrent()->updateBoundaryVolume(); } else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) @@ -177,47 +177,26 @@ void DynamicBoundarySimulator::deferredInit() { void DynamicBoundarySimulator::timeStep() { Simulation* sim = Simulation::getCurrent(); - if (sim->getBoundaryHandlingMethod() != BoundaryHandlingMethods::Akinci2012) { - updateBoundaryForces(); - const unsigned int nObjects = sim->numberOfBoundaryModels(); - #pragma omp parallel for - for (int i = 0; i < nObjects; i++) { - BoundaryModel* bm = sim->getBoundaryModel(i); - RigidBodyObject* rbo = bm->getRigidBodyObject(); - if (rbo->isDynamic()) { - DynamicRigidBody* drb = dynamic_cast(rbo); - drb->timeStep(); - // Apply damping - drb->setVelocity(drb->getVelocity() * (static_cast(1.0) - m_dampingCoeff)); - drb->setAngularVelocity(drb->getAngularVelocity() * (static_cast(1.0) - m_dampingCoeff)); - } + updateBoundaryForces(); + const unsigned int nObjects = sim->numberOfBoundaryModels(); + #pragma omp parallel for + for (int i = 0; i < nObjects; i++) { + BoundaryModel* bm = sim->getBoundaryModel(i); + RigidBodyObject* rbo = bm->getRigidBodyObject(); + if (rbo->isDynamic()) { + DynamicRigidBody* drb = dynamic_cast(rbo); + drb->timeStep(); + // Apply damping + drb->setVelocity(drb->getVelocity() * (static_cast(1.0) - m_dampingCoeff)); + drb->setAngularVelocity(drb->getAngularVelocity() * (static_cast(1.0) - m_dampingCoeff)); } - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) - m_base->updateDMVelocity(); - else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Bender2019) - m_base->updateVMVelocity(); } -} - -void DynamicBoundarySimulator::timeStepStrongCoupling() { - Simulation* sim = Simulation::getCurrent(); - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { - updateBoundaryForces(); //this is already used to compute the source term - const unsigned int nObjects = sim->numberOfBoundaryModels(); - #pragma omp parallel for - for (int i = 0; i < nObjects; i++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModel(i)); - RigidBodyObject* rbo = bm->getRigidBodyObject(); - if (rbo->isDynamic()) { - DynamicRigidBody* drb = dynamic_cast(rbo); - drb->timeStep(); - // Apply damping - drb->setVelocity(drb->getVelocity() * (static_cast(1.0) - m_dampingCoeff)); - drb->setAngularVelocity(drb->getAngularVelocity() * (static_cast(1.0) - m_dampingCoeff)); - } - } + if(sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) m_base->updateBoundaryParticles(false); - } + else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) + m_base->updateDMVelocity(); + else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Bender2019) + m_base->updateVMVelocity(); } void DynamicBoundarySimulator::reset() { @@ -229,7 +208,7 @@ void DynamicBoundarySimulator::reset() { } } - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) m_base->updateBoundaryParticles(true); else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) m_base->updateDMVelocity(); diff --git a/Simulator/DynamicBoundarySimulator.h b/Simulator/DynamicBoundarySimulator.h index f537363e..3536dbf3 100644 --- a/Simulator/DynamicBoundarySimulator.h +++ b/Simulator/DynamicBoundarySimulator.h @@ -26,7 +26,6 @@ namespace SPH { virtual void deferredInit(); virtual void timeStep(); - void timeStepStrongCoupling(); virtual void reset(); FORCE_INLINE const Real& getDampingCoeff() const { diff --git a/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp b/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp index 1d2d820d..1f36b5ee 100644 --- a/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp +++ b/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp @@ -507,14 +507,14 @@ void Simulator_GUI_imgui::initSimulationParameterGUI() DynamicBoundarySimulator* simulator = sim->getDynamicBoundarySimulator(); // Fields for all boundary models { - imguiParameters::imguiNumericParameter* damping = new imguiParameters::imguiNumericParameter(); - damping->description = "Damping of the system"; - damping->label = "Damping"; - damping->getFct = [simulator]()->Real {return simulator->getDampingCoeff(); }; - damping->setFct = [simulator](Real v) {simulator->setDampingCoeff(v); }; - imguiParameters::addParam("Boundary Model", "General", damping); - - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) { + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { + imguiParameters::imguiNumericParameter* damping = new imguiParameters::imguiNumericParameter(); + damping->description = "Damping of the system"; + damping->label = "Damping"; + damping->getFct = [simulator]()->Real {return simulator->getDampingCoeff(); }; + damping->setFct = [simulator](Real v) {simulator->setDampingCoeff(v); }; + imguiParameters::addParam("Boundary Model", "General", damping); + StrongCouplingBoundarySolver* bs = StrongCouplingBoundarySolver::getCurrent(); imguiParameters::imguiNumericParameter* maxIteration = new imguiParameters::imguiNumericParameter; @@ -740,7 +740,7 @@ void Simulator_GUI_imgui::renderBoundary() const int renderWalls = base->getValue(SimulatorBase::RENDER_WALLS); if (((renderWalls == 1) || (renderWalls == 2)) && - (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012)) + (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019)) { for (int body = sim->numberOfBoundaryModels() - 1; body >= 0; body--) { diff --git a/Simulator/SimulatorBase.cpp b/Simulator/SimulatorBase.cpp index 046df908..c8fc04e2 100644 --- a/Simulator/SimulatorBase.cpp +++ b/Simulator/SimulatorBase.cpp @@ -414,6 +414,7 @@ void SimulatorBase::init(int argc, char **argv, const std::string &windowName) ////////////////////////////////////////////////////////////////////////// // init boundary simulation ////////////////////////////////////////////////////////////////////////// + m_boundaryHandlingMethod = scene.boundaryHandlingMethod; m_isStaticScene = true; for (unsigned int i = 0; i < scene.boundaryModels.size(); i++) { @@ -431,8 +432,12 @@ void SimulatorBase::init(int argc, char **argv, const std::string &windowName) else { LOG_INFO << "Initialize dynamic boundary simulation"; - //m_boundarySimulator = new PBDBoundarySimulator(this); - m_boundarySimulator = new DynamicBoundarySimulator(this); + if (m_boundaryHandlingMethod == 3) { + // Gissler 2019 + m_boundarySimulator = new DynamicBoundarySimulator(this); + } else { + m_boundarySimulator = new PBDBoundarySimulator(this); + } } initExporters(); @@ -532,6 +537,7 @@ void SimulatorBase::initSimulation() #endif }); } + updateScalarField(); } @@ -540,7 +546,7 @@ void SimulatorBase::deferredInit() m_boundarySimulator->initBoundaryData(); Simulation* sim = Simulation::getCurrent(); - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { unsigned int nBoundaryParticles = 0; for (unsigned int i = 0; i < sim->numberOfBoundaryModels(); i++) @@ -1845,7 +1851,7 @@ void SPH::SimulatorBase::loadState(const std::string &stateFile) } if (dynamic) { - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) updateBoundaryParticles(true); else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) updateDMVelocity(); @@ -2177,7 +2183,7 @@ void SimulatorBase::readFluidParticlesState(const std::string &fileName, FluidMo void SimulatorBase::writeBoundaryState(const std::string &fileName, BoundaryModel *bm) { Simulation *sim = Simulation::getCurrent(); - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { BoundaryModel_Akinci2012 *model = static_cast(bm); Partio::ParticlesDataMutable& particleData = *Partio::create(); @@ -2223,7 +2229,7 @@ void SimulatorBase::writeBoundaryState(const std::string &fileName, BoundaryMode void SimulatorBase::readBoundaryState(const std::string &fileName, BoundaryModel *bm) { Simulation *sim = Simulation::getCurrent(); - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { if (!FileSystem::fileExists(fileName)) { diff --git a/Simulator/SimulatorBase.h b/Simulator/SimulatorBase.h index c5803f5b..0fa20694 100644 --- a/Simulator/SimulatorBase.h +++ b/Simulator/SimulatorBase.h @@ -46,6 +46,7 @@ namespace SPH bool m_useParticleCaching; bool m_useGUI; bool m_isStaticScene; + int m_boundaryHandlingMethod; int m_renderWalls; bool m_doPause; Real m_pauseAt; @@ -199,6 +200,7 @@ namespace SPH void setUseParticleCaching(bool val) { m_useParticleCaching = val; } bool getUseGUI() const { return m_useGUI; } void setUseGUI(bool val) { m_useGUI = val; } + int getBoundaryHandlingMethod() const { return m_boundaryHandlingMethod; } const std::string& getColorField(const unsigned int fluidModelIndex) { return m_colorField[fluidModelIndex]; } void setColorField(const unsigned int fluidModelIndex, const std::string& fieldName) { m_colorField[fluidModelIndex] = fieldName; } diff --git a/Simulator/main.cpp b/Simulator/main.cpp index f6b36d40..206b26ec 100644 --- a/Simulator/main.cpp +++ b/Simulator/main.cpp @@ -24,14 +24,15 @@ int main( int argc, char **argv ) REPORT_MEMORY_LEAKS; base = new SimulatorBase(); base->init(argc, argv, "SPlisHSPlasH"); - if (base->getUseGUI()) { - //if (base->isStaticScene()) - // gui = new Simulator_GUI_imgui(base); - //else - // gui = new PBD_Simulator_GUI_imgui(base, ((PBDBoundarySimulator*)base->getBoundarySimulator())->getPBDWrapper()); - gui = new Simulator_GUI_imgui(base); + if (base->isStaticScene()) + gui = new Simulator_GUI_imgui(base); + else if(base->getBoundaryHandlingMethod() == 3) // Gissler 2019 + gui = new Simulator_GUI_imgui(base); + else + gui = new PBD_Simulator_GUI_imgui(base, ((PBDBoundarySimulator*)base->getBoundarySimulator())->getPBDWrapper()); + base->setGui(gui); } base->run(); diff --git a/data/Scenes/Cubes.json b/data/Scenes/Cubes.json index 39f3096a..a2562660 100644 --- a/data/Scenes/Cubes.json +++ b/data/Scenes/Cubes.json @@ -17,7 +17,7 @@ "exponent": 7, "velocityUpdateMethod": 0, "enableDivergenceSolver": true, - "boundaryHandlingMethod": 0 + "boundaryHandlingMethod": 3 }, "Simulation": { @@ -63,7 +63,8 @@ "invertSDF": true, "mapInvert": true, "mapThickness": 0.0, - "mapResolution": [30,40,15] + "mapResolution": [30,40,15], + "samplingMode": 1 }, { "id": 2, @@ -82,7 +83,8 @@ "collisionObjectScale": [0.4, 0.4, 0.4], "mapInvert": false, "mapThickness": 0.0, - "mapResolution": [20,20,20] + "mapResolution": [20,20,20], + "samplingMode": 1 } ] } diff --git a/data/Scenes/CubesTwo.json b/data/Scenes/CubesTwo.json index 4224bb3e..84328199 100644 --- a/data/Scenes/CubesTwo.json +++ b/data/Scenes/CubesTwo.json @@ -17,7 +17,7 @@ "exponent": 7, "velocityUpdateMethod": 0, "enableDivergenceSolver": true, - "boundaryHandlingMethod": 0 + "boundaryHandlingMethod": 3 }, "Simulation": { @@ -63,7 +63,8 @@ "invertSDF": true, "mapInvert": true, "mapThickness": 0.0, - "mapResolution": [30,40,15] + "mapResolution": [30,40,15], + "samplingMode": 1 }, { "id": 2, @@ -82,7 +83,8 @@ "collisionObjectScale": [0.4, 0.4, 0.4], "mapInvert": false, "mapThickness": 0.0, - "mapResolution": [20,20,20] + "mapResolution": [20,20,20], + "samplingMode": 1 }, { "id": 3, @@ -101,7 +103,8 @@ "collisionObjectScale": [0.4, 0.4, 0.4], "mapInvert": false, "mapThickness": 0.0, - "mapResolution": [20,20,20] + "mapResolution": [20,20,20], + "samplingMode": 1 } ] } diff --git a/data/Scenes/DamBreakModel.json b/data/Scenes/DamBreakModel.json index 24e369b4..0529426d 100644 --- a/data/Scenes/DamBreakModel.json +++ b/data/Scenes/DamBreakModel.json @@ -18,7 +18,7 @@ "exponent": 7, "velocityUpdateMethod": 0, "enableDivergenceSolver": true, - "particleAttributes": "density;velocity", + "particleAttributes": "density;velocity;pressure", "boundaryHandlingMethod": 2 }, "Materials": [ diff --git a/data/Scenes/DamBreakWithCubes.json b/data/Scenes/DamBreakWithCubes.json index 5d351658..7236f8ca 100644 --- a/data/Scenes/DamBreakWithCubes.json +++ b/data/Scenes/DamBreakWithCubes.json @@ -4,7 +4,7 @@ "particleRadius": 0.025, "numberOfStepsPerRenderUpdate": 2, "density0": 1000, - "simulationMethod": 4, + "simulationMethod": 3, "gravitation": [0,-9.81,0], "cflMethod": 1, "cflFactor": 0.5, @@ -17,7 +17,7 @@ "exponent": 7, "velocityUpdateMethod": 0, "enableDivergenceSolver": true, - "boundaryHandlingMethod": 0 + "boundaryHandlingMethod": 3 }, "Simulation": { diff --git a/data/Scenes/DamBreakWithObjects.json b/data/Scenes/DamBreakWithObjects.json index b0f507f3..d87712bd 100644 --- a/data/Scenes/DamBreakWithObjects.json +++ b/data/Scenes/DamBreakWithObjects.json @@ -17,7 +17,7 @@ "exponent": 7, "velocityUpdateMethod": 0, "enableDivergenceSolver": true, - "boundaryHandlingMethod": 2 + "boundaryHandlingMethod": 0 }, "Simulation": { diff --git a/data/Scenes/DoubleDamBreakWithSphere.json b/data/Scenes/DoubleDamBreakWithSphere.json index eb4b6ad3..fb6bc07f 100644 --- a/data/Scenes/DoubleDamBreakWithSphere.json +++ b/data/Scenes/DoubleDamBreakWithSphere.json @@ -18,7 +18,7 @@ "exponent": 7, "velocityUpdateMethod": 0, "enableDivergenceSolver": true, - "boundaryHandlingMethod": 2 + "boundaryHandlingMethod": 0 }, "Materials": [ { From e51e9ec3c580baa1a7a7d80cb8fefc0b86029b13 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Fri, 23 Jun 2023 10:53:17 +0200 Subject: [PATCH 28/38] DFSPH integration --- SPlisHSPlasH/BoundaryModel_Akinci2012.cpp | 16 +- SPlisHSPlasH/DFSPH/SimulationDataDFSPH.cpp | 8 +- SPlisHSPlasH/DFSPH/SimulationDataDFSPH.h | 14 + SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp | 335 +++++++++++++++--- SPlisHSPlasH/DFSPH/TimeStepDFSPH.h | 1 + SPlisHSPlasH/DynamicRigidBody.h | 12 + SPlisHSPlasH/Simulation.cpp | 3 + SPlisHSPlasH/StrongCouplingBoundarySolver.cpp | 33 +- SPlisHSPlasH/StrongCouplingBoundarySolver.h | 7 + SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 1 - Simulator/DynamicBoundarySimulator.cpp | 15 + Simulator/DynamicBoundarySimulator.h | 5 + 12 files changed, 390 insertions(+), 60 deletions(-) diff --git a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp index 1285b141..ffd0a43f 100644 --- a/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp +++ b/SPlisHSPlasH/BoundaryModel_Akinci2012.cpp @@ -6,6 +6,7 @@ #include "Utilities/Logger.h" #include "NeighborhoodSearch.h" #include "Simulation.h" +#include "StrongCouplingBoundarySolver.h" using namespace SPH; @@ -79,7 +80,7 @@ void BoundaryModel_Akinci2012::computeBoundaryVolume() Simulation *sim = Simulation::getCurrent(); const unsigned int nFluids = sim->numberOfFluidModels(); NeighborhoodSearch *neighborhoodSearch = Simulation::getCurrent()->getNeighborhoodSearch(); - + StrongCouplingBoundarySolver* bs = StrongCouplingBoundarySolver::getCurrent(); const unsigned int numBoundaryParticles = numberOfParticles(); #pragma omp parallel default(shared) @@ -87,14 +88,23 @@ void BoundaryModel_Akinci2012::computeBoundaryVolume() #pragma omp for schedule(static) for (int i = 0; i < (int)numBoundaryParticles; i++) { - Real delta = sim->W_zero(); + Real delta; + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { + delta = bs->W_zero(); + } else { + delta = sim->W_zero(); + } for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { BoundaryModel_Akinci2012 *bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); for (unsigned int j = 0; j < neighborhoodSearch->point_set(m_pointSetIndex).n_neighbors(pid, i); j++) { const unsigned int neighborIndex = neighborhoodSearch->point_set(m_pointSetIndex).neighbor(pid, i, j); - delta += sim->W(getPosition(i) - bm_neighbor->getPosition(neighborIndex)); + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { + delta += bs->W(getPosition(i) - bm_neighbor->getPosition(neighborIndex)); + } else { + delta += sim->W(getPosition(i) - bm_neighbor->getPosition(neighborIndex)); + } } } const Real volume = static_cast(1.0) / delta; diff --git a/SPlisHSPlasH/DFSPH/SimulationDataDFSPH.cpp b/SPlisHSPlasH/DFSPH/SimulationDataDFSPH.cpp index 25fe8855..f0fce750 100644 --- a/SPlisHSPlasH/DFSPH/SimulationDataDFSPH.cpp +++ b/SPlisHSPlasH/DFSPH/SimulationDataDFSPH.cpp @@ -9,7 +9,8 @@ SimulationDataDFSPH::SimulationDataDFSPH() : m_pressure_rho2(), m_pressure_rho2_V(), m_pressureAccel(), - m_density_adv() + m_density_adv(), + m_density_adv_no_boundary() { } @@ -29,6 +30,7 @@ void SimulationDataDFSPH::init() m_pressure_rho2.resize(nModels); m_pressure_rho2_V.resize(nModels); m_pressureAccel.resize(nModels); + m_density_adv_no_boundary.resize(nModels); for (unsigned int i = 0; i < nModels; i++) { @@ -38,6 +40,7 @@ void SimulationDataDFSPH::init() m_pressure_rho2[i].resize(fm->numParticles(), 0.0); m_pressure_rho2_V[i].resize(fm->numParticles(), 0.0); m_pressureAccel[i].resize(fm->numParticles(), Vector3r::Zero()); + m_density_adv_no_boundary[i].resize(fm->numParticles(), 0.0); } } @@ -53,12 +56,14 @@ void SimulationDataDFSPH::cleanup() m_pressure_rho2[i].clear(); m_pressure_rho2_V[i].clear(); m_pressureAccel[i].clear(); + m_density_adv_no_boundary[i].clear(); } m_factor.clear(); m_density_adv.clear(); m_pressure_rho2.clear(); m_pressure_rho2_V.clear(); m_pressureAccel.clear(); + m_density_adv_no_boundary.clear(); } void SimulationDataDFSPH::reset() @@ -76,6 +81,7 @@ void SimulationDataDFSPH::reset() m_pressure_rho2_V[i][j] = 0.0; m_factor[i][j] = 0.0; m_pressureAccel[i][j].setZero(); + m_density_adv_no_boundary[i][j] = 0.0; } } } diff --git a/SPlisHSPlasH/DFSPH/SimulationDataDFSPH.h b/SPlisHSPlasH/DFSPH/SimulationDataDFSPH.h index e99d8a5f..8fb4c880 100644 --- a/SPlisHSPlasH/DFSPH/SimulationDataDFSPH.h +++ b/SPlisHSPlasH/DFSPH/SimulationDataDFSPH.h @@ -25,6 +25,8 @@ namespace SPH std::vector> m_factor; /** \brief advected density */ std::vector> m_density_adv; + /** \brief for strong coupling (Gissler2019) */ + std::vector> m_density_adv_no_boundary; /** \brief stores \f$\frac{p}{\rho^2}\f$ value of the constant density solver */ std::vector> m_pressure_rho2; @@ -85,6 +87,18 @@ namespace SPH m_density_adv[fluidIndex][i] = d; } + FORCE_INLINE const Real getDensityAdvNoBoundary(const unsigned int fluidIndex, const unsigned int i) const { + return m_density_adv_no_boundary[fluidIndex][i]; + } + + FORCE_INLINE Real& getDensityAdvNoBoundary(const unsigned int fluidIndex, const unsigned int i) { + return m_density_adv_no_boundary[fluidIndex][i]; + } + + FORCE_INLINE void setDensityAdvNoBoundary(const unsigned int fluidIndex, const unsigned int i, const Real d) { + m_density_adv_no_boundary[fluidIndex][i] = d; + } + FORCE_INLINE const Real getPressureRho2(const unsigned int fluidIndex, const unsigned int i) const { return m_pressure_rho2[fluidIndex][i]; diff --git a/SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp b/SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp index afd9cb04..0da5809b 100644 --- a/SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp +++ b/SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp @@ -9,6 +9,9 @@ #include "SPlisHSPlasH/BoundaryModel_Akinci2012.h" #include "SPlisHSPlasH/BoundaryModel_Koschier2017.h" #include "SPlisHSPlasH/BoundaryModel_Bender2019.h" +#include "SPlisHSPlasH/StrongCouplingBoundarySolver.h" +#include "Simulator/DynamicBoundarySimulator.h" +#include "SPlisHSPlasH/DynamicRigidBody.h" using namespace SPH; @@ -286,31 +289,137 @@ void TimeStepDFSPH::pressureSolve() ////////////////////////////////////////////////////////////////////////// // Start solver ////////////////////////////////////////////////////////////////////////// - + Real avg_density_err = 0.0; bool chk = false; + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { + StrongCouplingBoundarySolver* bs = StrongCouplingBoundarySolver::getCurrent(); + Real avg_density_err_rigid = 0; + bs->computeContacts(); + bool anyRigidContact = bs->getAllContacts() != 0; + if (anyRigidContact) { + bs->computeDensityAndVolume(); + } - ////////////////////////////////////////////////////////////////////////// - // Perform solver iterations - ////////////////////////////////////////////////////////////////////////// - while ((!chk || (m_iterations < m_minIterations)) && (m_iterations < m_maxIterations)) - { - chk = true; - for (unsigned int i = 0; i < nFluids; i++) - { - FluidModel *model = sim->getFluidModel(i); - const Real density0 = model->getDensity0(); + bool rigidSolverConverged = false; + + while ((!chk || !rigidSolverConverged || (m_iterations < m_minIterations)) && (m_iterations < m_maxIterations)) { + chk = true; + rigidSolverConverged = true; + + // fluid-rigid forces + for (unsigned int fluidModelIndex = 0; fluidModelIndex < nFluids; fluidModelIndex++) { + FluidModel* model = sim->getFluidModel(fluidModelIndex); + #pragma omp parallel default(shared) + { + const Real density0 = model->getDensity0(); + const int numParticles = (int)model->numActiveParticles(); + #pragma omp for schedule(static) + for (int i = 0; i < numParticles; i++) { + computePressureAccel(fluidModelIndex, i, density0, m_simulationData.getPressureRho2Data(), true); + } + } + } + + // apply force and torque for computing predicted velocity + sim->getDynamicBoundarySimulator()->updateBoundaryForces(); + + if (anyRigidContact) { + bs->computeSourceTerm(); + bs->computeDiagonalElement(); + avg_density_err_rigid = 0.0; + bs->pressureSolveIteration(avg_density_err_rigid); + if (avg_density_err_rigid > bs->getMaxDensityDeviation()) { + rigidSolverConverged = false; + } + } else { + // compute the predicted velocity and position without rigid-rigid contacts + bs->computeV_s(); + } + + // clear force and torque used to computed predicted velocity + for (int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)->getRigidBodyObject())->clearForceAndTorque(); + } + + // predict density advection using the predicted velocity of fluid an rigid velocities + for (unsigned int fluidModelIndex = 0; fluidModelIndex < nFluids; fluidModelIndex++) { + FluidModel* model = sim->getFluidModel(fluidModelIndex); + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int i = 0; i < (int)model->numActiveParticles(); i++) { + const Vector3r& xi = model->getPosition(i); + const Vector3r& vi = model->getVelocity(i); + const Vector3r& ai = m_simulationData.getPressureAccel(fluidModelIndex, i); + const Vector3r predictedV = vi + ai * h; + const Real& density = model->getDensity(i); + const Real density0 = model->getDensity0(); + Real densityAdv = m_simulationData.getDensityAdvNoBoundary(fluidModelIndex, i); + /*#ifdef USE_AVX + Scalarf8 delta_avx(0.0f); + const Vector3f8 xi_avx(xi); + Vector3f8 vi_avx(predictedV); + forall_boundary_neighbors_avx( + const Scalarf8 Vj_avx = convert_zero(&sim->getNeighborList(fluidModelIndex, pid, i)[j], &bm_neighbor->getVolume(0), count); + const Vector3f8 vj_avx = convertVec_zero(&sim->getNeighborList(fluidModelIndex, pid, i)[j], &bs->getPredictedVelocity(pid - fluidModelIndex, 0), count); + delta_avx += Vj_avx * (vi_avx - vj_avx).dot(CubicKernel_AVX::gradW(xi_avx - xj_avx)); + ); + densityAdv += h * delta_avx.reduce(); + #else*/ + Real delta = 0; + // density advection considering rigid bodies + forall_boundary_neighbors( + const Vector3r& vj = bm_neighbor->getVelocity(neighborIndex); + delta += bm_neighbor->getVolume(neighborIndex) * (predictedV - bs->getPredictedVelocity(pid - nFluids, neighborIndex)).dot(sim->gradW(xi - xj)); + ); + densityAdv += h * delta; + //#endif + m_simulationData.getDensityAdv(fluidModelIndex, i) = densityAdv; + } + } + } + + for (unsigned int i = 0; i < nFluids; i++) { + FluidModel* model = sim->getFluidModel(i); + const Real density0 = model->getDensity0(); + + avg_density_err = 0.0; + pressureSolveIteration(i, avg_density_err); - avg_density_err = 0.0; - pressureSolveIteration(i, avg_density_err); + // Maximal allowed density fluctuation + const Real eta = m_maxError * static_cast(0.01) * density0; // maxError is given in percent - // Maximal allowed density fluctuation - const Real eta = m_maxError * static_cast(0.01) * density0; // maxError is given in percent - chk = chk && (avg_density_err <= eta); + chk = chk && (avg_density_err <= eta); + } + m_iterations++; + } + if (anyRigidContact) { + bs->applyForce(); } + } else { + ////////////////////////////////////////////////////////////////////////// + // Perform solver iterations + ////////////////////////////////////////////////////////////////////////// + while ((!chk || (m_iterations < m_minIterations)) && (m_iterations < m_maxIterations)) + { + chk = true; + for (unsigned int i = 0; i < nFluids; i++) + { + FluidModel* model = sim->getFluidModel(i); + const Real density0 = model->getDensity0(); - m_iterations++; + avg_density_err = 0.0; + pressureSolveIteration(i, avg_density_err); + + // Maximal allowed density fluctuation + const Real eta = m_maxError * static_cast(0.01) * density0; // maxError is given in percent + chk = chk && (avg_density_err <= eta); + } + + m_iterations++; + } } INCREASE_COUNTER("DFSPH - iterations", static_cast(m_iterations)); @@ -440,36 +549,144 @@ void TimeStepDFSPH::divergenceSolve() ////////////////////////////////////////////////////////////////////////// // Start solver ////////////////////////////////////////////////////////////////////////// - + Real avg_density_err = 0.0; bool chk = false; - ////////////////////////////////////////////////////////////////////////// - // Perform solver iterations - ////////////////////////////////////////////////////////////////////////// - while ((!chk || (m_iterationsV < 1)) && (m_iterationsV < maxIter)) - { - chk = true; - for (unsigned int i = 0; i < nFluids; i++) - { - FluidModel *model = sim->getFluidModel(i); - const Real density0 = model->getDensity0(); + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { + ////////////////////////////////////////////////////////////////////////// + // Perform solver iterations (strong coupling) + ////////////////////////////////////////////////////////////////////////// + StrongCouplingBoundarySolver* bs = StrongCouplingBoundarySolver::getCurrent(); + Real avg_density_err_rigid = 0.0; + bs->computeContacts(); + bool anyRigidContact = bs->getAllContacts() != 0; + if (anyRigidContact) { + bs->computeDensityAndVolume(); + } + bool rigidSolverConverged = false; + + while ((!chk || !rigidSolverConverged || (m_iterationsV < 1)) && (m_iterationsV < maxIter)) { + chk = true; + rigidSolverConverged = true; + // fluid-rigid forces + for (unsigned int fluidModelIndex = 0; fluidModelIndex < nFluids; fluidModelIndex++) { + FluidModel* model = sim->getFluidModel(fluidModelIndex); + #pragma omp parallel default(shared) + { + const Real density0 = model->getDensity0(); + const int numParticles = (int)model->numActiveParticles(); + #pragma omp for schedule(static) + for (int i = 0; i < numParticles; i++) { + computePressureAccel(fluidModelIndex, i, density0, m_simulationData.getPressureRho2Data(), true); + } + } + } - avg_density_err = 0.0; - divergenceSolveIteration(i, avg_density_err); + // apply force and torque for computing predicted velocity + sim->getDynamicBoundarySimulator()->updateBoundaryForces(); + + if (anyRigidContact) { + bs->computeSourceTerm(); + bs->computeDiagonalElement(); + avg_density_err_rigid = 0.0; + bs->pressureSolveIteration(avg_density_err_rigid); + if (avg_density_err_rigid > bs->getMaxDensityDeviation()) { + rigidSolverConverged = false; + } + } else { + // compute the predicted velocity and position without rigid-rigid contacts + bs->computeV_s(); + } - // Maximal allowed density fluctuation - // use maximal density error divided by time step size - const Real eta = (static_cast(1.0) / h) * maxError * static_cast(0.01) * density0; // maxError is given in percent - chk = chk && (avg_density_err <= eta); + // clear force and torque used to computed predicted velocity + for (int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)->getRigidBodyObject())->clearForceAndTorque(); + } + + // predict density advection using the predicted velocity of fluid an rigid velocities + for (unsigned int fluidModelIndex = 0; fluidModelIndex < nFluids; fluidModelIndex++) { + FluidModel* model = sim->getFluidModel(fluidModelIndex); + #pragma omp parallel default(shared) + { + #pragma omp for schedule(static) + for (int i = 0; i < (int)model->numActiveParticles(); i++) { + const Vector3r& xi = model->getPosition(i); + const Vector3r& vi = model->getVelocity(i); + const Vector3r& ai = m_simulationData.getPressureAccel(fluidModelIndex, i); + const Vector3r predictedV = vi + ai * h; + + Real densityAdv = m_simulationData.getDensityAdvNoBoundary(fluidModelIndex, i); + + // #ifdef USE_AVX + //Scalarf8 densityAdv_avx(0.0f); + //const Vector3f8 xi_avx(xi); + //Vector3f8 vi_avx(predictedV); + //forall_boundary_neighbors_avx( + // const Scalarf8 Vj_avx = convert_zero(&sim->getNeighborList(fluidModelIndex, pid, i)[j], &bm_neighbor->getVolume(0), count); + // const Vector3f8 vj_avx = convertVec_zero(&sim->getNeighborList(fluidModelIndex, pid, i)[j], &bs->getPredictedVelocity(pid - fluidModelIndex, 0), count); + // densityAdv_avx += Vj_avx * (vi_avx - vj_avx).dot(CubicKernel_AVX::gradW(xi_avx - xj_avx)); + //); + //densityAdv += densityAdv_avx.reduce(); + // #else + // density advection considering rigid bodies + forall_boundary_neighbors( + densityAdv += bm_neighbor->getVolume(neighborIndex) * (predictedV - bs->getPredictedVelocity(pid - nFluids, neighborIndex)).dot(sim->gradW(xi - xj)); + ); + //#endif + + m_simulationData.getDensityAdv(fluidModelIndex, i) = densityAdv; + } + } + } + + for (unsigned int i = 0; i < nFluids; i++) { + FluidModel* model = sim->getFluidModel(i); + const Real density0 = model->getDensity0(); + + avg_density_err = 0.0; + divergenceSolveIteration(i, avg_density_err); + + // Maximal allowed density fluctuation + // use maximal density error divided by time step size + const Real eta = (static_cast(1.0) / h) * maxError * static_cast(0.01) * density0; // maxError is given in percent + + chk = chk && (avg_density_err <= eta); + } + + m_iterationsV++; } + if (anyRigidContact) { + bs->applyForce(); + } + } else { + ////////////////////////////////////////////////////////////////////////// + // Perform solver iterations + ////////////////////////////////////////////////////////////////////////// + while ((!chk || (m_iterationsV < 1)) && (m_iterationsV < maxIter)) + { + chk = true; + for (unsigned int i = 0; i < nFluids; i++) + { + FluidModel* model = sim->getFluidModel(i); + const Real density0 = model->getDensity0(); - m_iterationsV++; - } + avg_density_err = 0.0; + divergenceSolveIteration(i, avg_density_err); - INCREASE_COUNTER("DFSPH - iterationsV", static_cast(m_iterationsV)); + // Maximal allowed density fluctuation + // use maximal density error divided by time step size + const Real eta = (static_cast(1.0) / h) * maxError * static_cast(0.01) * density0; // maxError is given in percent + chk = chk && (avg_density_err <= eta); + } + m_iterationsV++; + } + } + INCREASE_COUNTER("DFSPH - iterationsV", static_cast(m_iterationsV)); + + for (unsigned int fluidModelIndex = 0; fluidModelIndex < nFluids; fluidModelIndex++) { FluidModel *model = sim->getFluidModel(fluidModelIndex); @@ -491,6 +708,14 @@ void TimeStepDFSPH::divergenceSolve() } } } + + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { + ///////////////////////////////////////////////////////////////////////// + // Update intermediate boundary velocity for strong coupling solver + ///////////////////////////////////////////////////////////////////////// + sim->getDynamicBoundarySimulator()->updateVelocities(); + } + #ifdef USE_WARMSTART_V for (unsigned int fluidModelIndex = 0; fluidModelIndex < nFluids; fluidModelIndex++) { @@ -537,7 +762,7 @@ void TimeStepDFSPH::pressureSolveIteration(const unsigned int fluidModelIndex, R // (see Algorithm 3, line 7 in [BK17]) ////////////////////////////////////////////////////////////////////////// #pragma omp for schedule(static) - for (int i = 0; i < numParticles; i++) + for (int i = 0; i < numParticles; i++) { computePressureAccel(fluidModelIndex, i, density0, m_simulationData.getPressureRho2Data()); } @@ -612,10 +837,10 @@ void TimeStepDFSPH::divergenceSolveIteration(const unsigned int fluidModelIndex, { ////////////////////////////////////////////////////////////////////////// // Compute pressure accelerations using the current pressure values. - // (see Algorithm 2, line 7 in [BK17]) + // (see Algorithm 2, line 7 in [BK17]) ////////////////////////////////////////////////////////////////////////// #pragma omp for schedule(static) - for (int i = 0; i < (int)numParticles; i++) + for (int i = 0; i < (int)numParticles; i++) { computePressureAccel(fluidModelIndex, i, density0, m_simulationData.getPressureRho2VData()); } @@ -768,7 +993,7 @@ void TimeStepDFSPH::computeDFSPHFactor(const unsigned int fluidModelIndex) ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors_avx( const Scalarf8 V_avx = convert_zero(&sim->getNeighborList(fluidModelIndex, pid, i)[j], &bm_neighbor->getVolume(0), count); @@ -870,8 +1095,12 @@ void TimeStepDFSPH::computeDensityAdv(const unsigned int fluidModelIndex, const delta += Vj * (vi - vj).dot(sim->gradW(xi - xj)); ); } + else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) + { + m_simulationData.getDensityAdvNoBoundary(fluidModelIndex, i) = density / density0 + h * delta; + } - densityAdv = density / density0 + h*delta; + densityAdv = density / density0 + h * delta; } /** Compute rho_adv,i^(0) (see equation (9) in Section 3.2 [BK17]) @@ -933,6 +1162,10 @@ void TimeStepDFSPH::computeDensityChange(const unsigned int fluidModelIndex, con densityAdv += Vj * (vi - vj).dot(sim->gradW(xi - xj)); ); } + else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) + { + m_simulationData.getDensityAdvNoBoundary(fluidModelIndex, i) = densityAdv; + } } /** Compute pressure accelerations using the current pressure values of the particles @@ -978,7 +1211,7 @@ void TimeStepDFSPH::computePressureAccel(const unsigned int fluidModelIndex, con ////////////////////////////////////////////////////////////////////////// if (fabs(p_rho2_i) > m_eps) { - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { const Scalarf8 mi_avx(model->getMass(i)); forall_boundary_neighbors_avx( @@ -1060,7 +1293,7 @@ Real TimeStepDFSPH::compute_aij_pj(const unsigned int fluidModelIndex, const uns ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors_avx( const Scalarf8 Vj_avx = convert_zero(&sim->getNeighborList(fluidModelIndex, pid, i)[j], &bm_neighbor->getVolume(0), count); @@ -1133,7 +1366,7 @@ void TimeStepDFSPH::computeDFSPHFactor(const unsigned int fluidModelIndex) ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( const Vector3r grad_p_j = -bm_neighbor->getVolume(neighborIndex) * sim->gradW(xi - xj); @@ -1222,6 +1455,10 @@ void TimeStepDFSPH::computeDensityAdv(const unsigned int fluidModelIndex, const bm_neighbor->getPointVelocity(xj, vj); delta += Vj * (vi - vj).dot(sim->gradW(xi - xj)); ); + } + else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) + { + m_simulationData.getDensityAdvNoBoundary(fluidModelIndex, i) = density / density0 + h * delta; } densityAdv = density / density0 + h*delta; @@ -1278,6 +1515,10 @@ void TimeStepDFSPH::computeDensityChange(const unsigned int fluidModelIndex, con densityAdv += Vj * (vi - vj).dot(sim->gradW(xi - xj)); ); } + else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) + { + m_simulationData.getDensityAdvNoBoundary() = densityAdv; + } } /** Compute pressure accelerations using the current pressure values of the particles @@ -1318,7 +1559,7 @@ void TimeStepDFSPH::computePressureAccel(const unsigned int fluidModelIndex, con ////////////////////////////////////////////////////////////////////////// if (fabs(p_rho2_i) > m_eps) { - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( const Vector3r grad_p_j = -bm_neighbor->getVolume(neighborIndex) * sim->gradW(xi - xj); @@ -1384,7 +1625,7 @@ Real TimeStepDFSPH::compute_aij_pj(const unsigned int fluidModelIndex, const uns ////////////////////////////////////////////////////////////////////////// // Boundary ////////////////////////////////////////////////////////////////////////// - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { forall_boundary_neighbors( aij_pj += bm_neighbor->getVolume(neighborIndex) * ai.dot(sim->gradW(xi - xj)); diff --git a/SPlisHSPlasH/DFSPH/TimeStepDFSPH.h b/SPlisHSPlasH/DFSPH/TimeStepDFSPH.h index 07478a0e..c866806f 100644 --- a/SPlisHSPlasH/DFSPH/TimeStepDFSPH.h +++ b/SPlisHSPlasH/DFSPH/TimeStepDFSPH.h @@ -36,6 +36,7 @@ namespace SPH void pressureSolve(); void pressureSolveIteration(const unsigned int fluidModelIndex, Real &avg_density_err); void divergenceSolve(); + void solveRigidRigidContacts(); void divergenceSolveIteration(const unsigned int fluidModelIndex, Real &avg_density_err); void computeDensityAdv(const unsigned int fluidModelIndex, const unsigned int index, const Real h, const Real density0); void computeDensityChange(const unsigned int fluidModelIndex, const unsigned int index, const Real h); diff --git a/SPlisHSPlasH/DynamicRigidBody.h b/SPlisHSPlasH/DynamicRigidBody.h index f74ce645..0224945b 100644 --- a/SPlisHSPlasH/DynamicRigidBody.h +++ b/SPlisHSPlasH/DynamicRigidBody.h @@ -624,6 +624,18 @@ namespace SPH { clearForceAndTorque(); } + // used in DFSPH + void updateVelocity() { + Simulation* sim = Simulation::getCurrent(); + const Vector3r gravAccel(sim->getVecValue(Simulation::GRAVITATION)); + const Real dt = TimeManager::getCurrent()->getTimeStepSize(); + m_a = m_invMass * m_force; + m_v += m_a * dt; + m_a_omega = m_inertiaTensorInverseW * (m_torque - (m_omega.cross(m_inertiaTensorW * m_omega))); + m_omega += m_a_omega * dt; + clearForceAndTorque(); + } + virtual const std::vector& getVertices() const { return m_geometry.getVertices(); }; diff --git a/SPlisHSPlasH/Simulation.cpp b/SPlisHSPlasH/Simulation.cpp index 36a630b8..c903a3b6 100644 --- a/SPlisHSPlasH/Simulation.cpp +++ b/SPlisHSPlasH/Simulation.cpp @@ -622,6 +622,9 @@ void Simulation::performNeighborhoodSearchSort() BoundaryModel *bm = getBoundaryModel(i); bm->performNeighborhoodSearchSort(); } + if (getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { + StrongCouplingBoundarySolver::getCurrent()->performNeighborhoodSearchSort(); + } #ifdef USE_DEBUG_TOOLS m_debugTools->performNeighborhoodSearchSort(); #endif diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp index 9b767215..1ab4775f 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp @@ -3,6 +3,7 @@ #include "TimeManager.h" #include "DynamicRigidBody.h" #include "Simulator/DynamicBoundarySimulator.h" +#include "SPlisHSPlasH/SPHKernels.h" using namespace SPH; @@ -30,6 +31,10 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_minIterations = 2; m_maxDensityDeviation = 0.001; + m_kernelFct = CubicKernel::W; + m_gradKernelFct = CubicKernel::gradW; + m_W_zero = CubicKernel::W_zero(); + Simulation* sim = Simulation::getCurrent(); const unsigned int nBoundaries = sim->numberOfBoundaryModels(); @@ -266,13 +271,13 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { for (int r = 0; r < bm->numberOfParticles(); r++) { if (rb->isDynamic()) { // compute density for particle r - Real particleDensity = getRestDensity() * bm->getVolume(r) * sim->W_zero(); + Real particleDensity = getRestDensity() * bm->getVolume(r) * W_zero(); // iterate over all rigid bodies for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { BoundaryModel_Akinci2012* bm_neighbor = static_cast(sim->getBoundaryModelFromPointSet(pid)); for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); - particleDensity += getRestDensity() * bm->getVolume(r) * sim->W(bm->getPosition(r) - bm_neighbor->getPosition(k)); + particleDensity += getRestDensity() * bm->getVolume(r) * W(bm->getPosition(r) - bm_neighbor->getPosition(k)); } } setDensity(bmIndex, r, std::max(particleDensity, getRestDensity())); @@ -349,7 +354,7 @@ void StrongCouplingBoundarySolver::computeSourceTerm() { for (unsigned int j = 0; j < sim->numberOfNeighbors(boundaryPointSetIndex, pid, r); j++) { const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, r, j); // sum up divergence of v_s - rho_div_v_s += getArtificialVolume(neighborIndex, k) * getDensity(neighborIndex, k) * (getV_s(neighborIndex, k) - getV_s(bmIndex, r)).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); + rho_div_v_s += getArtificialVolume(neighborIndex, k) * getDensity(neighborIndex, k) * (getV_s(neighborIndex, k) - getV_s(bmIndex, r)).dot(gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); } } } @@ -388,7 +393,7 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { DynamicRigidBody* rb_rk = static_cast(bm_rk->getRigidBodyObject()); for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_rk, r); n++) { const unsigned int rk = sim->getNeighbor(pointSetIndex_r, pointSetIndex_rk, r, n); - grad_p_b += getArtificialVolume(index_rk, rk) * getDensity(index_rk, rk) / density_r2 * sim->gradW(bm_r->getPosition(r) - bm_rk->getPosition(rk)); + grad_p_b += getArtificialVolume(index_rk, rk) * getDensity(index_rk, rk) / density_r2 * gradW(bm_r->getPosition(r) - bm_rk->getPosition(rk)); } } } @@ -408,7 +413,7 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_rk, r); n++) { const unsigned int rk = sim->getNeighbor(pointSetIndex_r, pointSetIndex_rk, r, n); Vector3r pos_rk = bm_rk->getPosition(rk) - rb_rk->getPosition(); - Vector3r grad_p_b_rkr = getDensity(index_rk, rk) * getArtificialVolume(index_r, r) * getDensity(index_r, r) / density_r2 * sim->gradW(bm_rk->getPosition(rk) - bm_r->getPosition(r)); + Vector3r grad_p_b_rkr = getDensity(index_rk, rk) * getArtificialVolume(index_r, r) * getDensity(index_r, r) / density_r2 * gradW(bm_rk->getPosition(rk) - bm_r->getPosition(r)); v_b_k_body += -dt * rb_rk->getInvMass() * getArtificialVolume(index_rk, rk) * grad_p_b_rkr; omega_b_k_body += -dt * rb_rk->getInertiaTensorInverseW() * getArtificialVolume(index_rk, rk) * pos_rk.cross(grad_p_b_rkr); } @@ -418,7 +423,7 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { const unsigned int rk = sim->getNeighbor(pointSetIndex_r, pointSetIndex_rk, r, n); Vector3r pos_rk = bm_rk->getPosition(rk) - rb_rk->getPosition(); Vector3r v_b_rk = v_b_k_body + omega_b_k_body.cross(pos_rk); - sum_rk += getArtificialVolume(index_rk, rk) * getDensity(index_rk, rk) * (v_b_rk - v_b_r).dot(sim->gradW(bm_r->getPosition(r) - bm_rk->getPosition(rk))); + sum_rk += getArtificialVolume(index_rk, rk) * getDensity(index_rk, rk) * (v_b_rk - v_b_r).dot(gradW(bm_r->getPosition(r) - bm_rk->getPosition(rk))); } b_r += sum_rk; } @@ -473,7 +478,7 @@ void SPH::StrongCouplingBoundarySolver::computeSourceTermRHSForBody(const unsign const Real density_k = getDensity(neighborIndex, k); const Real volume_k = getArtificialVolume(neighborIndex, k); const Real pressure_k = getPressure(neighborIndex, k); - pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); + pressureGrad_r += volume_k * density_k * (pressure_r / (density_r * density_r) + pressure_k / (density_k * density_k)) * gradW(bm->getPosition(r) - bm_neighbor->getPosition(k)); } } } @@ -520,7 +525,7 @@ void SPH::StrongCouplingBoundarySolver::computeSourceTermRHSForBody(const unsign const Real density_k = getDensity(neighborIndex, k); const Real volume_k = getArtificialVolume(neighborIndex, k); const Vector3r v_rr_k = getV_rr(pid - nFluids, k); - minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(sim->gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); + minus_rho_div_v_rr += volume_k * density_k * (v_rr_k - v_rr_r).dot(gradW(bm->getPosition(r) - bm_neighbor->getPosition(k))); } } } @@ -586,3 +591,15 @@ void StrongCouplingBoundarySolver::applyForce() { } } } + +Real StrongCouplingBoundarySolver::W(const Vector3r& r) { + return m_kernelFct(r); +} + +Vector3r SPH::StrongCouplingBoundarySolver::gradW(const Vector3r& r) { + return m_gradKernelFct(r); +} + +Real SPH::StrongCouplingBoundarySolver::W_zero() { + return m_W_zero; +} diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.h b/SPlisHSPlasH/StrongCouplingBoundarySolver.h index 37e4e8d0..12ef8095 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.h +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.h @@ -38,6 +38,10 @@ namespace SPH { Real m_maxDensityDeviation; + Real(*m_kernelFct)(const Vector3r&); + Vector3r(*m_gradKernelFct)(const Vector3r& r); + Real m_W_zero; + public: StrongCouplingBoundarySolver(); ~StrongCouplingBoundarySolver(); @@ -54,6 +58,9 @@ namespace SPH { void pressureSolveIteration(Real& avgDensityDeviation); void applyForce(); void performNeighborhoodSearchSort(); + Real W(const Vector3r& r); + Vector3r gradW(const Vector3r& r); + Real W_zero(); FORCE_INLINE const Real& getDensity(const unsigned int& rigidBodyIndex, const unsigned int& index) const { return m_density[rigidBodyIndex][index]; diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index 3e1ca7c2..41574252 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -244,7 +244,6 @@ void TimeStepWCSPH::performNeighborhoodSearch() if (m_counter % 500 == 0) { Simulation::getCurrent()->performNeighborhoodSearchSort(); - StrongCouplingBoundarySolver::getCurrent()->performNeighborhoodSearchSort(); m_simulationData.performNeighborhoodSearchSort(); } m_counter++; diff --git a/Simulator/DynamicBoundarySimulator.cpp b/Simulator/DynamicBoundarySimulator.cpp index 943eb20f..3393aab2 100644 --- a/Simulator/DynamicBoundarySimulator.cpp +++ b/Simulator/DynamicBoundarySimulator.cpp @@ -199,6 +199,21 @@ void DynamicBoundarySimulator::timeStep() { m_base->updateVMVelocity(); } +void DynamicBoundarySimulator::updateVelocities() { + Simulation* sim = Simulation::getCurrent(); + updateBoundaryForces(); + const unsigned int nObjects = sim->numberOfBoundaryModels(); + #pragma omp parallel for + for (int i = 0; i < nObjects; i++) { + BoundaryModel* bm = sim->getBoundaryModel(i); + RigidBodyObject* rbo = bm->getRigidBodyObject(); + if (rbo->isDynamic()) { + DynamicRigidBody* drb = dynamic_cast(rbo); + drb->updateVelocity(); + } + } +} + void DynamicBoundarySimulator::reset() { Simulation* sim = Simulation::getCurrent(); for (unsigned int i = 0; i < sim->numberOfBoundaryModels(); i++) { diff --git a/Simulator/DynamicBoundarySimulator.h b/Simulator/DynamicBoundarySimulator.h index 3536dbf3..7ea3a063 100644 --- a/Simulator/DynamicBoundarySimulator.h +++ b/Simulator/DynamicBoundarySimulator.h @@ -28,6 +28,11 @@ namespace SPH { virtual void timeStep(); virtual void reset(); + /** + * This function is used in DFSPH to compute the intermediate velocities after divergence solver + */ + void updateVelocities(); + FORCE_INLINE const Real& getDampingCoeff() const { return m_dampingCoeff; } From 39566743ef40247836bffd1bc231dc1d26a074e9 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Sun, 25 Jun 2023 11:56:07 +0200 Subject: [PATCH 29/38] bugfix and friction --- SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp | 75 ++++++++------- SPlisHSPlasH/IISPH/TimeStepIISPH.cpp | 36 +++---- SPlisHSPlasH/Simulation.cpp | 3 + SPlisHSPlasH/StrongCouplingBoundarySolver.cpp | 93 ++++++++++++++++--- SPlisHSPlasH/StrongCouplingBoundarySolver.h | 2 + Simulator/GUI/imgui/Simulator_GUI_imgui.cpp | 7 ++ Simulator/StaticBoundarySimulator.cpp | 10 +- 7 files changed, 153 insertions(+), 73 deletions(-) diff --git a/SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp b/SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp index 0da5809b..063245f9 100644 --- a/SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp +++ b/SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp @@ -322,27 +322,30 @@ void TimeStepDFSPH::pressureSolve() } } - // apply force and torque for computing predicted velocity - sim->getDynamicBoundarySimulator()->updateBoundaryForces(); - - if (anyRigidContact) { - bs->computeSourceTerm(); - bs->computeDiagonalElement(); - avg_density_err_rigid = 0.0; - bs->pressureSolveIteration(avg_density_err_rigid); - if (avg_density_err_rigid > bs->getMaxDensityDeviation()) { - rigidSolverConverged = false; + if (sim->getDynamicBoundarySimulator() != nullptr) { + // apply force and torque for computing predicted velocity + sim->getDynamicBoundarySimulator()->updateBoundaryForces(); + + if (anyRigidContact) { + bs->computeSourceTerm(); + bs->computeDiagonalElement(); + avg_density_err_rigid = 0.0; + bs->pressureSolveIteration(avg_density_err_rigid); + if (avg_density_err_rigid > bs->getMaxDensityDeviation()) { + rigidSolverConverged = false; + } + } else { + // compute the predicted velocity and position without rigid-rigid contacts + bs->computeV_s(); } - } else { - // compute the predicted velocity and position without rigid-rigid contacts - bs->computeV_s(); - } - // clear force and torque used to computed predicted velocity - for (int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)->getRigidBodyObject())->clearForceAndTorque(); + // clear force and torque used to computed predicted velocity + for (int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)->getRigidBodyObject())->clearForceAndTorque(); + } } + // predict density advection using the predicted velocity of fluid an rigid velocities for (unsigned int fluidModelIndex = 0; fluidModelIndex < nFluids; fluidModelIndex++) { FluidModel* model = sim->getFluidModel(fluidModelIndex); @@ -582,26 +585,26 @@ void TimeStepDFSPH::divergenceSolve() } } } - - // apply force and torque for computing predicted velocity - sim->getDynamicBoundarySimulator()->updateBoundaryForces(); - - if (anyRigidContact) { - bs->computeSourceTerm(); - bs->computeDiagonalElement(); - avg_density_err_rigid = 0.0; - bs->pressureSolveIteration(avg_density_err_rigid); - if (avg_density_err_rigid > bs->getMaxDensityDeviation()) { - rigidSolverConverged = false; + if (sim->getDynamicBoundarySimulator() != nullptr) { + // apply force and torque for computing predicted velocity + sim->getDynamicBoundarySimulator()->updateBoundaryForces(); + + if (anyRigidContact) { + bs->computeSourceTerm(); + bs->computeDiagonalElement(); + avg_density_err_rigid = 0.0; + bs->pressureSolveIteration(avg_density_err_rigid); + if (avg_density_err_rigid > bs->getMaxDensityDeviation()) { + rigidSolverConverged = false; + } + } else { + // compute the predicted velocity and position without rigid-rigid contacts + bs->computeV_s(); + } + // clear force and torque used to computed predicted velocity + for (int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)->getRigidBodyObject())->clearForceAndTorque(); } - } else { - // compute the predicted velocity and position without rigid-rigid contacts - bs->computeV_s(); - } - - // clear force and torque used to computed predicted velocity - for (int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)->getRigidBodyObject())->clearForceAndTorque(); } // predict density advection using the predicted velocity of fluid an rigid velocities diff --git a/SPlisHSPlasH/IISPH/TimeStepIISPH.cpp b/SPlisHSPlasH/IISPH/TimeStepIISPH.cpp index eb37fcbd..aa0d15f1 100644 --- a/SPlisHSPlasH/IISPH/TimeStepIISPH.cpp +++ b/SPlisHSPlasH/IISPH/TimeStepIISPH.cpp @@ -373,25 +373,27 @@ void TimeStepIISPH::pressureSolveStrongCoupling() { } } - // apply force and torque for computing predicted velocity - sim->getDynamicBoundarySimulator()->updateBoundaryForces(); - - if (anyRigidContact) { - bs->computeSourceTerm(); - bs->computeDiagonalElement(); - avg_density_err_rigid = 0.0; - bs->pressureSolveIteration(avg_density_err_rigid); - if (avg_density_err_rigid > bs->getMaxDensityDeviation()) { - rigidSolverConverged = false; + // apply force and torque for computing predicted velocity + if (sim->getDynamicBoundarySimulator() != nullptr) { + sim->getDynamicBoundarySimulator()->updateBoundaryForces(); + + if (anyRigidContact) { + bs->computeSourceTerm(); + bs->computeDiagonalElement(); + avg_density_err_rigid = 0.0; + bs->pressureSolveIteration(avg_density_err_rigid); + if (avg_density_err_rigid > bs->getMaxDensityDeviation()) { + rigidSolverConverged = false; + } + } else { + // compute the predicted velocity and position without rigid-rigid contacts + bs->computeV_s(); } - } else { - // compute the predicted velocity and position without rigid-rigid contacts - bs->computeV_s(); - } - // clear force and torque used to computed predicted velocity - for (int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { - static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)->getRigidBodyObject())->clearForceAndTorque(); + // clear force and torque used to computed predicted velocity + for (int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { + static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)->getRigidBodyObject())->clearForceAndTorque(); + } } // predict density advection using the predicted velocity of fluid and rigid velocities diff --git a/SPlisHSPlasH/Simulation.cpp b/SPlisHSPlasH/Simulation.cpp index c903a3b6..ff7d6b0e 100644 --- a/SPlisHSPlasH/Simulation.cpp +++ b/SPlisHSPlasH/Simulation.cpp @@ -513,6 +513,9 @@ void Simulation::reset() if (getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { updateBoundaryVolume(); + } + + if (getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { StrongCouplingBoundarySolver::getCurrent()->reset(); } diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp index 1ab4775f..9d64bb6b 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp @@ -264,7 +264,7 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); int bmIndex = boundaryPointSetIndex - nFluids; - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + RigidBodyObject* rb = bm->getRigidBodyObject(); #pragma omp parallel default(shared) { #pragma omp for schedule(static) @@ -305,15 +305,15 @@ void StrongCouplingBoundarySolver::computeV_s() { // Compute v_s for all particles for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - Vector3r gravForce = rb->getMass() * Vector3r(sim->getVecValue(Simulation::GRAVITATION)); - // the rb->getForce() contains only fluid-rigid forces - Vector3r F_R = rb->getForce() + gravForce; - if (rb->isDynamic()) { + DynamicRigidBody* rb = dynamic_cast(bm->getRigidBodyObject()); + if (rb != nullptr && rb->isDynamic()) { #pragma omp parallel default(shared) { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { + Vector3r gravForce = rb->getMass() * Vector3r(sim->getVecValue(Simulation::GRAVITATION)); + // the rb->getForce() contains only fluid-rigid forces + Vector3r F_R = rb->getForce() + gravForce; Vector3r pos = bm->getPosition(r) - rb->getPosition(); // compute v_s setV_s(boundaryPointSetIndex - nFluids, r, rb->getVelocity() + dt * rb->getInvMass() * F_R + @@ -376,8 +376,8 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { for (unsigned int pointSetIndex_r = nFluids; pointSetIndex_r < sim->numberOfPointSets(); pointSetIndex_r++) { BoundaryModel_Akinci2012* bm_r = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_r)); int index_r = pointSetIndex_r - nFluids; - DynamicRigidBody* rb = static_cast(bm_r->getRigidBodyObject()); - if (rb->isDynamic()) { + DynamicRigidBody* rb = dynamic_cast(bm_r->getRigidBodyObject()); + if (rb != nullptr && rb->isDynamic()) { #pragma omp parallel default(shared) { #pragma omp for schedule(static) @@ -454,14 +454,14 @@ void SPH::StrongCouplingBoundarySolver::computeSourceTermRHSForBody(const unsign // compute pressure gradient, v_rr and omega_rr for rigid bodies int bmIndex = boundaryPointSetIndex - nFluids; - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); + DynamicRigidBody* rb = dynamic_cast(bm->getRigidBodyObject()); Real vx = 0; Real vy = 0; Real vz = 0; Real omegax = 0; Real omegay = 0; Real omegaz = 0; - if (rb->isDynamic()) { + if (rb != nullptr && rb->isDynamic()) { #pragma omp parallel default(shared) { #pragma omp for schedule(static) reduction(+:vx) reduction(+:vy) reduction(+:vz) reduction(+:omegax) reduction(+:omegay) reduction(+:omegaz) @@ -576,14 +576,18 @@ void StrongCouplingBoundarySolver::applyForce() { for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); int bmIndex = boundaryPointSetIndex - nFluids; - DynamicRigidBody* rb = static_cast(bm->getRigidBodyObject()); - if (rb->isDynamic()) { + DynamicRigidBody* rb = dynamic_cast(bm->getRigidBodyObject()); + if (rb != nullptr && rb->isDynamic()) { #pragma omp parallel default(shared) { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - const Vector3r f = -getArtificialVolume(bmIndex, r) * getPressureGrad(bmIndex, r); + const Vector3r f = -getArtificialVolume(bmIndex, r) * getPressureGrad(bmIndex, r); bm->addForce(bm->getPosition(r), f); + if (f.norm() > 1e-10) { + const Vector3r fric = copmuteParticleFriction(boundaryPointSetIndex, r, f); + bm->addForce(bm->getPosition(r), fric); + } setPressure(bmIndex, r, static_cast(0.0)); setPressureGrad(bmIndex, r, Vector3r::Zero()); } @@ -592,14 +596,73 @@ void StrongCouplingBoundarySolver::applyForce() { } } +Vector3r StrongCouplingBoundarySolver::copmuteParticleFriction(const unsigned int& boundaryPointSetIndex, const unsigned int& index, const Vector3r& force) { + Simulation* sim = Simulation::getCurrent(); + DynamicBoundarySimulator* boundarySimulator = sim->getDynamicBoundarySimulator(); + TimeManager* tm = TimeManager::getCurrent(); + const Real dt = tm->getTimeStepSize(); + const unsigned int nFluids = sim->numberOfFluidModels(); + BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); + DynamicRigidBody* rb = dynamic_cast(bm->getRigidBodyObject()); + if (rb == nullptr) { + return Vector3r::Zero(); + } + int bmIndex = boundaryPointSetIndex - nFluids; + + // compute normal + Vector3r numerator = bm->getPosition(index) * W_zero(); + Real denom = W_zero(); + for (unsigned int n = 0; n < sim->numberOfNeighbors(boundaryPointSetIndex, boundaryPointSetIndex, index); n++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, boundaryPointSetIndex, index, n); + numerator += bm->getPosition(k) * W(bm->getPosition(index) - bm->getPosition(k)); + denom += W(bm->getPosition(index) - bm->getPosition(k)); + } + Vector3r normal = bm->getPosition(index) - numerator / denom; + normal.normalize(); + + // compute averaged relative predicted velocity + Vector3r numeratorV = Vector3r::Zero(); + Real denomV = 0; + for (unsigned int pid = nFluids; pid < sim->numberOfPointSets(); pid++) { + BoundaryModel_Akinci2012* bm_k = static_cast(sim->getBoundaryModelFromPointSet(pid)); + if (pid != boundaryPointSetIndex) { + for (unsigned int n = 0; n < sim->numberOfNeighbors(boundaryPointSetIndex, pid, index); n++) { + const unsigned int k = sim->getNeighbor(boundaryPointSetIndex, pid, index, n); + numeratorV += getPredictedVelocity(pid - nFluids, k) * W(bm->getPosition(index) - bm_k->getPosition(k)); + denomV += W(bm->getPosition(index) - bm_k->getPosition(k)); + } + } + } + Vector3r neighborV = numeratorV / denomV; + Vector3r relativeV = getPredictedVelocity(bmIndex, index) - neighborV; + Vector3r normalVPred = relativeV.dot(normal) * normal; + Vector3r tangentialVPred = relativeV - normalVPred; + + Vector3r tangent = tangentialVPred; + tangent.normalize(); + Vector3r normalF = -force.dot(normal) * normal; + Vector3r tangentF = -rb->getFrictionCoeff() * normalF.norm() * tangent; + Vector3r pos = bm->getPosition(index); + Matrix3r productMat; + productMat << 0, -pos.z(), pos.y(), + pos.z(), 0, -pos.x(), + -pos.y(), pos.x(), 0; + Matrix3r K = rb->getInvMass() * Matrix3r::Identity() - productMat * rb->getInertiaTensorInverseW() * productMat; + Vector3r max = -tangentialVPred / (dt * getBodyContacts(bmIndex) * tangent.transpose() * K * tangent); + if (max.norm() < tangentF.norm()) { + tangentF = max; + } + return tangentF; +} + Real StrongCouplingBoundarySolver::W(const Vector3r& r) { return m_kernelFct(r); } -Vector3r SPH::StrongCouplingBoundarySolver::gradW(const Vector3r& r) { +Vector3r StrongCouplingBoundarySolver::gradW(const Vector3r& r) { return m_gradKernelFct(r); } -Real SPH::StrongCouplingBoundarySolver::W_zero() { +Real StrongCouplingBoundarySolver::W_zero() { return m_W_zero; } diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.h b/SPlisHSPlasH/StrongCouplingBoundarySolver.h index 12ef8095..21d81f9f 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.h +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.h @@ -27,6 +27,7 @@ namespace SPH { std::vector> m_diagonalElement; // diagonal element for jacobi iteration std::vector m_v_rr_body; std::vector m_omega_rr_body; + std::vector> m_contacts; std::vector m_bodyContacts; unsigned int m_contactsAllBodies; @@ -56,6 +57,7 @@ namespace SPH { void computeSourceTerm(); void computeDiagonalElement(); void pressureSolveIteration(Real& avgDensityDeviation); + Vector3r copmuteParticleFriction(const unsigned int& boundaryPointSetIndex, const unsigned int& index, const Vector3r& force); void applyForce(); void performNeighborhoodSearchSort(); Real W(const Vector3r& r); diff --git a/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp b/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp index 1f36b5ee..8ce323b7 100644 --- a/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp +++ b/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp @@ -568,6 +568,13 @@ void Simulator_GUI_imgui::initSimulationParameterGUI() if (model->getRigidBodyObject()->isDynamic()) { DynamicRigidBody* drb = static_cast(model->getRigidBodyObject()); + imguiParameters::imguiNumericParameter* frictionCoeff = new imguiParameters::imguiNumericParameter(); + frictionCoeff->description = "friction coefficient of the rigid body"; + frictionCoeff->label = "friction coefficient"; + frictionCoeff->getFct = [drb]() -> Real {return drb->getFrictionCoeff(); }; + frictionCoeff->setFct = [drb](Real v) {drb->setFrictionCoeff(v); }; + imguiParameters::addParam("Boundary Model", "Property", frictionCoeff); + imguiParameters::imguiNumericParameter* density = new imguiParameters::imguiNumericParameter(); density->description = "Density of the rigid body"; density->label = "Density"; diff --git a/Simulator/StaticBoundarySimulator.cpp b/Simulator/StaticBoundarySimulator.cpp index 6a1b9cd4..dc69a729 100644 --- a/Simulator/StaticBoundarySimulator.cpp +++ b/Simulator/StaticBoundarySimulator.cpp @@ -61,7 +61,7 @@ void StaticBoundarySimulator::initBoundaryData() MeshImport::importMesh(meshFileName, geo, Vector3r::Zero(), Matrix3r::Identity(), scene.boundaryModels[i]->scale); std::vector boundaryParticles; - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { // if a samples file is given, use this one if (scene.boundaryModels[i]->samplesFile != "") @@ -150,7 +150,7 @@ void StaticBoundarySimulator::initBoundaryData() rb->setRotation0(q); rb->setRotation(q); - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { BoundaryModel_Akinci2012 *bm = new BoundaryModel_Akinci2012(); bm->initModel(rb, static_cast(boundaryParticles.size()), &boundaryParticles[0]); @@ -182,7 +182,7 @@ void StaticBoundarySimulator::deferredInit() { Simulation* sim = Simulation::getCurrent(); sim->performNeighborhoodSearchSort(); - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { m_base->updateBoundaryParticles(true); Simulation::getCurrent()->updateBoundaryVolume(); @@ -201,7 +201,7 @@ void StaticBoundarySimulator::deferredInit() void StaticBoundarySimulator::timeStep() { Simulation* sim = Simulation::getCurrent(); - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) m_base->updateBoundaryParticles(false); else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) m_base->updateDMVelocity(); @@ -221,7 +221,7 @@ void StaticBoundarySimulator::reset() } } - if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012) + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) m_base->updateBoundaryParticles(true); else if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Koschier2017) m_base->updateDMVelocity(); From 77d034ae001dba4d44d0dbdbee435d577f3da9de Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Mon, 26 Jun 2023 18:09:12 +0200 Subject: [PATCH 30/38] volume integration --- SPlisHSPlasH/DynamicRigidBody.h | 98 +++------ SPlisHSPlasH/Simulation.cpp | 1 + .../Utilities/SceneParameterObjects.h | 2 +- Utilities/CMakeLists.txt | 3 + Utilities/VolumeIntegration.cpp | 207 ++++++++++++++++++ Utilities/VolumeIntegration.h | 72 ++++++ 6 files changed, 309 insertions(+), 74 deletions(-) create mode 100644 Utilities/VolumeIntegration.cpp create mode 100644 Utilities/VolumeIntegration.h diff --git a/SPlisHSPlasH/DynamicRigidBody.h b/SPlisHSPlasH/DynamicRigidBody.h index 0224945b..e38319ea 100644 --- a/SPlisHSPlasH/DynamicRigidBody.h +++ b/SPlisHSPlasH/DynamicRigidBody.h @@ -6,6 +6,7 @@ #include "TriangleMesh.h" #include "TimeManager.h" #include "Simulation.h" +#include "Utilities/VolumeIntegration.h" namespace SPH { @@ -98,18 +99,18 @@ namespace SPH { void initBody(const Real density, const bool isDynamic, const Vector3r &position, const Quaternionr &rotation, const Vector3r &scale, const Vector3r &velocity, const Real &friction) { - m_density = density; - m_scale = scale; - determineMassProperties(density, isDynamic, scale); + m_isDynamic = isDynamic; + m_mass = 1.0; + m_inertiaTensor = Vector3r(1.0, 1.0, 1.0); + determineMassProperties(density); m_x = position; m_x0 = position; m_lastX = position; m_oldX = position; m_v0 = velocity; - m_v = m_v0; + m_v = velocity; m_a.setZero(); - m_force.setZero(); m_q = rotation; m_q0 = rotation; @@ -123,7 +124,6 @@ namespace SPH { //m_restitutionCoeff = static_cast(0.6); m_frictionCoeff = friction; - updateMeshTransformation(); } @@ -170,23 +170,28 @@ namespace SPH { } // Determine mass and inertia tensor - void determineMassProperties(const Real density, bool isDynamic, const Vector3r scale) { - m_isDynamic = isDynamic; - // for now only consider cubiod which is scaled from a unit cube - setMass(density * scale.x() * scale.y() * scale.z()); - Vector3r value = m_mass * Vector3r((scale.y() * scale.y() + scale.z() * scale.z()) / 12, (scale.x() * scale.x() + scale.z() * scale.z()) / 12, (scale.x() * scale.x() + scale.y() * scale.y()) / 12); - m_inertiaTensor = value; - m_inertiaTensorInverse = Vector3r(static_cast(1.0) / value[0], static_cast(1.0) / value[1], static_cast(1.0) / value[2]); + void determineMassProperties(const Real density) { + Utilities::VolumeIntegration vi(m_geometry.numVertices(), m_geometry.numFaces(), &m_geometry.getVertices()[0], m_geometry.getFaces().data()); + vi.compute_inertia_tensor(density); + + // Diagonalize Inertia Tensor + Eigen::SelfAdjointEigenSolver es(vi.getInertia()); + Vector3r inertiaTensor = Vector3r::Zero(); + inertiaTensor += es.eigenvalues().x() * es.eigenvectors().col(0); + inertiaTensor += es.eigenvalues().y() * es.eigenvectors().col(1); + inertiaTensor += es.eigenvalues().z() * es.eigenvectors().col(2); + inertiaTensor.x() = std::abs(inertiaTensor.x()); + inertiaTensor.y() = std::abs(inertiaTensor.y()); + inertiaTensor.z() = std::abs(inertiaTensor.z()); + setMass(vi.getMass()); + setInertiaTensor(inertiaTensor); } void rotationUpdated() { - if (m_mass != 0.0) - { - m_rot = m_q.matrix(); - updateInertiaW(); - updateInverseTransformation(); - } + m_rot = m_q.matrix(); + updateInertiaW(); + updateInverseTransformation(); } void updateInertiaW() @@ -198,59 +203,6 @@ namespace SPH { } } - /** Determine mass and inertia tensor of the given geometry. - */ - //void determineMassProperties(const Real density) - //{ - // // apply initial rotation - // VertexData &vd = m_geometry.getVertexDataLocal(); - // - // Utilities::VolumeIntegration vi(m_geometry.getVertexDataLocal().size(), m_geometry.getMesh().numFaces(), &m_geometry.getVertexDataLocal().getPosition(0), m_geometry.getMesh().getFaces().data()); - // vi.compute_inertia_tensor(density); - // - // // Diagonalize Inertia Tensor - // Eigen::SelfAdjointEigenSolver es(vi.getInertia()); - // Vector3r inertiaTensor = es.eigenvalues(); - // Matrix3r R = es.eigenvectors(); - // - // setMass(1.0); - // setInertiaTensor(inertiaTensor); - // - // if (R.determinant() < 0.0) - // R = -R; - // - // for (unsigned int i = 0; i < vd.size(); i++) - // vd.getPosition(i) = m_rot * vd.getPosition(i) + m_x0; - // - // Vector3r x_MAT = vi.getCenterOfMass(); - // R = m_rot * R; - // x_MAT = m_rot * x_MAT + m_x0; - // - // // rotate vertices back - // for (unsigned int i = 0; i < vd.size(); i++) - // vd.getPosition(i) = R.transpose() * (vd.getPosition(i) - x_MAT); - // - // // set rotation - // Quaternionr qR = Quaternionr(R); - // qR.normalize(); - // m_q_mat = qR; - // m_q_initial = m_q0; - // m_x0_mat = m_x0 - x_MAT; - // - // m_q0 = qR; - // m_q = m_q0; - // m_lastQ = m_q0; - // m_oldQ = m_q0; - // rotationUpdated(); - // - // // set translation - // m_x0 = x_MAT; - // m_x = m_x0; - // m_lastX = m_x0; - // m_oldX = m_x0; - // updateInverseTransformation(); - //} - const Matrix3r &getTransformationR() { return m_transformation_R; } const Vector3r &getTransformationV1() { return m_transformation_v1; } const Vector3r &getTransformationV2() { return m_transformation_v2; } @@ -284,7 +236,7 @@ namespace SPH { FORCE_INLINE void setDensity(const Real& density) { m_density = density; - determineMassProperties(density, isDynamic(), m_scale); + determineMassProperties(density); } FORCE_INLINE Vector3r &getLastPosition() diff --git a/SPlisHSPlasH/Simulation.cpp b/SPlisHSPlasH/Simulation.cpp index ff7d6b0e..5994eca1 100644 --- a/SPlisHSPlasH/Simulation.cpp +++ b/SPlisHSPlasH/Simulation.cpp @@ -85,6 +85,7 @@ Simulation::Simulation () m_animationFieldSystem = new AnimationFieldSystem(); m_boundaryHandlingMethod = static_cast(BoundaryHandlingMethods::Bender2019); + m_dynamicBoundarySimulator = nullptr; } Simulation::~Simulation () diff --git a/SPlisHSPlasH/Utilities/SceneParameterObjects.h b/SPlisHSPlasH/Utilities/SceneParameterObjects.h index e7f20707..b9957c53 100644 --- a/SPlisHSPlasH/Utilities/SceneParameterObjects.h +++ b/SPlisHSPlasH/Utilities/SceneParameterObjects.h @@ -350,7 +350,7 @@ namespace Utilities scale = Vector3r::Ones(); dynamic = false; isWall = false; - friction = 0.0; + friction = 0.2; color = Eigen::Vector4f(1.0f, 0.0f, 0.0f, 0.0f); samplingMode = 0; isAnimated = false; diff --git a/Utilities/CMakeLists.txt b/Utilities/CMakeLists.txt index dd9d2199..bf38579e 100644 --- a/Utilities/CMakeLists.txt +++ b/Utilities/CMakeLists.txt @@ -26,6 +26,9 @@ add_library(Utilities SystemInfo.h Timing.h Version.h + VolumeIntegration.cpp + VolumeIntegration.h + ) add_dependencies(Utilities partio zlib) diff --git a/Utilities/VolumeIntegration.cpp b/Utilities/VolumeIntegration.cpp new file mode 100644 index 00000000..97ca8fbb --- /dev/null +++ b/Utilities/VolumeIntegration.cpp @@ -0,0 +1,207 @@ + +#include "VolumeIntegration.h" +#include + +using namespace std; +using namespace Eigen; +using namespace Utilities; + +#define SQR(x) ((x)*(x)) +#define CUBE(x) ((x)*(x)*(x)) + +VolumeIntegration::VolumeIntegration(const unsigned int nVertices, const unsigned int nFaces, Vector3r * const vertices, const unsigned int* indices) + : m_nVertices(nVertices), m_nFaces(nFaces), m_indices(indices), m_face_normals(nFaces), m_weights(nFaces) +{ + // compute center of mass + m_x.setZero(); + for (unsigned int i(0); i < m_nVertices; ++i) + m_x += vertices[i]; + m_x /= (Real)m_nVertices; + + m_vertices.resize(nVertices); + for (unsigned int i(0); i < m_nVertices; ++i) + m_vertices[i] = vertices[i] - m_x; + + for (unsigned int i(0); i < m_nFaces; ++i) + { + const Vector3r &a = m_vertices[m_indices[3 * i]]; + const Vector3r &b = m_vertices[m_indices[3 * i + 1]]; + const Vector3r &c = m_vertices[m_indices[3 * i + 2]]; + + const Vector3r d1 = b - a; + const Vector3r d2 = c - a; + + m_face_normals[i] = d1.cross(d2); + if (m_face_normals[i].isZero(1.e-10)) + m_face_normals[i].setZero(); + else + m_face_normals[i].normalize(); + + m_weights[i] = -m_face_normals[i].dot(a); + } +} + +void VolumeIntegration::compute_inertia_tensor(Real density) +{ + volume_integrals(); + m_volume = static_cast(T0); + + m_mass = static_cast(density * T0); + + /* compute center of mass */ + m_r[0] = static_cast(T1[0] / T0); + m_r[1] = static_cast(T1[1] / T0); + m_r[2] = static_cast(T1[2] / T0); + + /* compute inertia tensor */ + m_theta(0, 0) = static_cast(density * (T2[1] + T2[2])); + m_theta(1, 1) = static_cast(density * (T2[2] + T2[0])); + m_theta(2, 2) = static_cast(density * (T2[0] + T2[1])); + m_theta(0, 1) = m_theta(1, 0) = -density * static_cast(TP[0]); + m_theta(1, 2) = m_theta(2, 1) = -density * static_cast(TP[1]); + m_theta(2, 0) = m_theta(0, 2) = -density * static_cast(TP[2]); + + /* translate inertia tensor to center of mass */ + m_theta(0, 0) -= m_mass * (m_r[1]*m_r[1] + m_r[2]*m_r[2]); + m_theta(1, 1) -= m_mass * (m_r[2]*m_r[2] + m_r[0]*m_r[0]); + m_theta(2, 2) -= m_mass * (m_r[0]*m_r[0] + m_r[1]*m_r[1]); + m_theta(0, 1) = m_theta(1, 0) += m_mass * m_r[0] * m_r[1]; + m_theta(1, 2) = m_theta(2, 1) += m_mass * m_r[1] * m_r[2]; + m_theta(2, 0) = m_theta(0, 2) += m_mass * m_r[2] * m_r[0]; + + m_r += m_x; +} + + +void VolumeIntegration::projection_integrals(unsigned int f) +{ + Real a0, a1, da; + Real b0, b1, db; + Real a0_2, a0_3, a0_4, b0_2, b0_3, b0_4; + Real a1_2, a1_3, b1_2, b1_3; + Real C1, Ca, Caa, Caaa, Cb, Cbb, Cbbb; + Real Cab, Kab, Caab, Kaab, Cabb, Kabb; + + P1 = Pa = Pb = Paa = Pab = Pbb = Paaa = Paab = Pabb = Pbbb = 0.0; + + for (int i = 0; i < 3; i++) + { + a0 = m_vertices[m_indices[3 * f + i]][A]; + b0 = m_vertices[m_indices[3 * f + i]][B]; + a1 = m_vertices[m_indices[3 * f + ((i + 1) % 3)]][A]; + b1 = m_vertices[m_indices[3 * f + ((i + 1) % 3)]][B]; + + da = a1 - a0; + db = b1 - b0; + a0_2 = a0 * a0; a0_3 = a0_2 * a0; a0_4 = a0_3 * a0; + b0_2 = b0 * b0; b0_3 = b0_2 * b0; b0_4 = b0_3 * b0; + a1_2 = a1 * a1; a1_3 = a1_2 * a1; + b1_2 = b1 * b1; b1_3 = b1_2 * b1; + + C1 = a1 + a0; + Ca = a1*C1 + a0_2; Caa = a1*Ca + a0_3; Caaa = a1*Caa + a0_4; + Cb = b1*(b1 + b0) + b0_2; Cbb = b1*Cb + b0_3; Cbbb = b1*Cbb + b0_4; + Cab = 3 * a1_2 + 2 * a1*a0 + a0_2; Kab = a1_2 + 2 * a1*a0 + 3 * a0_2; + Caab = a0*Cab + 4 * a1_3; Kaab = a1*Kab + 4 * a0_3; + Cabb = 4 * b1_3 + 3 * b1_2*b0 + 2 * b1*b0_2 + b0_3; + Kabb = b1_3 + 2 * b1_2*b0 + 3 * b1*b0_2 + 4 * b0_3; + + P1 += db*C1; + Pa += db*Ca; + Paa += db*Caa; + Paaa += db*Caaa; + Pb += da*Cb; + Pbb += da*Cbb; + Pbbb += da*Cbbb; + Pab += db*(b1*Cab + b0*Kab); + Paab += db*(b1*Caab + b0*Kaab); + Pabb += da*(a1*Cabb + a0*Kabb); + } + + P1 /= 2.0; + Pa /= 6.0; + Paa /= 12.0; + Paaa /= 20.0; + Pb /= -6.0; + Pbb /= -12.0; + Pbbb /= -20.0; + Pab /= 24.0; + Paab /= 60.0; + Pabb /= -60.0; +} + +void VolumeIntegration::face_integrals(unsigned int f) +{ + Real w; + Vector3r n; + Real k1, k2, k3, k4; + + projection_integrals(f); + + w = m_weights[f]; + n = m_face_normals[f]; + k1 = (n[C] == 0) ? 0 : 1 / n[C]; + k2 = k1 * k1; k3 = k2 * k1; k4 = k3 * k1; + + Fa = k1 * Pa; + Fb = k1 * Pb; + Fc = -k2 * (n[A]*Pa + n[B]*Pb + w*P1); + + Faa = k1 * Paa; + Fbb = k1 * Pbb; + Fcc = k3 * (SQR(n[A])*Paa + 2*n[A]*n[B]*Pab + SQR(n[B])*Pbb + + w*(2*(n[A]*Pa + n[B]*Pb) + w*P1)); + + Faaa = k1 * Paaa; + Fbbb = k1 * Pbbb; + Fccc = -k4 * (CUBE(n[A])*Paaa + 3*SQR(n[A])*n[B]*Paab + + 3*n[A]*SQR(n[B])*Pabb + CUBE(n[B])*Pbbb + + 3*w*(SQR(n[A])*Paa + 2*n[A]*n[B]*Pab + SQR(n[B])*Pbb) + + w*w*(3*(n[A]*Pa + n[B]*Pb) + w*P1)); + + Faab = k1 * Paab; + Fbbc = -k2 * (n[A]*Pabb + n[B]*Pbbb + w*Pbb); + Fcca = k3 * (SQR(n[A])*Paaa + 2*n[A]*n[B]*Paab + SQR(n[B])*Pabb + + w*(2*(n[A]*Paa + n[B]*Pab) + w*Pa)); +} + +void VolumeIntegration::volume_integrals() +{ + Real nx, ny, nz; + + T0 = T1[0] = T1[1] = T1[2] + = T2[0] = T2[1] = T2[2] + = TP[0] = TP[1] = TP[2] = 0; + + for (unsigned int i(0); i < m_nFaces; ++i) + { + Vector3r const& n = m_face_normals[i]; + nx = std::abs(n[0]); + ny = std::abs(n[1]); + nz = std::abs(n[2]); + if (nx > ny && nx > nz) + C = 0; + else + C = (ny > nz) ? 1 : 2; + A = (C + 1) % 3; + B = (A + 1) % 3; + + face_integrals(i); + + T0 += n[0] * ((A == 0) ? Fa : ((B == 0) ? Fb : Fc)); + + T1[A] += n[A] * Faa; + T1[B] += n[B] * Fbb; + T1[C] += n[C] * Fcc; + T2[A] += n[A] * Faaa; + T2[B] += n[B] * Fbbb; + T2[C] += n[C] * Fccc; + TP[A] += n[A] * Faab; + TP[B] += n[B] * Fbbc; + TP[C] += n[C] * Fcca; + } + + T1[0] /= 2; T1[1] /= 2; T1[2] /= 2; + T2[0] /= 3; T2[1] /= 3; T2[2] /= 3; + TP[0] /= 2; TP[1] /= 2; TP[2] /= 2; +} diff --git a/Utilities/VolumeIntegration.h b/Utilities/VolumeIntegration.h new file mode 100644 index 00000000..db394125 --- /dev/null +++ b/Utilities/VolumeIntegration.h @@ -0,0 +1,72 @@ + +#ifndef __VOLUME_INTEGRATION_H__ +#define __VOLUME_INTEGRATION_H__ + +#include +#include +#include + +#include + +namespace Utilities +{ + class VolumeIntegration + { + + private: + int A; + int B; + int C; + + // projection integrals + Real P1, Pa, Pb, Paa, Pab, Pbb, Paaa, Paab, Pabb, Pbbb; + // face integrals + Real Fa, Fb, Fc, Faa, Fbb, Fcc, Faaa, Fbbb, Fccc, Faab, Fbbc, Fcca; + // volume integrals + Real T0; + Real T1[3]; + Real T2[3]; + Real TP[3]; + + public: + + VolumeIntegration(const unsigned int nVertices, const unsigned int nFaces, Vector3r * const vertices, const unsigned int* indices); + + /** Compute inertia tensor for given geometry and given density. + */ + void compute_inertia_tensor(Real density); + + /** Return mass of body. */ + Real getMass() const { return m_mass; } + /** Return volume of body. */ + Real getVolume() const { return m_volume; } + /** Return inertia tensor of body. */ + Matrix3r const& getInertia() const { return m_theta; } + /** Return center of mass. */ + Vector3r const& getCenterOfMass() const { return m_r; } + + private: + + void volume_integrals(); + void face_integrals(unsigned int i); + + /** Compute various integrations over projection of face. + */ + void projection_integrals(unsigned int i); + + + std::vector m_face_normals; + std::vector m_weights; + unsigned int m_nVertices; + unsigned int m_nFaces; + std::vector m_vertices; + const unsigned int* m_indices; + + Real m_mass, m_volume; + Vector3r m_r; + Vector3r m_x; + Matrix3r m_theta; + }; +} + +#endif From 0397009130730736aaf306bf45d871d0d340785f Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Thu, 13 Jul 2023 18:10:33 +0200 Subject: [PATCH 31/38] modified python bindings correspondingly --- SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp | 32 ++++++++++++++-------------- SPlisHSPlasH/DynamicRigidBody.h | 1 + pySPlisHSPlasH/UtilitiesModule.cpp | 9 +++++--- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp b/SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp index 063245f9..3ac47799 100644 --- a/SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp +++ b/SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp @@ -360,17 +360,17 @@ void TimeStepDFSPH::pressureSolve() const Real& density = model->getDensity(i); const Real density0 = model->getDensity0(); Real densityAdv = m_simulationData.getDensityAdvNoBoundary(fluidModelIndex, i); - /*#ifdef USE_AVX + #ifdef USE_AVX Scalarf8 delta_avx(0.0f); const Vector3f8 xi_avx(xi); Vector3f8 vi_avx(predictedV); forall_boundary_neighbors_avx( const Scalarf8 Vj_avx = convert_zero(&sim->getNeighborList(fluidModelIndex, pid, i)[j], &bm_neighbor->getVolume(0), count); - const Vector3f8 vj_avx = convertVec_zero(&sim->getNeighborList(fluidModelIndex, pid, i)[j], &bs->getPredictedVelocity(pid - fluidModelIndex, 0), count); + const Vector3f8 vj_avx = convertVec_zero(&sim->getNeighborList(fluidModelIndex, pid, i)[j], &bs->getPredictedVelocity(pid - nFluids, 0), count); delta_avx += Vj_avx * (vi_avx - vj_avx).dot(CubicKernel_AVX::gradW(xi_avx - xj_avx)); ); densityAdv += h * delta_avx.reduce(); - #else*/ + #else Real delta = 0; // density advection considering rigid bodies forall_boundary_neighbors( @@ -378,7 +378,7 @@ void TimeStepDFSPH::pressureSolve() delta += bm_neighbor->getVolume(neighborIndex) * (predictedV - bs->getPredictedVelocity(pid - nFluids, neighborIndex)).dot(sim->gradW(xi - xj)); ); densityAdv += h * delta; - //#endif + #endif m_simulationData.getDensityAdv(fluidModelIndex, i) = densityAdv; } } @@ -621,22 +621,22 @@ void TimeStepDFSPH::divergenceSolve() Real densityAdv = m_simulationData.getDensityAdvNoBoundary(fluidModelIndex, i); - // #ifdef USE_AVX - //Scalarf8 densityAdv_avx(0.0f); - //const Vector3f8 xi_avx(xi); - //Vector3f8 vi_avx(predictedV); - //forall_boundary_neighbors_avx( - // const Scalarf8 Vj_avx = convert_zero(&sim->getNeighborList(fluidModelIndex, pid, i)[j], &bm_neighbor->getVolume(0), count); - // const Vector3f8 vj_avx = convertVec_zero(&sim->getNeighborList(fluidModelIndex, pid, i)[j], &bs->getPredictedVelocity(pid - fluidModelIndex, 0), count); - // densityAdv_avx += Vj_avx * (vi_avx - vj_avx).dot(CubicKernel_AVX::gradW(xi_avx - xj_avx)); - //); - //densityAdv += densityAdv_avx.reduce(); - // #else + #ifdef USE_AVX + Scalarf8 densityAdv_avx(0.0f); + const Vector3f8 xi_avx(xi); + Vector3f8 vi_avx(predictedV); + forall_boundary_neighbors_avx( + const Scalarf8 Vj_avx = convert_zero(&sim->getNeighborList(fluidModelIndex, pid, i)[j], &bm_neighbor->getVolume(0), count); + const Vector3f8 vj_avx = convertVec_zero(&sim->getNeighborList(fluidModelIndex, pid, i)[j], &bs->getPredictedVelocity(pid - nFluids, 0), count); + densityAdv_avx += Vj_avx * (vi_avx - vj_avx).dot(CubicKernel_AVX::gradW(xi_avx - xj_avx)); + ); + densityAdv += densityAdv_avx.reduce(); + #else // density advection considering rigid bodies forall_boundary_neighbors( densityAdv += bm_neighbor->getVolume(neighborIndex) * (predictedV - bs->getPredictedVelocity(pid - nFluids, neighborIndex)).dot(sim->gradW(xi - xj)); ); - //#endif + #endif m_simulationData.getDensityAdv(fluidModelIndex, i) = densityAdv; } diff --git a/SPlisHSPlasH/DynamicRigidBody.h b/SPlisHSPlasH/DynamicRigidBody.h index e38319ea..b8934175 100644 --- a/SPlisHSPlasH/DynamicRigidBody.h +++ b/SPlisHSPlasH/DynamicRigidBody.h @@ -171,6 +171,7 @@ namespace SPH { // Determine mass and inertia tensor void determineMassProperties(const Real density) { + m_density = density; Utilities::VolumeIntegration vi(m_geometry.numVertices(), m_geometry.numFaces(), &m_geometry.getVertices()[0], m_geometry.getFaces().data()); vi.compute_inertia_tensor(density); diff --git a/pySPlisHSPlasH/UtilitiesModule.cpp b/pySPlisHSPlasH/UtilitiesModule.cpp index 7584ed2a..8133a92c 100644 --- a/pySPlisHSPlasH/UtilitiesModule.cpp +++ b/pySPlisHSPlasH/UtilitiesModule.cpp @@ -277,20 +277,23 @@ void UtilitiesModule(py::module m) { .def(py::init<>()) .def(py::init, std::string, bool, Real, - Eigen::Matrix, unsigned int, bool>(), + Eigen::Matrix, unsigned int, bool, Vector3r, Real, Real>(), "samplesFile"_a = "", "meshFile"_a = "", "translation"_a = Vector3r::Zero(), - "axis"_a = Vector3r(1,0,0), "angle"_a = 0.0, "scale"_a = Vector3r::Ones(), + "axis"_a = Vector3r(1,0,0), "angle"_a = 0.0, "scale"_a = Vector3r::Ones(), "isDynamic"_a = false, "isWall"_a = false, "color"_a = Eigen::Vector4f(1.f, 0.f, 0.f, 0.f), "mapFile"_a = "", "mapInvert"_a = false, "mapThickness"_a = 0.0, "mapResolution"_a = Eigen::Matrix(20, 20, 20), - "samplingMode"_a = 0, "isAnimated"_a = false) + "samplingMode"_a = 0, "isAnimated"_a = false, "velocity"_a = Vector3r::Zero(), "density"_a = 1000, "friction"_a = 0.2) .def_readwrite("samplesFile", &Utilities::BoundaryParameterObject::samplesFile) .def_readwrite("meshFile", &Utilities::BoundaryParameterObject::meshFile) .def_readwrite("translation", &Utilities::BoundaryParameterObject::translation) .def_readwrite("axis", &Utilities::BoundaryParameterObject::axis) + .def_readwrite("velocity", &Utilities::BoundaryParameterObject::velocity) .def_readwrite("angle", &Utilities::BoundaryParameterObject::angle) .def_readwrite("scale", &Utilities::BoundaryParameterObject::scale) + .def_readwrite("density", &Utilities::BoundaryParameterObject::density) + .def_readwrite("friction", &Utilities::BoundaryParameterObject::friction) .def_readwrite("dynamic", &Utilities::BoundaryParameterObject::dynamic) .def_readwrite("isWall", &Utilities::BoundaryParameterObject::isWall) .def_readwrite("color", &Utilities::BoundaryParameterObject::color) From 2237caf9b374f305a1f97c474794072b75e23566 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Wed, 2 Aug 2023 19:11:47 +0200 Subject: [PATCH 32/38] pybinding fix --- SPlisHSPlasH/DynamicRigidBody.h | 9 ++++++++ SPlisHSPlasH/StrongCouplingBoundarySolver.cpp | 8 +++---- Simulator/DynamicBoundarySimulator.cpp | 2 +- pySPlisHSPlasH/RigidBodyModule.cpp | 22 +++++++++++++++++++ pySPlisHSPlasH/UtilitiesModule.cpp | 12 +++++----- 5 files changed, 42 insertions(+), 11 deletions(-) diff --git a/SPlisHSPlasH/DynamicRigidBody.h b/SPlisHSPlasH/DynamicRigidBody.h index b8934175..4aec5922 100644 --- a/SPlisHSPlasH/DynamicRigidBody.h +++ b/SPlisHSPlasH/DynamicRigidBody.h @@ -589,6 +589,15 @@ namespace SPH { clearForceAndTorque(); } + void animate() { + const Real dt = TimeManager::getCurrent()->getTimeStepSize(); + m_x += m_v * dt; + Quaternionr angVelQ(0.0, m_omega[0], m_omega[1], m_omega[2]); + m_q.coeffs() += dt * 0.5 * (angVelQ * m_q).coeffs(); + m_q.normalize(); + updateMeshTransformation(); + } + virtual const std::vector& getVertices() const { return m_geometry.getVertices(); }; diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp index 9d64bb6b..009e31de 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp @@ -269,6 +269,8 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { + //gamma = 0.7, see the paper + const Real gamma = static_cast(0.7); if (rb->isDynamic()) { // compute density for particle r Real particleDensity = getRestDensity() * bm->getVolume(r) * W_zero(); @@ -280,16 +282,14 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { particleDensity += getRestDensity() * bm->getVolume(r) * W(bm->getPosition(r) - bm_neighbor->getPosition(k)); } } - setDensity(bmIndex, r, std::max(particleDensity, getRestDensity())); - //gamma = 0.7, see the paper - const Real gamma = static_cast(0.7); + setDensity(bmIndex, r, std::max(particleDensity, getRestDensity())); if (getDensity(bmIndex, r) > getRestDensity()) { setArtificialVolume(bmIndex, r, gamma * getRestDensity() * bm->getVolume(r) / getDensity(bmIndex, r)); } else { setArtificialVolume(bmIndex, r, gamma * bm->getVolume(r)); } } else { - setArtificialVolume(bmIndex, r, bm->getVolume(r)); + setArtificialVolume(bmIndex, r, gamma * bm->getVolume(r)); } } } diff --git a/Simulator/DynamicBoundarySimulator.cpp b/Simulator/DynamicBoundarySimulator.cpp index 3393aab2..b15b79ab 100644 --- a/Simulator/DynamicBoundarySimulator.cpp +++ b/Simulator/DynamicBoundarySimulator.cpp @@ -53,7 +53,7 @@ void DynamicBoundarySimulator::initBoundaryData() { } DynamicRigidBody* rb = new DynamicRigidBody(); - rb->setIsAnimated(true); + rb->setIsAnimated(scene.boundaryModels[i]->isAnimated); TriangleMesh& geo = rb->getGeometry(); MeshImport::importMesh(meshFileName, geo, Vector3r::Zero(), Matrix3r::Identity(), scene.boundaryModels[i]->scale); diff --git a/pySPlisHSPlasH/RigidBodyModule.cpp b/pySPlisHSPlasH/RigidBodyModule.cpp index 9d892218..1d8da191 100644 --- a/pySPlisHSPlasH/RigidBodyModule.cpp +++ b/pySPlisHSPlasH/RigidBodyModule.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -64,4 +65,25 @@ void RigidBodyModule(py::module m_sub){ return py::memoryview::from_buffer(base_ptr, { faces.size() }, { sizeof(unsigned int) }); }); + // --------------------------------------- + // Class Dynamic Rigid Body + // --------------------------------------- + py::class_(m_sub, "DynamicRigidBody") + .def(py::init<>()) + .def("setWorldSpacePosition", &SPH::DynamicRigidBody::setWorldSpacePosition) + .def("setWorldSpaceRotation", &SPH::DynamicRigidBody::setWorldSpaceRotation) + .def("animate", &SPH::DynamicRigidBody::animate) + .def("getGeometry", &SPH::DynamicRigidBody::getGeometry) + .def("getVertexBuffer", [](SPH::DynamicRigidBody& obj) -> py::memoryview { + auto vertices = obj.getVertices(); + void* base_ptr = &vertices[0][0]; + int num_vert = vertices.size(); + return py::memoryview::from_buffer((Real*)base_ptr, { num_vert, 3 }, { sizeof(Real) * 3, sizeof(Real) }); + }) + .def("getFaceBuffer", [](SPH::DynamicRigidBody& obj) -> py::memoryview { + auto faces = obj.getFaces(); + unsigned int* base_ptr = faces.data(); + return py::memoryview::from_buffer(base_ptr, { faces.size() }, { sizeof(unsigned int) }); + }); + } diff --git a/pySPlisHSPlasH/UtilitiesModule.cpp b/pySPlisHSPlasH/UtilitiesModule.cpp index 8133a92c..f6479b84 100644 --- a/pySPlisHSPlasH/UtilitiesModule.cpp +++ b/pySPlisHSPlasH/UtilitiesModule.cpp @@ -288,12 +288,9 @@ void UtilitiesModule(py::module m) { .def_readwrite("samplesFile", &Utilities::BoundaryParameterObject::samplesFile) .def_readwrite("meshFile", &Utilities::BoundaryParameterObject::meshFile) .def_readwrite("translation", &Utilities::BoundaryParameterObject::translation) - .def_readwrite("axis", &Utilities::BoundaryParameterObject::axis) - .def_readwrite("velocity", &Utilities::BoundaryParameterObject::velocity) + .def_readwrite("axis", &Utilities::BoundaryParameterObject::axis) .def_readwrite("angle", &Utilities::BoundaryParameterObject::angle) - .def_readwrite("scale", &Utilities::BoundaryParameterObject::scale) - .def_readwrite("density", &Utilities::BoundaryParameterObject::density) - .def_readwrite("friction", &Utilities::BoundaryParameterObject::friction) + .def_readwrite("scale", &Utilities::BoundaryParameterObject::scale) .def_readwrite("dynamic", &Utilities::BoundaryParameterObject::dynamic) .def_readwrite("isWall", &Utilities::BoundaryParameterObject::isWall) .def_readwrite("color", &Utilities::BoundaryParameterObject::color) @@ -302,7 +299,10 @@ void UtilitiesModule(py::module m) { .def_readwrite("mapThickness", &Utilities::BoundaryParameterObject::mapThickness) .def_readwrite("mapResolution", &Utilities::BoundaryParameterObject::mapResolution) .def_readwrite("samplingMode", &Utilities::BoundaryParameterObject::samplingMode) - .def_readwrite("isAnimated", &Utilities::BoundaryParameterObject::isAnimated); + .def_readwrite("isAnimated", &Utilities::BoundaryParameterObject::isAnimated) + .def_readwrite("velocity", &Utilities::BoundaryParameterObject::velocity) + .def_readwrite("density", &Utilities::BoundaryParameterObject::density) + .def_readwrite("friction", &Utilities::BoundaryParameterObject::friction); py::class_(m_sub_sub, "FluidData") .def(py::init<>()) From 978be1d5dae4882df6c922e3e9c2c353e1336a0c Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Mon, 21 Aug 2023 12:40:09 +0200 Subject: [PATCH 33/38] boundary solver kernel on gui --- SPlisHSPlasH/StrongCouplingBoundarySolver.cpp | 133 +++++++++++++++++- SPlisHSPlasH/StrongCouplingBoundarySolver.h | 34 ++++- Simulator/GUI/imgui/Simulator_GUI_imgui.cpp | 4 +- 3 files changed, 166 insertions(+), 5 deletions(-) diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp index 009e31de..32e4fb35 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp @@ -6,7 +6,22 @@ #include "SPlisHSPlasH/SPHKernels.h" using namespace SPH; - +using namespace GenParam; + +int StrongCouplingBoundarySolver::KERNEL_METHOD = -1; +int StrongCouplingBoundarySolver::GRAD_KERNEL_METHOD = -1; +int StrongCouplingBoundarySolver::ENUM_KERNEL_CUBIC = -1; +int StrongCouplingBoundarySolver::ENUM_KERNEL_WENDLANDQUINTICC2 = -1; +int StrongCouplingBoundarySolver::ENUM_KERNEL_POLY6 = -1; +int StrongCouplingBoundarySolver::ENUM_KERNEL_SPIKY = -1; +int StrongCouplingBoundarySolver::ENUM_KERNEL_CUBIC_2D = -1; +int StrongCouplingBoundarySolver::ENUM_KERNEL_WENDLANDQUINTICC2_2D = -1; +int StrongCouplingBoundarySolver::ENUM_GRADKERNEL_CUBIC = -1; +int StrongCouplingBoundarySolver::ENUM_GRADKERNEL_WENDLANDQUINTICC2 = -1; +int StrongCouplingBoundarySolver::ENUM_GRADKERNEL_POLY6 = -1; +int StrongCouplingBoundarySolver::ENUM_GRADKERNEL_SPIKY = -1; +int StrongCouplingBoundarySolver::ENUM_GRADKERNEL_CUBIC_2D = -1; +int StrongCouplingBoundarySolver::ENUM_GRADKERNEL_WENDLANDQUINTICC2_2D = -1; StrongCouplingBoundarySolver* StrongCouplingBoundarySolver::current = nullptr; StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : @@ -31,10 +46,14 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_minIterations = 2; m_maxDensityDeviation = 0.001; + m_kernelMethod = 0; + m_gradKernelMethod = 0; m_kernelFct = CubicKernel::W; m_gradKernelFct = CubicKernel::gradW; m_W_zero = CubicKernel::W_zero(); + initParameters(); + Simulation* sim = Simulation::getCurrent(); const unsigned int nBoundaries = sim->numberOfBoundaryModels(); @@ -198,6 +217,43 @@ StrongCouplingBoundarySolver* StrongCouplingBoundarySolver::getCurrent() { return current; } +void StrongCouplingBoundarySolver::initParameters() { + ParameterObject::initParameters(); + + Simulation* sim = Simulation::getCurrent(); + ParameterBase::GetFunc getKernelFct = std::bind(&StrongCouplingBoundarySolver::getKernel, this); + ParameterBase::SetFunc setKernelFct = std::bind(&StrongCouplingBoundarySolver::setKernel, this, std::placeholders::_1); + KERNEL_METHOD = createEnumParameter("kernel", "Kernel", getKernelFct, setKernelFct); + setGroup(KERNEL_METHOD, "Boundary Model|Kernel"); + setDescription(KERNEL_METHOD, "Kernel function used in the boundary solver."); + EnumParameter* enumParam = static_cast(getParameter(KERNEL_METHOD)); + if (!sim->is2DSimulation()) { + enumParam->addEnumValue("Cubic spline", ENUM_KERNEL_CUBIC); + enumParam->addEnumValue("Wendland quintic C2", ENUM_KERNEL_WENDLANDQUINTICC2); + enumParam->addEnumValue("Poly6", ENUM_KERNEL_POLY6); + enumParam->addEnumValue("Spiky", ENUM_KERNEL_SPIKY); + } else { + enumParam->addEnumValue("Cubic spline 2D", ENUM_KERNEL_CUBIC_2D); + enumParam->addEnumValue("Wendland quintic C2 2D", ENUM_KERNEL_WENDLANDQUINTICC2_2D); + } + + ParameterBase::GetFunc getGradKernelFct = std::bind(&StrongCouplingBoundarySolver::getGradKernel, this); + ParameterBase::SetFunc setGradKernelFct = std::bind(&StrongCouplingBoundarySolver::setGradKernel, this, std::placeholders::_1); + GRAD_KERNEL_METHOD = createEnumParameter("gradKernel", "Gradient of kernel", getGradKernelFct, setGradKernelFct); + setGroup(GRAD_KERNEL_METHOD, "Boundary Model|Kernel"); + setDescription(GRAD_KERNEL_METHOD, "Gradient of the kernel function used in the boundary solver."); + enumParam = static_cast(getParameter(GRAD_KERNEL_METHOD)); + if (!sim->is2DSimulation()) { + enumParam->addEnumValue("Cubic spline", ENUM_GRADKERNEL_CUBIC); + enumParam->addEnumValue("Wendland quintic C2", ENUM_GRADKERNEL_WENDLANDQUINTICC2); + enumParam->addEnumValue("Poly6", ENUM_GRADKERNEL_POLY6); + enumParam->addEnumValue("Spiky", ENUM_GRADKERNEL_SPIKY); + } else { + enumParam->addEnumValue("Cubic spline 2D", ENUM_GRADKERNEL_CUBIC_2D); + enumParam->addEnumValue("Wendland quintic C2 2D", ENUM_GRADKERNEL_WENDLANDQUINTICC2_2D); + } +} + void StrongCouplingBoundarySolver::performNeighborhoodSearchSort() { Simulation* sim = Simulation::getCurrent(); const unsigned int nModels = sim->numberOfBoundaryModels(); @@ -503,7 +559,7 @@ void SPH::StrongCouplingBoundarySolver::computeSourceTermRHSForBody(const unsign setOmega_rr_body(bmIndex, omega_rr_body); // compute v_rr and predicted velocity (v_rr+v_s) for all particles - if (rb->isDynamic()) { + if (rb != nullptr && rb->isDynamic()) { #pragma omp parallel default(shared) { #pragma omp for schedule(static) @@ -666,3 +722,76 @@ Vector3r StrongCouplingBoundarySolver::gradW(const Vector3r& r) { Real StrongCouplingBoundarySolver::W_zero() { return m_W_zero; } + +void StrongCouplingBoundarySolver::setKernel(int val) { + std::cout << " set kernel " << std::endl; + Simulation* sim = Simulation::getCurrent(); + if (val == m_kernelMethod) + return; + + m_kernelMethod = val; + if (!sim->is2DSimulation()) { + if ((m_kernelMethod < 0) || (m_kernelMethod > 4)) + m_kernelMethod = 0; + + if (m_kernelMethod == 0) { + m_W_zero = CubicKernel::W_zero(); + m_kernelFct = CubicKernel::W; + } else if (m_kernelMethod == 1) { + m_W_zero = WendlandQuinticC2Kernel::W_zero(); + m_kernelFct = WendlandQuinticC2Kernel::W; + } else if (m_kernelMethod == 2) { + m_W_zero = Poly6Kernel::W_zero(); + m_kernelFct = Poly6Kernel::W; + } else if (m_kernelMethod == 3) { + m_W_zero = SpikyKernel::W_zero(); + m_kernelFct = SpikyKernel::W; + } else if (m_kernelMethod == 4) { + m_W_zero = Simulation::PrecomputedCubicKernel::W_zero(); + m_kernelFct = Simulation::PrecomputedCubicKernel::W; + } + } else { + if ((m_kernelMethod < 0) || (m_kernelMethod > 1)) + m_kernelMethod = 0; + + if (m_kernelMethod == 0) { + m_W_zero = CubicKernel2D::W_zero(); + m_kernelFct = CubicKernel2D::W; + } else if (m_kernelMethod == 1) { + m_W_zero = WendlandQuinticC2Kernel2D::W_zero(); + m_kernelFct = WendlandQuinticC2Kernel2D::W; + } + } + + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Akinci2012 || sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) + sim->updateBoundaryVolume(); +} + +void StrongCouplingBoundarySolver::setGradKernel(int val) { + Simulation* sim = Simulation::getCurrent(); + m_gradKernelMethod = val; + + if (!sim->is2DSimulation()) { + if ((m_gradKernelMethod < 0) || (m_gradKernelMethod > 4)) + m_gradKernelMethod = 0; + + if (m_gradKernelMethod == 0) + m_gradKernelFct = CubicKernel::gradW; + else if (m_gradKernelMethod == 1) + m_gradKernelFct = WendlandQuinticC2Kernel::gradW; + else if (m_gradKernelMethod == 2) + m_gradKernelFct = Poly6Kernel::gradW; + else if (m_gradKernelMethod == 3) + m_gradKernelFct = SpikyKernel::gradW; + else if (m_gradKernelMethod == 4) + m_gradKernelFct = Simulation::PrecomputedCubicKernel::gradW; + } else { + if ((m_gradKernelMethod < 0) || (m_gradKernelMethod > 1)) + m_gradKernelMethod = 0; + + if (m_gradKernelMethod == 0) + m_gradKernelFct = CubicKernel2D::gradW; + else if (m_gradKernelMethod == 1) + m_gradKernelFct = WendlandQuinticC2Kernel2D::gradW; + } +} diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.h b/SPlisHSPlasH/StrongCouplingBoundarySolver.h index 21d81f9f..b44f8755 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.h +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.h @@ -1,14 +1,15 @@ #include "SPlisHSPlasH/Common.h" #include "SPlisHSPlasH/TimeStep.h" #include "SPlisHSPlasH/SPHKernels.h" - +#include "ParameterObject.h" +#include namespace SPH { /** \brief This class stores the information of a dynamic rigid body which * is used for the strong coupling method introduced in * Interlinked SPH Pressure Solvers for Strong Fluid-Rigid Coupling. Gissler et al. https://doi.org/10.1145/3284980 */ - class StrongCouplingBoundarySolver { + class StrongCouplingBoundarySolver : public GenParam::ParameterObject { private: // values required for Gissler 2019 strong coupling based on Akinci 2012 Real m_restDensity; @@ -39,14 +40,32 @@ namespace SPH { Real m_maxDensityDeviation; + int m_kernelMethod; + int m_gradKernelMethod; Real(*m_kernelFct)(const Vector3r&); Vector3r(*m_gradKernelFct)(const Vector3r& r); Real m_W_zero; public: + static int KERNEL_METHOD; + static int GRAD_KERNEL_METHOD; + static int ENUM_KERNEL_CUBIC; + static int ENUM_KERNEL_WENDLANDQUINTICC2; + static int ENUM_KERNEL_POLY6; + static int ENUM_KERNEL_SPIKY; + static int ENUM_KERNEL_CUBIC_2D; + static int ENUM_KERNEL_WENDLANDQUINTICC2_2D; + static int ENUM_GRADKERNEL_CUBIC; + static int ENUM_GRADKERNEL_WENDLANDQUINTICC2; + static int ENUM_GRADKERNEL_POLY6; + static int ENUM_GRADKERNEL_SPIKY; + static int ENUM_GRADKERNEL_CUBIC_2D; + static int ENUM_GRADKERNEL_WENDLANDQUINTICC2_2D; + StrongCouplingBoundarySolver(); ~StrongCouplingBoundarySolver(); static StrongCouplingBoundarySolver* getCurrent(); + virtual void initParameters(); void reset(); void resize(unsigned int size); void computeContacts(); @@ -64,6 +83,8 @@ namespace SPH { Vector3r gradW(const Vector3r& r); Real W_zero(); + + FORCE_INLINE const Real& getDensity(const unsigned int& rigidBodyIndex, const unsigned int& index) const { return m_density[rigidBodyIndex][index]; } @@ -301,5 +322,14 @@ namespace SPH { FORCE_INLINE void setMaxDensityDeviation(const Real& value) { m_maxDensityDeviation = value; } + + int getKernel() const { + return m_kernelMethod; + } + void setKernel(int val); + int getGradKernel() const { + return m_gradKernelMethod; + } + void setGradKernel(int val); }; } \ No newline at end of file diff --git a/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp b/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp index 8ce323b7..05dfc050 100644 --- a/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp +++ b/Simulator/GUI/imgui/Simulator_GUI_imgui.cpp @@ -503,7 +503,7 @@ void Simulator_GUI_imgui::initSimulationParameterGUI() imguiParameters::createParameterObjectGUI((GenParam::ParameterObject*) model->getElasticityBase()); } - if (!m_simulatorBase->isStaticScene()) { + if (!m_simulatorBase->isStaticScene() && sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { DynamicBoundarySimulator* simulator = sim->getDynamicBoundarySimulator(); // Fields for all boundary models { @@ -517,6 +517,8 @@ void Simulator_GUI_imgui::initSimulationParameterGUI() StrongCouplingBoundarySolver* bs = StrongCouplingBoundarySolver::getCurrent(); + imguiParameters::createParameterObjectGUI(bs); + imguiParameters::imguiNumericParameter* maxIteration = new imguiParameters::imguiNumericParameter; maxIteration->description = "max iteration to solve the strong coupling method"; maxIteration->label = "Max Iterations"; From 9e827a74becc6475aec1bfe02eaa9d3424ae8952 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Sat, 2 Sep 2023 11:17:30 +0200 Subject: [PATCH 34/38] the solver now only solves for rigid bodies which have contacts --- SPlisHSPlasH/StrongCouplingBoundarySolver.cpp | 108 +++++++++--------- 1 file changed, 56 insertions(+), 52 deletions(-) diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp index 32e4fb35..05eb7818 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp @@ -320,14 +320,13 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); int bmIndex = boundaryPointSetIndex - nFluids; - RigidBodyObject* rb = bm->getRigidBodyObject(); #pragma omp parallel default(shared) { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { //gamma = 0.7, see the paper const Real gamma = static_cast(0.7); - if (rb->isDynamic()) { + if (bm->getRigidBodyObject()->isDynamic() && m_bodyContacts[bmIndex] > 0) { // compute density for particle r Real particleDensity = getRestDensity() * bm->getVolume(r) * W_zero(); // iterate over all rigid bodies @@ -345,6 +344,7 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { setArtificialVolume(bmIndex, r, gamma * bm->getVolume(r)); } } else { + setDensity(bmIndex, r, getRestDensity()); setArtificialVolume(bmIndex, r, gamma * bm->getVolume(r)); } } @@ -362,7 +362,7 @@ void StrongCouplingBoundarySolver::computeV_s() { for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); DynamicRigidBody* rb = dynamic_cast(bm->getRigidBodyObject()); - if (rb != nullptr && rb->isDynamic()) { + if (rb != nullptr && rb->isDynamic() && m_bodyContacts[boundaryPointSetIndex - nFluids] > 0) { #pragma omp parallel default(shared) { #pragma omp for schedule(static) @@ -396,7 +396,7 @@ void StrongCouplingBoundarySolver::computeSourceTerm() { for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); int bmIndex = boundaryPointSetIndex - nFluids; - if (bm->getRigidBodyObject()->isDynamic()) { + if (bm->getRigidBodyObject()->isDynamic() && m_bodyContacts[bmIndex] > 0) { #pragma omp parallel default(shared) { #pragma omp for schedule(static) @@ -438,55 +438,59 @@ void StrongCouplingBoundarySolver::computeDiagonalElement() { { #pragma omp for schedule(static) for (int r = 0; r < bm_r->numberOfParticles(); r++) { - Vector3r pos_r = bm_r->getPosition(r) - rb->getPosition(); - Vector3r grad_p_b = Vector3r::Zero(); - const Real density_r2 = getDensity(index_r, r) * getDensity(index_r, r); - // rk are neighboring rigid particles of r of other rigid bodies k - for (unsigned int pointSetIndex_rk = nFluids; pointSetIndex_rk < sim->numberOfPointSets(); pointSetIndex_rk++) { - if (pointSetIndex_rk != pointSetIndex_r) { - BoundaryModel_Akinci2012* bm_rk = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_rk)); - int index_rk = pointSetIndex_rk - nFluids; - DynamicRigidBody* rb_rk = static_cast(bm_rk->getRigidBodyObject()); - for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_rk, r); n++) { - const unsigned int rk = sim->getNeighbor(pointSetIndex_r, pointSetIndex_rk, r, n); - grad_p_b += getArtificialVolume(index_rk, rk) * getDensity(index_rk, rk) / density_r2 * gradW(bm_r->getPosition(r) - bm_rk->getPosition(rk)); + if (m_bodyContacts[index_r] == 0) { + setDiagonalElement(index_r, r, 0); + } else { + Vector3r pos_r = bm_r->getPosition(r) - rb->getPosition(); + Vector3r grad_p_b = Vector3r::Zero(); + const Real density_r2 = getDensity(index_r, r) * getDensity(index_r, r); + // rk are neighboring rigid particles of r of other rigid bodies k + for (unsigned int pointSetIndex_rk = nFluids; pointSetIndex_rk < sim->numberOfPointSets(); pointSetIndex_rk++) { + if (pointSetIndex_rk != pointSetIndex_r) { + BoundaryModel_Akinci2012* bm_rk = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_rk)); + int index_rk = pointSetIndex_rk - nFluids; + DynamicRigidBody* rb_rk = static_cast(bm_rk->getRigidBodyObject()); + for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_rk, r); n++) { + const unsigned int rk = sim->getNeighbor(pointSetIndex_r, pointSetIndex_rk, r, n); + grad_p_b += getArtificialVolume(index_rk, rk) * getDensity(index_rk, rk) / density_r2 * gradW(bm_r->getPosition(r) - bm_rk->getPosition(rk)); + } } } - } - grad_p_b *= getDensity(index_r, r); - Vector3r v_b = -dt * rb->getInvMass() * getArtificialVolume(index_r, r) * grad_p_b; - Vector3r omega_b = -dt * rb->getInertiaTensorInverseW() * getArtificialVolume(index_r, r) * pos_r.cross(grad_p_b); - Vector3r v_b_r = v_b + omega_b.cross(pos_r); - Real b_r = 0; - // for all neighboring rigid bodies - for (unsigned int pointSetIndex_rk = nFluids; pointSetIndex_rk < sim->numberOfPointSets(); pointSetIndex_rk++) { - if (pointSetIndex_rk != pointSetIndex_r) { - Vector3r v_b_k_body = Vector3r::Zero(); - Vector3r omega_b_k_body = Vector3r::Zero(); - BoundaryModel_Akinci2012* bm_rk = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_rk)); - int index_rk = pointSetIndex_rk - nFluids; - DynamicRigidBody* rb_rk = static_cast(bm_rk->getRigidBodyObject()); - for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_rk, r); n++) { - const unsigned int rk = sim->getNeighbor(pointSetIndex_r, pointSetIndex_rk, r, n); - Vector3r pos_rk = bm_rk->getPosition(rk) - rb_rk->getPosition(); - Vector3r grad_p_b_rkr = getDensity(index_rk, rk) * getArtificialVolume(index_r, r) * getDensity(index_r, r) / density_r2 * gradW(bm_rk->getPosition(rk) - bm_r->getPosition(r)); - v_b_k_body += -dt * rb_rk->getInvMass() * getArtificialVolume(index_rk, rk) * grad_p_b_rkr; - omega_b_k_body += -dt * rb_rk->getInertiaTensorInverseW() * getArtificialVolume(index_rk, rk) * pos_rk.cross(grad_p_b_rkr); + grad_p_b *= getDensity(index_r, r); + Vector3r v_b = -dt * rb->getInvMass() * getArtificialVolume(index_r, r) * grad_p_b; + Vector3r omega_b = -dt * rb->getInertiaTensorInverseW() * getArtificialVolume(index_r, r) * pos_r.cross(grad_p_b); + Vector3r v_b_r = v_b + omega_b.cross(pos_r); + Real b_r = 0; + // for all neighboring rigid bodies + for (unsigned int pointSetIndex_rk = nFluids; pointSetIndex_rk < sim->numberOfPointSets(); pointSetIndex_rk++) { + if (pointSetIndex_rk != pointSetIndex_r) { + Vector3r v_b_k_body = Vector3r::Zero(); + Vector3r omega_b_k_body = Vector3r::Zero(); + BoundaryModel_Akinci2012* bm_rk = static_cast(sim->getBoundaryModelFromPointSet(pointSetIndex_rk)); + int index_rk = pointSetIndex_rk - nFluids; + DynamicRigidBody* rb_rk = static_cast(bm_rk->getRigidBodyObject()); + for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_rk, r); n++) { + const unsigned int rk = sim->getNeighbor(pointSetIndex_r, pointSetIndex_rk, r, n); + Vector3r pos_rk = bm_rk->getPosition(rk) - rb_rk->getPosition(); + Vector3r grad_p_b_rkr = getDensity(index_rk, rk) * getArtificialVolume(index_r, r) * getDensity(index_r, r) / density_r2 * gradW(bm_rk->getPosition(rk) - bm_r->getPosition(r)); + v_b_k_body += -dt * rb_rk->getInvMass() * getArtificialVolume(index_rk, rk) * grad_p_b_rkr; + omega_b_k_body += -dt * rb_rk->getInertiaTensorInverseW() * getArtificialVolume(index_rk, rk) * pos_rk.cross(grad_p_b_rkr); + } + // divergence + Real sum_rk = 0; + for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_rk, r); n++) { + const unsigned int rk = sim->getNeighbor(pointSetIndex_r, pointSetIndex_rk, r, n); + Vector3r pos_rk = bm_rk->getPosition(rk) - rb_rk->getPosition(); + Vector3r v_b_rk = v_b_k_body + omega_b_k_body.cross(pos_rk); + sum_rk += getArtificialVolume(index_rk, rk) * getDensity(index_rk, rk) * (v_b_rk - v_b_r).dot(gradW(bm_r->getPosition(r) - bm_rk->getPosition(rk))); + } + b_r += sum_rk; } - // divergence - Real sum_rk = 0; - for (unsigned int n = 0; n < sim->numberOfNeighbors(pointSetIndex_r, pointSetIndex_rk, r); n++) { - const unsigned int rk = sim->getNeighbor(pointSetIndex_r, pointSetIndex_rk, r, n); - Vector3r pos_rk = bm_rk->getPosition(rk) - rb_rk->getPosition(); - Vector3r v_b_rk = v_b_k_body + omega_b_k_body.cross(pos_rk); - sum_rk += getArtificialVolume(index_rk, rk) * getDensity(index_rk, rk) * (v_b_rk - v_b_r).dot(gradW(bm_r->getPosition(r) - bm_rk->getPosition(rk))); - } - b_r += sum_rk; } - } - b_r = -b_r; - //setDiagonalElement(index_r, r, b_r < 0 ? b_r : 0); - setDiagonalElement(index_r, r, b_r); + b_r = -b_r; + //setDiagonalElement(index_r, r, b_r < 0 ? b_r : 0); + setDiagonalElement(index_r, r, b_r); + } } } } @@ -517,7 +521,7 @@ void SPH::StrongCouplingBoundarySolver::computeSourceTermRHSForBody(const unsign Real omegax = 0; Real omegay = 0; Real omegaz = 0; - if (rb != nullptr && rb->isDynamic()) { + if (rb != nullptr && rb->isDynamic() && m_bodyContacts[bmIndex] > 0) { #pragma omp parallel default(shared) { #pragma omp for schedule(static) reduction(+:vx) reduction(+:vy) reduction(+:vz) reduction(+:omegax) reduction(+:omegay) reduction(+:omegaz) @@ -559,7 +563,7 @@ void SPH::StrongCouplingBoundarySolver::computeSourceTermRHSForBody(const unsign setOmega_rr_body(bmIndex, omega_rr_body); // compute v_rr and predicted velocity (v_rr+v_s) for all particles - if (rb != nullptr && rb->isDynamic()) { + if (rb != nullptr && rb->isDynamic() && m_bodyContacts[bmIndex] > 0) { #pragma omp parallel default(shared) { #pragma omp for schedule(static) @@ -601,7 +605,7 @@ void StrongCouplingBoundarySolver::pressureSolveIteration(Real& avgDensityDeviat for (unsigned int boundaryPointSetIndex = nFluids; boundaryPointSetIndex < sim->numberOfPointSets(); boundaryPointSetIndex++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModelFromPointSet(boundaryPointSetIndex)); int bmIndex = boundaryPointSetIndex - nFluids; - if (bm->getRigidBodyObject()->isDynamic()) { + if (bm->getRigidBodyObject()->isDynamic() && m_bodyContacts[bmIndex] > 0) { int numContactsBody = getBodyContacts(bmIndex); computeSourceTermRHSForBody(boundaryPointSetIndex); // beta_r_RJ From 0359e8931eb749fb1eb9f7c3fde0c79b166c063f Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Tue, 5 Sep 2023 18:16:22 +0200 Subject: [PATCH 35/38] slightly modified structure --- SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp | 19 ++++++++++++------- SPlisHSPlasH/IISPH/TimeStepIISPH.cpp | 3 --- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp b/SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp index 3ac47799..bf04ed2a 100644 --- a/SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp +++ b/SPlisHSPlasH/DFSPH/TimeStepDFSPH.cpp @@ -398,9 +398,6 @@ void TimeStepDFSPH::pressureSolve() } m_iterations++; } - if (anyRigidContact) { - bs->applyForce(); - } } else { ////////////////////////////////////////////////////////////////////////// // Perform solver iterations @@ -446,6 +443,13 @@ void TimeStepDFSPH::pressureSolve() } } } + + if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { + StrongCouplingBoundarySolver* bs = StrongCouplingBoundarySolver::getCurrent(); + if (bs->getAllContacts() != 0) { + bs->applyForce(); + } + } #ifdef USE_WARMSTART for (unsigned int fluidModelIndex = 0; fluidModelIndex < nFluids; fluidModelIndex++) { @@ -607,7 +611,7 @@ void TimeStepDFSPH::divergenceSolve() } } - // predict density advection using the predicted velocity of fluid an rigid velocities + // predict density advection using the predicted velocity of fluid and rigid velocities for (unsigned int fluidModelIndex = 0; fluidModelIndex < nFluids; fluidModelIndex++) { FluidModel* model = sim->getFluidModel(fluidModelIndex); #pragma omp parallel default(shared) @@ -659,9 +663,6 @@ void TimeStepDFSPH::divergenceSolve() m_iterationsV++; } - if (anyRigidContact) { - bs->applyForce(); - } } else { ////////////////////////////////////////////////////////////////////////// // Perform solver iterations @@ -713,6 +714,10 @@ void TimeStepDFSPH::divergenceSolve() } if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { + StrongCouplingBoundarySolver* bs = StrongCouplingBoundarySolver::getCurrent(); + if (bs->getAllContacts() != 0) { + bs->applyForce(); + } ///////////////////////////////////////////////////////////////////////// // Update intermediate boundary velocity for strong coupling solver ///////////////////////////////////////////////////////////////////////// diff --git a/SPlisHSPlasH/IISPH/TimeStepIISPH.cpp b/SPlisHSPlasH/IISPH/TimeStepIISPH.cpp index aa0d15f1..c32d9302 100644 --- a/SPlisHSPlasH/IISPH/TimeStepIISPH.cpp +++ b/SPlisHSPlasH/IISPH/TimeStepIISPH.cpp @@ -434,9 +434,6 @@ void TimeStepIISPH::pressureSolveStrongCoupling() { m_iterations++; } - if (anyRigidContact) { - bs->applyForce(); - } INCREASE_COUNTER("IISPH - iterations", static_cast(m_iterations)); } From f34ea71cc9c423e3a0ab8c58d5230c7f3df5134d Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Sun, 10 Sep 2023 20:47:15 +0800 Subject: [PATCH 36/38] improved RigidBodyParticleExporter --- SPlisHSPlasH/StrongCouplingBoundarySolver.cpp | 54 +++---------------- .../RigidBodyParticleExporter_VTK.cpp | 2 +- Simulator/SimulatorBase.cpp | 9 +++- Simulator/SimulatorBase.h | 2 + 4 files changed, 18 insertions(+), 49 deletions(-) diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp index 05eb7818..70c5b964 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp @@ -56,51 +56,9 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : Simulation* sim = Simulation::getCurrent(); const unsigned int nBoundaries = sim->numberOfBoundaryModels(); - - m_restDensity = 1; - m_density.resize(nBoundaries); - m_v_s.resize(nBoundaries); - m_s.resize(nBoundaries); - m_pressure.resize(nBoundaries); - m_v_rr.resize(nBoundaries); - m_minus_rho_div_v_s.resize(nBoundaries); - m_minus_rho_div_v_rr.resize(nBoundaries); - m_diagonalElement.resize(nBoundaries); - m_pressureGrad.resize(nBoundaries); - m_artificialVolume.resize(nBoundaries); - m_lastPressure.resize(nBoundaries); - m_predictedVelocity.resize(nBoundaries); - m_predictedPosition.resize(nBoundaries); - m_v_rr_body.resize(nBoundaries, Vector3r::Zero()); - m_omega_rr_body.resize(nBoundaries, Vector3r::Zero()); - m_bodyContacts.resize(nBoundaries, 0); - m_contactsAllBodies = 0; - - for (unsigned int i = 0; i < nBoundaries; i++) { - BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModel(i)); - m_density[i].resize(bm->numberOfParticles(), m_restDensity); - m_v_s[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - m_s[i].resize(bm->numberOfParticles(), 0.0); - m_pressure[i].resize(bm->numberOfParticles(), 0.0); - m_v_rr[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - m_minus_rho_div_v_s[i].resize(bm->numberOfParticles(), 0.0); - m_minus_rho_div_v_rr[i].resize(bm->numberOfParticles(), 0.0); - m_diagonalElement[i].resize(bm->numberOfParticles(), 0.0); - m_pressureGrad[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - m_artificialVolume[i].resize(bm->numberOfParticles(), 0.0); - m_lastPressure[i].resize(bm->numberOfParticles(), 0.0); - m_predictedVelocity[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - m_predictedPosition[i].resize(bm->numberOfParticles(), Vector3r::Zero()); - - bm->addField({ "density", FieldType::Scalar, [this, i](const unsigned int j) -> Real* { return &getDensity(i, j); } }); - bm->addField({ "sourceTerm", FieldType::Scalar, [this, i](const unsigned int j)->Real* {return &getSourceTerm(i,j); } }); - bm->addField({ "v_s", FieldType::Vector3, [this,i](const unsigned int j)->Vector3r* {return &getV_s(i,j); } }); - bm->addField({ "v_rr", FieldType::Vector3, [this,i](const unsigned int j)->Vector3r* {return &getV_rr(i,j); } }); - bm->addField({ "pressure", FieldType::Scalar,[this,i](const unsigned int j)->Real* {return &getPressure(i,j); } }); - bm->addField({ "rigidbodyVelocity", FieldType::Vector3,[bm](const unsigned int j)->Vector3r* {return &(static_cast(bm->getRigidBodyObject())->getVelocity()); } }); - bm->addField({ "v_rr_body", FieldType::Vector3,[this,i](const unsigned int j)->Vector3r* {return &getV_rr_body(i); } }); - } - + + // export fields should be added in resize() + resize(nBoundaries); } @@ -141,6 +99,9 @@ void SPH::StrongCouplingBoundarySolver::resize(unsigned int size) { m_lastPressure[i].resize(bm->numberOfParticles(), 0.0); m_predictedVelocity[i].resize(bm->numberOfParticles(), Vector3r::Zero()); m_predictedPosition[i].resize(bm->numberOfParticles(), Vector3r::Zero()); + + //bm->addField({ "particle position", FieldType::Vector3, [sim, bm, i](const unsigned int j)->Vector3r* {return &bm->getPosition(j); } }); + //bm->addField({ "body position", FieldType::Vector3, [bm](const unsigned int j)->Vector3r* {return &static_cast(bm->getRigidBodyObject())->getPosition(); } }); } } @@ -324,8 +285,7 @@ void StrongCouplingBoundarySolver::computeDensityAndVolume() { { #pragma omp for schedule(static) for (int r = 0; r < bm->numberOfParticles(); r++) { - //gamma = 0.7, see the paper - const Real gamma = static_cast(0.7); + const Real gamma = static_cast(1); if (bm->getRigidBodyObject()->isDynamic() && m_bodyContacts[bmIndex] > 0) { // compute density for particle r Real particleDensity = getRestDensity() * bm->getVolume(r) * W_zero(); diff --git a/Simulator/Exporter/RigidBodyParticleExporter_VTK.cpp b/Simulator/Exporter/RigidBodyParticleExporter_VTK.cpp index 85e22d53..7ef964e6 100644 --- a/Simulator/Exporter/RigidBodyParticleExporter_VTK.cpp +++ b/Simulator/Exporter/RigidBodyParticleExporter_VTK.cpp @@ -75,7 +75,7 @@ void RigidBodyParticleExporter_VTK::writeRigidBodies(const unsigned int frame) { // add attributes m_attributes.clear(); - StringTools::tokenize(m_base->getValue(SimulatorBase::PARTICLE_EXPORT_ATTRIBUTES), m_attributes, ";"); + StringTools::tokenize(m_base->getValue(SimulatorBase::RIGIDBODY_PARTICLE_EXPORT_ATTRIBUTES), m_attributes, ";"); ////////////////////////////////////////////////////////////////////////// // positions and ids exported anyways diff --git a/Simulator/SimulatorBase.cpp b/Simulator/SimulatorBase.cpp index c8fc04e2..4b3ad14d 100644 --- a/Simulator/SimulatorBase.cpp +++ b/Simulator/SimulatorBase.cpp @@ -50,6 +50,7 @@ int SimulatorBase::STOP_AT = -1; int SimulatorBase::NUM_STEPS_PER_RENDER = -1; int SimulatorBase::DATA_EXPORT_FPS = -1; int SimulatorBase::PARTICLE_EXPORT_ATTRIBUTES = -1; +int SimulatorBase::RIGIDBODY_PARTICLE_EXPORT_ATTRIBUTES = -1; int SimulatorBase::STATE_EXPORT = -1; int SimulatorBase::STATE_EXPORT_FPS = -1; int SimulatorBase::ASYNC_EXPORT = -1; @@ -97,7 +98,8 @@ SimulatorBase::SimulatorBase() m_colorMapType.resize(1, 0); m_renderMinValue.resize(1, 0.0); m_renderMaxValue.resize(1, 5.0); - m_particleAttributes = "velocity;density;sourceTerm;v_s;v_rr;pressure;rigidbodyVelocity"; + m_particleAttributes = "velocity;density;"; + m_rigidbodyParticleAttributes = "particle position;body position"; m_timeStepCB = nullptr; m_resetCB = nullptr; m_updateGUI = false; @@ -183,6 +185,11 @@ void SimulatorBase::initParameters() setGroup(PARTICLE_EXPORT_ATTRIBUTES, "Export|General"); setDescription(PARTICLE_EXPORT_ATTRIBUTES, "Attributes that are exported in the partio files (except id and position)."); + RIGIDBODY_PARTICLE_EXPORT_ATTRIBUTES = createStringParameter("rigidbodyParticleAttributes", "Export attributes", &m_rigidbodyParticleAttributes); + getParameter(RIGIDBODY_PARTICLE_EXPORT_ATTRIBUTES)->setReadOnly(true); + setGroup(RIGIDBODY_PARTICLE_EXPORT_ATTRIBUTES, "Export|General"); + setDescription(RIGIDBODY_PARTICLE_EXPORT_ATTRIBUTES, "Attributes that are exported in the partio files (except id and position)."); + ASYNC_EXPORT = createBoolParameter("enableAsyncExport", "Asynchronous export", &m_enableAsyncExport); setGroup(ASYNC_EXPORT, "Export|General"); setDescription(ASYNC_EXPORT, "Enable/disable asynchronous export of data. The total performance is faster but disable it when measuring the timings of simulation components. \n\n Currently only supported by partio exporter."); diff --git a/Simulator/SimulatorBase.h b/Simulator/SimulatorBase.h index 0fa20694..b7802ddc 100644 --- a/Simulator/SimulatorBase.h +++ b/Simulator/SimulatorBase.h @@ -63,6 +63,7 @@ namespace SPH Vector3r m_cameraPosition; Vector3r m_cameraLookAt; std::string m_particleAttributes; + std::string m_rigidbodyParticleAttributes; std::unique_ptr m_sceneLoader; Real m_nextFrameTime; Real m_nextFrameTimeState; @@ -118,6 +119,7 @@ namespace SPH static int NUM_STEPS_PER_RENDER; static int DATA_EXPORT_FPS; static int PARTICLE_EXPORT_ATTRIBUTES; + static int RIGIDBODY_PARTICLE_EXPORT_ATTRIBUTES; static int STATE_EXPORT; static int STATE_EXPORT_FPS; static int ASYNC_EXPORT; From 5ae3effc1f5793a30ee5d9e1d41a2f645660700d Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Wed, 13 Sep 2023 16:01:27 +0800 Subject: [PATCH 37/38] reset bug fix --- SPlisHSPlasH/StrongCouplingBoundarySolver.cpp | 8 +------- SPlisHSPlasH/StrongCouplingBoundarySolver.h | 14 -------------- Simulator/SimulatorBase.cpp | 4 ++-- 3 files changed, 3 insertions(+), 23 deletions(-) diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp index 70c5b964..ad437b4d 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp @@ -35,7 +35,6 @@ StrongCouplingBoundarySolver::StrongCouplingBoundarySolver() : m_minus_rho_div_v_rr(), m_diagonalElement(), m_artificialVolume(), - m_lastPressure(), m_predictedVelocity(), m_predictedPosition(), m_v_rr_body(), @@ -77,7 +76,6 @@ void SPH::StrongCouplingBoundarySolver::resize(unsigned int size) { m_diagonalElement.resize(nBoundaries); m_pressureGrad.resize(nBoundaries); m_artificialVolume.resize(nBoundaries); - m_lastPressure.resize(nBoundaries); m_predictedVelocity.resize(nBoundaries); m_predictedPosition.resize(nBoundaries); m_v_rr_body.resize(nBoundaries, Vector3r::Zero()); @@ -96,7 +94,6 @@ void SPH::StrongCouplingBoundarySolver::resize(unsigned int size) { m_diagonalElement[i].resize(bm->numberOfParticles(), 0.0); m_pressureGrad[i].resize(bm->numberOfParticles(), Vector3r::Zero()); m_artificialVolume[i].resize(bm->numberOfParticles(), 0.0); - m_lastPressure[i].resize(bm->numberOfParticles(), 0.0); m_predictedVelocity[i].resize(bm->numberOfParticles(), Vector3r::Zero()); m_predictedPosition[i].resize(bm->numberOfParticles(), Vector3r::Zero()); @@ -113,6 +110,7 @@ void SPH::StrongCouplingBoundarySolver::reset() { for (unsigned int i = 0; i < nBoundaries; i++) { BoundaryModel_Akinci2012* bm = static_cast(sim->getBoundaryModel(i)); for (int j = 0; j < bm->numberOfParticles(); j++) { + m_density[i][j] = m_restDensity; m_v_s[i][j] = Vector3r::Zero(); m_s[i][j] = 0.0; m_pressure[i][j] = 0.0; @@ -122,7 +120,6 @@ void SPH::StrongCouplingBoundarySolver::reset() { m_diagonalElement[i][j] = 0.0; m_pressureGrad[i][j] = Vector3r::Zero(); m_artificialVolume[i][j] = 0.0; - m_lastPressure[i][j] = 0.0; m_predictedVelocity[i][j] = Vector3r::Zero(); m_predictedPosition[i][j] = Vector3r::Zero(); } @@ -145,7 +142,6 @@ StrongCouplingBoundarySolver::~StrongCouplingBoundarySolver() { m_diagonalElement[i].clear(); m_pressureGrad[i].clear(); m_artificialVolume[i].clear(); - m_lastPressure[i].clear(); m_predictedVelocity[i].clear(); m_predictedPosition[i].clear(); } @@ -159,7 +155,6 @@ StrongCouplingBoundarySolver::~StrongCouplingBoundarySolver() { m_diagonalElement.clear(); m_pressureGrad.clear(); m_artificialVolume.clear(); - m_lastPressure.clear(); m_predictedVelocity.clear(); m_predictedPosition.clear(); m_v_rr_body.clear(); @@ -234,7 +229,6 @@ void StrongCouplingBoundarySolver::performNeighborhoodSearchSort() { d.sort_field(&m_diagonalElement[i][0]); d.sort_field(&m_pressureGrad[i][0]); d.sort_field(&m_artificialVolume[i][0]); - d.sort_field(&m_lastPressure[i][0]); d.sort_field(&m_predictedVelocity[i][0]); d.sort_field(&m_predictedPosition[i][0]); } diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.h b/SPlisHSPlasH/StrongCouplingBoundarySolver.h index b44f8755..717e8dd9 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.h +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.h @@ -15,7 +15,6 @@ namespace SPH { Real m_restDensity; std::vector> m_density; std::vector> m_pressure; - std::vector> m_lastPressure; std::vector> m_artificialVolume; std::vector> m_v_s; std::vector> m_s; // source term @@ -28,7 +27,6 @@ namespace SPH { std::vector> m_diagonalElement; // diagonal element for jacobi iteration std::vector m_v_rr_body; std::vector m_omega_rr_body; - std::vector> m_contacts; std::vector m_bodyContacts; unsigned int m_contactsAllBodies; @@ -109,18 +107,6 @@ namespace SPH { m_pressure[rigidBodyIndex][index] = value; } - FORCE_INLINE const Real& getLastPressure(const unsigned int& rigidBodyIndex, const unsigned int& index) const { - return m_lastPressure[rigidBodyIndex][index]; - } - - FORCE_INLINE Real& getLastPressure(const unsigned int& rigidBodyIndex, const unsigned int& index) { - return m_lastPressure[rigidBodyIndex][index]; - } - - FORCE_INLINE void setLastPressure(const unsigned int& rigidBodyIndex, const unsigned int& index, const Real& value) { - m_lastPressure[rigidBodyIndex][index] = value; - } - FORCE_INLINE const Real& getRestDensity() const { return m_restDensity; } diff --git a/Simulator/SimulatorBase.cpp b/Simulator/SimulatorBase.cpp index 4b3ad14d..b696cb0e 100644 --- a/Simulator/SimulatorBase.cpp +++ b/Simulator/SimulatorBase.cpp @@ -99,7 +99,7 @@ SimulatorBase::SimulatorBase() m_renderMinValue.resize(1, 0.0); m_renderMaxValue.resize(1, 5.0); m_particleAttributes = "velocity;density;"; - m_rigidbodyParticleAttributes = "particle position;body position"; + m_rigidbodyParticleAttributes = ""; m_timeStepCB = nullptr; m_resetCB = nullptr; m_updateGUI = false; @@ -185,7 +185,7 @@ void SimulatorBase::initParameters() setGroup(PARTICLE_EXPORT_ATTRIBUTES, "Export|General"); setDescription(PARTICLE_EXPORT_ATTRIBUTES, "Attributes that are exported in the partio files (except id and position)."); - RIGIDBODY_PARTICLE_EXPORT_ATTRIBUTES = createStringParameter("rigidbodyParticleAttributes", "Export attributes", &m_rigidbodyParticleAttributes); + RIGIDBODY_PARTICLE_EXPORT_ATTRIBUTES = createStringParameter("rigidbodyParticleAttributes", "Rigidbody export attributes", &m_rigidbodyParticleAttributes); getParameter(RIGIDBODY_PARTICLE_EXPORT_ATTRIBUTES)->setReadOnly(true); setGroup(RIGIDBODY_PARTICLE_EXPORT_ATTRIBUTES, "Export|General"); setDescription(RIGIDBODY_PARTICLE_EXPORT_ATTRIBUTES, "Attributes that are exported in the partio files (except id and position)."); From ca5b4d02d1813c5a025e4bcf63deaca12394fd70 Mon Sep 17 00:00:00 2001 From: YanxiLiu <951159548@qq.com> Date: Sun, 15 Oct 2023 10:30:17 +0200 Subject: [PATCH 38/38] small change --- SPlisHSPlasH/DynamicRigidBody.h | 51 ++++++++++++++++++- SPlisHSPlasH/IISPH/TimeStepIISPH.cpp | 5 +- SPlisHSPlasH/StrongCouplingBoundarySolver.cpp | 4 +- SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp | 2 - Simulator/SimulatorBase.cpp | 2 +- 5 files changed, 55 insertions(+), 9 deletions(-) diff --git a/SPlisHSPlasH/DynamicRigidBody.h b/SPlisHSPlasH/DynamicRigidBody.h index 4aec5922..23531f13 100644 --- a/SPlisHSPlasH/DynamicRigidBody.h +++ b/SPlisHSPlasH/DynamicRigidBody.h @@ -94,7 +94,7 @@ namespace SPH { ~DynamicRigidBody(void) { - } + } void initBody(const Real density, const bool isDynamic, const Vector3r &position, const Quaternionr &rotation, const Vector3r &scale, const Vector3r &velocity, const Real &friction) @@ -102,7 +102,7 @@ namespace SPH { m_isDynamic = isDynamic; m_mass = 1.0; m_inertiaTensor = Vector3r(1.0, 1.0, 1.0); - determineMassProperties(density); + m_x = position; m_x0 = position; m_lastX = position; @@ -112,6 +112,8 @@ namespace SPH { m_v = velocity; m_a.setZero(); + determineMassProperties(density); + m_q = rotation; m_q0 = rotation; m_lastQ = rotation; @@ -124,6 +126,7 @@ namespace SPH { //m_restitutionCoeff = static_cast(0.6); m_frictionCoeff = friction; + updateMeshTransformation(); } @@ -172,20 +175,60 @@ namespace SPH { // Determine mass and inertia tensor void determineMassProperties(const Real density) { m_density = density; + std::vector vd = getGeometry().getVertices(); Utilities::VolumeIntegration vi(m_geometry.numVertices(), m_geometry.numFaces(), &m_geometry.getVertices()[0], m_geometry.getFaces().data()); vi.compute_inertia_tensor(density); // Diagonalize Inertia Tensor Eigen::SelfAdjointEigenSolver es(vi.getInertia()); Vector3r inertiaTensor = Vector3r::Zero(); + Matrix3r R; inertiaTensor += es.eigenvalues().x() * es.eigenvectors().col(0); inertiaTensor += es.eigenvalues().y() * es.eigenvectors().col(1); inertiaTensor += es.eigenvalues().z() * es.eigenvectors().col(2); inertiaTensor.x() = std::abs(inertiaTensor.x()); inertiaTensor.y() = std::abs(inertiaTensor.y()); inertiaTensor.z() = std::abs(inertiaTensor.z()); + R << inertiaTensor.x(), 0, 0, + 0, inertiaTensor.y(), 0, + 0, 0, inertiaTensor.z(); + setMass(vi.getMass()); setInertiaTensor(inertiaTensor); + + //if (R.determinant() < 0.0) + // R = -R; + + //for (unsigned int i = 0; i < vd.size(); i++) + // vd[i] = m_rot * vd[i] + m_x0; + + //Vector3r x_MAT = vi.getCenterOfMass(); + //R = m_rot * R; + //x_MAT = m_rot * x_MAT + m_x0; + + //// rotate vertices back + //for (unsigned int i = 0; i < vd.size(); i++) + // vd[i] = R.transpose() * (vd[i] - x_MAT); + + //// set rotation + //Quaternionr qR = Quaternionr(R); + //qR.normalize(); + //m_q_mat = qR; + //m_q_initial = m_q0; + //m_x0_mat = m_x0 - x_MAT; + + //m_q0 = qR; + //m_q = m_q0; + //m_lastQ = m_q0; + //m_oldQ = m_q0; + //rotationUpdated(); + + //// set translation + //m_x0 = x_MAT; + //m_x = m_x0; + //m_lastX = m_x0; + //m_oldX = m_x0; + //updateInverseTransformation(); } void rotationUpdated() @@ -240,6 +283,10 @@ namespace SPH { determineMassProperties(density); } + FORCE_INLINE Vector3r& getPosition() { + return m_x; + } + FORCE_INLINE Vector3r &getLastPosition() { return m_lastX; diff --git a/SPlisHSPlasH/IISPH/TimeStepIISPH.cpp b/SPlisHSPlasH/IISPH/TimeStepIISPH.cpp index c32d9302..124807f1 100644 --- a/SPlisHSPlasH/IISPH/TimeStepIISPH.cpp +++ b/SPlisHSPlasH/IISPH/TimeStepIISPH.cpp @@ -100,7 +100,10 @@ void TimeStepIISPH::step() integration(fluidModelIndex); if (sim->getBoundaryHandlingMethod() == BoundaryHandlingMethods::Gissler2019) { - StrongCouplingBoundarySolver::getCurrent()->applyForce(); + StrongCouplingBoundarySolver* bs = StrongCouplingBoundarySolver::getCurrent(); + if (bs->getAllContacts() != 0) { + bs->applyForce(); + } } sim->emitParticles(); diff --git a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp index ad437b4d..44ea7b06 100644 --- a/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp +++ b/SPlisHSPlasH/StrongCouplingBoundarySolver.cpp @@ -98,7 +98,7 @@ void SPH::StrongCouplingBoundarySolver::resize(unsigned int size) { m_predictedPosition[i].resize(bm->numberOfParticles(), Vector3r::Zero()); //bm->addField({ "particle position", FieldType::Vector3, [sim, bm, i](const unsigned int j)->Vector3r* {return &bm->getPosition(j); } }); - //bm->addField({ "body position", FieldType::Vector3, [bm](const unsigned int j)->Vector3r* {return &static_cast(bm->getRigidBodyObject())->getPosition(); } }); + bm->addField({ "body position", FieldType::Vector3, [bm](const unsigned int j)->Vector3r* {return &static_cast(bm->getRigidBodyObject())->getPosition(); } }); } } @@ -682,7 +682,6 @@ Real StrongCouplingBoundarySolver::W_zero() { } void StrongCouplingBoundarySolver::setKernel(int val) { - std::cout << " set kernel " << std::endl; Simulation* sim = Simulation::getCurrent(); if (val == m_kernelMethod) return; @@ -728,7 +727,6 @@ void StrongCouplingBoundarySolver::setKernel(int val) { void StrongCouplingBoundarySolver::setGradKernel(int val) { Simulation* sim = Simulation::getCurrent(); m_gradKernelMethod = val; - if (!sim->is2DSimulation()) { if ((m_gradKernelMethod < 0) || (m_gradKernelMethod > 4)) m_gradKernelMethod = 0; diff --git a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp index 41574252..4abb4236 100644 --- a/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp +++ b/SPlisHSPlasH/WCSPH/TimeStepWCSPH.cpp @@ -230,10 +230,8 @@ void TimeStepWCSPH::solveRigidRigidContacts() { while ((avgDensityDeviation > bs->getMaxDensityDeviation() && iterations < bs->getMaxIterations()) || iterations < bs->getMinIterations()) { avgDensityDeviation = 0.0; bs->pressureSolveIteration(avgDensityDeviation); - //std::cout << avgDensityDeviation << std::endl; iterations++; } - //std::cout << "------------------------------" << std::endl; bs->applyForce(); } diff --git a/Simulator/SimulatorBase.cpp b/Simulator/SimulatorBase.cpp index b696cb0e..afb40b3f 100644 --- a/Simulator/SimulatorBase.cpp +++ b/Simulator/SimulatorBase.cpp @@ -99,7 +99,7 @@ SimulatorBase::SimulatorBase() m_renderMinValue.resize(1, 0.0); m_renderMaxValue.resize(1, 5.0); m_particleAttributes = "velocity;density;"; - m_rigidbodyParticleAttributes = ""; + m_rigidbodyParticleAttributes = "body position"; m_timeStepCB = nullptr; m_resetCB = nullptr; m_updateGUI = false;