iMSTK
Interactive Medical Simulation Toolkit
imstkSPHKernels.h
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #pragma once
8 
9 #include "imstkMath.h"
10 #include "imstkLogger.h"
11 
12 namespace imstk
13 {
14 namespace sph
15 {
21 template<int N>
23 {
24 using VecXd = Eigen::Matrix<double, N, 1>;
25 
26 public:
27  Poly6Kernel()
28  {
29  static_assert(N == 2 || N == 3, "Invalid kernel dimension");
30  }
31 
35  void setRadius(const double radius)
36  {
37  m_radius = radius;
39 
40 #ifdef WIN32
41 #pragma warning(push)
42 #pragma warning(disable:4127)
43 #endif
44  if (N == 2)
45 #ifdef WIN32
46 #pragma warning(pop)
47 #endif
48  {
49  m_k = 4.0 / (PI * std::pow(m_radius, 8));
50  m_l = -24.0 / (PI * std::pow(m_radius, 8));
51  }
52  else
53  {
54  m_k = 315.0 / (64.0 * PI * std::pow(m_radius, 9));
55  m_l = -945.0 / (32.0 * PI * std::pow(m_radius, 9));
56  }
57  m_m = m_l;
58  m_W0 = W(VecXd::Zero());
59  }
60 
65  double W(const double r) const
66  {
67  const double r2 = r * r;
68  const double rd = m_radiusSquared - r2;
69  return (r2 <= m_radiusSquared) ? rd * rd * rd * m_k : 0.0;
70  }
71 
76  double W(const VecXd& r) const
77  {
78  const double r2 = r.squaredNorm();
79  const double rd = m_radiusSquared - r2;
80  return (r2 <= m_radiusSquared) ? rd * rd * rd * m_k : 0.0;
81  }
82 
86  double W0() const { return m_W0; }
87 
92  VecXd gradW(const VecXd& r) const
93  {
94  VecXd res = VecXd::Zero();
95  const double r2 = r.squaredNorm();
96  if (r2 <= m_radiusSquared && r2 > 1.0e-12)
97  {
98  double tmp = m_radiusSquared - r2;
99  res = m_l * tmp * tmp * r;
100  }
101 
102  return res;
103  }
104 
109  double laplacian(const VecXd& r) const
110  {
111  double res = 0.;
112  const double r2 = r.squaredNorm();
113  if (r2 <= m_radiusSquared)
114  {
115  double tmp = m_radiusSquared - r2;
116  double tmp2 = 3.0 * m_radiusSquared - 7.0 * r2;
117  res = m_m * tmp * tmp2;
118  }
119 
120  return res;
121  }
122 
123 protected:
124  double m_radius;
126  double m_k;
127  double m_l;
128  double m_m;
129  double m_W0;
130 };
131 
137 template<int N>
139 {
140 using VecXd = Eigen::Matrix<double, N, 1>;
141 
142 public:
143  SpikyKernel()
144  {
145  static_assert(N == 2 || N == 3, "Invalid kernel dimension");
146  }
147 
151  void setRadius(const double radius)
152  {
153  m_radius = radius;
155 
156 #ifdef WIN32
157 #pragma warning(push)
158 #pragma warning(disable:4127)
159 #endif
160  if (N == 2)
161 #ifdef WIN32
162 #pragma warning(pop)
163 #endif
164  {
165  const double radius5 = std::pow(m_radius, 5);
166  m_k = 10.0 / (PI * radius5);
167  m_l = -30.0 / (PI * radius5);
168  }
169  else
170  {
171  const double radius6 = std::pow(m_radius, 6);
172  m_k = 15.0 / (PI * radius6);
173  m_l = -45.0 / (PI * radius6);
174  }
175  m_W0 = W(VecXd::Zero());
176  }
177 
182  double W(const double r) const
183  {
184  const double rd = m_radius - r;
185  return (r <= m_radius) ? rd * rd * rd * m_k : 0.0;
186  }
187 
192  double W(const VecXd& r) const
193  {
194  const double r2 = r.squaredNorm();
195  const double rd = m_radius - std::sqrt(r2);
196  return (r2 <= m_radiusSquared) ? rd * rd * rd * m_k : 0.0;
197  }
198 
202  double W0() const { return m_W0; }
203 
208  VecXd gradW(const VecXd& r) const
209  {
210  VecXd res = VecXd::Zero();
211  const auto r2 = r.squaredNorm();
212  if (r2 <= m_radiusSquared && r2 > 1.0e-12)
213  {
214  const double rl = std::sqrt(r2);
215  const double hr = m_radius - rl;
216  const double hr2 = hr * hr;
217  res = m_l * hr2 * (r / rl);
218  }
219 
220  return res;
221  }
222 
223 protected:
224  double m_radius;
226  double m_k;
227  double m_l;
228  double m_W0;
229 };
230 
236 template<int N>
238 {
239 using VecXd = Eigen::Matrix<double, N, 1>;
240 
241 public:
243  {
244  static_assert(N == 3, "Invalid kernel dimension");
245  }
246 
250  void setRadius(const double radius)
251  {
252  m_radius = radius;
254 
255 #ifdef WIN32
256 #pragma warning(push)
257 #pragma warning(disable:4127)
258 #endif
259  CHECK(N != 2) << "Unimplemented function";
260 #ifdef WIN32
261 #pragma warning(pop)
262 #endif
263 
264  m_k = 32.0 / (PI * std::pow(m_radius, 9));
265  m_c = std::pow(m_radius, 6) / 64.0;
266  m_W0 = W(VecXd::Zero());
267  }
268 
273  double W(const double r) const
274  {
275  double res = 0.;
276  const double r2 = r * r;
277  if (r2 <= m_radiusSquared)
278  {
279  const double r1 = std::sqrt(r2);
280  const double r3 = r2 * r1;
281  if (r1 > 0.5 * m_radius)
282  {
283  const double rd = m_radius - r1;
284  res = m_k * rd * rd * rd * r3;
285  }
286  else
287  {
288  const double rd = m_radius - r1;
289  res = m_k * 2.0 * rd * rd * rd * r3 - m_c;
290  }
291  }
292  return res;
293  }
294 
299  double W(const VecXd& r) const
300  {
301  double res = 0.;
302  const double r2 = r.squaredNorm();
303  if (r2 <= m_radiusSquared)
304  {
305  const double r1 = std::sqrt(r2);
306  const double r3 = r2 * r1;
307  if (r1 > 0.5 * m_radius)
308  {
309  const double rd = m_radius - r1;
310  res = m_k * rd * rd * rd * r3;
311  }
312  else
313  {
314  const double rd = m_radius - r1;
315  res = m_k * 2.0 * rd * rd * rd * r3 - m_c;
316  }
317  }
318  return res;
319  }
320 
324  double W0() const { return m_W0; }
325 
326 protected:
327  double m_radius;
329  double m_k;
330  double m_c;
331  double m_W0;
332 };
333 
339 template<int N>
341 {
342 using VecXd = Eigen::Matrix<double, N, 1>;
343 
344 public:
346  {
347  static_assert(N == 3, "Invalid kernel dimension");
348  }
349 
353  void setRadius(const double radius)
354  {
355  m_radius = radius;
357 
358  CHECK(N != 2) << "Unimplemented function";
359 
360  m_k = 0.007 / std::pow(m_radius, 3.25);
361  m_W0 = W(VecXd::Zero());
362  }
363 
368  double W(const double r) const
369  {
370  double res = 0.;
371  const double r2 = r * r;
372  if (r2 <= m_radiusSquared)
373  {
374  const double r = std::sqrt(r2);
375  if (r > 0.5 * m_radius)
376  {
377  res = m_k * std::pow(-4.0 * r2 / m_radius + 6.0 * r - 2.0 * m_radius, 0.25);
378  }
379  }
380  return res;
381  }
382 
387  double W(const VecXd& r) const
388  {
389  double res = 0.;
390  const double r2 = r.squaredNorm();
391  if (r2 <= m_radiusSquared)
392  {
393  const double r = std::sqrt(r2);
394  if (r > 0.5 * m_radius)
395  {
396  res = m_k * std::pow(-4.0 * r2 / m_radius + 6.0 * r - 2.0 * m_radius, 0.25);
397  }
398  }
399  return res;
400  }
401 
405  double W0() const { return m_W0; }
406 
407 protected:
408  double m_radius;
410  double m_k;
411  double m_W0;
412 };
413 
419 template<int N>
421 {
422 using VecXd = Eigen::Matrix<double, N, 1>;
423 
424 public:
426  {
427  static_assert(N == 2 || N == 3, "Invalid kernel dimension");
428  }
429 
433  void setRadius(const double radius)
434  {
435  m_radius = radius;
436  m_radiusSquared = radius * radius;
437  m_k = (45.0 / PI) / (m_radiusSquared * m_radiusSquared * m_radiusSquared);
438  }
439 
444  double laplace(const VecXd& r) const
445  {
446  double res = 0.;
447  const double r2 = r.squaredNorm();
448  if (r2 <= m_radiusSquared)
449  {
450  const double d = std::sqrt(r2);
451  res = m_k * (m_radius - d);
452  }
453  return res;
454  }
455 
456 protected:
457  double m_radius;
459  double m_k;
460 };
461 } // namespace sph
462 
470 {
471 public:
475  void initialize(const double kernelRadius)
476  {
477  m_poly6.setRadius(kernelRadius);
478  m_spiky.setRadius(kernelRadius);
479  m_viscosity.setRadius(kernelRadius);
480  m_cohesion.setRadius(kernelRadius);
481  }
482 
486  double W0() const { return m_poly6.W0(); }
487 
491  double W(const Vec3d& r) const { return m_poly6.W(r); }
492 
496  Vec3d gradW(const Vec3d& r) const { return m_spiky.gradW(r); }
497 
501  double laplace(const Vec3d& r) const { return m_viscosity.laplace(r); }
502 
506  double cohesionW(const Vec3d& r) const { return m_cohesion.W(r); }
507 
508 protected:
509  sph::Poly6Kernel<3> m_poly6;
510  sph::SpikyKernel<3> m_spiky;
511  sph::ViscosityKernel<3> m_viscosity;
512  sph::CohesionKernel<3> m_cohesion;
513 };
514 } // namespace imstk
double m_k
Kernel coefficient for W()
double m_k
Kernel coefficient for W()
void setRadius(const double radius)
Set the kernel radius.
double m_k
Kernel coefficient for laplacian()
double W(const VecXd &r) const
Compute weight value W(r,h) = (32/(PI h^9))(h-r)^3*r^3 if h/2 < r <= h, (32/(PI h^9))(2*(h-r)^3*r^3 -...
double m_radiusSquared
Kernel radius squared.
double m_radius
Kernel radius.
double W(const VecXd &r) const
Compute weight value W(r,h) = 15/(PI*h^6) * (h-r)^3.
double W(const Vec3d &r) const
Compute weight W using poly6 kernel.
double W0() const
Get W(0)
double m_l
Kernel coefficient for gradW()
double laplace(const VecXd &r) const
Compute laplacian Laplace(r) = (45/PI/h^6) * (h - |r|)
double m_radiusSquared
Kernel radius squared.
double m_W0
Precomputed W(0)
double m_radiusSquared
Kernel radius squared.
Compound Geometry.
VecXd gradW(const VecXd &r) const
Compute weight gradient grad(W(r,h)) = r(-945/(32 PI h^9))(h^2-|r|^2)^2.
void initialize(const double kernelRadius)
Initialize with kernel radius kernelRadius.
double m_k
Kernel coefficient for W()
Vec3d gradW(const Vec3d &r) const
Compute gradW using spiky kernel.
double cohesionW(const Vec3d &r) const
Compute cohesion W using cohesion kernel.
double W(const double r) const
Compute weight value W(r,h) = (32/(PI h^9))(h-r)^3*r^3 if h/2 < r <= h, (32/(PI h^9))(2*(h-r)^3*r^3 -...
double W(const VecXd &r) const
Compute weight value W(r,h) = (0.007/h^3.25)(-4r^2/h + 6r -2h)^0.25 if h/2 < r <= h...
double W0() const
Compute weight W(0) using poly6 kernel.
double m_radius
Kernel radius.
double m_radiusSquared
Kernel radius squared.
void setRadius(const double radius)
Set the kernel radius.
double W(const double r) const
Compute weight value W(r,h) = (0.007/h^3.25)(-4r^2/h + 6r -2h)^0.25 if h/2 < r <= h...
double m_W0
Precomputed W(0)
double W0() const
Get W(0)
double m_radius
Kernel radius.
The poly6 Kernel.
double laplace(const Vec3d &r) const
Compute laplacian using viscosity kernel.
double m_k
Kernel coefficient for W()
double m_W0
Precomputed W(0)
double W(const VecXd &r) const
Compute weight value W(r,h) = (315/(64 PI h^9))(h^2-|r|^2)^3.
Class contains SPH kernels for time integration, using different kernel for different purposes...
double m_l
Kernel coefficient for gradW()
double W(const double r) const
Compute weight value W(r,h) = 15/(PI*h^6) * (h-r)^3.
VecXd gradW(const VecXd &r) const
Compute weight gradient grad(W(r,h)) = -r(45/(PI*h^6) * (h-r)^2)
double m_m
Kernel coefficient for laplacian()
double W0() const
Get W(0)
void setRadius(const double radius)
Set the kernel radius.
double W(const double r) const
Compute weight value W(r,h) = (315/(64 PI h^9))(h^2-|r|^2)^3.
double W0() const
Get W(0)
double m_radius
Kernel radius.
double m_radius
Kernel radius.
double m_c
Kernel coefficient for W()
double m_radiusSquared
Kernel radius squared.
double m_W0
Precomputed W(0)
void setRadius(const double radius)
Set the kernel radius.
void setRadius(const double radius)
Set the kernel radius.
double laplacian(const VecXd &r) const
Compute laplacian laplacian(W(r,h)) = (-945/(32 PI h^9))(h^2-|r|^2)(-7|r|^2+3h^2) ...