Non-recursive method to find cells in BoundingIntervalHierarchyExec

CUDA devices have problems with recursive algorithms that have no well-
defined depth because the stack on a CUDA device tends to be pretty
short. Fix the problem for BoundingIntervalHierarchyExec by changing to
a state-machine based algorithm that follows the hierarchy up and down.
This commit is contained in:
Kenneth Moreland 2018-07-12 15:04:50 -06:00
parent c463bbec93
commit c008df90cc

@ -66,47 +66,126 @@ public:
vtkm::Vec<vtkm::FloatDefault, 3>& parametric, vtkm::Vec<vtkm::FloatDefault, 3>& parametric,
const vtkm::exec::FunctorBase& worklet) const override const vtkm::exec::FunctorBase& worklet) const override
{ {
cellId = Find(0, point, parametric, worklet); cellId = -1;
vtkm::Id nodeIndex = 0;
FindCellState state = FindCellState::EnterNode;
while ((cellId < 0) && !((nodeIndex == 0) && (state == FindCellState::AscendFromNode)))
{
switch (state)
{
case FindCellState::EnterNode:
this->EnterNode(state, point, cellId, nodeIndex, parametric, worklet);
break;
case FindCellState::AscendFromNode:
this->AscendFromNode(state, nodeIndex);
break;
case FindCellState::DescendLeftChild:
this->DescendLeftChild(state, point, nodeIndex);
break;
case FindCellState::DescendRightChild:
this->DescendRightChild(state, point, nodeIndex);
break;
}
}
} }
private: private:
VTKM_EXEC vtkm::Id Find(vtkm::Id index, enum struct FindCellState
const vtkm::Vec<vtkm::FloatDefault, 3>& point,
vtkm::Vec<vtkm::FloatDefault, 3>& parametric,
const vtkm::exec::FunctorBase& worklet) const
{ {
const vtkm::cont::BoundingIntervalHierarchyNode& node = Nodes.Get(index); EnterNode,
AscendFromNode,
DescendLeftChild,
DescendRightChild
};
VTKM_EXEC
void EnterNode(FindCellState& state,
const vtkm::Vec<vtkm::FloatDefault, 3>& point,
vtkm::Id& cellId,
vtkm::Id nodeIndex,
vtkm::Vec<vtkm::FloatDefault, 3>& parametric,
const vtkm::exec::FunctorBase& worklet) const
{
VTKM_ASSERT(state == FindCellState::EnterNode);
const vtkm::cont::BoundingIntervalHierarchyNode& node = this->Nodes.Get(nodeIndex);
if (node.ChildIndex < 0) if (node.ChildIndex < 0)
{ {
return FindInLeaf(point, parametric, node, worklet); // In a leaf node. Look for a containing cell.
cellId = this->FindInLeaf(point, parametric, node, worklet);
state = FindCellState::AscendFromNode;
} }
else else
{ {
const vtkm::FloatDefault& c = point[node.Dimension]; state = FindCellState::DescendLeftChild;
vtkm::Id id1 = -1; }
vtkm::Id id2 = -1; }
if (c <= node.Node.LMax)
{ VTKM_EXEC
VTKM_ASSERT(Nodes.Get(node.ChildIndex).ParentIndex == index); void AscendFromNode(FindCellState& state, vtkm::Id& nodeIndex) const
id1 = Find(node.ChildIndex, point, parametric, worklet); {
} VTKM_ASSERT(state == FindCellState::AscendFromNode);
if (id1 == -1 && c >= node.Node.RMin)
{ vtkm::Id childNodeIndex = nodeIndex;
VTKM_ASSERT(Nodes.Get(node.ChildIndex + 1).ParentIndex == index); const vtkm::cont::BoundingIntervalHierarchyNode& childNode = this->Nodes.Get(childNodeIndex);
id2 = Find(node.ChildIndex + 1, point, parametric, worklet); nodeIndex = childNode.ParentIndex;
} const vtkm::cont::BoundingIntervalHierarchyNode& parentNode = this->Nodes.Get(nodeIndex);
if (id1 == -1 && id2 == -1)
{ if (parentNode.ChildIndex == childNodeIndex)
return -1; {
} // Ascending from left child. Descend into the right child.
else if (id1 == -1) state = FindCellState::DescendRightChild;
{ }
return id2; else
} {
else VTKM_ASSERT(parentNode.ChildIndex + 1 == childNodeIndex);
{ // Ascending from right child. Ascend again. (Don't need to change state.)
return id1; }
} }
VTKM_EXEC
void DescendLeftChild(FindCellState& state,
const vtkm::Vec<vtkm::FloatDefault, 3>& point,
vtkm::Id& nodeIndex) const
{
VTKM_ASSERT(state == FindCellState::DescendLeftChild);
const vtkm::cont::BoundingIntervalHierarchyNode& node = this->Nodes.Get(nodeIndex);
const vtkm::FloatDefault& coordinate = point[node.Dimension];
if (coordinate <= node.Node.LMax)
{
// Left child does contain the point. Do the actual descent.
nodeIndex = node.ChildIndex;
state = FindCellState::EnterNode;
}
else
{
// Left child does not contain the point. Skip to the right child.
state = FindCellState::DescendRightChild;
}
}
VTKM_EXEC
void DescendRightChild(FindCellState& state,
const vtkm::Vec<vtkm::FloatDefault, 3>& point,
vtkm::Id& nodeIndex) const
{
VTKM_ASSERT(state == FindCellState::DescendRightChild);
const vtkm::cont::BoundingIntervalHierarchyNode& node = this->Nodes.Get(nodeIndex);
const vtkm::FloatDefault& coordinate = point[node.Dimension];
if (coordinate >= node.Node.RMin)
{
// Right child does contain the point. Do the actual descent.
nodeIndex = node.ChildIndex + 1;
state = FindCellState::EnterNode;
}
else
{
// Right child does not contain the point. Skip to ascent
state = FindCellState::AscendFromNode;
} }
} }