Skip to content
Snippets Groups Projects
Commit 6178219d authored by Dmitri Naumov's avatar Dmitri Naumov
Browse files

[MeL] Optimize find element within radius algo.

 - Use contigiuos memory for start element's nodes.
 - Store sizes of arrays before for-loops.
 - Extract element_in_radius predicate. (This is surprisingly also an optimization.)
 - Revert to depth-first search. Uses vector instead of deque.
parent b85bc1bc
No related branches found
No related tags found
No related merge requests found
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include "findElementsWithinRadius.h" #include "findElementsWithinRadius.h"
#include <deque> #include <vector>
#include <unordered_set> #include <unordered_set>
#include "BaseLib/uniqueInsert.h" #include "BaseLib/uniqueInsert.h"
...@@ -29,29 +29,50 @@ std::vector<std::size_t> findElementsWithinRadius(Element const& start_element, ...@@ -29,29 +29,50 @@ std::vector<std::size_t> findElementsWithinRadius(Element const& start_element,
if (radius_squared == 0.) if (radius_squared == 0.)
return {start_element.getID()}; return {start_element.getID()};
// Collect start element node coordinates into local contigiuos memory.
std::vector<MathLib::Point3d> start_element_nodes;
{
auto const start_element_n_nodes = start_element.getNumberOfNodes();
start_element_nodes.reserve(start_element_n_nodes);
for (unsigned n = 0; n < start_element_n_nodes; ++n)
start_element_nodes.push_back(*start_element.getNode(n));
}
// Returns true if the test node is inside the radius of any of the // Returns true if the test node is inside the radius of any of the
// element's nodes. // element's nodes.
auto node_inside_radius = [&start_element, auto node_inside_radius = [&start_element_nodes,
radius_squared](Node const* test_node) { radius_squared](Node const* test_node) {
for (unsigned n = 0; n < start_element.getNumberOfNodes(); ++n) for (auto const& n : start_element_nodes)
{ {
if (MathLib::sqrDist(*test_node, *start_element.getNode(n)) <= if (MathLib::sqrDist(*test_node, n) <= radius_squared)
radius_squared) return true;
}
return false;
};
// Returns true if any of the test element's nodes is inside the start
// element's radius.
auto element_in_radius = [&node_inside_radius](Element const& element) {
auto const n_nodes = element.getNumberOfNodes();
for (unsigned i = 0; i < n_nodes; ++i)
{
if (node_inside_radius(element.getNode(i)))
return true; return true;
} }
return false; return false;
}; };
std::set<std::size_t> found_elements; std::set<std::size_t> found_elements;
std::deque<Element const*> neighbors_to_visit; std::vector<Element const*> neighbors_to_visit;
std::unordered_set<std::size_t> visited_elements; std::unordered_set<std::size_t> visited_elements;
auto mark_visited_and_add_neighbors = auto mark_visited_and_add_neighbors =
[&found_elements, &neighbors_to_visit, [&found_elements, &neighbors_to_visit, &visited_elements](
&visited_elements](Element const& element) { Element const& element) {
found_elements.insert(element.getID()); found_elements.insert(element.getID());
visited_elements.insert(element.getID()); visited_elements.insert(element.getID());
for (unsigned n = 0; n < element.getNumberOfNeighbors(); ++n) auto const n_neighbors = element.getNumberOfNeighbors();
for (unsigned n = 0; n < n_neighbors; ++n)
{ {
auto neighbor = element.getNeighbor(n); auto neighbor = element.getNeighbor(n);
if (neighbor == nullptr) if (neighbor == nullptr)
...@@ -61,6 +82,7 @@ std::vector<std::size_t> findElementsWithinRadius(Element const& start_element, ...@@ -61,6 +82,7 @@ std::vector<std::size_t> findElementsWithinRadius(Element const& start_element,
continue; continue;
neighbors_to_visit.push_back(neighbor); neighbors_to_visit.push_back(neighbor);
visited_elements.insert(neighbor->getID()); visited_elements.insert(neighbor->getID());
} }
}; };
...@@ -70,17 +92,12 @@ std::vector<std::size_t> findElementsWithinRadius(Element const& start_element, ...@@ -70,17 +92,12 @@ std::vector<std::size_t> findElementsWithinRadius(Element const& start_element,
while (!neighbors_to_visit.empty()) while (!neighbors_to_visit.empty())
{ {
auto const& current_element = *neighbors_to_visit.front(); auto const& current_element = *neighbors_to_visit.back();
neighbors_to_visit.pop_front(); neighbors_to_visit.pop_back();
// if any node is inside the radius, all neighbors are visited.
for (unsigned i = 0; i < current_element.getNumberOfNodes(); ++i)
{
if (!node_inside_radius(current_element.getNode(i)))
continue;
// If any node is inside the radius, all neighbors are visited.
if (element_in_radius(current_element))
mark_visited_and_add_neighbors(current_element); mark_visited_and_add_neighbors(current_element);
}
} }
return {std::begin(found_elements), std::end(found_elements)}; return {std::begin(found_elements), std::end(found_elements)};
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment