SPH
GravityKernel.h
Go to the documentation of this file.
1 #pragma once
2 
7 
8 #include "common/Traits.h"
9 #include "math/Functional.h"
10 #include "objects/wrappers/Lut.h"
11 #include "sph/kernel/Kernel.h"
12 
14 
18 template <typename TKernel>
20 
21 struct GravityKernelTag {};
22 
23 template <typename T, typename = void>
24 struct IsGravityKernel;
25 
36 private:
38  LutKernel<3> close;
39 
40 public:
41  GravityLutKernel() = default;
42 
43  template <typename TKernel>
44  GravityLutKernel(TKernel&& source)
45  : close(std::forward<TKernel>(source)) {
46  using T = std::decay_t<TKernel>;
47  static_assert(IsGravityKernel<T>::value,
48  "Use GravityKernel to get gravity smoothing kernel associated to SPH kernel");
49  }
50 
51  INLINE Float radius() const {
52  return close.radius();
53  }
54 
55  INLINE Float value(const Vector& r, const Float h) const {
56  SPH_ASSERT(h >= 0._f);
57  const Float hInv = 1._f / h;
58  const Float qSqr = getSqrLength(r * hInv);
59  if (qSqr + EPS >= sqr(close.radius())) {
60  return -1._f / getLength(r);
61  } else {
62  // LUT kernel returns 0 for qSqr >= radiusSqr
63  const Float value = close.valueImpl(qSqr);
64  SPH_ASSERT(value < 0._f);
65  return hInv * value;
66  }
67  }
68 
69  INLINE Vector grad(const Vector& r, const Float h) const {
70  SPH_ASSERT(h >= 0._f);
71  const Float hInv = 1._f / h;
72  const Float qSqr = getSqrLength(r * hInv);
73  if (qSqr + EPS >= sqr(close.radius())) {
74  return r / pow<3>(getLength(r));
75  } else {
76  const Float grad = close.gradImpl(qSqr);
77  SPH_ASSERT(grad != 0._f);
78  return pow<3>(hInv) * r * grad;
79  }
80  }
81 };
82 
83 template <>
84 class GravityKernel<CubicSpline<3>> : public Kernel<GravityKernel<CubicSpline<3>>, 3> {
85 public:
86  INLINE Float radius() const {
87  return 2._f;
88  }
89 
90  INLINE Float valueImpl(const Float qSqr) const {
91  SPH_ASSERT(qSqr >= 0._f && qSqr <= sqr(radius()));
92  const Float q = sqrt(qSqr);
93  if (q < 1._f) {
94  return 2._f / 3._f * qSqr - 3._f / 10._f * pow<4>(q) + 1._f / 10._f * pow<5>(q) - 7._f / 5._f;
95  } else {
96  return 4._f / 3._f * qSqr - pow<3>(q) + 3._f / 10._f * pow<2>(qSqr) - 1._f / 30._f * pow<5>(q) -
97  8._f / 5._f + 1._f / (15._f * q);
98  }
99  }
100 
101  INLINE Float gradImpl(const Float qSqr) const {
102  SPH_ASSERT(qSqr >= 0._f && qSqr <= sqr(radius()));
103  const Float q = sqrt(qSqr);
104  if (q == 0._f) {
105  return 4._f / 3._f;
106  } else if (q < 1._f) {
107  return 1._f / q * (4._f / 3._f * q - 6._f / 5._f * pow<3>(q) + 1._f / 2._f * pow<2>(qSqr));
108  } else {
109  return 1._f / q *
110  (8._f / 3._f * q - 3._f * qSqr + 6._f / 5._f * pow<3>(q) - 1._f / 6._f * pow<2>(qSqr) -
111  1._f / (15._f * qSqr));
112  }
113  }
114 };
115 
117 template <>
118 class GravityKernel<ThomasCouchmanKernel<3>> : public GravityKernel<CubicSpline<3>> {};
119 
121 class SolidSphereKernel : public Kernel<SolidSphereKernel, 3>, public GravityKernelTag {
122 public:
123  SolidSphereKernel() = default;
124 
125  INLINE Float radius() const {
126  return 2._f;
127  }
128 
129  INLINE Float valueImpl(const Float UNUSED(qSqr)) const {
130  return 0._f;
131  }
132 
133  INLINE Float gradImpl(const Float UNUSED(qSqr)) const {
134  return 1._f;
135  }
136 };
137 
140 template <typename TKernel,
141  typename = std::enable_if_t<IsKernel<TKernel>::value && !IsGravityKernel<TKernel>::value>>
142 auto getAssociatedGravityKernel(const TKernel& W, const Size resolution = 40000) {
143  Array<Float> psi(resolution);
144  const Float radius = W.radius();
145  Float integral = 0._f;
146  psi[0] = 0._f;
147  Float q1 = 0._f;
148  for (Size i = 1; i < resolution; ++i) {
149  const Float q2 = Float(i) / resolution * radius;
150  integral += integrate(Interval(q1, q2), [&W](const Float q) { return sqr(q) * W.valueImpl(sqr(q)); });
151  psi[i] = 4._f * PI / sqr(q2) * integral;
152  SPH_ASSERT(isReal(psi[i]));
153 
154  q1 = q2;
155  }
156 
157  class KernelImpl : public Kernel<KernelImpl, 3>, public GravityKernelTag {
158  Lut<Float> values;
159  Lut<Float> gradients;
160  Float grad0;
161 
162  public:
163  KernelImpl(Array<Float>&& psi, const Float grad0, const Interval& range)
164  : gradients(range, std::move(psi))
165  , grad0(grad0) {
166  const Float r = range.upper();
167  values = gradients.integral(r, -1._f / r);
168  }
169 
170  INLINE Float valueImpl(const Float qSqr) const {
171  return values(sqrt(qSqr));
172  }
173  INLINE Float gradImpl(const Float qSqr) const {
174  const Float q = sqrt(qSqr);
175  if (q == 0._f) {
176  return grad0;
177  }
178  return gradients(q) / q;
179  }
180  INLINE Float radius() const {
181  return values.getRange().upper();
182  }
183  };
184 
185  // integral q^2 dq = 1/3 * q^3
186  const Float grad0 = 4._f / 3._f * PI * W.valueImpl(0._f);
187  return KernelImpl(std::move(psi), grad0, Interval(0._f, radius));
188 }
189 
190 template <typename T, typename>
192  static constexpr bool value = false;
193 };
194 
195 template <typename T>
197  static constexpr bool value = IsKernel<T>::value;
198 };
199 
200 template <typename T>
201 struct IsGravityKernel<T, std::enable_if_t<std::is_base_of<GravityKernelTag, std::decay_t<T>>::value>> {
202  static constexpr bool value = IsKernel<T>::value;
203 };
204 
INLINE bool isReal(const AntisymmetricTensor &t)
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
const float radius
Definition: CurveDialog.cpp:18
NAMESPACE_SPH_BEGIN INLINE Float integrate(const Interval range, const TFunctor &functor)
Integrates a one-dimensional function using Simpson's rule.
Definition: Functional.h:18
uint32_t Size
Integral type used to index arrays (by default).
Definition: Globals.h:16
double Float
Precision used withing the code. Use Float instead of float or double where precision is important.
Definition: Globals.h:13
auto getAssociatedGravityKernel(const TKernel &W, const Size resolution=40000)
Computes the gravitational softening kernel from the associated SPH kernel by integrating the Poisson...
SPH kernels.
Approximation of generic function by look-up table.
constexpr INLINE Float pow< 5 >(const Float v)
Definition: MathUtils.h:140
constexpr Float EPS
Definition: MathUtils.h:30
constexpr INLINE T sqr(const T &f) noexcept
Return a squared value.
Definition: MathUtils.h:67
INLINE T sqrt(const T f)
Return a squared root of a value.
Definition: MathUtils.h:78
constexpr INLINE Float pow< 3 >(const Float v)
Definition: MathUtils.h:132
constexpr INLINE Float pow< 4 >(const Float v)
Definition: MathUtils.h:136
constexpr INLINE Float pow< 2 >(const Float v)
Definition: MathUtils.h:128
constexpr Float PI
Mathematical constants.
Definition: MathUtils.h:361
#define INLINE
Macros for conditional compilation based on selected compiler.
Definition: Object.h:31
#define UNUSED(x)
Definition: Object.h:37
#define NAMESPACE_SPH_END
Definition: Object.h:12
Few non-standard type traits.
INLINE Float getLength(const Vector &v)
Returns the length of the vector. Enabled only for vectors of floating-point precision.
Definition: Vector.h:579
INLINE Float getSqrLength(const Vector &v)
Definition: Vector.h:574
Cubic spline (M4) kernel.
Definition: Kernel.h:150
INLINE Float gradImpl(const Float qSqr) const
INLINE Float valueImpl(const Float qSqr) const
Definition: GravityKernel.h:90
Gravity smoothing kernels associated with standard SPH kernels.
Definition: GravityKernel.h:19
Gravitational kernel approximated by LUT for close particles.
Definition: GravityKernel.h:35
GravityLutKernel(TKernel &&source)
Definition: GravityKernel.h:44
INLINE Vector grad(const Vector &r, const Float h) const
Definition: GravityKernel.h:69
GravityLutKernel()=default
INLINE Float value(const Vector &r, const Float h) const
Definition: GravityKernel.h:55
INLINE Float radius() const
Definition: GravityKernel.h:51
Object representing a 1D interval of real numbers.
Definition: Interval.h:17
INLINE Float upper() const
Returns upper bound of the interval.
Definition: Interval.h:79
Base class for all SPH kernels.
Definition: Kernel.h:19
INLINE Float valueImpl(const Float qSqr) const noexcept
Definition: Kernel.h:111
INLINE Float radius() const noexcept
Definition: Kernel.h:107
INLINE Float gradImpl(const Float qSqr) const noexcept
Definition: Kernel.h:129
Interval getRange() const
Returns the definition interval of the function.
Definition: Lut.h:115
Lut integral(const Float x0, const Float y0) const
Computes the indefinite integral of the function.
Definition: Lut.h:133
Gravity kernel of a solid sphere.
SolidSphereKernel()=default
INLINE Float gradImpl(const Float UNUSED(qSqr)) const
INLINE Float valueImpl(const Float UNUSED(qSqr)) const
INLINE Float radius() const
Kernel introduced by Thomas & Couchman (1992).
Definition: Kernel.h:286
Overload of std::swap for Sph::Array.
Definition: Array.h:578
static constexpr bool value