#14806 Cell search tree: Group cells in leaves and store leaf ids in flat arrays

Building the cell search tree was dominated by one small std::vector<int>
allocation per leaf, and a tree with one cell per leaf becomes very deep for
large grids.

- BoundingBoxTree: Store leaf ids in flat arrays, and move the input data
  instead of copying it. The tree shape is unchanged. Queries no longer copy
  the ids of each leaf.
- RigMainGrid: Always group at least 8 cells along K in each leaf.
  findIntersectingCells() removes cells not intersecting the query bounding
  box, so the result is the same set of cells as for a tree with one cell per
  leaf. This also applies to very large grids, which previously got the
  cells of the whole leaf.
- Include cells of nested LGRs and LGR cells in invalid main grid cells in
  the grouped tree, as the previous tree with one cell per leaf did.
This commit is contained in:
Magne Sjaastad authored and Kristian Bendiksen committed 2026-10-03 07:57:03 +02:00
1 parent c5c0e05012
commit 6b96df134e
5 files changed
+241 -162

No files matched your search

+70 -47
View File
@@ -134,11 +134,11 @@ namespace cvf {
public:
AABBTreeNodeLeaf();
std::vector<int> ids() const;
void setIds(const std::vector<int>& ids);
size_t index() const;
void setIndex(size_t index);
private:
std::vector<int> m_ids; ///< An list of IDs of the leaf node. The interpretation of these values depends on which tree the node is in.
size_t m_index; ///< Index of the leaf in the input data. The interpretation of this value depends on which tree the node is in.
};
//=================================================================================================================================
@@ -186,7 +186,7 @@ namespace cvf {
bool intersect(const AABBTreeNode* pA, const AABBTreeNode* pB) const;
AABBTreeNodeInternal* createNode();
AABBTreeNodeLeaf* createOrAssignLeaf(size_t leafIndex, const std::vector<int>& bbIds);
AABBTreeNodeLeaf* createOrAssignLeaf(size_t leafIndex);
private:
static void deleteInternalNodesBottomUp(AABBTreeNode* node);
@@ -220,7 +220,7 @@ namespace cvf {
{
BoundingBoxTreeImpl() {}
void buildTree(const std::vector<cvf::BoundingBox>& boundingBoxes, const std::vector<std::vector<int>>& ids);
void buildTree(std::vector<cvf::BoundingBox>&& boundingBoxes, std::vector<int>&& ids, std::vector<size_t>&& idOffsets);
private:
friend class BoundingBoxTree;
@@ -229,9 +229,15 @@ namespace cvf {
void findIntersections(const cvf::BoundingBox& bb, std::vector<size_t>& bbIds) const;
void findIntersections(const cvf::BoundingBox& bb, const AABBTreeNode* node, std::vector<size_t>& ids) const;
void appendLeafIds(const AABBTreeNodeLeaf* leaf, std::vector<size_t>& ids) const;
std::vector<cvf::BoundingBox> m_validBoundingBoxes;
std::vector<std::vector<int>> m_validOptionalBoundingBoxIds;
// The IDs are stored in flat arrays instead of in each leaf, to avoid one allocation per leaf.
// If m_idOffsets is empty, leaf i has the single ID m_ids[i], or the ID i if m_ids is also empty.
// Otherwise, the IDs of leaf i are m_ids[m_idOffsets[i]] to m_ids[m_idOffsets[i + 1] - 1].
std::vector<int> m_ids;
std::vector<size_t> m_idOffsets;
};
}
@@ -413,24 +419,25 @@ void AABBTreeNodeInternal::setRight(AABBTreeNode* right)
//--------------------------------------------------------------------------------------------------
AABBTreeNodeLeaf::AABBTreeNodeLeaf()
{
m_type = AB_LEAF;
m_type = AB_LEAF;
m_index = 0;
}
//--------------------------------------------------------------------------------------------------
///
///
//--------------------------------------------------------------------------------------------------
std::vector<int> AABBTreeNodeLeaf::ids() const
size_t AABBTreeNodeLeaf::index() const
{
return m_ids;
return m_index;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void AABBTreeNodeLeaf::setIds(const std::vector<int>& ids)
void AABBTreeNodeLeaf::setIndex(size_t index)
{
m_ids = ids;
m_index = index;
}
//--------------------------------------------------------------------------------------------------
@@ -779,10 +786,10 @@ cvf::AABBTreeNodeInternal* AABBTree::createNode()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::AABBTreeNodeLeaf* AABBTree::createOrAssignLeaf(size_t leafIndex, const std::vector<int>& bbIds)
cvf::AABBTreeNodeLeaf* AABBTree::createOrAssignLeaf(size_t leafIndex)
{
cvf::AABBTreeNodeLeaf* leaf = &m_leafPool[leafIndex];
leaf->setIds(bbIds);
leaf->setIndex(leafIndex);
return leaf;
}
@@ -821,17 +828,17 @@ void AABBTree::deleteInternalNodesBottomUp(AABBTreeNode* node)
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void BoundingBoxTreeImpl::buildTree(const std::vector<cvf::BoundingBox>& boundingBoxes, const std::vector<std::vector<int>>& ids)
void BoundingBoxTreeImpl::buildTree(std::vector<cvf::BoundingBox>&& boundingBoxes, std::vector<int>&& ids, std::vector<size_t>&& idOffsets)
{
// Assign data used in the tree construction
m_validBoundingBoxes = boundingBoxes;
m_validOptionalBoundingBoxIds = ids;
m_validBoundingBoxes = std::move(boundingBoxes);
m_ids = std::move(ids);
m_idOffsets = std::move(idOffsets);
AABBTree::buildTree();
// Release the memory used by the bounding boxes and ids, as this information is now distributed in the tree
m_validBoundingBoxes.clear();
m_validOptionalBoundingBoxIds.clear();
// Release the memory used by the bounding boxes, as this information is now distributed in the tree
std::vector<cvf::BoundingBox>().swap(m_validBoundingBoxes);
}
//--------------------------------------------------------------------------------------------------
@@ -850,10 +857,7 @@ cvf::BoundingBox BoundingBoxTreeImpl::createLeaves()
#pragma omp for
for (int i = 0; i < (int)m_validBoundingBoxes.size(); i++)
{
std::vector<int> bbIds = {i};
if (!m_validOptionalBoundingBoxIds.empty()) bbIds = m_validOptionalBoundingBoxIds[i];
AABBTreeNodeLeaf* leaf = createOrAssignLeaf(i, bbIds);
AABBTreeNodeLeaf* leaf = createOrAssignLeaf(i);
leaf->setBoundingBox(m_validBoundingBoxes[i]);
@@ -893,13 +897,8 @@ void BoundingBoxTreeImpl::findIntersections(const cvf::BoundingBox& bb, const AA
{
if (node->type() == AB_LEAF)
{
const AABBTreeNodeLeaf* leaf = static_cast<const AABBTreeNodeLeaf*>(node);
{
auto leafIds = leaf->ids();
ids.insert(ids.end(), leafIds.begin(), leafIds.end());
return;
}
appendLeafIds(static_cast<const AABBTreeNodeLeaf*>(node), ids);
return;
}
else if (node->type() == AB_INTERNAL)
{
@@ -912,7 +911,28 @@ void BoundingBoxTreeImpl::findIntersections(const cvf::BoundingBox& bb, const AA
}
//--------------------------------------------------------------------------------------------------
///
///
//--------------------------------------------------------------------------------------------------
void BoundingBoxTreeImpl::appendLeafIds(const AABBTreeNodeLeaf* leaf, std::vector<size_t>& ids) const
{
const size_t leafIndex = leaf->index();
if (!m_idOffsets.empty())
{
ids.insert(ids.end(), m_ids.begin() + m_idOffsets[leafIndex], m_ids.begin() + m_idOffsets[leafIndex + 1]);
}
else if (!m_ids.empty())
{
ids.push_back(static_cast<size_t>(m_ids[leafIndex]));
}
else
{
ids.push_back(leafIndex);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
BoundingBoxTree::BoundingBoxTree()
{
@@ -938,11 +958,11 @@ void BoundingBoxTree::buildTreeFromBoundingBoxes(const std::vector<cvf::Bounding
if (optionalBoundingBoxIds) CVF_ASSERT(boundingBoxes.size() == optionalBoundingBoxIds->size());
std::vector<cvf::BoundingBox> validBoundingBoxes;
std::vector<std::vector<int>> validOptionalBoundingBoxIds;
std::vector<int> validBoundingBoxIds;
validBoundingBoxes.reserve(boundingBoxes.size());
if (optionalBoundingBoxIds)
validOptionalBoundingBoxIds.reserve(optionalBoundingBoxIds->size());
validBoundingBoxIds.reserve(optionalBoundingBoxIds->size());
for (size_t i = 0; i < boundingBoxes.size(); ++i)
{
@@ -951,15 +971,12 @@ void BoundingBoxTree::buildTreeFromBoundingBoxes(const std::vector<cvf::Bounding
validBoundingBoxes.push_back(boundingBoxes[i]);
if (optionalBoundingBoxIds)
{
const auto& id = (*optionalBoundingBoxIds)[i];
std::vector<int> ids = {static_cast<int>(id)};
validOptionalBoundingBoxIds.push_back(ids);
validBoundingBoxIds.push_back(static_cast<int>((*optionalBoundingBoxIds)[i]));
}
}
}
m_implTree->buildTree(validBoundingBoxes, validOptionalBoundingBoxIds);
m_implTree->buildTree(std::move(validBoundingBoxes), std::move(validBoundingBoxIds), {});
}
//--------------------------------------------------------------------------------------------------
@@ -969,18 +986,24 @@ void BoundingBoxTree::buildTreeFromBoundingBoxesOptimized(const std::vector<cvf:
const std::vector<std::vector<int>>& optionalBoundingBoxIds)
{
std::vector<cvf::BoundingBox> validBoundingBoxes;
std::vector<std::vector<int>> validOptionalBoundingBoxIds;
std::vector<int> validBoundingBoxIds;
std::vector<size_t> validBoundingBoxIdOffsets;
validBoundingBoxes.reserve(boundingBoxes.size());
validBoundingBoxIdOffsets.reserve(boundingBoxes.size() + 1);
validBoundingBoxIdOffsets.push_back(0);
for (int i = 0; i < (int)boundingBoxes.size(); ++i)
{
if (boundingBoxes[i].isValid())
{
validBoundingBoxes.push_back(boundingBoxes[i]);
validOptionalBoundingBoxIds.push_back(optionalBoundingBoxIds[i]);
validBoundingBoxIds.insert(validBoundingBoxIds.end(), optionalBoundingBoxIds[i].begin(), optionalBoundingBoxIds[i].end());
validBoundingBoxIdOffsets.push_back(validBoundingBoxIds.size());
}
}
m_implTree->buildTree(validBoundingBoxes, validOptionalBoundingBoxIds);
m_implTree->buildTree(std::move(validBoundingBoxes), std::move(validBoundingBoxIds), std::move(validBoundingBoxIdOffsets));
}
//--------------------------------------------------------------------------------------------------