#include <algorithm> #include <cmath> #include <numeric> #include <iostream> #include <limits> #include "Node.hpp" #include "Tree.hpp" namespace nbody { Node::Node(Tree* tree_):tree(tree_) {} Node::Node(const Box& bb_, std::vector<Body> bodies_, Tree* tree_): bodies(std::move(bodies_)), bb(bb_), tree(tree_) {} Node::Node(std::vector<Body> bodies_, Tree* tree_) : bodies(std::move(bodies_)), bb(bodies), tree(tree_) {} Box Node::getBB() const { return bb; } //check if node needs to be splitted during tree build bool Node::isSplitable() const { bool result = true; if (bodies.size() <= tree->maxLeafBodies) { result = false; } //this is to prevent errors with collocated particles if (bb.volume() <= std::numeric_limits<float>::epsilon()) { result = false; } return result; } void Node::extendBBforBodies() { bb.extendForBodies(bodies); } void Node::extendBBtoCube() { bb.extendToCube(); } std::vector<Body> Node::getBodies() const { return bodies; } void Node::insertBefore(Node* node) { node->next = this; node->prev = this->prev; this->prev->next = node; this->prev = node; } void Node::insertAfter(Node* node) { this->next->insertBefore(node); } void Node::unlink() { this->next->prev = this->prev; this->prev->next = this->next; this->next = this; this->prev = this; } bool Node::isCorrect() const { if (afterSubtree == nullptr) { std::cerr << "after subtree null\n"; return false; } if (!bb.isCorrectBox()) { std::cerr << "bb wrong\n"; return false; } if (bb.min > bb.max) { std::cerr << "bb min " << bb.min << " max " << bb.max << '\n'; return false; } if (std::any_of(std::begin(bodies), std::end(bodies), [&](const Body& b) {return !isContained(b, bb); })) { std::cerr << "bb out of bounds\n"; return false; } if (!leaf) { Node* current = next; std::size_t children = 0; while (current != nullptr && current != afterSubtree) { current = current->afterSubtree; children++; } if (current == nullptr) { std::cerr << "afterSubtree null\n"; return false; } if (children != tree->numberOfChildren()) { std::cerr << "wrong number of children " << children << '\n'; return false; } current = next; for (std::size_t i = 0; i < tree->numberOfChildren(); i++) { current = current->afterSubtree; } if (current != afterSubtree) { std::cerr << "last sibling afterSubtree inconsistent\n"; return false; } } if (!leaf && !bodies.empty()) { std::cerr << "non-empty inner node\n"; return false; } if (leaf && nextSibling != nullptr && next != nextSibling) { std::cerr << "wrong next sibling\n"; return false; } return true; } //update overall node information void Node::update() { auto siblingNodesView = tree->getSiblingNodesView(this); auto mass = [&] { return leaf ? std::accumulate(std::begin(bodies), std::end(bodies), 0.0, [](double m, const Body& b) { return m + b.mass; }) : std::accumulate(std::begin(siblingNodesView), std::end(siblingNodesView), 0.0, [](double m, const Node& n) { return m + n.representative.mass; }); }(); auto position = [&] { return leaf ? std::accumulate(std::begin(bodies), std::end(bodies), Vec3{}, [](Vec3 p, const Body& b) { return p + (b.position * b.mass); }) : Vec3{ 0.0 }; }(); representative.position = position / mass; representative.mass = mass; } //get criterion to check if node is sufficient for force evaluation double Node::getL() const { return bb.maxSidelength(); } void Node::print(std::size_t parallelId) const { bb.printBB(parallelId); for (const auto& body : bodies) { std::cout << " "; body.print(parallelId); } } //check if node is sufficient for force evaluation bool Node::sufficientForBody(const Body& body) const { const auto distance2 = SquaredDistance(representative.position, body.position); return distance2 > std::pow(getL(), 2.0); } //check if node is sufficient for force evaluation for all bodies in box bool Node::sufficientForBox(const Box& box) const { return bb.distanceToBox(box) > getL(); } //get local bodies void Node::extractLocalBodiesTo(std::vector<Body>& result) { std::copy_if(std::begin(bodies), std::end(bodies), std::back_inserter(result), [](const Body& b) {return !b.refinement; }); bodies.clear(); } } // namespace nbody