Merge topic 'add/ct_iter_check'
ca86402f9 Provide additional debug info in case contour tree hangs 48d91b99f Throw exception if merge tree gets stuck in a loop c7ea03ee2 Throw exception if contour tree gets stuck in a loop Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !2420
This commit is contained in:
commit
fa0ce37b96
@ -377,6 +377,7 @@ inline void ActiveGraph::MakeMergeTree(MergeTree& tree, MeshExtrema& meshExtrema
|
||||
DebugPrint("Active Graph Computation Starting", __FILE__, __LINE__);
|
||||
|
||||
// loop until we run out of active edges
|
||||
vtkm::Id maxNumIterations = this->EdgeSorter.GetNumberOfValues();
|
||||
this->NumIterations = 0;
|
||||
while (true)
|
||||
{ // main loop
|
||||
@ -385,7 +386,16 @@ inline void ActiveGraph::MakeMergeTree(MergeTree& tree, MeshExtrema& meshExtrema
|
||||
|
||||
// test whether there are any left (if not, we're on the trunk)
|
||||
if (this->EdgeSorter.GetNumberOfValues() <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// test whether we are in a bad infinite loop due to bad input data. Usually
|
||||
// this is not an issue for the merge tree (only for the contour tree), but
|
||||
// we check just to make absolutely sure we won't get stuck in an infinite loop
|
||||
if (this->NumIterations >= maxNumIterations)
|
||||
{
|
||||
throw new std::domain_error("Bad iteration. Merge tree unable to process all edges.");
|
||||
}
|
||||
|
||||
// find & label the extrema with their governing saddles
|
||||
FindGoverningSaddles();
|
||||
|
@ -201,6 +201,7 @@ inline void ContourTreeMaker::ComputeHyperAndSuperStructure()
|
||||
// tree can end with either 0 or 1 vertices unprocessed
|
||||
// 0 means the last edge was pruned from both ends
|
||||
// 1 means that there were two final edges meeting at a vertex
|
||||
vtkm::Id maxNumIterations = this->ActiveSupernodes.GetNumberOfValues();
|
||||
while (this->ActiveSupernodes.GetNumberOfValues() > 1)
|
||||
{ // loop until no active vertices remaining
|
||||
// recompute the vertex degrees
|
||||
@ -218,6 +219,15 @@ inline void ContourTreeMaker::ComputeHyperAndSuperStructure()
|
||||
CompressActiveSupernodes();
|
||||
this->ContourTreeResult.NumIterations++;
|
||||
|
||||
// Check to make sure we are not iterating too long
|
||||
// this can happen if we are given a bad mesh that defines
|
||||
// a forest of contour trees, rather than a single tree.
|
||||
// Raise error if we have done more itertions than there are active nodes to remove
|
||||
if (this->ContourTreeResult.NumIterations >= maxNumIterations)
|
||||
{
|
||||
throw new std::domain_error("Bad iteration. This can happen if the input mesh "
|
||||
"defines a contour forest rather than a simple tree.");
|
||||
}
|
||||
} // loop until no active vertices remaining
|
||||
|
||||
// test for final edges meeting
|
||||
|
@ -95,12 +95,14 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/// Operator used by DIY to compute a step in the fan in
|
||||
/// @param[in] block The local data block to be processed in this step. Instance of DistributedContourTreeBlockData.
|
||||
/// @param[in] rp DIY communication proxy
|
||||
/// @param[in] unused partners of the current block (unused)
|
||||
void operator()(
|
||||
vtkm::worklet::contourtree_distributed::DistributedContourTreeBlockData<FieldType>*
|
||||
block, // local Block.
|
||||
const vtkmdiy::ReduceProxy& rp, // communication proxy
|
||||
const vtkmdiy::RegularSwapPartners& // partners of the current block (unused)
|
||||
) const
|
||||
vtkm::worklet::contourtree_distributed::DistributedContourTreeBlockData<FieldType>* block,
|
||||
const vtkmdiy::ReduceProxy& rp,
|
||||
const vtkmdiy::RegularSwapPartners&) const
|
||||
{
|
||||
// Track timing of main steps
|
||||
vtkm::cont::Timer totalTimer; // Total time for each call
|
||||
@ -218,14 +220,39 @@ public:
|
||||
currBlockOrigin[2] + currBlockSize[2] - 1 };
|
||||
auto meshBoundaryExecObj = block->ContourTreeMeshes.back().GetMeshBoundaryExecutionObject(
|
||||
this->GlobalSize, currBlockOrigin, maxIdx);
|
||||
worklet.Run(block->ContourTreeMeshes.back()
|
||||
.SortedValues, // Unused param. Provide something to keep the API happy
|
||||
block->ContourTreeMeshes.back(),
|
||||
block->ContourTrees.back(),
|
||||
currSortOrder,
|
||||
currNumIterations,
|
||||
1, // Fully augmented
|
||||
meshBoundaryExecObj);
|
||||
try
|
||||
{
|
||||
worklet.Run(block->ContourTreeMeshes.back()
|
||||
.SortedValues, // Unused param. Provide something to keep the API happy
|
||||
block->ContourTreeMeshes.back(),
|
||||
block->ContourTrees.back(),
|
||||
currSortOrder,
|
||||
currNumIterations,
|
||||
1, // Fully augmented
|
||||
meshBoundaryExecObj);
|
||||
}
|
||||
// In case the contour tree got stuck, expand the debug information from
|
||||
// the message to check whether we combined bad blocks
|
||||
catch (const std::domain_error& ex)
|
||||
{
|
||||
std::stringstream ex_message;
|
||||
ex_message << ex.what();
|
||||
ex_message << " Self/In DIY Id=(" << selfid << ", " << ingid << ")";
|
||||
ex_message << " Rank=" << rank << " Round=" << rp.round();
|
||||
ex_message << " Origin Self=(" << block->BlockOrigin[0] << ", " << block->BlockOrigin[1]
|
||||
<< ", " << block->BlockOrigin[2] << ")";
|
||||
ex_message << " Origin In=(" << otherBlockOrigin[0] << ", " << otherBlockOrigin[1] << ", "
|
||||
<< otherBlockOrigin[2] << ")";
|
||||
ex_message << " Origin Comb=(" << currBlockOrigin[0] << ", " << currBlockOrigin[1] << ", "
|
||||
<< currBlockOrigin[2] << ")";
|
||||
ex_message << " Size Self=(" << block->BlockSize[0] << ", " << block->BlockSize[1] << ", "
|
||||
<< block->BlockSize[2] << ")";
|
||||
ex_message << " Size In=(" << otherBlockSize[0] << ", " << otherBlockSize[1] << ", "
|
||||
<< otherBlockSize[2] << ")";
|
||||
ex_message << " Size Comb=(" << currBlockSize[0] << ", " << currBlockSize[1] << ", "
|
||||
<< currBlockSize[2] << ")";
|
||||
std::throw_with_nested(std::domain_error(ex_message.str()));
|
||||
}
|
||||
|
||||
// Update block extents
|
||||
block->BlockOrigin = currBlockOrigin;
|
||||
|
Loading…
Reference in New Issue
Block a user