7 #include "imstkSphModel.h" 8 #include "imstkParallelUtils.h" 9 #include "imstkPointSet.h" 10 #include "imstkTaskGraph.h" 11 #include "imstkVTKMeshIO.h" 15 SphModelConfig::SphModelConfig(
const double particleRadius)
18 if (std::abs(particleRadius) > 1.0e-6)
20 LOG_IF(WARNING, (particleRadius < 0)) <<
"Particle radius supplied is negative! Using absolute value of the supplied radius.";
21 m_particleRadius = std::abs(particleRadius);
25 LOG(WARNING) <<
"Particle radius too small! Setting to 1.e-6";
26 m_particleRadius = 1.e-6;
31 SphModelConfig::SphModelConfig(
const double particleRadius,
const double speedOfSound,
const double restDensity)
33 if (std::abs(particleRadius) > 1.0e-6)
35 LOG_IF(WARNING, (particleRadius < 0)) <<
"Particle radius supplied is negative! Using absolute value of the supplied radius.";
36 m_particleRadius = std::abs(particleRadius);
40 LOG(WARNING) <<
"Particle radius too small! Setting to 1.e-6";
41 m_particleRadius = 1.e-6;
46 LOG(WARNING) <<
"Speed of sound is negative! Setting speed of sound to default value.";
50 m_speedOfSound = speedOfSound;
55 LOG(WARNING) <<
"Rest density is negative! Setting rest density to default value.";
59 m_restDensity = restDensity;
65 SphModelConfig::initialize()
74 m_kernelRadius = m_particleRadius * m_kernelOverParticleRadiusRatio;
77 m_pressureStiffness = m_restDensity * m_speedOfSound * m_speedOfSound / 7.0;
80 SphModel::SphModel() : DynamicalModel<SphState>(
DynamicalModelType::SmoothedParticleHydrodynamics)
82 m_validGeometryTypes = {
"PointSet" };
84 m_findParticleNeighborsNode = m_taskGraph->addFunction(
"SPHModel_Partition", std::bind(&SphModel::findParticleNeighbors,
this));
85 m_computeDensityNode = m_taskGraph->addFunction(
"SPHModel_ComputeDensity", [&]()
87 computeNeighborRelativePositions();
91 m_normalizeDensityNode = m_taskGraph->addFunction(
"SPHModel_NormalizeDensity", std::bind(&SphModel::normalizeDensity,
this));
93 m_collectNeighborDensityNode = m_taskGraph->addFunction(
"SPHModel_CollectNeighborDensity", std::bind(&SphModel::collectNeighborDensity,
this));
95 m_computeTimeStepSizeNode =
96 m_taskGraph->addFunction(
"SPHModel_ComputeTimestep", std::bind(&SphModel::computeTimeStepSize,
this));
98 m_computePressureAccelNode =
99 m_taskGraph->addFunction(
"SPHModel_ComputePressureAccel", std::bind(&SphModel::computePressureAcceleration,
this));
101 m_computeSurfaceTensionNode =
102 m_taskGraph->addFunction(
"SPHModel_ComputeSurfaceTensionAccel", std::bind(&SphModel::computeSurfaceTension,
this));
104 m_computeViscosityNode =
105 m_taskGraph->addFunction(
"SPHModel_ComputeViscosity", std::bind(&SphModel::computeViscosity,
this));
108 m_taskGraph->addFunction(
"SPHModel_Integrate", std::bind(&SphModel::sumAccels,
this));
110 m_updateVelocityNode =
111 m_taskGraph->addFunction(
"SPHModel_UpdateVelocity", [&]()
113 updateVelocity(getTimeStep());
116 m_moveParticlesNode =
117 m_taskGraph->addFunction(
"SPHModel_MoveParticles", [&]()
119 moveParticles(getTimeStep());
132 LOG_IF(FATAL, (!this->getModelGeometry())) <<
"Model geometry is not yet set! Cannot initialize without model geometry.";
133 m_pointSetGeometry = std::dynamic_pointer_cast<
PointSet>(m_geometry);
137 m_initialState = std::make_shared<SphState>(numParticles);
138 m_currentState = std::make_shared<SphState>(numParticles);
141 if (m_initialVelocities !=
nullptr)
143 m_currentState->setVelocities(m_initialVelocities);
147 m_initialState->setState(m_currentState);
150 m_currentState->setPositions(m_pointSetGeometry->getVertexPositions());
151 m_initialState->setPositions(m_pointSetGeometry->getInitialVertexPositions());
154 m_kernels.initialize(m_modelParameters->m_kernelRadius);
157 m_neighborSearcher = std::make_shared<NeighborSearch>(m_modelParameters->m_neighborSearchMethod,
158 m_modelParameters->m_kernelRadius);
160 m_pressureAccels = std::make_shared<VecDataArray<double, 3>>(numParticles);
161 std::fill_n(m_pressureAccels->getPointer(), m_pressureAccels->size(), Vec3d(0, 0, 0));
164 m_surfaceTensionAccels = std::make_shared<VecDataArray<double, 3>>(numParticles);
165 std::fill_n(m_surfaceTensionAccels->getPointer(), m_surfaceTensionAccels->size(), Vec3d(0, 0, 0));
167 m_viscousAccels = std::make_shared<VecDataArray<double, 3>>(numParticles);
168 std::fill_n(m_viscousAccels->getPointer(), m_viscousAccels->size(), Vec3d(0, 0, 0));
170 m_neighborVelContr = std::make_shared<VecDataArray<double, 3>>(numParticles);
171 std::fill_n(m_neighborVelContr->getPointer(), m_neighborVelContr->size(), Vec3d(0, 0, 0));
173 m_particleShift = std::make_shared<VecDataArray<double, 3>>(numParticles);
174 std::fill_n(m_particleShift->getPointer(), m_particleShift->size(), Vec3d(0, 0, 0));
177 m_pointSetGeometry->setVertexAttribute(
"Pressure Accels", m_pressureAccels);
178 m_pointSetGeometry->setVertexAttribute(
"Surface Tension Accels", m_surfaceTensionAccels);
179 m_pointSetGeometry->setVertexAttribute(
"Viscous Accels", m_viscousAccels);
180 m_pointSetGeometry->setVertexAttribute(
"Densities", m_currentState->getDensities());
181 m_pointSetGeometry->setVertexAttribute(
"Velocities", m_currentState->getVelocities());
182 m_pointSetGeometry->setVertexAttribute(
"Diffuse Velocities", m_currentState->getDiffuseVelocities());
183 m_pointSetGeometry->setVertexAttribute(
"Normals", m_currentState->getNormals());
184 m_pointSetGeometry->setVertexAttribute(
"Accels", m_currentState->getAccelerations());
193 m_taskGraph->addEdge(source, m_findParticleNeighborsNode);
194 m_taskGraph->addEdge(m_findParticleNeighborsNode, m_computeDensityNode);
195 m_taskGraph->addEdge(m_computeDensityNode, m_normalizeDensityNode);
196 m_taskGraph->addEdge(m_normalizeDensityNode, m_collectNeighborDensityNode);
199 m_taskGraph->addEdge(m_collectNeighborDensityNode, m_computePressureAccelNode);
200 m_taskGraph->addEdge(m_collectNeighborDensityNode, m_computeSurfaceTensionNode);
201 m_taskGraph->addEdge(m_collectNeighborDensityNode, m_computeViscosityNode);
202 m_taskGraph->addEdge(m_collectNeighborDensityNode, m_computeTimeStepSizeNode);
204 m_taskGraph->addEdge(m_computePressureAccelNode, m_integrateNode);
205 m_taskGraph->addEdge(m_computeSurfaceTensionNode, m_integrateNode);
206 m_taskGraph->addEdge(m_computeViscosityNode, m_integrateNode);
207 m_taskGraph->addEdge(m_computeTimeStepSizeNode, m_integrateNode);
209 m_taskGraph->addEdge(m_integrateNode, m_updateVelocityNode);
210 m_taskGraph->addEdge(m_updateVelocityNode, m_moveParticlesNode);
211 m_taskGraph->addEdge(m_moveParticlesNode, sink);
215 SphModel::computeTimeStepSize()
217 m_dt = (this->m_timeStepSizeType == TimeSteppingType::Fixed) ? m_defaultDt : computeCFLTimeStepSize();
221 SphModel::computeCFLTimeStepSize()
223 auto maxVel = ParallelUtils::findMaxL2Norm(*getCurrentState()->getFullStepVelocities());
226 double timestep = maxVel > 1.0e-6 ?
227 m_modelParameters->m_cflFactor * (2.0 * m_modelParameters->m_particleRadius / (m_modelParameters->m_speedOfSound + maxVel)) :
228 m_modelParameters->m_maxTimestep;
231 if (timestep > m_modelParameters->m_maxTimestep)
233 timestep = m_modelParameters->m_maxTimestep;
235 else if (timestep < m_modelParameters->m_minTimestep)
237 timestep = m_modelParameters->m_minTimestep;
243 SphModel::findParticleNeighbors()
245 m_neighborSearcher->getNeighbors(getCurrentState()->getFluidNeighborLists(), *getCurrentState()->getPositions());
247 if (m_modelParameters->m_bDensityWithBoundary)
249 m_neighborSearcher->getNeighbors(getCurrentState()->getBoundaryNeighborLists(),
250 *getCurrentState()->getPositions(),
251 *getCurrentState()->getBoundaryParticlePositions());
256 SphModel::computeNeighborRelativePositions()
258 auto computeRelativePositions = [&](
const Vec3d& ppos,
const std::vector<size_t>& neighborList,
261 for (
const size_t q : neighborList)
263 const Vec3d& qpos = allPositions[q];
264 const Vec3d r = ppos - qpos;
265 neighborInfo.push_back({ r, m_modelParameters->m_restDensity });
269 std::shared_ptr<VecDataArray<double, 3>> positionsPtr = getCurrentState()->getPositions();
272 std::vector<std::vector<NeighborInfo>>& neighborInfos = getCurrentState()->getNeighborInfo();
274 ParallelUtils::parallelFor(getCurrentState()->getNumParticles(),
277 if (m_sphBoundaryConditions
278 && m_sphBoundaryConditions->getParticleTypes()[p] == SphBoundaryConditions::ParticleType::Buffer)
283 const Vec3d& ppos = positions[p];
284 std::vector<NeighborInfo>& neighborInfo = neighborInfos[p];
286 neighborInfo.reserve(48);
288 computeRelativePositions(ppos, getCurrentState()->getFluidNeighborLists()[p], *getCurrentState()->getPositions(), neighborInfo);
290 if (m_modelParameters->m_bDensityWithBoundary)
292 computeRelativePositions(ppos, getCurrentState()->getBoundaryNeighborLists()[p], *getCurrentState()->getBoundaryParticlePositions(), neighborInfo);
298 SphModel::collectNeighborDensity()
303 std::shared_ptr<DataArray<double>> densitiesPtr = getCurrentState()->getDensities();
306 const std::vector<std::vector<size_t>>& neighborLists = getCurrentState()->getFluidNeighborLists();
307 const std::vector<SphBoundaryConditions::ParticleType>& particleTypes = m_sphBoundaryConditions->getParticleTypes();
309 ParallelUtils::parallelFor(getCurrentState()->getNumParticles(),
312 if (m_sphBoundaryConditions && particleTypes[p] == SphBoundaryConditions::ParticleType::Buffer)
317 auto& neighborInfo = getCurrentState()->getNeighborInfo()[p];
318 if (neighborInfo.size() <= 1)
323 const auto& fluidNeighborList = neighborLists[p];
324 for (
size_t i = 0; i < fluidNeighborList.size(); ++i)
326 auto q = fluidNeighborList[i];
327 neighborInfo[i].density = densities[q];
333 SphModel::computeDensity()
335 std::shared_ptr<DataArray<double>> densitiesPtr = getCurrentState()->getDensities();
338 const std::vector<std::vector<NeighborInfo>>& neighborInfos = getCurrentState()->getNeighborInfo();
340 ParallelUtils::parallelFor(getCurrentState()->getNumParticles(),
343 if (m_sphBoundaryConditions && m_sphBoundaryConditions->getParticleTypes()[p] == SphBoundaryConditions::ParticleType::Buffer)
348 const std::vector<NeighborInfo>& neighborInfo = neighborInfos[p];
349 if (neighborInfo.size() <= 1)
354 double pdensity = 0.0;
355 for (
const auto& qInfo : neighborInfo)
357 pdensity += m_kernels.W(qInfo.relativePos);
359 pdensity *= m_modelParameters->m_particleMass;
360 densities[p] = pdensity;
377 SphModel::normalizeDensity()
379 if (!m_modelParameters->m_bNormalizeDensity)
384 std::shared_ptr<DataArray<double>> densitiesPtr = getCurrentState()->getDensities();
387 const std::vector<std::vector<size_t>>& neighborLists = getCurrentState()->getFluidNeighborLists();
388 const std::vector<std::vector<NeighborInfo>>& neighborInfos = getCurrentState()->getNeighborInfo();
389 const std::vector<SphBoundaryConditions::ParticleType>& particleTypes = m_sphBoundaryConditions->getParticleTypes();
391 ParallelUtils::parallelFor(getCurrentState()->getNumParticles(),
394 if (m_sphBoundaryConditions && particleTypes[p] == SphBoundaryConditions::ParticleType::Buffer)
399 const std::vector<NeighborInfo>& neighborInfo = neighborInfos[p];
400 if (neighborInfo.size() <= 1)
405 const auto& fluidNeighborList = neighborLists[p];
408 for (
size_t i = 0; i < fluidNeighborList.size(); ++i)
410 const auto& qInfo = neighborInfo[i];
413 const auto q = fluidNeighborList[i];
414 const auto qdensity = densities[q];
415 tmp += m_kernels.W(qInfo.relativePos) / qdensity;
418 densities[p] /= (tmp * m_modelParameters->m_particleMass);
423 SphModel::computePressureAcceleration()
425 std::shared_ptr<DataArray<double>> densitiesPtr = getCurrentState()->getDensities();
429 const std::vector<std::vector<NeighborInfo>>& neighborInfos = getCurrentState()->getNeighborInfo();
430 const std::vector<SphBoundaryConditions::ParticleType>& particleTypes = m_sphBoundaryConditions->getParticleTypes();
432 ParallelUtils::parallelFor(getCurrentState()->getNumParticles(),
435 if (m_sphBoundaryConditions && particleTypes[p] == SphBoundaryConditions::ParticleType::Buffer)
440 Vec3d accel = Vec3d::Zero();
441 const std::vector<NeighborInfo>& neighborInfo = neighborInfos[p];
442 if (neighborInfo.size() <= 1)
444 pressureAccels[p] = accel;
448 const auto pdensity = densities[p];
449 const auto ppressure = getParticlePressure(pdensity);
451 for (
size_t idx = 0; idx < neighborInfo.size(); ++idx)
453 const auto& qInfo = neighborInfo[idx];
454 const auto r = qInfo.relativePos;
455 const auto qdensity = qInfo.density;
456 const auto qpressure = getParticlePressure(qdensity);
458 accel += -(ppressure / (pdensity * pdensity) + qpressure / (qdensity * qdensity)) * m_kernels.gradW(r);
461 accel *= m_modelParameters->m_particleMass;
464 pressureAccels[p] = accel;
469 SphModel::computeViscosity()
476 const std::vector<std::vector<NeighborInfo>>& neighborInfos = getCurrentState()->getNeighborInfo();
477 const std::vector<std::vector<size_t>>& neighborLists = getCurrentState()->getFluidNeighborLists();
479 ParallelUtils::parallelFor(getCurrentState()->getNumParticles(),
482 if (m_sphBoundaryConditions
483 && (m_sphBoundaryConditions->getParticleTypes()[p] == SphBoundaryConditions::ParticleType::Buffer
484 || m_sphBoundaryConditions->getParticleTypes()[p] == SphBoundaryConditions::ParticleType::Wall))
489 const std::vector<NeighborInfo>& neighborInfo = neighborInfos[p];
490 if (neighborInfo.size() <= 1)
492 neighborVelContr[p] = Vec3d::Zero();
493 viscousAccels[p] = Vec3d::Zero();
497 Vec3d neighborVelContributionsNumerator = Vec3d::Zero();
498 double neighborVelContributionsDenominator = 0.0;
499 Vec3d particleShifts = Vec3d::Zero();
501 const Vec3d& pvel = halfStepVelocities[p];
502 const std::vector<size_t>& fluidNeighborList = neighborLists[p];
504 Vec3d diffuseFluid = Vec3d::Zero();
505 for (
size_t i = 0; i < fluidNeighborList.size(); ++i)
507 const auto q = fluidNeighborList[i];
508 const auto& qvel = halfStepVelocities[q];
509 const auto& qInfo = neighborInfo[i];
510 const auto r = qInfo.relativePos;
511 const auto qdensity = qInfo.density;
512 diffuseFluid += (1.0 / qdensity) * m_kernels.laplace(r) * (qvel - pvel);
514 neighborVelContributionsNumerator += (qvel - pvel) * m_kernels.W(r);
515 neighborVelContributionsDenominator += m_kernels.W(r);
516 particleShifts += m_kernels.gradW(r);
520 const double particleRadius = m_modelParameters->m_particleRadius;
521 particleShifts *= 4 / 3 * PI * particleRadius * particleRadius * particleRadius * 0.5 * m_modelParameters->m_kernelRadius * halfStepVelocities[p].norm();
522 diffuseFluid *= m_modelParameters->m_dynamicViscosityCoeff * m_modelParameters->m_particleMass;
523 neighborVelContr[p] = neighborVelContributionsNumerator * m_modelParameters->m_eta / neighborVelContributionsDenominator;
524 particleShift[p] = -particleShifts;
526 viscousAccels[p] = diffuseFluid;
531 SphModel::computeSurfaceTension()
535 const std::vector<std::vector<NeighborInfo>>& neighborInfos = getCurrentState()->getNeighborInfo();
538 ParallelUtils::parallelFor(getCurrentState()->getNumParticles(),
541 if (m_sphBoundaryConditions && m_sphBoundaryConditions->getParticleTypes()[p] == SphBoundaryConditions::ParticleType::Buffer)
546 Vec3d n(0.0, 0.0, 0.0);
547 const std::vector<NeighborInfo>& neighborInfo = neighborInfos[p];
548 if (neighborInfo.size() <= 1)
550 surfaceNormals[p] = n;
554 for (
size_t i = 0; i < neighborInfo.size(); ++i)
556 const auto& qInfo = neighborInfo[i];
557 const auto r = qInfo.relativePos;
558 const auto qdensity = qInfo.density;
559 n += (1.0 / qdensity) * m_kernels.gradW(r);
562 n *= m_modelParameters->m_kernelRadius * m_modelParameters->m_particleMass;
563 surfaceNormals[p] = n;
569 const std::vector<std::vector<size_t>>& neighborLists = getCurrentState()->getFluidNeighborLists();
572 ParallelUtils::parallelFor(getCurrentState()->getNumParticles(),
575 if (m_sphBoundaryConditions
576 && (m_sphBoundaryConditions->getParticleTypes()[p] == SphBoundaryConditions::ParticleType::Buffer
577 || m_sphBoundaryConditions->getParticleTypes()[p] == SphBoundaryConditions::ParticleType::Wall))
582 const std::vector<size_t>& fluidNeighborList = neighborLists[p];
583 if (fluidNeighborList.size() <= 1)
588 const Vec3d& ni = surfaceNormals[p];
589 const double pdensity = densities[p];
590 const auto& neighborInfo = neighborInfos[p];
592 Vec3d accel = Vec3d::Zero();
593 for (
size_t i = 0; i < fluidNeighborList.size(); ++i)
595 const size_t q = fluidNeighborList[i];
601 const double qdensity = qInfo.
density;
604 const double K_ij = 2.0 * m_modelParameters->m_restDensity / (pdensity + qdensity);
608 const double d2 = r.squaredNorm();
611 accel -= K_ij * m_modelParameters->m_particleMass * (r / std::sqrt(d2)) * m_kernels.cohesionW(r);
615 const Vec3d& nj = surfaceNormals[q];
616 accel -= K_ij * (ni - nj);
619 accel *= m_modelParameters->m_surfaceTensionStiffness;
621 surfaceTensionAccels[p] = accel;
626 SphModel::sumAccels()
633 ParallelUtils::parallelFor(getCurrentState()->getNumParticles(),
636 if (m_sphBoundaryConditions
637 && (m_sphBoundaryConditions->getParticleTypes()[p] == SphBoundaryConditions::ParticleType::Buffer
638 || m_sphBoundaryConditions->getParticleTypes()[p] == SphBoundaryConditions::ParticleType::Wall))
643 accels[p] = pressureAccels[p] + surfaceTensionAccels[p] + viscousAccels[p];
648 SphModel::updateVelocity(
const double timestep)
655 ParallelUtils::parallelFor(getCurrentState()->getNumParticles(),
658 if (m_sphBoundaryConditions
659 && (m_sphBoundaryConditions->getParticleTypes()[p] == SphBoundaryConditions::ParticleType::Buffer
660 || m_sphBoundaryConditions->getParticleTypes()[p] == SphBoundaryConditions::ParticleType::Wall))
666 if (m_timeStepCount == 0)
668 halfStepVelocities[p] = fullStepVelocities[p] + (m_modelParameters->m_gravity + accels[p]) * timestep * 0.5;
669 fullStepVelocities[p] += (m_modelParameters->m_gravity + accels[p]) * timestep;
673 halfStepVelocities[p] += (m_modelParameters->m_gravity + accels[p]) * timestep;
674 fullStepVelocities[p] = halfStepVelocities[p] + (m_modelParameters->m_gravity + accels[p]) * timestep * 0.5;
676 if (m_sphBoundaryConditions && m_sphBoundaryConditions->getParticleTypes()[p] == SphBoundaryConditions::ParticleType::Inlet)
678 halfStepVelocities[p] = m_sphBoundaryConditions->computeParabolicInletVelocity(positions[p]);
679 fullStepVelocities[p] = m_sphBoundaryConditions->computeParabolicInletVelocity(positions[p]);
685 SphModel::moveParticles(
const double timestep)
696 for (
int p = 0; p < static_cast<int>(getCurrentState()->getNumParticles()); p++)
698 if (m_sphBoundaryConditions
699 && (m_sphBoundaryConditions->getParticleTypes()[p] == SphBoundaryConditions::ParticleType::Buffer
700 || m_sphBoundaryConditions->getParticleTypes()[p] == SphBoundaryConditions::ParticleType::Wall))
705 Vec3d oldPosition = positions[p];
706 Vec3d newPosition = oldPosition + particleShift[p] * timestep + (halfStepVelocities[p] + neighborVelContr[p]) * timestep;
708 positions[p] = newPosition;
710 if (m_sphBoundaryConditions)
712 std::vector<SphBoundaryConditions::ParticleType>& particleTypes = m_sphBoundaryConditions->getParticleTypes();
713 if (particleTypes[p] == SphBoundaryConditions::ParticleType::Inlet
714 && !m_sphBoundaryConditions->isInInletDomain(newPosition))
717 particleTypes[p] = SphBoundaryConditions::ParticleType::Fluid;
721 const size_t bufferParticleIndex = m_sphBoundaryConditions->getBufferIndices().back();
722 m_sphBoundaryConditions->getBufferIndices().pop_back();
723 particleTypes[bufferParticleIndex] = SphBoundaryConditions::ParticleType::Inlet;
725 positions[bufferParticleIndex] = m_sphBoundaryConditions->placeParticleAtInlet(oldPosition);
726 halfStepVelocities[bufferParticleIndex] = m_sphBoundaryConditions->computeParabolicInletVelocity(positions[bufferParticleIndex]);
727 fullStepVelocities[bufferParticleIndex] = m_sphBoundaryConditions->computeParabolicInletVelocity(positions[bufferParticleIndex]);
729 else if (particleTypes[p] == SphBoundaryConditions::ParticleType::Outlet
730 && !m_sphBoundaryConditions->isInOutletDomain(newPosition))
732 particleTypes[p] = SphBoundaryConditions::ParticleType::Buffer;
734 positions[p] = m_sphBoundaryConditions->getBufferCoord();
735 m_sphBoundaryConditions->getBufferIndices().
push_back(p);
737 else if (particleTypes[p] == SphBoundaryConditions::ParticleType::Fluid
738 && m_sphBoundaryConditions->isInOutletDomain(newPosition))
740 particleTypes[p] = SphBoundaryConditions::ParticleType::Outlet;
742 else if (particleTypes[p] == SphBoundaryConditions::ParticleType::Fluid
743 && !m_sphBoundaryConditions->isInFluidDomain(newPosition))
745 particleTypes[p] = SphBoundaryConditions::ParticleType::Buffer;
746 positions[p] = m_sphBoundaryConditions->getBufferCoord();
747 m_sphBoundaryConditions->getBufferIndices().push_back(p);
755 SphModel::getParticlePressure(
const double density)
757 const double d = density / m_modelParameters->m_restDensity;
758 const double d2 = d * d;
759 const double d4 = d2 * d2;
760 const double error = m_modelParameters->m_pressureStiffness * (d4 * d2 * d - 1.0);
762 return error > 0.0 ? error : 0.0;
766 SphModel::setInitialVelocities(
const size_t numParticles,
const Vec3d& initialVelocity)
768 m_initialVelocities->clear();
769 m_initialVelocities->reserve(static_cast<int>(numParticles));
770 for (
size_t p = 0; p < numParticles; p++)
772 if (m_sphBoundaryConditions
773 && (m_sphBoundaryConditions->getParticleTypes()[p] == SphBoundaryConditions::ParticleType::Buffer
774 || m_sphBoundaryConditions->getParticleTypes()[p] == SphBoundaryConditions::ParticleType::Wall))
776 m_initialVelocities->push_back(Vec3d::Zero());
780 m_initialVelocities->push_back(initialVelocity);
789 for (
size_t i = 0; i < static_cast<size_t>(points.size()); i++)
791 double minDistance = 1e10;
793 for (
const size_t j : indices[i])
795 const Vec3d p1 = positions[j];
796 const double distance = (points[i] - p1).norm();
797 if (distance < minDistance)
799 minDistance = distance;
803 m_minIndices[i] = minIndex;
Base class for all geometries represented by discrete points and elements The pointsets follow a pipe...
double m_particleMassScale
scale particle mass to a smaller value to maintain stability
void resize(const int size) override
Resize data array to hold exactly size number of values.
void push_back(const ValueType &val)
Append the data array to hold the new value, resizes if neccesary.
DynamicalModelType
Type of the time dependent mathematical model.
void findNearestParticleToVertex(const VecDataArray< double, 3 > &points, const std::vector< std::vector< size_t >> &indices)
Write the state to external file.
double m_particleRadiusSqr
double density
density of neighbor particle
Vec3d relativePos
relative position
int getNumVertices() const
Returns the number of total vertices in the mesh.
bool initialize() override
Initialize the dynamical model.
The helper struct to store relative positions and densities of neighbor particlcles.
void initGraphEdges()
Initializes the edges of the graph.