SPH
BarnesHut.cpp
Go to the documentation of this file.
1 #include "gravity/BarnesHut.h"
2 #include "gravity/Moments.h"
5 #include "quantities/Storage.h"
6 #include "system/Profiler.h"
7 #include "system/Statistics.h"
8 #include "thread/Scheduler.h"
9 
11 
12 static_assert(sizeof(InnerNode<BarnesHutNode>) == sizeof(LeafNode<BarnesHutNode>),
13  "Invalid size of BarnesHut nodes");
14 static_assert(alignof(InnerNode<BarnesHutNode>) == alignof(LeafNode<BarnesHutNode>),
15  "Invalid alignment of BarnesHut nodes");
16 
18  const MultipoleOrder order,
19  const Size leafSize,
20  const Size maxDepth,
21  const Float gravityConstant)
22  : kdTree(leafSize, maxDepth)
23  , thetaInv(1._f / theta)
24  , order(order)
25  , maxDepth(maxDepth)
26  , gravityConstant(gravityConstant) {
27  // use default-constructed kernel; it works, because by default LutKernel has zero radius and functions
28  // valueImpl and gradImpl are never called.
29  // Check by assert to make sure this trick will work
30  SPH_ASSERT(kernel.radius() == 0._f);
31  SPH_ASSERT(theta > 0._f, theta);
32 }
33 
35  const MultipoleOrder order,
36  GravityLutKernel&& kernel,
37  const Size leafSize,
38  const Size maxDepth,
39  const Float gravityConstant)
40  : kdTree(leafSize, maxDepth)
41  , kernel(std::move(kernel))
42  , thetaInv(1._f / theta)
43  , order(order)
44  , maxDepth(maxDepth)
45  , gravityConstant(gravityConstant) {
46  SPH_ASSERT(theta > 0._f, theta);
47 }
48 
49 void BarnesHut::build(IScheduler& scheduler, const Storage& storage) {
51 
52  // save source data
54 
55  m.resize(r.size());
57  for (Size i = 0; i < m.size(); ++i) {
58  m[i] = gravityConstant * masses[i];
59  }
60 
61  // build K-d Tree; no need for rank as we are never searching neighbours
62  kdTree.build(scheduler, r, FinderFlag::SKIP_RANK);
63 
64  if (SPH_UNLIKELY(r.empty())) {
65  return;
66  }
67  // constructs nodes
68  auto functor = [this](BarnesHutNode& node, BarnesHutNode* left, BarnesHutNode* right) INL {
69  if (node.isLeaf()) {
70  SPH_ASSERT(left == nullptr && right == nullptr);
71  buildLeaf(node);
72 
73  } else {
74  SPH_ASSERT(left != nullptr && right != nullptr);
75  buildInner(node, *left, *right);
76  }
77  return true;
78  };
80  iterateTree<IterateDirection::BOTTOM_UP>(kdTree, SEQUENTIAL, functor, 0, maxDepth);
81 }
82 
83 void BarnesHut::evalAll(IScheduler& scheduler, ArrayView<Vector> dv, Statistics& stats) const {
85 
86  TreeWalkState data;
87  TreeWalkResult result;
88  SharedPtr<ITask> rootTask = scheduler.submit([this, &scheduler, dv, &data, &result] { //
89  this->evalNode(scheduler, dv, 0, std::move(data), result);
90  });
91  rootTask->wait();
92 
96 }
97 
98 
99 Vector BarnesHut::eval(const Vector& r0) const {
100  return this->evalImpl(r0, Size(-1));
101 }
102 
105 }
106 
107 Vector BarnesHut::evalImpl(const Vector& r0, const Size idx) const {
108  if (SPH_UNLIKELY(r.empty())) {
109  return Vector(0._f);
110  }
111  Vector f(0._f);
112 
113  auto lambda = [this, &r0, &f, idx](
114  const BarnesHutNode& node, const BarnesHutNode*, const BarnesHutNode*) {
115  if (node.box == Box::EMPTY()) {
116  // no particles in this node, skip
117  return false;
118  }
119  const Float boxSizeSqr = getSqrLength(node.box.size());
120  const Float boxDistSqr = getSqrLength(node.box.center() - r0);
121  SPH_ASSERT(isReal(boxDistSqr));
122 
123  if (!node.box.contains(r0) && boxSizeSqr > 0._f &&
124  boxSizeSqr / (boxDistSqr + EPS) < 1._f / sqr(thetaInv)) {
125  // small node, use multipole approximation
126  f += evaluateGravity(r0 - node.com, node.moments, order);
127 
128  // skip the children
129  return false;
130  } else {
131  // too large box; if inner, recurse into children, otherwise sum each particle of the leaf
132  if (node.isLeaf()) {
133  const LeafNode<BarnesHutNode>& leaf = reinterpret_cast<const LeafNode<BarnesHutNode>&>(node);
134  f += this->evalExact(leaf, r0, idx);
135  return false; // return value doesn't matter here
136  } else {
137  // continue with children
138  return true;
139  }
140  }
141  };
142  iterateTree<IterateDirection::TOP_DOWN>(kdTree, SEQUENTIAL, lambda);
143 
144  return f;
145 }
146 
148 private:
149  const BarnesHut& bh;
150  IScheduler& scheduler;
152  Size nodeIdx;
155 
156 public:
157  NodeTask(const BarnesHut& bh,
158  IScheduler& scheduler,
160  const Size nodeIdx,
163  : bh(bh)
164  , scheduler(scheduler)
165  , dv(dv)
166  , nodeIdx(nodeIdx)
167  , data(std::move(data))
168  , result(result) {}
169 
170  void operator()() {
171  bh.evalNode(scheduler, dv, nodeIdx, std::move(data), result);
172  }
173 };
174 
176  TreeWalkState cloned;
177  cloned.checkList = checkList.clone();
178  cloned.particleList = particleList.clone();
179  cloned.nodeList = nodeList.clone();
180  cloned.depth = depth;
181  return cloned;
182 }
183 
187  const Size evaluatedNodeIdx,
188  TreeWalkState data,
189  TreeWalkResult& result) const {
190 
191  const BarnesHutNode& evaluatedNode = kdTree.getNode(evaluatedNodeIdx);
192  const Box& box = evaluatedNode.box;
193 
194  if (box == Box::EMPTY()) {
195  // no particles in the box, skip
197  SPH_ASSERT(evaluatedNode.isLeaf());
198  return;
199  }
200 
201  // we cannot use range-based for loop because we need the iterator for erasing the element
202  for (auto iter = data.checkList.begin(); iter != data.checkList.end();) {
204 
205  const Size idx = *iter;
206  const BarnesHutNode& node = kdTree.getNode(idx);
207  if (node.r_open == 0._f) {
208  // either empty node or a single particle in a leaf, just add it to particle list
209  SPH_ASSERT(node.isLeaf());
210  data.particleList.push(idx);
211  iter = data.checkList.erase(iter);
212  continue;
213  }
214 
215  const Sphere openBall(node.com, node.r_open);
216  const IntersectResult intersect = openBall.intersectsBox(box);
217 
218  if (intersect == IntersectResult::BOX_INSIDE_SPHERE ||
219  (evaluatedNode.isLeaf() && intersect != IntersectResult::BOX_OUTSIDE_SPHERE)) {
220  // if leaf, add it into the particle interaction list
221  if (node.isLeaf()) {
222  // let's add only nodes with higher indices, the evalution is symmetric anyway
223  data.particleList.push(idx);
224  } else {
225  // add child nodes into the checklist
226  const InnerNode<BarnesHutNode>& inner =
227  reinterpret_cast<const InnerNode<BarnesHutNode>&>(node);
228  data.checkList.pushBack(inner.left);
229  data.checkList.pushBack(inner.right);
230  }
231  iter = data.checkList.erase(iter);
232 
233  continue;
234  } else if (intersect == IntersectResult::BOX_OUTSIDE_SPHERE) {
235  // node is outside the opening ball, we can approximate it; add to the node list
236  data.nodeList.push(idx);
237 
238  // erase this node from checklist
239  iter = data.checkList.erase(iter);
240  continue;
241  }
242  // for leafs we have to move all nodes from the checklist to one of interaction lists
243  SPH_ASSERT(!evaluatedNode.isLeaf());
244  ++iter;
245  }
246 
247  if (evaluatedNode.isLeaf()) {
248  // checklist must be empty, otherwise we forgot something
249  SPH_ASSERT(data.checkList.empty(), data.checkList);
250  const LeafNode<BarnesHutNode>& leaf = reinterpret_cast<const LeafNode<BarnesHutNode>&>(evaluatedNode);
251 
252  // 1) evaluate the particle list:
253  this->evalParticleList(leaf, data.particleList, dv);
254  result.exactNodes += data.particleList.size();
255 
256  // 2) evaluate the node list
257  this->evalNodeList(leaf, data.nodeList, dv);
258  result.approximatedNodes += data.nodeList.size();
259 
260  } else {
261  const InnerNode<BarnesHutNode>& inner =
262  reinterpret_cast<const InnerNode<BarnesHutNode>&>(evaluatedNode);
263  // recurse into child nodes
264  data.depth++;
265  // we evaluate the left one from a (possibly) different thread, we thus have to clone buffers now so
266  // that we don't override the lists when evaluating different node (each node has its own lists).
267  TreeWalkState childData = data.clone();
268  childData.checkList.pushBack(inner.right);
269  auto task = makeShared<NodeTask>(*this, scheduler, dv, inner.left, std::move(childData), result);
270  if (childData.depth < maxDepth) {
271  // Ad-hoc decision (see also KdTree.cpp where we do the same trick);
272  // only split the treewalk in the topmost nodes, process the bottom nodes in the same thread to
273  // avoid high scheduling overhead of ThreadPool (TBBs deal with this quite well)
274  //
275  // The expression above can be modified to get optimal performance.
276  scheduler.submit(std::move(task));
277  } else {
278  task();
279  }
280 
281  // since we go only once through the tree (we never go 'up'), we can simply move the lists into the
282  // right child and modify them for the child node
283  data.checkList.pushBack(inner.left);
284  this->evalNode(scheduler, dv, inner.right, std::move(data), result);
285  }
286 }
287 
289  ArrayView<Size> particleList,
290  ArrayView<Vector> dv) const {
291  // needs to symmetrize smoothing length to keep the total momentum conserved
293  // go through all nodes in the list and compute the pair-wise interactions
295  SPH_ASSERT(areElementsUnique(particleList), particleList);
296  for (Size idx : particleList) {
297  // the particle lists do not have to be necessarily symmetric, we have to do each node separately
298  SPH_ASSERT(idx < kdTree.getNodeCnt(), idx, kdTree.getNodeCnt());
299  const BarnesHutNode& node = kdTree.getNode(idx);
300  SPH_ASSERT(node.isLeaf());
301  LeafIndexSequence seq2 =
302  kdTree.getLeafIndices(reinterpret_cast<const LeafNode<BarnesHutNode>&>(node));
303  for (Size i : seq1) {
304  SPH_ASSERT(r[i][H] > 0._f, r[i][H]);
305  for (Size j : seq2) {
306  SPH_ASSERT(r[j][H] > 0._f, r[j][H]);
307  const Vector grad = actKernel.grad(r[j], r[i]);
308  dv[i] += m[j] * grad;
309  }
310  }
311  }
312  // evaluate intra-leaf interactions (the leaf itself is not included in the list)
313  for (Size i : seq1) {
314  for (Size j : seq1) {
315  if (i == j) {
316  // skip, we are doing a symmetric evaluation
317  continue;
318  }
319  const Vector grad = actKernel.grad(r[j], r[i]);
320  dv[i] += m[j] * grad;
321  }
322  }
323 }
324 
326  ArrayView<Size> nodeList,
327  ArrayView<Vector> dv) const {
328  SPH_ASSERT(areElementsUnique(nodeList), nodeList);
330  for (Size idx : nodeList) {
331  const BarnesHutNode& node = kdTree.getNode(idx);
332  SPH_ASSERT(seq1.size() > 0);
333  for (Size i : seq1) {
334  dv[i] += evaluateGravity(r[i] - node.com, node.moments, order);
335  }
336  }
337 }
338 
339 Vector BarnesHut::evalExact(const LeafNode<BarnesHutNode>& leaf, const Vector& r0, const Size idx) const {
340  LeafIndexSequence sequence = kdTree.getLeafIndices(leaf);
341  Vector f(0._f);
342  for (Size i : sequence) {
343  if (idx == i) {
344  continue;
345  }
346  f += m[i] * kernel.grad(r[i] - r0, r[i][H]);
347  }
348  return f;
349 }
350 
353 
354  switch (leaf.size()) {
355  case 0:
356  // empty leaf - set to zero to correctly compute mass and com of parent nodes
357  leaf.com = Vector(0._f);
358  leaf.moments.order<0>() = 0._f;
359  leaf.moments.order<1>() = TracelessMultipole<1>(0._f);
360  leaf.moments.order<2>() = TracelessMultipole<2>(0._f);
361  leaf.moments.order<3>() = TracelessMultipole<3>(0._f);
362  leaf.r_open = 0._f;
363  return;
364  case 1:
365  // single particle - requires special handling to avoid numerical problems
366  const Size i = *kdTree.getLeafIndices(leaf).begin();
367  leaf.com = r[i];
368  leaf.box.extend(r[i]);
369  leaf.moments.order<0>() = m[i];
370  leaf.moments.order<1>() = TracelessMultipole<1>(0._f);
371  leaf.moments.order<2>() = TracelessMultipole<2>(0._f);
372  leaf.moments.order<3>() = TracelessMultipole<3>(0._f);
373  leaf.r_open = 0._f;
374  return;
375  }
376  // compute the center of gravity (the box is already done)
377  leaf.com = Vector(0._f);
378  Float m_leaf = 0._f;
379  LeafIndexSequence sequence = kdTree.getLeafIndices(leaf);
380  for (Size i : sequence) {
381  leaf.com += m[i] * r[i];
382  m_leaf += m[i];
383 
384  // extend the bounding box
385  leaf.box.extend(r[i]);
386  }
387  SPH_ASSERT(m_leaf > 0._f, m_leaf);
388  leaf.com /= m_leaf;
389  SPH_ASSERT(isReal(leaf.com) && getLength(leaf.com) < LARGE, leaf.com);
390 
391  // compute opening radius using Eq. (2.36) of Stadel Phd Thesis
392  const Vector r_max = max(leaf.com - leaf.box.lower(), leaf.box.upper() - leaf.com);
393  SPH_ASSERT(minElement(r_max) >= 0._f, r_max);
394  leaf.r_open = 2._f / sqrt(3._f) * thetaInv * getLength(r_max);
395 
396  // compute gravitational moments from individual particles
397  // M0 is a sum of particle masses, M1 is a dipole moment = zero around center of mass
398  SPH_ASSERT(computeMultipole<0>(r, m, leaf.com, sequence).value() == m_leaf);
399  const Multipole<2> m2 = computeMultipole<2>(r, m, leaf.com, sequence);
400  const Multipole<3> m3 = computeMultipole<3>(r, m, leaf.com, sequence);
401 
402  // compute traceless tensors to reduce number of independent components
405 
406  // save the moments to the leaf
407  leaf.moments.order<0>() = m_leaf;
408  leaf.moments.order<1>() = TracelessMultipole<1>(0._f);
409  leaf.moments.order<2>() = q2;
410  leaf.moments.order<3>() = q3;
411 }
412 
415 
416  // update bounding box
417  inner.box = Box::EMPTY();
418  inner.box.extend(left.box);
419  inner.box.extend(right.box);
420 
421  // update center of mass
422  const Float ml = left.moments.order<0>();
423  const Float mr = right.moments.order<0>();
424 
425  // check for empty node
426  if (ml + mr == 0._f) {
427  // set to zero to correctly compute sum and com of parent nodes
428  inner.com = Vector(0._f);
429  inner.moments.order<0>() = 0._f;
430  inner.moments.order<1>() = TracelessMultipole<1>(0._f);
431  inner.moments.order<2>() = TracelessMultipole<2>(0._f);
432  inner.moments.order<3>() = TracelessMultipole<3>(0._f);
433  inner.r_open = 0._f;
434  return;
435  }
436 
437  inner.com = (ml * left.com + mr * right.com) / (ml + mr);
438  SPH_ASSERT(isReal(inner.com) && getLength(inner.com) < LARGE, inner.com);
439 
440  // compute opening radius
441  const Vector r_max = max(inner.com - inner.box.lower(), inner.box.upper() - inner.com);
442  SPH_ASSERT(minElement(r_max) >= 0._f, r_max);
443  inner.r_open = 2._f / sqrt(3._f) * thetaInv * getLength(r_max);
444 
445  inner.moments.order<0>() = ml + mr;
446 
447  // we already computed moments of children nodes, sum up using parallel axis theorem
448  Vector d = left.com - inner.com;
449  TracelessMultipole<1>& Ml1 = left.moments.order<1>();
450  TracelessMultipole<2>& Ml2 = left.moments.order<2>();
451  TracelessMultipole<3>& Ml3 = left.moments.order<3>();
452  inner.moments.order<1>() = parallelAxisTheorem(Ml1, ml, d);
453  inner.moments.order<2>() = parallelAxisTheorem(Ml2, ml, d);
454  inner.moments.order<3>() = parallelAxisTheorem(Ml3, Ml2, ml, d);
455 
456  d = right.com - inner.com;
457  TracelessMultipole<1>& Mr1 = right.moments.order<1>();
458  TracelessMultipole<2>& Mr2 = right.moments.order<2>();
459  TracelessMultipole<3>& Mr3 = right.moments.order<3>();
460  inner.moments.order<1>() += parallelAxisTheorem(Mr1, mr, d);
461  inner.moments.order<2>() += parallelAxisTheorem(Mr2, mr, d);
462  inner.moments.order<3>() += parallelAxisTheorem(Mr3, Mr2, mr, d);
463 }
464 
466  // masses are premultiplied by gravitational constants, so we have to divide
467  return kdTree.getNode(0).moments.multiply(1._f / gravityConstant);
468 }
469 
472  return &kdTree;
473 }
474 
INLINE bool isReal(const AntisymmetricTensor &t)
INLINE Float minElement(const AntisymmetricTensor &t)
Returns the minimal element of the tensor.
Utilities to simplify working with arrays.
bool areElementsUnique(const TStorage &container)
Definition: ArrayUtils.h:125
#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
Barnes-Hut algorithm for computation of gravitational acceleration.
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
#define VERBOSE_LOG
Helper macro, creating.
Definition: Logger.h:242
constexpr INLINE T max(const T &f1, const T &f2)
Definition: MathBasic.h:20
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 Float LARGE
Definition: MathUtils.h:34
MultipoleOrder
Definition: Moments.h:309
INLINE TracelessMultipole< 1 > parallelAxisTheorem(const TracelessMultipole< 1 > &Qi, const Float Q, const Vector &d)
Definition: Moments.h:164
TracelessMultipole< N > computeReducedMultipole(const Multipole< N > &m)
Vector evaluateGravity(const Vector &dr, const MultipoleExpansion< N > &ms, const MultipoleOrder maxOrder)
Definition: Moments.h:317
@ SKIP_RANK
The rank of particles is not created. 'Dummy' option that can be used to improve readability.
#define UNUSED(x)
Definition: Object.h:37
#define SPH_UNLIKELY(x)
Definition: Object.h:50
#define NAMESPACE_SPH_END
Definition: Object.h:12
#define INL
Definition: Object.h:32
Tool to measure time spent in functions and profile the code.
@ POSITION
Positions (velocities, accelerations) of particles, always a vector quantity,.
@ MASS
Paricles masses, always a scalar quantity.
SequentialScheduler SEQUENTIAL
Global instance of the sequential scheduler.
Definition: Scheduler.cpp:43
Interface for executing tasks (potentially) asynchronously.
Object representing a three-dimensional sphere.
IntersectResult
Definition: Sphere.h:12
@ BOX_INSIDE_SPHERE
Sphere contains the whole box.
@ BOX_OUTSIDE_SPHERE
Sphere has no intersection with the box.
Statistics gathered and periodically displayed during the run.
@ GRAVITY_NODES_APPROX
Number of tree nodes evaluated using multipole approximation.
@ GRAVITY_NODE_COUNT
Number of nodes in used gravity tree.
@ GRAVITY_NODES_EXACT
Number of tree nodes evaluated by pair-wise interacting.
Container for storing particle quantities and materials.
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
BasicVector< Float > Vector
Definition: Vector.h:539
@ H
Definition: Vector.h:25
void resize(const TCounter newSize)
Resizes the array to new size.
Definition: Array.h:215
INLINE void push(U &&u)
Adds new element to the end of the array, resizing the array if necessary.
Definition: Array.h:306
INLINE TCounter size() const noexcept
Definition: Array.h:193
Array clone() const
Performs a deep copy of all elements of the array.
Definition: Array.h:147
NodeTask(const BarnesHut &bh, IScheduler &scheduler, ArrayView< Vector > dv, const Size nodeIdx, BarnesHut::TreeWalkState &&data, BarnesHut::TreeWalkResult &result)
Definition: BarnesHut.cpp:157
Multipole approximation of distance particle.
Definition: BarnesHut.h:43
virtual void evalAll(IScheduler &pool, ArrayView< Vector > dv, Statistics &stats) const override
Evaluates the gravitational acceleration concurrently.
Definition: BarnesHut.cpp:83
void evalNode(IScheduler &scheduler, ArrayView< Vector > dv, const Size nodeIdx, TreeWalkState data, TreeWalkResult &result) const
Performs a recursive treewalk evaluating gravity for all particles.
Definition: BarnesHut.cpp:185
ArrayView< const Vector > r
View of a position buffer in the storage.
Definition: BarnesHut.h:46
MultipoleOrder order
Order of multipole approximation.
Definition: BarnesHut.h:61
GravityLutKernel kernel
Kernel used to evaluate gravity of close particles.
Definition: BarnesHut.h:55
BarnesHut(const Float theta, const MultipoleOrder order, const Size leafSize=25, const Size maxDepth=50, const Float gravityConstant=Constants::gravity)
Constructs the Barnes-Hut gravity assuming point-like particles (with zero radius).
Definition: BarnesHut.cpp:17
virtual Vector eval(const Vector &r0) const override
Evaluates the gravitational acceleration at given point.
Definition: BarnesHut.cpp:99
MultipoleExpansion< 3 > getMoments() const
Returns the multipole moments computed from root node.
Definition: BarnesHut.cpp:465
void buildInner(BarnesHutNode &node, BarnesHutNode &left, BarnesHutNode &right)
Definition: BarnesHut.cpp:413
Vector evalExact(const LeafNode< BarnesHutNode > &node, const Vector &r0, const Size idx) const
Definition: BarnesHut.cpp:339
Size maxDepth
Maximum depth at which the nodes evaluation is parallelized.
Definition: BarnesHut.h:66
Vector evalImpl(const Vector &r0, const Size idx) const
Evaluates the gravity at a single point in space.
Definition: BarnesHut.cpp:107
void evalParticleList(const LeafNode< BarnesHutNode > &leaf, ArrayView< Size > particleList, ArrayView< Vector > dv) const
Definition: BarnesHut.cpp:288
virtual RawPtr< const IBasicFinder > getFinder() const override
Optionally returns a finder used by the gravity implementation.
Definition: BarnesHut.cpp:470
Array< Float > m
Particle masses multiplied by gravitational constant.
Definition: BarnesHut.h:49
void evalNodeList(const LeafNode< BarnesHutNode > &leaf, ArrayView< Size > nodeList, ArrayView< Vector > dv) const
Definition: BarnesHut.cpp:325
void buildLeaf(BarnesHutNode &node)
Definition: BarnesHut.cpp:351
KdTree< BarnesHutNode > kdTree
K-d tree storing gravitational moments.
Definition: BarnesHut.h:52
virtual Float evalEnergy(IScheduler &scheduler, Statistics &stats) const override
Computes the total potential energy of the particles.
Definition: BarnesHut.cpp:103
Float gravityConstant
Gravitational constant in the selected unit system.
Definition: BarnesHut.h:72
Float thetaInv
Inverted value of the opening angle for multipole approximation (in radians)
Definition: BarnesHut.h:58
virtual void build(IScheduler &pool, const Storage &storage) override
Masses of particles must be strictly positive, otherwise center of mass would be undefined.
Definition: BarnesHut.cpp:49
Helper object defining three-dimensional interval (box).
Definition: Box.h:17
static Box EMPTY()
Syntactic sugar, returns a default-constructed (empty) box.
Definition: Box.h:41
Gravitational kernel approximated by LUT for close particles.
Definition: GravityKernel.h:35
INLINE Vector grad(const Vector &r, const Float h) const
Definition: GravityKernel.h:69
INLINE Float radius() const
Definition: GravityKernel.h:51
Interface that allows unified implementation of sequential and parallelized versions of algorithms.
Definition: Scheduler.h:27
virtual SharedPtr< ITask > submit(const Function< void()> &task)=0
Submits a task to be potentially executed asynchronously.
void build(IScheduler &scheduler, ArrayView< const Vector > points, Flags< FinderFlag > flags=FinderFlag::MAKE_RANK)
Constructs the struct with an array of vectors.
INLINE Size size() const
INLINE TNode & getNode(const Size nodeIdx)
Returns the node with given index.
Definition: KdTree.h:169
INLINE LeafIndexSequence getLeafIndices(const LeafNode< TNode > &leaf) const
Returns the sequence of particles indices belonging to given leaf.
Definition: KdTree.h:184
Outcome sanityCheck() const
Performs some checks of KdTree consistency, returns SUCCESS if everything is OK.
Definition: KdTree.inl.h:394
INLINE Size getNodeCnt() const
Returns the number of nodes in the tree.
Definition: KdTree.h:179
Helper index sequence to iterate over particle indices of a leaf node.
Definition: KdTree.h:100
INLINE LeafIndexIterator begin() const
Definition: KdTree.h:111
ListIterator< T > end()
Returns a bidirectional iterator pointing to the one-past-last element of the list.
Definition: List.h:307
INLINE bool empty() const
Returns true if there are no elements in the list.
Definition: List.h:170
List clone() const
Creates a copy of the list.
Definition: List.h:286
void pushBack(U &&value)
Adds a new element to the back of the list.
Definition: List.h:189
ListIterator< T > erase(const ListIterator< T > iter)
Removes an element given by the iterator.
Definition: List.h:229
ListIterator< T > begin()
Returns a bidirectional iterator pointing to the first element of the list.
Definition: List.h:295
Non-owning wrapper of pointer.
Definition: RawPtr.h:19
Definition: Sphere.h:18
INLINE IntersectResult intersectsBox(const Box &box) const
Checks the intersection of the sphere with a box.
Definition: Sphere.h:83
Object holding various statistics about current run.
Definition: Statistics.h:22
Statistics & set(const StatisticsId idx, TValue &&value)
Sets new values of a statistic.
Definition: Statistics.h:52
Container storing all quantities used within the simulations.
Definition: Storage.h:230
Array< TValue > & getValue(const QuantityId key)
Retrieves a quantity values from the storage, given its key and value type.
Definition: Storage.cpp:191
INLINE Vector grad(const Vector &r1, const Vector &r2) const
Definition: Kernel.h:578
Overload of std::swap for Sph::Array.
Definition: Array.h:578
MultipoleExpansion< 3 > moments
Gravitational moments with a respect to the center of mass, using expansion to octupole order.
Definition: BarnesHut.h:26
Vector com
Center of mass of contained particles.
Definition: BarnesHut.h:23
Float r_open
Definition: BarnesHut.h:30
std::atomic_int approximatedNodes
Number of nodes approximated using multipole expansion.
Definition: BarnesHut.h:147
std::atomic_int exactNodes
Number of opened leafs where exact (pair-wise) solution has been used.
Definition: BarnesHut.h:150
Data passed into each node during treewalk.
Definition: BarnesHut.h:125
TreeWalkState clone() const
Clones all lists in the state object.
Definition: BarnesHut.cpp:175
Array< Size > nodeList
Indices of nodes that shall be evaluated using multipole approximation.
Definition: BarnesHut.h:136
Size depth
Current depth in the tree; root node has depth equal to zero.
Definition: BarnesHut.h:139
List< Size > checkList
Definition: BarnesHut.h:130
Array< Size > particleList
Indices of nodes where the exact (pair-wise) gravity solution have to be used.
Definition: BarnesHut.h:133
Inner node of K-d tree.
Definition: KdTree.h:42
Size right
Index of right child node.
Definition: KdTree.h:50
Size left
Index of left child node.
Definition: KdTree.h:47
INLINE bool isLeaf() const
Definition: KdTree.h:35
Box box
Bounding box of particles in the node.
Definition: KdTree.h:30
Leaf (bucket) node of K-d tree.
Definition: KdTree.h:61
INLINE Size size() const
Returns the number of points in the leaf. Can be zero.
Definition: KdTree.h:75
INLINE std::enable_if_t< M !=N, TracelessMultipole< M > & > order()
Definition: Multipole.h:979
MultipoleExpansion multiply(const Float factor) const
Definition: Multipole.h:994
Object with deleted copy constructor and copy operator.
Definition: Object.h:54