MPS-Basic
Loading...
Searching...
No Matches
mps.cpp
Go to the documentation of this file.
1#include "mps.hpp"
2
3#include "particle.hpp"
4#include "weight.hpp"
5
6#include <queue>
7
8// This include is for checking if the pressure calculator is explicit.
9// This is needed because we need to update the pressure again when using EMPS.
11
12using std::cerr;
13using std::endl;
14
16 const Input& input,
17 Eigen::Vector3d& gravity,
18 std::unique_ptr<PressureCalculator::Interface>&& pressureCalculator,
19 std::unique_ptr<SurfaceDetector::Interface>&& surfaceDetector
20) {
21 this->settings = input.settings;
22 this->domain = input.settings.domain;
23 this->particles = input.particles;
24 this->gravity = gravity;
25 this->pressureCalculator = std::move(pressureCalculator);
26 this->surfaceDetector = std::move(surfaceDetector);
28
34 );
40 );
46 );
47
48 this->weight =
50 this->weightGrad = Weight(
52 );
53}
54
57 calGravity();
60
62 collision();
63
66 auto pressures = pressureCalculator->calc(particles);
67 for (auto& particle : particles) {
68 particle.pressure = pressures[particle.id];
69 }
70
71 if (settings.pressureCalculationMethod == "Implicit")
75
76 // Update pressure again when using EMPS
77 if (auto explicitPressureCalculator = dynamic_cast<PressureCalculator::Explicit*>(pressureCalculator.get())) {
78 auto pressures = explicitPressureCalculator->calc(particles);
79 for (auto& particle : particles) {
80 particle.pressure = pressures[particle.id];
81 }
82 }
83
84 calCourant();
85}
86
88#pragma omp parallel for
89 for (auto& p : particles) {
90 if (p.type == ParticleType::Fluid) {
91 p.acceleration += gravity;
92 } else {
93 p.acceleration.setZero();
94 }
95 }
96}
97
98void MPS::calViscosity(const double& re) {
99 double n0 = refValuesForLaplacian.n0;
100 double lambda = refValuesForLaplacian.lambda;
101 double a = (settings.kinematicViscosity) * (2.0 * settings.dim) / (n0 * lambda);
102
103#pragma omp parallel for
104 for (auto& pi : particles) {
105 if (pi.type != ParticleType::Fluid)
106 continue;
107
108 Eigen::Vector3d viscosityTerm = Eigen::Vector3d::Zero();
109
110 for (auto& neighbor : pi.neighbors) {
111 auto& pj = particles[neighbor.id];
112
113 if (neighbor.distance < re) {
114 double w = weight.weightFn(neighbor.distance, re);
115 viscosityTerm += (pj.velocity - pi.velocity) * w;
116 }
117 }
118
119 viscosityTerm *= a;
120 pi.acceleration += viscosityTerm;
121 }
122}
123
125#pragma omp parallel for
126 for (auto& p : particles) {
127 if (p.type == ParticleType::Fluid) {
128 p.velocity += p.acceleration * settings.dt;
129 p.position += p.velocity * settings.dt;
130 }
131 p.acceleration.setZero();
132 }
133}
134
136 for (auto& pi : particles) {
137 if (pi.type != ParticleType::Fluid)
138 continue;
139
140 for (auto& neighbor : pi.neighbors) {
141 Particle& pj = particles[neighbor.id];
142 if (pj.type == ParticleType::Fluid && pj.id >= pi.id)
143 continue;
144
145 if (neighbor.distance < settings.collisionDistance) {
146
147 double invMi = pi.inverseDensity();
148 double invMj = pj.inverseDensity();
149 double mass = 1.0 / (invMi + invMj);
150
151 Eigen::Vector3d normal = (pj.position - pi.position).normalized();
152 double relVel = (pj.velocity - pi.velocity).dot(normal);
153 double impulse = 0.0;
154 if (relVel < 0.0)
155 impulse = -(1 + settings.coefficientOfRestitution) * relVel * mass;
156 pi.velocity -= impulse * invMi * normal;
157 pj.velocity += impulse * invMj * normal;
158
159 double depth = settings.collisionDistance - neighbor.distance;
160 double positionImpulse = depth * mass;
161 pi.position -= positionImpulse * invMi * normal;
162 pj.position += positionImpulse * invMj * normal;
163
164 // cerr << "WARNING: Collision between particles " << pi.id << " and " << pj.id << " occurred."
165 // << endl;
166 }
167 }
168 }
169}
170
171void MPS::calNumberDensity(const double& re) {
172#pragma omp parallel for
173 for (auto& pi : particles) {
174 pi.numberDensity = 0.0;
175
176 if (pi.type == ParticleType::Ghost)
177 continue;
178
179 for (auto& neighbor : pi.neighbors)
180 pi.numberDensity += weight.weightFn(neighbor.distance, re);
181 }
182}
183
184void MPS::setMinimumPressure(const double& re) {
185#pragma omp parallel for
186 for (auto& p : particles) {
187 p.minimumPressure = p.pressure;
188 }
189
190 for (auto& pi : particles) {
191 if (pi.type == ParticleType::Ghost || pi.type == ParticleType::DummyWall)
192 continue;
193
194 for (auto& neighbor : pi.neighbors) {
195 Particle& pj = particles[neighbor.id];
197 continue;
198 if (pj.id > pi.id)
199 continue;
200
201 if (neighbor.distance < re) {
202 pi.minimumPressure = std::min(pi.minimumPressure, pj.pressure);
203 pj.minimumPressure = std::min(pj.minimumPressure, pi.pressure);
204 }
205 }
206 }
207}
208
209void MPS::calPressureGradient(const double& re) {
210 double a = settings.dim / refValuesForGradient.n0;
211
212#pragma omp parallel for
213 for (auto& pi : particles) {
214 if (pi.type != ParticleType::Fluid)
215 continue;
216
217 Eigen::Vector3d grad = Eigen::Vector3d::Zero();
218 for (auto& neighbor : pi.neighbors) {
219 Particle& pj = particles[neighbor.id];
221 continue;
222
223 if (neighbor.distance < re) {
224 double w = weightGrad.weightFn(neighbor.distance, re);
225 // double dist2 = pow(neighbor.distance, 2);
226 double dist2 = (pj.position - pi.position).squaredNorm();
227 double pij = (settings.pressureCalculationMethod == "Implicit")
228 ? (pj.pressure - pi.minimumPressure) / dist2
229 : (pj.pressure + pi.pressure) / dist2;
230 grad += (pj.position - pi.position) * pij * w;
231 }
232 }
233 grad *= a;
234 pi.acceleration -= grad / pi.density;
235 }
236}
237
239#pragma omp parallel for
240 for (auto&& p : particles) {
241 if (p.type == ParticleType::Fluid) {
242 p.velocity += p.acceleration * settings.dt;
243 p.position += p.acceleration * settings.dt * settings.dt;
244 }
245
246 p.acceleration.setZero();
247 }
248}
249
251 courant = 0.0;
252
253 for (auto& pi : particles) {
254 if (pi.type != ParticleType::Fluid)
255 continue;
256
257 double iCourant = (pi.velocity.norm() * settings.dt) / settings.particleDistance;
258 courant = std::max(courant, iCourant);
259 }
260
262 cerr << "ERROR: Courant number is larger than CFL condition. Courant = " << courant << endl;
263 }
264}
void setMinimumPressure(const double &re)
set minimum pressure for pressure gradient calculation
Definition mps.cpp:184
void stepForward()
Definition mps.cpp:55
void calViscosity(const double &re)
calculate viscosity term of Navier-Stokes equation
Definition mps.cpp:98
std::unique_ptr< PressureCalculator::Interface > pressureCalculator
Interface for pressure calculation.
Definition mps.hpp:36
void moveParticleUsingPressureGradient()
move particles in correction step
Definition mps.cpp:238
Settings settings
Settings for the simulation.
Definition mps.hpp:28
Weight weightGrad
Weight function instance for the gradient calculation.
Definition mps.hpp:53
double courant
Maximum courant number among all particles.
Definition mps.hpp:38
void calPressureGradient(const double &re)
calculate pressure gradient term
Definition mps.cpp:209
MPS()=default
RefValues refValuesForLaplacian
Reference values for the simulation ( , )
Definition mps.hpp:31
void moveParticle()
move particles in prediction step
Definition mps.cpp:124
RefValues refValuesForNumberDensity
Reference values for the simulation ( , )
Definition mps.hpp:30
void calCourant()
calculate Courant number
Definition mps.cpp:250
void collision()
calculate collision between particles when they are too close
Definition mps.cpp:135
Eigen::Vector3d gravity
Gravity vector for the simulation.
Definition mps.hpp:29
NeighborSearcher neighborSearcher
Neighbor searcher for neighbor search.
Definition mps.hpp:50
std::unique_ptr< SurfaceDetector::Interface > surfaceDetector
Interface for free surface detection.
Definition mps.hpp:51
void calNumberDensity(const double &re)
calculate number density of each particle
Definition mps.cpp:171
RefValues refValuesForGradient
Reference values for the simulation ( , )
Definition mps.hpp:32
Weight weight
Weight function instance except for gradient calculation.
Definition mps.hpp:52
void calGravity()
calculate gravity term
Definition mps.cpp:87
Particles particles
Particles in the simulation.
Definition mps.hpp:33
Domain domain
Domain of the simulation.
Definition mps.hpp:34
void setNeighbors(Particles &particles)
Class for particle in MPS method.
Definition particle.hpp:47
double inverseDensity() const
calculate inverse of density for collision
Definition particle.cpp:12
Eigen::Vector3d position
position of the particle
Definition particle.hpp:55
double pressure
pressure of the particle
Definition particle.hpp:58
int id
index of the particle
Definition particle.hpp:50
double minimumPressure
minimum pressure of the particle
Definition particle.hpp:64
Eigen::Vector3d velocity
velocity of the particle
Definition particle.hpp:56
ParticleType type
type of the particle
Definition particle.hpp:51
int size() const
Get the number of particles.
Definition particles.cpp:22
Class for explicit pressure calculation.
Definition explicit.hpp:14
Struct for reference values of MPS method.
Definition refvalues.hpp:9
double n0
reference value of number density for source term of pressure Poisson equation
Definition refvalues.hpp:11
double lambda
coefficient for laplacian
Definition refvalues.hpp:12
Provides a weight function.
Definition weight.hpp:15
double weightFn(double dis, double re)
Weight function for MPS method.
Definition weight.cpp:10
@ Ghost
Ghost particle (outside of the domain, not used for calculation)
@ DummyWall
Dummy wall particle (pressure is not calculated)
@ Fluid
Fluid particle.
Represents the input data for MPS simulation.
Definition input.hpp:12
Particles particles
Initial particles arrangement in the simulation.
Definition input.hpp:14
Settings settings
Settings for the simulation.
Definition input.hpp:13
double reMax
Maximum of effective radius.
Definition settings.hpp:59
double collisionDistance
Distance for collision detection.
Definition settings.hpp:52
double particleDistance
Initial distance between particles.
Definition settings.hpp:18
int dim
Dimension of the simulation.
Definition settings.hpp:17
double re_forNumberDensity
Effective radius for number density.
Definition settings.hpp:56
std::string pressureCalculationMethod
Method for pressure calculation.
Definition settings.hpp:44
double kinematicViscosity
Kinematic viscosity.
Definition settings.hpp:27
double cflCondition
CFL condition.
Definition settings.hpp:22
double coefficientOfRestitution
Coefficient of restitution.
Definition settings.hpp:53
double re_forGradient
Effective radius for gradient.
Definition settings.hpp:57
double dt
Time step.
Definition settings.hpp:19
Domain domain
domain of the simulation
Definition settings.hpp:24
double re_forLaplacian
Effective radius for Laplacian.
Definition settings.hpp:58