SPH
Moments.h
Go to the documentation of this file.
1 #pragma once
2 
4 
6 
7 template <Size N>
9  const Float invDistSqr = 1._f / getSqrLength(dr);
10  gamma[0] = -sqrt(invDistSqr);
11  for (Size i = 1; i < N + 2; ++i) {
12  gamma[i] = -(2._f * i - 1._f) * invDistSqr * gamma[i - 1];
13  }
14 }
15 
16 
17 template <Size M>
18 struct ComputeTrace;
19 
20 template <>
21 struct ComputeTrace<1> {
22  template <Size N>
23  INLINE static Multipole<N - 2> make(const Multipole<N>& m) {
24  static_assert(N >= 2, "invalid parameter");
26  }
27 };
28 
29 template <>
30 struct ComputeTrace<2> {
31  template <Size N>
32  INLINE static Multipole<N - 4> make(const Multipole<N>& m) {
33  static_assert(N >= 4, "invalid parameter");
35  }
36 };
37 
39 template <Size M, Size N>
40 Multipole<N - 2 * M> computeTrace(const Multipole<N>& m) {
41  static_assert(N >= 2 * M, "invalid parameter");
42  return ComputeTrace<M>::make(m);
43 }
44 
45 template <Size N, Size M>
47  static_assert(N > 0, "Cannot be used for N == 0");
48  static_assert(2 * N - 2 * M > 0, "invalid parameter");
49  const SignedSize sign = (isOdd(M) ? -1 : 1);
50  const Float num = doubleFactorial(2 * N - 2 * M - 1);
51  const Float denom = factorial(M) * doubleFactorial(2 * N - 1);
52  const Float factor = sign * num / denom;
53  return factor;
54 }
55 
56 template <Size N>
58 
59 template <>
61  // compute traces
62  const Multipole<4>& T0 = m;
63  Multipole<2> T1 = computeTrace<1>(m);
64  Float T2 = computeTrace<2>(m).value();
65 
66  // compute factors
67  const Float f0 = reducedFactor<4, 0>();
68  const Float f1 = reducedFactor<4, 1>();
69  const Float f2 = reducedFactor<4, 2>();
70 
71  using namespace MomentOperators;
72 
73  // sum up the terms
74  return makeTracelessMultipole<4>(T0 * f0 + makePermutations(Delta<2>{}, T1) * f1 + Delta<4>{} * T2 * f2);
75 }
76 
77 template <>
79  const Multipole<3>& T0 = m;
80  Multipole<1> T1 = computeTrace<1>(m);
81 
82  const Float f0 = reducedFactor<3, 0>();
83  const Float f1 = reducedFactor<3, 1>();
84 
85  using namespace MomentOperators;
86  return makeTracelessMultipole<3>(T0 * f0 + makePermutations(Delta<2>{}, T1) * f1);
87 }
88 
89 template <>
91  const Multipole<2>& T0 = m;
92  Multipole<0> T1 = computeTrace<1>(m);
93 
94  const Float f0 = reducedFactor<2, 0>();
95  const Float f1 = reducedFactor<2, 1>();
96 
97  using namespace MomentOperators;
98  return makeTracelessMultipole<2>(T0 * f0 + makePermutations(Delta<2>{}, T1) * f1);
99 }
100 
101 template <>
103  const Multipole<1>& T0 = m;
104 
105  const Float f0 = reducedFactor<1, 0>();
106 
107  using namespace MomentOperators;
108  return makeTracelessMultipole<1>(T0 * f0);
109 }
110 
111 template <>
113  return makeTracelessMultipole<0>(m);
114 }
115 
116 template <Size M, Size N>
117 std::enable_if_t<(M < N), TracelessMultipole<M>> computeMultipolePotential(const TracelessMultipole<N>& q,
118  const Vector& r) {
119  static_assert(M <= N, "Incorrect parameters");
120  using namespace MomentOperators;
121  OuterProduct<N - M> dr{ r };
122  return makeTracelessMultipole<M>(makeInner<N - M>(dr, q) * (1._f / factorial(N - M)));
123 }
124 
125 template <Size M, Size N>
126 std::enable_if_t<M == N, TracelessMultipole<M>> computeMultipolePotential(const TracelessMultipole<N>& q,
127  const Vector& UNUSED(r)) {
128  return q;
129 }
130 
131 template <Size M, Size N>
133  const TracelessMultipole<N>& UNUSED(q),
134  const Vector& UNUSED(r)) {
135  return TracelessMultipole<M>(0._f);
136 }
137 
138 
139 namespace Detail {
140 template <Size N>
142  return makeMultipole<N>(MomentOperators::OuterProduct<N>{ dr }) * m;
143 }
144 
145 template <>
147  return m;
148 }
149 } // namespace Detail
150 
151 template <Size N, typename TSequence>
154  const Vector& r0,
155  const TSequence& sequence) {
156  Multipole<N> moments(0._f);
157  for (Size i : sequence) {
158  const Vector dr = r[i] - r0;
159  moments += Detail::computeMultipoleImpl<N>(dr, m[i]);
160  }
161  return moments;
162 }
163 
165  const Float Q,
166  const Vector& d) {
167  using namespace MomentOperators;
168  return makeTracelessMultipole<1>(Qi + OuterProduct<1>{ d } * Q);
169 }
170 
172  const Float Q,
173  const Vector& d) {
174  using namespace MomentOperators;
175  const Multipole<2> d2 = makeMultipole<2>(OuterProduct<2>{ d });
177  return makeTracelessMultipole<2>(Qij + f2 * Q);
178 }
179 
180 namespace MomentOperators {
181 struct Term2 {
183  const Vector& d;
184 
185  template <Size I, Size J, Size K, Size L>
186  INLINE Float perm() const {
187  const Delta<2> delta;
188  return delta.value<I, J>() * Q.value<K, L>() + delta.value<I, K>() * Q.value<J, L>() +
189  delta.value<J, K>() * Q.value<I, L>();
190  }
191 
192  template <Size I, Size J, Size K>
193  INLINE Float value() const {
194  return -2._f / 5._f *
195  (perm<I, J, K, 0>() * d[0] + perm<I, J, K, 1>() * d[1] + perm<I, J, K, 2>() * d[2]);
196  }
197 };
198 
199 struct Term30 {
201  const Vector& d;
202 
203  template <Size I, Size J, Size K, Size L, Size M>
204  INLINE Float perm() const {
205  const Delta<2> delta;
206  return delta.value<I, J>() * Q.value<K, L, M>() + delta.value<I, K>() * Q.value<J, L, M>() +
207  delta.value<I, L>() * Q.value<J, K, M>() + delta.value<J, K>() * Q.value<I, L, M>() +
208  delta.value<J, L>() * Q.value<I, K, M>() + delta.value<K, L>() * Q.value<I, J, M>();
209  }
210 
211  template <Size I, Size J, Size K, Size L>
212  INLINE Float value() const {
213  return perm<I, J, K, L, 0>() * d[0] + perm<I, J, K, L, 1>() * d[1] + perm<I, J, K, L, 2>() * d[2];
214  }
215 };
216 
217 struct Term31 {
220 
221  const static Delta<2> delta1, delta2;
222 
223  template <Size I, Size J, Size K, Size L, Size M, Size N>
224  INLINE Float ddq() const {
225  return delta1.template value<I, J>() * delta2.template value<K, M>() * Q.template value<L, N>();
226  }
227 
228  template <Size I, Size J, Size K, Size L, Size M, Size N>
229  INLINE Float perm() const {
230 #if 0
231  return ddq<I, J, K, L, M, N>() + ddq<I, J, L, K, M, N>() + ddq<I, L, J, K, M, N>() +
232  ddq<I, L, K, J, M, N>() + ddq<I, K, J, L, M, N>() + ddq<I, K, L, J, M, N>() +
233  ddq<J, K, L, I, M, N>() + ddq<J, K, I, L, M, N>() + ddq<J, L, I, K, M, N>() +
234  ddq<J, L, K, I, M, N>() + ddq<K, L, I, J, M, N>() + ddq<K, L, J, I, M, N>();
235 #else
236  return ddq<I, J, K, L, M, N>() + ddq<I, L, J, K, M, N>() + ddq<I, K, J, L, M, N>() +
237  ddq<J, K, L, I, M, N>() + ddq<J, L, I, K, M, N>() + ddq<K, L, I, J, M, N>();
238 #endif
239  }
240 
241  template <Size I, Size J, Size K, Size L>
242  INLINE Float value() const {
243  return perm<I, J, K, L, 0, 0>() * f2.template value<0, 0>() +
244  perm<I, J, K, L, 0, 1>() * f2.template value<0, 1>() +
245  perm<I, J, K, L, 0, 2>() * f2.template value<0, 2>() +
246  perm<I, J, K, L, 1, 0>() * f2.template value<1, 0>() +
247  perm<I, J, K, L, 1, 1>() * f2.template value<1, 1>() +
248  perm<I, J, K, L, 1, 2>() * f2.template value<1, 2>() +
249  perm<I, J, K, L, 2, 0>() * f2.template value<2, 0>() +
250  perm<I, J, K, L, 2, 1>() * f2.template value<2, 1>() +
251  perm<I, J, K, L, 2, 2>() * f2.template value<2, 2>();
252  }
253 };
254 
255 struct Term32 {
258 
259  template <Size I, Size J, Size K, Size L>
260  INLINE Float value() const {
261  return makePermutations(Delta<2>{}, Delta<2>{}).template value<I, J, K, L>() *
262  makeInner<2>(Q, f2).value() * (-1._f / 5._f);
263  }
264 };
265 } // namespace MomentOperators
266 
268  const TracelessMultipole<2>& Qij,
269  const Float Q,
270  const Vector& d) {
271  using namespace MomentOperators;
272  const OuterProduct<1> d1{ d };
273  const Multipole<3> d3 = makeMultipole<3>(OuterProduct<3>{ d });
275  return makeTracelessMultipole<3>(Qijk + f3 * Q + makePermutations(Qij, d1) + Term2{ Qij, d });
276 }
277 
278 
280  const TracelessMultipole<3>& Qijk,
281  const TracelessMultipole<2>& Qij,
282  const Float Q,
283  const Vector& d) {
284  using namespace MomentOperators;
285  OuterProduct<1> d1{ d };
286  OuterProduct<2> d2{ d };
287  OuterProduct<4> d4{ d };
288  const TracelessMultipole<2> f2 = computeReducedMultipole(makeMultipole<2>(d2));
289  const TracelessMultipole<4> f4 = computeReducedMultipole(makeMultipole<4>(d4));
290 
291  return makeTracelessMultipole<4>(
292  Qijkl + f4 * Q + makePermutations(Qijk, d1) + makePermutations(Qij, f2) +
293  (Term30{ Qijk, d } + Term31{ Qij, f2 } + Term32{ Qij, f2 }) * (-2._f / 7._f));
294 }
295 
296 template <Size M, Size N>
299  const Vector& dr) {
300  const TracelessMultipole<M>& q = ms.template order<M>();
301  const Float Q0 = computeMultipolePotential<0>(q, dr).value();
302  const Vector Q1 = (N > 0) ? computeMultipolePotential<1>(q, dr).vector() : Vector(0._f);
303  const Vector a = gamma[M + 1] * dr * Q0 + gamma[M] * Q1;
304  SPH_ASSERT(isReal(a), dr, Q0, Q1, gamma);
305  return a;
306 }
307 
308 
309 enum class MultipoleOrder {
310  MONOPOLE = 0,
311  QUADRUPOLE = 2,
312  OCTUPOLE = 3,
313  HEXADECAPOLE = 4,
314 };
315 
316 template <Size N>
317 Vector evaluateGravity(const Vector& dr, const MultipoleExpansion<N>& ms, const MultipoleOrder maxOrder) {
319 #ifdef SPH_DEBUG
320  gamma.fill(NAN);
321 #endif
322  computeGreenGamma<N>(gamma, dr);
323 
324  Vector a(0._f);
325  switch (maxOrder) {
327  a += computeMultipoleAcceleration<3>(ms, gamma, -dr);
330  a += computeMultipoleAcceleration<2>(ms, gamma, -dr);
333  a += computeMultipoleAcceleration<0>(ms, gamma, -dr);
334  break;
335  default:
337  };
338 
339  SPH_ASSERT(isReal(a) && getSqrLength(a) > 0._f);
340  return a;
341 }
342 
343 
INLINE bool isReal(const AntisymmetricTensor &t)
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
#define NOT_IMPLEMENTED
Helper macro marking missing implementation.
Definition: Assert.h:100
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
uint32_t Size
Integral type used to index arrays (by default).
Definition: Globals.h:16
int32_t SignedSize
Signed integral type, used where negative numbers are necessary. Should match Size.
Definition: Globals.h:19
double Float
Precision used withing the code. Use Float instead of float or double where precision is important.
Definition: Globals.h:13
constexpr INLINE bool isOdd(const T &f)
Definition: MathBasic.h:40
INLINE T sqrt(const T f)
Return a squared root of a value.
Definition: MathUtils.h:78
std::enable_if_t<(M< N), TracelessMultipole< M > > computeMultipolePotential(const TracelessMultipole< N > &q, const Vector &r)
Definition: Moments.h:117
MultipoleOrder
Definition: Moments.h:309
Multipole< N > computeMultipole(ArrayView< const Vector > r, ArrayView< const Float > m, const Vector &r0, const TSequence &sequence)
Definition: Moments.h:152
INLINE TracelessMultipole< 1 > parallelAxisTheorem(const TracelessMultipole< 1 > &Qi, const Float Q, const Vector &d)
Definition: Moments.h:164
Multipole< N - 2 *M > computeTrace(const Multipole< N > &m)
Computes M-fold trace of given multipole moment.
Definition: Moments.h:40
INLINE Vector computeMultipoleAcceleration(const MultipoleExpansion< N > &ms, ArrayView< const Float > gamma, const Vector &dr)
Definition: Moments.h:297
TracelessMultipole< N > computeReducedMultipole(const Multipole< N > &m)
INLINE Float reducedFactor()
Definition: Moments.h:46
Vector evaluateGravity(const Vector &dr, const MultipoleExpansion< N > &ms, const MultipoleOrder maxOrder)
Definition: Moments.h:317
NAMESPACE_SPH_BEGIN INLINE void computeGreenGamma(ArrayView< Float > gamma, const Vector dr)
Definition: Moments.h:8
Multipole< N > makeMultipole(const TValue &v)
Definition: Multipole.h:256
constexpr Size doubleFactorial(const Size n)
Definition: Multipole.h:628
constexpr Size factorial(const Size n)
Definition: Multipole.h:620
#define INLINE
Macros for conditional compilation based on selected compiler.
Definition: Object.h:31
#define UNUSED(x)
Definition: Object.h:37
#define SPH_FALLTHROUGH
Definition: Object.h:44
#define NAMESPACE_SPH_END
Definition: Object.h:12
constexpr int N
INLINE Float getSqrLength(const Vector &v)
Definition: Vector.h:574
BasicVector< Float > Vector
Definition: Vector.h:539
Array with fixed number of allocated elements.
Definition: StaticArray.h:19
void fill(const T &value)
Assigns a value to all constructed elements of the array.
Definition: StaticArray.h:121
constexpr INLINE Float value() const
Definition: Multipole.h:323
INLINE Multipole< N > computeMultipoleImpl(const Vector &dr, const Float m)
Definition: Moments.h:141
Permutations< Value1::ORDER, Value2::ORDER, Value1, Value2 > makePermutations(const Value1 &v1, const Value2 &v2)
Definition: Multipole.h:742
Contraction< TValue > makeContraction(const TValue &v)
Definition: Multipole.h:759
SharedPtr< JobNode > make(const Id id, UniqueNameManager &nameMgr, const Size particleCnt=10000)
Creates a node tree for the preset with given ID.
Definition: Presets.cpp:39
static INLINE Multipole< N - 2 > make(const Multipole< N > &m)
Definition: Moments.h:23
static INLINE Multipole< N - 4 > make(const Multipole< N > &m)
Definition: Moments.h:32
static constexpr INLINE int value()
Definition: Multipole.h:645
INLINE Float value() const
Definition: Moments.h:193
const TracelessMultipole< 2 > & Q
Definition: Moments.h:182
const Vector & d
Definition: Moments.h:183
INLINE Float perm() const
Definition: Moments.h:186
const Vector & d
Definition: Moments.h:201
INLINE Float value() const
Definition: Moments.h:212
const TracelessMultipole< 3 > & Q
Definition: Moments.h:200
INLINE Float perm() const
Definition: Moments.h:204
INLINE Float perm() const
Definition: Moments.h:229
INLINE Float value() const
Definition: Moments.h:242
static const Delta< 2 > delta1
Definition: Moments.h:221
const TracelessMultipole< 2 > & Q
Definition: Moments.h:218
static const Delta< 2 > delta2
Definition: Moments.h:221
INLINE Float ddq() const
Definition: Moments.h:224
const TracelessMultipole< 2 > & f2
Definition: Moments.h:219
INLINE Float value() const
Definition: Moments.h:260
const TracelessMultipole< 2 > & f2
Definition: Moments.h:257
const TracelessMultipole< 2 > & Q
Definition: Moments.h:256