SPH
Multipole.h
Go to the documentation of this file.
1 #pragma once
2 
5 
7 
9 template <Size... Is>
10 constexpr auto sortIndices() {
11  constexpr Size N = sizeof...(Is);
12  ConstexprArray<Size, N> array{ Is... };
13 
14  for (Size i = 0; i < N - 1; i++) {
15  for (Size j = 0; j < N - i - 1; j++) {
16  if (array[j] > array[j + 1]) {
17  Size k = array[j];
18  array[j] = array[j + 1];
19  array[j + 1] = k;
20  }
21  }
22  }
23  return array;
24 }
25 
26 namespace Detail {
27 constexpr Size multipoleComponentCnt(Size order) {
28  return (order + 1) * (order + 2) / 2;
29 }
30 template <Size Last>
31 constexpr Size sum() {
32  return Last;
33 }
34 template <Size First, Size Second, Size... Idxs>
35 constexpr Size sum() {
36  return First + sum<Second, Idxs...>();
37 }
38 
39 template <Size... Idxs>
41 
42 template <Size Second, Size... Idxs>
43 struct MultipoleMappingImpl<X, Second, Idxs...> {
44  static constexpr Size value = MultipoleMappingImpl<Second, Idxs...>::value;
45 };
46 template <Size I>
48  static constexpr Size value = I;
49 };
50 template <Size Second, Size... Idxs>
51 struct MultipoleMappingImpl<Y, Second, Idxs...> {
52  static constexpr Size value =
53  multipoleComponentCnt(sizeof...(Idxs) + 1) - 1 - sizeof...(Idxs) + sum<Second, Idxs...>();
54 };
55 template <Size Second, Size... Idxs>
56 struct MultipoleMappingImpl<Z, Second, Idxs...> {
57  static constexpr Size value = multipoleComponentCnt(sizeof...(Idxs) + 2) - 1;
58 };
59 
60 template <std::size_t... Idxs, std::size_t... Is>
61 constexpr Size expandMultipoleArray(std::index_sequence<Is...>) {
62  constexpr ConstexprArray<Size, sizeof...(Idxs)> ar = sortIndices<Idxs...>();
63  return MultipoleMappingImpl<ar[Is]...>::value;
64 }
65 
66 template <Size... Idxs>
68  using Sequence = std::make_index_sequence<sizeof...(Idxs)>;
69 
70  static constexpr Size value = expandMultipoleArray<Idxs...>(Sequence{});
71 };
72 
73 template <Size I>
74 struct MultipoleMapping<I> {
75  static constexpr Size value = I;
76 };
77 template <>
78 struct MultipoleMapping<> {
79  static constexpr Size value = 0;
80 };
81 } // namespace Detail
82 
83 template <Size Order>
84 class Multipole {
85 private:
86  static constexpr Size COMPONENT_CNT = Detail::multipoleComponentCnt(Order);
87 
88  Float data[COMPONENT_CNT];
89 
90 public:
91  static constexpr Size ORDER = Order;
92 
93  Multipole() = default;
94 
95  Multipole(const Float f) {
96  for (Float& v : data) {
97  v = f;
98  }
99  }
100 
101  template <Size... Idxs>
102  INLINE Float value() const {
103  static_assert(sizeof...(Idxs) == Order, "Number of indices must match the order");
104  const Size idx = Detail::MultipoleMapping<Idxs...>::value;
105  SPH_ASSERT(idx < COMPONENT_CNT, idx);
106  return *(&data[0] + idx);
107  }
108 
109  template <Size... Idxs>
111  static_assert(sizeof...(Idxs) == Order, "Number of indices must match the order");
112  const Size idx = Detail::MultipoleMapping<Idxs...>::value;
113  SPH_ASSERT(idx < COMPONENT_CNT, idx);
114  return *(&data[0] + idx);
115  }
116 
117  INLINE Float operator[](const Size idx) const {
118  SPH_ASSERT(idx < COMPONENT_CNT, idx);
119  return data[idx];
120  }
121 
122  Multipole& operator+=(const Multipole& other) {
123  for (Size i = 0; i < COMPONENT_CNT; ++i) {
124  data[i] += other[i];
125  }
126  return *this;
127  }
128 
129  Multipole operator*(const Float f) const {
130  Multipole m;
131  for (Size i = 0; i < COMPONENT_CNT; ++i) {
132  m.data[i] = data[i] * f;
133  }
134  return m;
135  }
136 
137  bool operator==(const Multipole& other) const {
138  for (Size i = 0; i < COMPONENT_CNT; ++i) {
139  if (data[i] != other[i]) {
140  return false;
141  }
142  }
143  return true;
144  }
145 
146  friend std::ostream& operator<<(std::ostream& stream, const Multipole& m) {
147  for (Size i = 0; i < COMPONENT_CNT; ++i) {
148  stream << m.data[i] << " ";
149  }
150  return stream;
151  }
152 };
153 
154 template <Size N>
155 INLINE auto almostEqual(const Multipole<N>& f1, const Multipole<N>& f2, const Float& eps = EPS) {
156  for (Size i = 0; i < Detail::multipoleComponentCnt(N); ++i) {
157  if (!almostEqual(f1[i], f2[i], eps)) {
158  return false;
159  }
160  }
161  return true;
162 }
163 
164 
166 template <Size N>
168 
169 template <>
170 struct MakeMultipole<0> {
171  template <typename TValue>
172  static Multipole<0> make(const TValue& v) {
173  Multipole<0> m;
174  m.value() = v.value();
175  return m;
176  }
177 };
178 
179 template <>
180 struct MakeMultipole<1> {
181  template <typename TValue>
182  static Multipole<1> make(const TValue& v) {
183  Multipole<1> m;
184  m.value<X>() = v.template value<X>();
185  m.value<Y>() = v.template value<Y>();
186  m.value<Z>() = v.template value<Z>();
187  return m;
188  }
189 };
190 
191 template <>
192 struct MakeMultipole<2> {
193  template <typename TValue>
194  static Multipole<2> make(const TValue& v) {
195  Multipole<2> m;
196  m.value<X, X>() = v.template value<X, X>();
197  m.value<X, Y>() = v.template value<X, Y>();
198  m.value<X, Z>() = v.template value<X, Z>();
199 
200  m.value<Y, Y>() = v.template value<Y, Y>();
201  m.value<Y, Z>() = v.template value<Y, Z>();
202 
203  m.value<Z, Z>() = v.template value<Z, Z>();
204  return m;
205  }
206 };
207 
208 template <>
209 struct MakeMultipole<3> {
210  template <typename TValue>
211  static Multipole<3> make(const TValue& v) {
212  Multipole<3> m;
213  m.value<X, X, X>() = v.template value<X, X, X>();
214  m.value<X, X, Y>() = v.template value<X, X, Y>();
215  m.value<X, X, Z>() = v.template value<X, X, Z>();
216  m.value<X, Y, Y>() = v.template value<X, Y, Y>();
217  m.value<X, Y, Z>() = v.template value<X, Y, Z>();
218  m.value<X, Z, Z>() = v.template value<X, Z, Z>();
219 
220  m.value<Y, Y, Y>() = v.template value<Y, Y, Y>();
221  m.value<Y, Y, Z>() = v.template value<Y, Y, Z>();
222  m.value<Y, Z, Z>() = v.template value<Y, Z, Z>();
223 
224  m.value<Z, Z, Z>() = v.template value<Z, Z, Z>();
225  return m;
226  }
227 };
228 
229 template <>
230 struct MakeMultipole<4> {
231  template <typename TValue>
232  static Multipole<4> make(const TValue& v) {
233  Multipole<4> m;
234  m.value<X, X, X, X>() = v.template value<X, X, X, X>();
235  m.value<X, X, X, Y>() = v.template value<X, X, X, Y>();
236  m.value<X, X, X, Z>() = v.template value<X, X, X, Z>();
237  m.value<X, X, Y, Y>() = v.template value<X, X, Y, Y>();
238  m.value<X, X, Y, Z>() = v.template value<X, X, Y, Z>();
239  m.value<X, X, Z, Z>() = v.template value<X, X, Z, Z>();
240  m.value<X, Y, Y, Y>() = v.template value<X, Y, Y, Y>();
241  m.value<X, Y, Y, Z>() = v.template value<X, Y, Y, Z>();
242  m.value<X, Y, Z, Z>() = v.template value<X, Y, Z, Z>();
243  m.value<X, Z, Z, Z>() = v.template value<X, Z, Z, Z>();
244 
245  m.value<Y, Y, Y, Y>() = v.template value<Y, Y, Y, Y>();
246  m.value<Y, Y, Y, Z>() = v.template value<Y, Y, Y, Z>();
247  m.value<Y, Y, Z, Z>() = v.template value<Y, Y, Z, Z>();
248  m.value<Y, Z, Z, Z>() = v.template value<Y, Z, Z, Z>();
249 
250  m.value<Z, Z, Z, Z>() = v.template value<Z, Z, Z, Z>();
251  return m;
252  }
253 };
254 
255 template <Size N, typename TValue>
256 Multipole<N> makeMultipole(const TValue& v) {
257  return MakeMultipole<N>::make(v);
258 }
259 
260 
261 namespace Detail {
263  return 2 * order + 1;
264 }
265 
266 template <Size... Idxs>
268 
269 template <Size Second, Size... Idxs>
270 struct TracelessMultipoleMappingImpl<X, Second, Idxs...> {
271  static constexpr Size value = TracelessMultipoleMappingImpl<Second, Idxs...>::value;
272 };
273 template <Size Second, Size... Idxs>
274 struct TracelessMultipoleMappingImpl<Y, Second, Idxs...> {
275  static constexpr Size value =
276  tracelessMultipoleComponentCnt(sizeof...(Idxs) + 1) - 1 - sizeof...(Idxs) + sum<Second, Idxs...>();
277 };
278 template <Size I>
280  static constexpr Size value = I;
281 };
282 
283 template <std::size_t... Idxs, std::size_t... Is>
284 constexpr Size expandTracelessMultipoleArray(std::index_sequence<Is...>) {
285  constexpr ConstexprArray<Size, sizeof...(Idxs)> ar = sortIndices<Idxs...>();
286  return TracelessMultipoleMappingImpl<ar[Is]...>::value;
287 }
288 
289 template <Size... Idxs>
291  using Sequence = std::make_index_sequence<sizeof...(Idxs)>;
292 
293  static constexpr Size value = expandTracelessMultipoleArray<Idxs...>(Sequence{});
294 };
295 template <Size I>
297  static constexpr Size value = I;
298 };
299 } // namespace Detail
300 
301 template <Size... Idxs>
303 
304 template <Size Order>
306 private:
307  static constexpr Size COMPONENT_CNT = Detail::tracelessMultipoleComponentCnt(Order);
308 
309  Float data[COMPONENT_CNT];
310 
311 public:
312  static constexpr Size ORDER = Order;
313 
314  constexpr TracelessMultipole() = default;
315 
316  constexpr TracelessMultipole(const Float f) {
317  for (Float& v : data) {
318  v = f;
319  }
320  }
321 
322  template <Size... Idxs>
323  INLINE constexpr Float value() const {
324  return TracelessMultipoleComponent<Idxs...>{}.get(*this);
325  }
326 
327  template <Size... Idxs>
329  static_assert(sizeof...(Idxs) == Order, "Number of indices must match the order");
330  const Size idx = Detail::TracelessMultipoleMapping<Idxs...>::value;
331  SPH_ASSERT(idx < COMPONENT_CNT, idx);
332  return *(&data[0] + idx);
333  }
334 
335  template <Size... Idxs>
336  INLINE constexpr Float valueImpl() const {
337  static_assert(sizeof...(Idxs) == Order, "Number of indices must match the order");
338  const Size idx = Detail::TracelessMultipoleMapping<Idxs...>::value;
339  SPH_ASSERT(idx < COMPONENT_CNT, idx, Idxs...);
340  return *(&data[0] + idx);
341  }
342 
343  INLINE constexpr Float operator[](const Size idx) const {
344  SPH_ASSERT(idx < COMPONENT_CNT, idx);
345  return data[idx];
346  }
347 
348  INLINE Float& operator[](const Size idx) {
349  SPH_ASSERT(idx < COMPONENT_CNT, idx);
350  return data[idx];
351  }
352 
353  INLINE constexpr Size size() const {
354  return COMPONENT_CNT;
355  }
356 
358  for (Size i = 0; i < COMPONENT_CNT; ++i) {
359  data[i] += other.data[i];
360  }
361  return *this;
362  }
363 
364  bool operator==(const TracelessMultipole& other) const {
365  for (Size i = 0; i < COMPONENT_CNT; ++i) {
366  if (data[i] != other.data[i]) {
367  return false;
368  }
369  }
370  return true;
371  }
372 
373  friend std::ostream& operator<<(std::ostream& stream, const TracelessMultipole& m) {
374  for (Size i = 0; i < COMPONENT_CNT; ++i) {
375  stream << m.data[i] << " ";
376  }
377  return stream;
378  }
379 };
380 
381 template <>
383 private:
384  Vector data;
385 
386 public:
388 
390  : data(v) {}
391 
392  static constexpr Size ORDER = 1;
393 
394  template <Size Idx>
396  return data[Idx];
397  }
398 
399  template <Size Idx>
400  INLINE Float value() const {
401  return data[Idx];
402  }
403 
404  INLINE Float operator[](const Size idx) const {
405  SPH_ASSERT(idx < 3, idx);
406  return data[idx];
407  }
408 
409  INLINE Float& operator[](const Size idx) {
410  SPH_ASSERT(idx < 3, idx);
411  return data[idx];
412  }
413 
414  INLINE constexpr Size size() const {
415  return 3;
416  }
417 
418  Vector vector() const {
419  return data;
420  }
421 
423  data += other.data;
424  return *this;
425  }
426 
427  bool operator==(const TracelessMultipole& other) const {
428  return data == other.data;
429  }
430 
431  friend std::ostream& operator<<(std::ostream& stream, const TracelessMultipole& m) {
432  stream << m.data;
433  return stream;
434  }
435 };
436 
437 
438 template <>
440 private:
441  Float data;
442 
443 public:
444  TracelessMultipole() = default;
445 
446  constexpr INLINE TracelessMultipole(const Float v)
447  : data(v) {}
448 
449  static constexpr Size ORDER = 0;
450 
451  INLINE constexpr Float& value() {
452  return data;
453  }
454 
455  INLINE constexpr Float value() const {
456  return data;
457  }
458 
459  INLINE Float operator[](const Size idx) const {
460  SPH_ASSERT(idx == 0);
461  return data;
462  }
463 
464  INLINE constexpr Size size() const {
465  return 1;
466  }
467 
468  INLINE constexpr operator Float() const {
469  return data;
470  }
471 
473  data += other.data;
474  return *this;
475  }
476 
477  constexpr bool operator==(const TracelessMultipole& other) const {
478  return data == other.data;
479  }
480 };
481 
482 
483 template <Size N>
485  const TracelessMultipole<N>& f2,
486  const Float& eps = EPS) {
487  for (Size i = 0; i < Detail::tracelessMultipoleComponentCnt(N); ++i) {
488  if (!almostEqual(f1[i], f2[i], eps)) {
489  return false;
490  }
491  }
492  return true;
493 }
494 
496 
497 template <Size N>
499 
500 template <>
502  template <typename TValue>
503  static TracelessMultipole<0> make(const TValue& v) {
505  m.value() = v.value();
506  return m;
507  }
508 };
509 
510 template <>
512  template <typename TValue>
513  static TracelessMultipole<1> make(const TValue& v) {
515  m.value<X>() = v.template value<X>();
516  m.value<Y>() = v.template value<Y>();
517  m.value<Z>() = v.template value<Z>();
518  return m;
519  }
520 };
521 
522 template <>
524  template <typename TValue>
525  static TracelessMultipole<2> make(const TValue& v) {
527  m.value<X, X>() = v.template value<X, X>();
528  m.value<X, Y>() = v.template value<X, Y>();
529  m.value<X, Z>() = v.template value<X, Z>();
530 
531  m.value<Y, Y>() = v.template value<Y, Y>();
532  m.value<Y, Z>() = v.template value<Y, Z>();
533  return m;
534  }
535 };
536 
537 template <>
539  template <typename TValue>
540  static TracelessMultipole<3> make(const TValue& v) {
542  m.value<X, X, X>() = v.template value<X, X, X>();
543  m.value<X, X, Y>() = v.template value<X, X, Y>();
544  m.value<X, X, Z>() = v.template value<X, X, Z>();
545  m.value<X, Y, Y>() = v.template value<X, Y, Y>();
546  m.value<X, Y, Z>() = v.template value<X, Y, Z>();
547 
548  m.value<Y, Y, Y>() = v.template value<Y, Y, Y>();
549  m.value<Y, Y, Z>() = v.template value<Y, Y, Z>();
550  return m;
551  }
552 };
553 
554 template <>
556  template <typename TValue>
557  static TracelessMultipole<4> make(const TValue& v) {
559  m.value<X, X, X, X>() = v.template value<X, X, X, X>();
560  m.value<X, X, X, Y>() = v.template value<X, X, X, Y>();
561  m.value<X, X, X, Z>() = v.template value<X, X, X, Z>();
562  m.value<X, X, Y, Y>() = v.template value<X, X, Y, Y>();
563  m.value<X, X, Y, Z>() = v.template value<X, X, Y, Z>();
564  m.value<X, Y, Y, Y>() = v.template value<X, Y, Y, Y>();
565  m.value<X, Y, Y, Z>() = v.template value<X, Y, Y, Z>();
566 
567  m.value<Y, Y, Y, Y>() = v.template value<Y, Y, Y, Y>();
568  m.value<Y, Y, Y, Z>() = v.template value<Y, Y, Y, Z>();
569  return m;
570  }
571 };
572 
573 template <Size N, typename TValue>
576 }
577 template <Size... Idxs>
579  INLINE static Float get(const TracelessMultipole<sizeof...(Idxs)>& m) {
580  return m.template valueImpl<Idxs...>();
581  }
582 };
583 template <std::size_t... Idxs, std::size_t... Is>
584 constexpr Float expandTracelessMultipoleComponent(const TracelessMultipole<sizeof...(Idxs)>& m,
585  std::index_sequence<Is...>) {
586  constexpr ConstexprArray<Size, sizeof...(Idxs)> ar = sortIndices<Idxs...>();
588 }
589 
590 // computes component from traceless multipole
591 template <Size... Idxs>
593  using Sequence = std::make_index_sequence<sizeof...(Idxs)>;
594 
595  INLINE static constexpr Float get(const TracelessMultipole<sizeof...(Idxs)>& m) {
596  return expandTracelessMultipoleComponent<Idxs...>(m, Sequence{});
597  }
598 };
599 
600 template <>
602  INLINE static constexpr Float get(const TracelessMultipole<2>& m) {
603  return -m.valueImpl<X, X>() - m.valueImpl<Y, Y>();
604  }
605 };
606 template <Size I>
608  INLINE static constexpr Float get(const TracelessMultipole<3>& m) {
609  return -m.valueImpl<X, X, I>() - m.valueImpl<Y, Y, I>();
610  }
611 };
612 template <Size I, Size J>
614  INLINE static constexpr Float get(const TracelessMultipole<4>& m) {
615  return -m.valueImpl<X, X, I, J>() - m.valueImpl<Y, Y, I, J>();
616  }
617 };
618 
619 
620 inline constexpr Size factorial(const Size n) {
621  return n <= 1 ? 1 : n * factorial(n - 1);
622 }
623 static_assert(factorial(1) == 1, "static test failed");
624 static_assert(factorial(2) == 2, "static test failed");
625 static_assert(factorial(3) == 6, "static test failed");
626 static_assert(factorial(4) == 24, "static test failed");
627 
628 inline constexpr Size doubleFactorial(const Size n) {
629  return n <= 1 ? 1 : n * doubleFactorial(n - 2);
630 }
631 static_assert(doubleFactorial(1) == 1, "static test failed");
632 static_assert(doubleFactorial(2) == 2, "static test failed");
633 static_assert(doubleFactorial(3) == 3, "static test failed");
634 static_assert(doubleFactorial(4) == 8, "static test failed");
635 static_assert(doubleFactorial(5) == 15, "static test failed");
636 
637 
638 namespace MomentOperators {
639 
640 template <Size Order>
641 struct Delta {
642  static constexpr Size ORDER = Order;
643 
644  template <Size I, Size J, Size K, Size L, Size... Rest>
645  INLINE static constexpr int value() {
646  static_assert(sizeof...(Rest) + 4 == Order, "Invalid number of indices");
647  return ((I == J) ? 1 : 0) * Delta<Order - 2>::template value<K, L, Rest...>();
648  }
649  template <Size I, Size J>
650  INLINE static constexpr int value() {
651  static_assert(Order == 2, "Invalid number of indices");
652  return ((I == J) ? 1 : 0);
653  }
654 };
655 
656 
657 template <Size N1, Size N2, typename Value1, typename Value2>
659 
660 template <Size N, typename Value1, typename Value2>
661 struct Permutations<N, 0, Value1, Value2> {
662  const Value1& v1;
663  const Value2& v2;
664  static constexpr Size ORDER = N;
665 
666  template <Size... Is>
667  INLINE constexpr Float value() const {
668  static_assert(sizeof...(Is) == N, "Invalid number of indices");
669  return v1.template value<Is...>() * v2.value();
670  }
671 };
672 template <Size N, typename Value1, typename Value2>
673 struct Permutations<0, N, Value1, Value2> {
674  const Value1& v1;
675  const Value2& v2;
676  static constexpr Size ORDER = N;
677 
678  template <Size... Is>
679  INLINE constexpr Float value() const {
680  static_assert(sizeof...(Is) == N, "Invalid number of indices");
681  return v1.value() * v2.template value<Is...>();
682  }
683 };
684 template <typename Value1, typename Value2>
685 struct Permutations<2, 2, Value1, Value2> {
686  const Value1& v1;
687  const Value2& v2;
688  static constexpr Size ORDER = 4;
689 
690  template <Size I, Size J, Size K, Size L>
691  INLINE constexpr Float value() const {
692  return v1.template value<I, J>() * v2.template value<K, L>() +
693  v1.template value<I, K>() * v2.template value<J, L>() +
694  v1.template value<I, L>() * v2.template value<J, K>() +
695  v1.template value<J, K>() * v2.template value<I, L>() +
696  v1.template value<J, L>() * v2.template value<I, K>() +
697  v1.template value<K, L>() * v2.template value<I, J>();
698  }
699 };
700 template <typename Value1, typename Value2>
701 struct Permutations<3, 1, Value1, Value2> {
702  const Value1& v1;
703  const Value2& v2;
704  static constexpr Size ORDER = 4;
705 
706  template <Size I, Size J, Size K, Size L>
707  INLINE constexpr Float value() const {
708  return v1.template value<I, J, K>() * v2.template value<L>() +
709  v1.template value<I, J, L>() * v2.template value<K>() +
710  v1.template value<I, K, L>() * v2.template value<J>() +
711  v1.template value<J, K, L>() * v2.template value<I>();
712  }
713 };
714 template <typename Value1, typename Value2>
715 struct Permutations<2, 1, Value1, Value2> {
716  const Value1& v1;
717  const Value2& v2;
718  static constexpr Size ORDER = 3;
719 
720  template <Size I, Size J, Size K>
721  INLINE constexpr Float value() const {
722  return v1.template value<I, J>() * v2.template value<K>() +
723  v1.template value<J, K>() * v2.template value<I>() +
724  v1.template value<K, I>() * v2.template value<J>();
725  }
726 };
727 template <typename Value1, typename Value2>
728 struct Permutations<1, 2, Value1, Value2> {
729  const Value1& v1;
730  const Value2& v2;
731  static constexpr Size ORDER = 3;
732 
733  template <Size I, Size J, Size K>
734  INLINE constexpr Float value() const {
735  return v1.template value<I>() * v2.template value<J, K>() +
736  v1.template value<J>() * v2.template value<K, I>() +
737  v1.template value<K>() * v2.template value<I, J>();
738  }
739 };
740 
741 template <typename Value1, typename Value2>
743  const Value2& v2) {
745 }
746 
747 template <typename TValue>
748 struct Contraction {
749  const TValue& v;
750 
751  template <Size... Is>
752  INLINE constexpr Float value() const {
753  return v.template value<0, 0, Is...>() + v.template value<1, 1, Is...>() +
754  v.template value<2, 2, Is...>();
755  }
756 };
757 
758 template <typename TValue>
760  return Contraction<TValue>{ v };
761 }
762 
763 template <Size N, Size O1, typename TValue1, typename TValue2>
765 
766 template <typename TValue1, typename TValue2>
767 struct InnerProduct<1, 2, TValue1, TValue2> {
768  const TValue1& v1;
769  const TValue2& v2;
770 
771  template <Size I, Size... Is>
772  INLINE constexpr Float value() const {
773  static_assert(TValue1::ORDER == 2, "Invalid number of indices");
774  static_assert(TValue2::ORDER == sizeof...(Is) + 1, "Invalid number of indices");
775  return v1.template value<0, I>() * v2.template value<0, Is...>() +
776  v1.template value<1, I>() * v2.template value<1, Is...>() +
777  v1.template value<2, I>() * v2.template value<2, Is...>();
778  }
779 };
780 template <typename TValue1, typename TValue2>
781 struct InnerProduct<1, 1, TValue1, TValue2> {
782  const TValue1& v1;
783  const TValue2& v2;
784 
785  template <Size... Is>
786  INLINE constexpr Float value() const {
787  static_assert(TValue1::ORDER == 1, "Invalid number of indices");
788  static_assert(TValue2::ORDER == sizeof...(Is) + 1, "Invalid number of indices");
789  return v1.template value<0>() * v2.template value<0, Is...>() +
790  v1.template value<1>() * v2.template value<1, Is...>() +
791  v1.template value<2>() * v2.template value<2, Is...>();
792  }
793 };
794 
795 template <typename TValue1, typename TValue2>
796 struct InnerProduct<2, 2, TValue1, TValue2> {
797  const TValue1& v1;
798  const TValue2& v2;
799 
800  template <Size... Is>
801  INLINE constexpr Float value() const {
802  static_assert(TValue1::ORDER == 2, "Invalid number of indices");
803  static_assert(TValue2::ORDER == sizeof...(Is) + 2, "Invalid number of indices");
804  return v1.template value<0, 0>() * v2.template value<0, 0, Is...>() +
805  v1.template value<0, 1>() * v2.template value<0, 1, Is...>() +
806  v1.template value<0, 2>() * v2.template value<0, 2, Is...>() +
807  v1.template value<1, 0>() * v2.template value<1, 0, Is...>() +
808  v1.template value<1, 1>() * v2.template value<1, 1, Is...>() +
809  v1.template value<1, 2>() * v2.template value<1, 2, Is...>() +
810  v1.template value<2, 0>() * v2.template value<2, 0, Is...>() +
811  v1.template value<2, 1>() * v2.template value<2, 1, Is...>() +
812  v1.template value<2, 2>() * v2.template value<2, 2, Is...>();
813  }
814 };
815 
816 template <typename TValue1, typename TValue2>
817 struct InnerProduct<3, 3, TValue1, TValue2> {
818  const TValue1& v1;
819  const TValue2& v2;
820 
821  template <Size... Is>
822  INLINE constexpr Float value() const {
823  static_assert(TValue1::ORDER == 3, "Invalid number of indices");
824  static_assert(TValue2::ORDER == sizeof...(Is) + 3, "Invalid number of indices");
825  return v1.template value<0, 0, 0>() * v2.template value<0, 0, 0, Is...>() +
826  v1.template value<0, 0, 1>() * v2.template value<0, 0, 1, Is...>() +
827  v1.template value<0, 0, 2>() * v2.template value<0, 0, 2, Is...>() +
828  v1.template value<0, 1, 0>() * v2.template value<0, 1, 0, Is...>() +
829  v1.template value<0, 1, 1>() * v2.template value<0, 1, 1, Is...>() +
830  v1.template value<0, 1, 2>() * v2.template value<0, 1, 2, Is...>() +
831  v1.template value<0, 2, 0>() * v2.template value<0, 2, 0, Is...>() +
832  v1.template value<0, 2, 1>() * v2.template value<0, 2, 1, Is...>() +
833  v1.template value<0, 2, 2>() * v2.template value<0, 2, 2, Is...>() +
834  v1.template value<1, 0, 0>() * v2.template value<1, 0, 0, Is...>() +
835  v1.template value<1, 0, 1>() * v2.template value<1, 0, 1, Is...>() +
836  v1.template value<1, 0, 2>() * v2.template value<1, 0, 2, Is...>() +
837  v1.template value<1, 1, 0>() * v2.template value<1, 1, 0, Is...>() +
838  v1.template value<1, 1, 1>() * v2.template value<1, 1, 1, Is...>() +
839  v1.template value<1, 1, 2>() * v2.template value<1, 1, 2, Is...>() +
840  v1.template value<1, 2, 0>() * v2.template value<1, 2, 0, Is...>() +
841  v1.template value<1, 2, 1>() * v2.template value<1, 2, 1, Is...>() +
842  v1.template value<1, 2, 2>() * v2.template value<1, 2, 2, Is...>() +
843  v1.template value<2, 0, 0>() * v2.template value<2, 0, 0, Is...>() +
844  v1.template value<2, 0, 1>() * v2.template value<2, 0, 1, Is...>() +
845  v1.template value<2, 0, 2>() * v2.template value<2, 0, 2, Is...>() +
846  v1.template value<2, 1, 0>() * v2.template value<2, 1, 0, Is...>() +
847  v1.template value<2, 1, 1>() * v2.template value<2, 1, 1, Is...>() +
848  v1.template value<2, 1, 2>() * v2.template value<2, 1, 2, Is...>() +
849  v1.template value<2, 2, 0>() * v2.template value<2, 2, 0, Is...>() +
850  v1.template value<2, 2, 1>() * v2.template value<2, 2, 1, Is...>() +
851  v1.template value<2, 2, 2>() * v2.template value<2, 2, 2, Is...>();
852  }
853 };
854 
855 template <Size N, typename TValue1, typename TValue2>
856 InnerProduct<N, TValue1::ORDER, TValue1, TValue2> makeInner(const TValue1& v1, const TValue2& v2) {
858 }
859 
860 
861 template <typename TValue>
863  const TValue& v;
864  const Float f;
865 
866  template <Size... Is>
867  INLINE constexpr Float value() const {
868  return f * v.template value<Is...>();
869  }
870 };
871 
872 template <Size O1, typename TValue1, typename TValue2>
873 struct MultiplyTwo;
874 
875 template <typename TValue1, typename TValue2>
876 struct MultiplyTwo<1, TValue1, TValue2> {
877  const TValue1& v1;
878  const TValue2& v2;
879 
880  template <Size I, Size... Is>
881  INLINE constexpr Float value() const {
882  static_assert(TValue1::ORDER == 1 && TValue2::ORDER == sizeof...(Is), "Invalid number of indices");
883  return v1.template value<I>() * v2.template value<Is...>();
884  }
885 };
886 
887 template <typename TValue1, typename TValue2>
888 struct MultiplyTwo<2, TValue1, TValue2> {
889  const TValue1& v1;
890  const TValue2& v2;
891 
892  template <Size I, Size J, Size... Is>
893  INLINE constexpr Float value() const {
894  static_assert(TValue1::ORDER == 2 && TValue2::ORDER == sizeof...(Is), "Invalid number of indices");
895  return v1.template value<I, J>() * v2.template value<Is...>();
896  }
897 };
898 
899 template <typename TValue1, typename TValue2>
900 struct MultiplyTwo<4, TValue1, TValue2> {
901  const TValue1& v1;
902  const TValue2& v2;
903 
904  template <Size I, Size J, Size K, Size L, Size... Is>
905  INLINE constexpr Float value() const {
906  static_assert(TValue1::ORDER == 4 && TValue2::ORDER == sizeof...(Is), "Invalid number of indices");
907  return v1.template value<I, J, K, L>() * v2.template value<Is...>();
908  }
909 };
910 
911 template <typename TValue>
912 MultiplyByScalar<TValue> operator*(const TValue& v, const Float f) {
913  return MultiplyByScalar<TValue>{ v, f };
914 }
915 
916 template <typename TValue1, typename TValue2>
917 MultiplyTwo<TValue1::ORDER, TValue1, TValue2> makeMultiply(const TValue1& v1, const TValue2& v2) {
919 }
920 
921 template <typename TValue1, typename TValue2>
922 struct Sum {
923  const TValue1& v1;
924  const TValue2& v2;
925 
926  template <Size... Is>
927  INLINE constexpr Float value() const {
928  return v1.template value<Is...>() + v2.template value<Is...>();
929  }
930 };
931 
932 template <typename TValue1, typename TValue2>
933 Sum<TValue1, TValue2> operator+(const TValue1& v1, const TValue2& v2) {
934  return Sum<TValue1, TValue2>{ v1, v2 };
935 }
936 
937 template <typename TValue1, typename TValue2>
938 struct Difference {
939  const TValue1& v1;
940  const TValue2& v2;
941 
942  template <Size... Is>
943  INLINE constexpr Float value() const {
944  return v1.template value<Is...>() - v2.template value<Is...>();
945  }
946 };
947 
948 template <typename TValue1, typename TValue2>
949 Difference<TValue1, TValue2> operator-(const TValue1& v1, const TValue2& v2) {
950  return Difference<TValue1, TValue2>{ v1, v2 };
951 }
952 
953 template <Size Order>
954 struct OuterProduct {
955  static constexpr Size ORDER = Order;
956 
957  const Vector& v;
958 
959  template <Size I, Size J, Size... Is>
960  INLINE constexpr Float value() const {
961  static_assert(sizeof...(Is) + 2 == Order, "Invalid number of indices");
962  return v[I] * OuterProduct<Order - 1>{ v }.template value<J, Is...>();
963  }
964 
965  template <Size I>
966  INLINE constexpr Float value() const {
967  static_assert(Order == 1, "Invalid number of indices");
968  return v[I];
969  }
970 };
971 } // namespace MomentOperators
972 
973 template <Size N>
977 
978  template <Size M>
979  INLINE std::enable_if_t<M != N, TracelessMultipole<M>&> order() {
980  return lower.template order<M>();
981  }
982  template <Size M>
983  INLINE std::enable_if_t<M != N, const TracelessMultipole<M>&> order() const {
984  return lower.template order<M>();
985  }
986  template <Size M>
987  INLINE std::enable_if_t<M == N, TracelessMultipole<M>&> order() {
988  return Qn;
989  }
990  template <Size M>
991  INLINE std::enable_if_t<M == N, const TracelessMultipole<M>&> order() const {
992  return Qn;
993  }
994  MultipoleExpansion multiply(const Float factor) const {
995  MultipoleExpansion m = *this;
996  m.lower = lower.multiply(factor);
997  for (Size i = 0; i < Qn.size(); ++i) {
998  m.Qn[i] *= factor;
999  }
1000  return m;
1001  }
1002 };
1003 
1004 template <>
1007 
1008  template <Size M>
1010  static_assert(M == 0, "Invalid index");
1011  return Qn;
1012  }
1013 
1014  template <Size M>
1016  static_assert(M == 0, "Invalid index");
1017  return Qn;
1018  }
1019  MultipoleExpansion multiply(const Float factor) const {
1020  MultipoleExpansion m = *this;
1021  m.Qn.value() *= factor;
1022  return m;
1023  }
1024 };
1025 
1026 
1027 /*template <Size M, Size N>
1028 INLINE const TracelessMultipole<M>& getOrder(const MultipoleExpansion<N>& ms) {
1029  return getOrder<M>(ms.lower);
1030 }
1031 template <Size M, Size N>
1032 INLINE TracelessMultipole<M>& getOrder(MultipoleExpansion<N>& ms) {
1033  return getOrder<M>(ms.lower);
1034 }
1035 template <Size M>
1036 INLINE const TracelessMultipole<M>& getOrder(const MultipoleExpansion<M>& ms) {
1037  return ms.Qn;
1038 }
1039 template <Size M>
1040 INLINE TracelessMultipole<M>& getOrder(MultipoleExpansion<M>& ms) {
1041  return ms.Qn;
1042 }*/
1043 /*
1044 template <>
1045 class Multipole<3> {
1046 private:
1047  Vector data[3];
1048 
1049 
1050  Float components[COMPONENT_CNT];
1051 
1052 public:
1053  Multipole() = default;
1054 
1055  Multipole(const Multipole& other) = default;
1056 
1057  Multipole(const Float value) {
1058  for (Size i = 0; i < COMPONENT_CNT; ++i) {
1059  components[i] = value;
1060  }
1061  }
1062 
1063  template <typename... TArgs>
1064  INLINE Float& value()(const Size idx, const TArgs... rest) {
1065  static_assert(sizeof...(T1Args) == Order - 1, "Number of indices must be equal to multipole
1066 order");
1067  SPH_ASSERT(min(rest...) >= idx);
1068  switch (idx) {
1069  case Z:
1070  // other components must be all Zs
1071  return components[COMPONENT_CNT - 1];
1072  }
1073  }
1074 
1076  INLINE Multipole operator*(const Float f) const {
1077  return Multipole(data[0] * f, data[1] * f, data[2] * f);
1078  }
1079 
1081  INLINE Multipole<Order - 1> operator*(const Vector& v) {
1082  return v[0] * data[0] + v[1] * data[1] + v[2] * data[2];
1083  }
1084 
1085  template <typename... TArgs>
1086  INLINE Float apply(const Vector& v1, const TArgs&... rest) {
1087  static_assert(sizeof...(TArgs) == Order - 1, "Number of vectors must be equal to multipole
1088 order");
1089  return (*this * v1).apply(rest...);
1090  }
1091 
1092  INLINE Multipole operator+(const Multipole& other) {
1093  return Multipole(data[0] + other.data[0], data[1] + other.data[1], data[2] + other.data[2]);
1094  }
1095 
1096  INLINE Multipole& operator+=(const Multipole& other) {
1097  data[0] += other.data[0];
1098  data[1] += other.data[1];
1099  data[2] += other.data[2];
1100  return *this;
1101  }
1102 
1103  bool operator==(const Multipole& other) const {
1104  return data[0] == other.data[0] && data[1] == other.data[1] && data[2] == other.data[2];
1105  }
1106 
1107  friend std::ostream& operator<<(std::ostream& stream, const Multipole& t) {
1108  stream << t.data[0] << std::endl;
1109  stream << t.data[1] << std::endl;
1110  stream << t.data[2] << std::endl << std::endl;
1111  return stream;
1112  }
1113 };
1114 */
1115 
1116 /*
1117 template <>
1118 class Multipole<0> {
1119 private:
1120  Float data;
1121 
1122 public:
1123  Multipole() = default;
1124 
1125  Multipole(const Multipole& other) = default;
1126 
1127  Multipole(const Float& v)
1128  : data(v) {}
1129 
1130  INLINE Float& value() {
1131  return data;
1132  }
1133 
1134  INLINE const Float& value() const {
1135  return data;
1136  }
1137 
1138  INLINE Multipole operator*(const Float f) const ,1{
1139  return data * f;
1140  }
1141 
1142  INLINE Multipole operator+(const Multipole& other) {
1143  return data + other.data;
1144  }
1145 
1146  INLINE Multipole& operator+=(const Multipole& other) {
1147  data += other.data;
1148  return *this;
1149  }
1150 
1151  INLINE bool operator==(const Multipole& other) const {
1152  return data == other.data;
1153  }
1154 
1155  friend std::ostream& operator<<(std::ostream& stream, const Multipole& t) {
1156  stream << t.data;
1157  return stream;
1158  }
1159 };
1160 
1162 template <>
1163 class Multipole<1> {
1164 private:
1165  Vector data;
1166 
1167 public:
1168  Multipole() = default;
1169 
1170  Multipole(const Multipole& other) = default;
1171 
1172  Multipole(const Vector& v)
1173  : data(v) {}
1174 
1175  Multipole(const Float m1, const Float m2, const Float m3)
1176  : data{ m1, m2, m3 } {}
1177 
1178  Multipole(const Float value)
1179  : data{ value, value, value } {}
1180 
1181  INLINE Multipole<0>& operator[](const Size idx) {
1182  SPH_ASSERT(unsigned(idx) < 3);
1183  return (Multipole<0>&)data[idx];
1184  }
1185 
1186  INLINE Vector& value() {
1187  return data;
1188  }
1189 
1190  INLINE const Vector& value() const {
1191  return data;
1192  }
1193 
1194  INLINE Multipole<0> operator[](const Size idx) const {
1195  SPH_ASSERT(unsigned(idx) < 3);
1196  return data[idx];
1197  }
1198 
1199  INLINE Float& operator()(const Size idx) {
1200  return data[idx];
1201  }
1202 
1203  INLINE Multipole operator*(const Float f) const {
1204  return data * f;
1205  }
1206 
1207  INLINE Float operator*(const Vector& v) {
1208  return dot(data, v);
1209  }
1210 
1211  INLINE Float apply(const Vector& v) {
1212  return dot(data, v);
1213  }
1214 
1215  INLINE Multipole operator+(const Multipole& other) {
1216  return data + other.data;
1217  }
1218 
1219  INLINE Multipole& operator+=(const Multipole& other) {
1220  data += other.data;
1221  return *this;
1222  }
1223 
1224  INLINE bool operator==(const Multipole& other) const {
1225  return data == other.data;
1226  }
1227 
1228  friend std::ostream& operator<<(std::ostream& stream, const Multipole& t) {
1229  stream << t.data;
1230  return stream;
1231  }
1232 };*/
1233 
1234 namespace Experimental {
1235 template <Size N>
1237 protected:
1238  static constexpr Size COMPONENT_CNT = (N + 1) * (N + 2) / 2;
1239 
1241 
1242 public:
1243  // inner
1244 };
1245 } // namespace Experimental
1246 
1247 
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
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
constexpr Float EPS
Definition: MathUtils.h:30
constexpr NAMESPACE_SPH_BEGIN auto sortIndices()
c++14 sort of template parameters
Definition: Multipole.h:10
INLINE auto almostEqual(const Multipole< N > &f1, const Multipole< N > &f2, const Float &eps=EPS)
Definition: Multipole.h:155
Multipole< N > makeMultipole(const TValue &v)
Definition: Multipole.h:256
TracelessMultipole< N > makeTracelessMultipole(const TValue &v)
Definition: Multipole.h:574
constexpr Size doubleFactorial(const Size n)
Definition: Multipole.h:628
constexpr Size factorial(const Size n)
Definition: Multipole.h:620
constexpr Float expandTracelessMultipoleComponent(const TracelessMultipole< sizeof...(Idxs)> &m, std::index_sequence< Is... >)
Definition: Multipole.h:584
#define INLINE
Macros for conditional compilation based on selected compiler.
Definition: Object.h:31
#define NAMESPACE_SPH_END
Definition: Object.h:12
constexpr int N
Basic vector algebra. Computations are accelerated using SIMD.
@ Y
Definition: Vector.h:23
@ X
Definition: Vector.h:22
@ Z
Definition: Vector.h:24
Container similar to StaticArray, but with constexpr constructors and getters.
Definition: StaticArray.h:292
Float data[COMPONENT_CNT]
Definition: Multipole.h:1240
static constexpr Size COMPONENT_CNT
Definition: Multipole.h:1238
INLINE Float value() const
Definition: Multipole.h:102
INLINE Float operator[](const Size idx) const
Definition: Multipole.h:117
INLINE Float & value()
Definition: Multipole.h:110
static constexpr Size ORDER
Definition: Multipole.h:91
Multipole(const Float f)
Definition: Multipole.h:95
Multipole()=default
bool operator==(const Multipole &other) const
Definition: Multipole.h:137
friend std::ostream & operator<<(std::ostream &stream, const Multipole &m)
Definition: Multipole.h:146
Multipole & operator+=(const Multipole &other)
Definition: Multipole.h:122
Multipole operator*(const Float f) const
Definition: Multipole.h:129
Permutation, i.e. (discrete) invertible function int->int.
Definition: Order.h:18
constexpr bool operator==(const TracelessMultipole &other) const
Definition: Multipole.h:477
constexpr INLINE Float & value()
Definition: Multipole.h:451
constexpr INLINE Size size() const
Definition: Multipole.h:464
constexpr INLINE TracelessMultipole(const Float v)
Definition: Multipole.h:446
TracelessMultipole & operator+=(const TracelessMultipole &other)
Definition: Multipole.h:472
constexpr INLINE Float value() const
Definition: Multipole.h:455
INLINE Float operator[](const Size idx) const
Definition: Multipole.h:459
INLINE Float value() const
Definition: Multipole.h:400
INLINE Float & operator[](const Size idx)
Definition: Multipole.h:409
TracelessMultipole & operator+=(const TracelessMultipole &other)
Definition: Multipole.h:422
INLINE TracelessMultipole(const Float v)
Definition: Multipole.h:389
bool operator==(const TracelessMultipole &other) const
Definition: Multipole.h:427
Vector vector() const
Definition: Multipole.h:418
INLINE Float operator[](const Size idx) const
Definition: Multipole.h:404
constexpr INLINE Size size() const
Definition: Multipole.h:414
INLINE TracelessMultipole()=default
friend std::ostream & operator<<(std::ostream &stream, const TracelessMultipole &m)
Definition: Multipole.h:431
INLINE Float & value()
Definition: Multipole.h:395
TracelessMultipole & operator+=(const TracelessMultipole &other)
Definition: Multipole.h:357
constexpr INLINE Size size() const
Definition: Multipole.h:353
constexpr TracelessMultipole()=default
INLINE Float & value()
Definition: Multipole.h:328
bool operator==(const TracelessMultipole &other) const
Definition: Multipole.h:364
constexpr INLINE Float operator[](const Size idx) const
Definition: Multipole.h:343
constexpr INLINE Float value() const
Definition: Multipole.h:323
static constexpr Size ORDER
Definition: Multipole.h:312
INLINE Float & operator[](const Size idx)
Definition: Multipole.h:348
constexpr INLINE Float valueImpl() const
Definition: Multipole.h:336
constexpr TracelessMultipole(const Float f)
Definition: Multipole.h:316
friend std::ostream & operator<<(std::ostream &stream, const TracelessMultipole &m)
Definition: Multipole.h:373
constexpr Size multipoleComponentCnt(Size order)
Definition: Multipole.h:27
constexpr Size expandMultipoleArray(std::index_sequence< Is... >)
Definition: Multipole.h:61
constexpr Size tracelessMultipoleComponentCnt(Size order)
Definition: Multipole.h:262
constexpr Size expandTracelessMultipoleArray(std::index_sequence< Is... >)
Definition: Multipole.h:284
constexpr Size sum()
Definition: Multipole.h:31
InnerProduct< N, TValue1::ORDER, TValue1, TValue2 > makeInner(const TValue1 &v1, const TValue2 &v2)
Definition: Multipole.h:856
Permutations< Value1::ORDER, Value2::ORDER, Value1, Value2 > makePermutations(const Value1 &v1, const Value2 &v2)
Definition: Multipole.h:742
Difference< TValue1, TValue2 > operator-(const TValue1 &v1, const TValue2 &v2)
Definition: Multipole.h:949
MultiplyByScalar< TValue > operator*(const TValue &v, const Float f)
Definition: Multipole.h:912
Sum< TValue1, TValue2 > operator+(const TValue1 &v1, const TValue2 &v2)
Definition: Multipole.h:933
MultiplyTwo< TValue1::ORDER, TValue1, TValue2 > makeMultiply(const TValue1 &v1, const TValue2 &v2)
Definition: Multipole.h:917
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 constexpr Size value
Definition: Multipole.h:70
std::make_index_sequence< sizeof...(Idxs)> Sequence
Definition: Multipole.h:68
std::make_index_sequence< sizeof...(Idxs)> Sequence
Definition: Multipole.h:291
static constexpr Size value
Definition: Multipole.h:293
static Multipole< 0 > make(const TValue &v)
Definition: Multipole.h:172
static Multipole< 1 > make(const TValue &v)
Definition: Multipole.h:182
static Multipole< 2 > make(const TValue &v)
Definition: Multipole.h:194
static Multipole< 3 > make(const TValue &v)
Definition: Multipole.h:211
static Multipole< 4 > make(const TValue &v)
Definition: Multipole.h:232
Creates multipole by evaluating given object for each independent component.
Definition: Multipole.h:167
static TracelessMultipole< 0 > make(const TValue &v)
Definition: Multipole.h:503
static TracelessMultipole< 1 > make(const TValue &v)
Definition: Multipole.h:513
static TracelessMultipole< 2 > make(const TValue &v)
Definition: Multipole.h:525
static TracelessMultipole< 3 > make(const TValue &v)
Definition: Multipole.h:540
static TracelessMultipole< 4 > make(const TValue &v)
Definition: Multipole.h:557
Creates multipole by evaluating given object for each independent component.
Definition: Multipole.h:498
constexpr INLINE Float value() const
Definition: Multipole.h:752
static constexpr INLINE int value()
Definition: Multipole.h:645
static constexpr INLINE int value()
Definition: Multipole.h:650
static constexpr Size ORDER
Definition: Multipole.h:642
constexpr INLINE Float value() const
Definition: Multipole.h:943
constexpr INLINE Float value() const
Definition: Multipole.h:867
static constexpr Size ORDER
Definition: Multipole.h:955
constexpr INLINE Float value() const
Definition: Multipole.h:960
constexpr INLINE Float value() const
Definition: Multipole.h:966
const TValue1 & v1
Definition: Multipole.h:923
constexpr INLINE Float value() const
Definition: Multipole.h:927
const TValue2 & v2
Definition: Multipole.h:924
INLINE const TracelessMultipole< 0 > & order() const
Definition: Multipole.h:1015
MultipoleExpansion multiply(const Float factor) const
Definition: Multipole.h:1019
TracelessMultipole< 0 > Qn
Definition: Multipole.h:1006
INLINE TracelessMultipole< 0 > & order()
Definition: Multipole.h:1009
INLINE std::enable_if_t< M !=N, TracelessMultipole< M > & > order()
Definition: Multipole.h:979
INLINE std::enable_if_t< M==N, const TracelessMultipole< M > & > order() const
Definition: Multipole.h:991
TracelessMultipole< N > Qn
Definition: Multipole.h:975
INLINE std::enable_if_t< M !=N, const TracelessMultipole< M > & > order() const
Definition: Multipole.h:983
INLINE std::enable_if_t< M==N, TracelessMultipole< M > & > order()
Definition: Multipole.h:987
MultipoleExpansion multiply(const Float factor) const
Definition: Multipole.h:994
MultipoleExpansion< N - 1 > lower
Definition: Multipole.h:976
static constexpr INLINE Float get(const TracelessMultipole< 4 > &m)
Definition: Multipole.h:614
static constexpr INLINE Float get(const TracelessMultipole< 3 > &m)
Definition: Multipole.h:608
static constexpr INLINE Float get(const TracelessMultipole< 2 > &m)
Definition: Multipole.h:602
static INLINE Float get(const TracelessMultipole< sizeof...(Idxs)> &m)
Definition: Multipole.h:579
std::make_index_sequence< sizeof...(Idxs)> Sequence
Definition: Multipole.h:593
static constexpr INLINE Float get(const TracelessMultipole< sizeof...(Idxs)> &m)
Definition: Multipole.h:595