Compare commits

...

2 Commits

9 changed files with 821 additions and 548 deletions

@ -186,30 +186,30 @@ VTKM_CONT vtkm::cont::PartitionedDataSet SelectTopVolumeContoursFilter::DoExecut
branch_top_volume_master.foreach ([&](SelectTopVolumeContoursBlock* b,
const vtkmdiy::Master::ProxyWithLink&) {
vtkm::cont::Field BranchVolumeField(
"BranchVolume", vtkm::cont::Field::Association::WholeDataSet, b->BranchVolume);
"BranchVolume", vtkm::cont::Field::Association::WholeDataSet, b->tData.BranchVolume);
outputDataSets[b->LocalBlockNo].AddField(BranchVolumeField);
vtkm::cont::Field BranchSaddleEpsilonField(
"BranchSaddleEpsilon", vtkm::cont::Field::Association::WholeDataSet, b->BranchSaddleEpsilon);
"BranchSaddleEpsilon", vtkm::cont::Field::Association::WholeDataSet, b->tData.BranchSaddleEpsilon);
outputDataSets[b->LocalBlockNo].AddField(BranchSaddleEpsilonField);
vtkm::cont::Field TopVolBranchUpperEndField("TopVolumeBranchUpperEnd",
vtkm::cont::Field::Association::WholeDataSet,
b->TopVolumeBranchUpperEndGRId);
b->tData.TopVolumeBranchUpperEndGRId);
outputDataSets[b->LocalBlockNo].AddField(TopVolBranchUpperEndField);
vtkm::cont::Field TopVolBranchLowerEndField("TopVolumeBranchLowerEnd",
vtkm::cont::Field::Association::WholeDataSet,
b->TopVolumeBranchLowerEndGRId);
b->tData.TopVolumeBranchLowerEndGRId);
outputDataSets[b->LocalBlockNo].AddField(TopVolBranchLowerEndField);
vtkm::cont::Field TopVolumeBranchGRIdsField("TopVolumeBranchGlobalRegularIds",
vtkm::cont::Field::Association::WholeDataSet,
b->TopVolumeBranchRootGRId);
b->tData.TopVolumeBranchRootGRId);
outputDataSets[b->LocalBlockNo].AddField(TopVolumeBranchGRIdsField);
vtkm::cont::Field TopVolBranchVolumeField("TopVolumeBranchVolume",
vtkm::cont::Field::Association::WholeDataSet,
b->TopVolumeBranchVolume);
b->tData.TopVolumeBranchVolume);
outputDataSets[b->LocalBlockNo].AddField(TopVolBranchVolumeField);
vtkm::cont::Field TopVolBranchSaddleEpsilonField("TopVolumeBranchSaddleEpsilon",
vtkm::cont::Field::Association::WholeDataSet,
b->TopVolumeBranchSaddleEpsilon);
b->tData.TopVolumeBranchSaddleEpsilon);
outputDataSets[b->LocalBlockNo].AddField(TopVolBranchSaddleEpsilonField);
vtkm::cont::Field IsosurfaceEdgeFromField(
@ -243,7 +243,7 @@ VTKM_CONT vtkm::cont::PartitionedDataSet SelectTopVolumeContoursFilter::DoExecut
"TopVolumeBranchSaddleIsoValue", vtkm::cont::Field::Association::WholeDataSet, inArray);
outputDataSets[b->LocalBlockNo].AddField(TopVolBranchSaddleIsoValueField);
};
b->TopVolumeBranchSaddleIsoValue
b->tData.TopVolumeBranchSaddleIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(resolveArray);
});

@ -73,9 +73,9 @@ public:
this->isMarchingCubes = marchingCubes;
}
VTKM_CONT const vtkm::Id GetSavedBranches() { return this->nSavedBranches; }
VTKM_CONT const bool GetMarchingCubes() { return this->isMarchingCubes; }
VTKM_CONT const vtkm::cont::LogLevel GetTimingsLogLevel() { return this->TimingsLogLevel; }
VTKM_CONT vtkm::Id GetSavedBranches() { return this->nSavedBranches; }
VTKM_CONT bool GetMarchingCubes() { return this->isMarchingCubes; }
VTKM_CONT vtkm::cont::LogLevel GetTimingsLogLevel() { return this->TimingsLogLevel; }
private:
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet&) override;

@ -97,7 +97,7 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Block " << b->GlobalBlockId << " enqueue to Block " << target.gid);
#endif
auto extraMaximaBranchOrderPortal = b->ExtraMaximaBranchOrder.ReadPortal();
auto extraMaximaBranchOrderPortal = b->tData.ExtraMaximaBranchOrder.ReadPortal();
vtkm::Id nExtraMaxBranches = extraMaximaBranchOrderPortal.GetNumberOfValues();
rp.enqueue(target, nExtraMaxBranches);
@ -112,14 +112,14 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
for (vtkm::Id branch = 0; branch < nExtraMaxBranches; ++branch)
rp.enqueue<ValueType>(target, extraMaxBranchIsoValuePortal.Get(branch));
};
if (b->ExtraMaximaBranchIsoValue.GetNumberOfValues())
b->ExtraMaximaBranchIsoValue
if (b->tData.ExtraMaximaBranchIsoValue.GetNumberOfValues())
b->tData.ExtraMaximaBranchIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
resolveMaxArray);
// rp.enqueue(target, b->ExtraMaximaBranchOrder);
// rp.enqueue(target, b->ExtraMaximaBranchIsoValue);
// rp.enqueue(target, b->tData.ExtraMaximaBranchOrder);
// rp.enqueue(target, b->tData.ExtraMaximaBranchIsoValue);
auto extraMinimaBranchOrderPortal = b->ExtraMinimaBranchOrder.ReadPortal();
auto extraMinimaBranchOrderPortal = b->tData.ExtraMinimaBranchOrder.ReadPortal();
vtkm::Id nExtraMinBranches = extraMinimaBranchOrderPortal.GetNumberOfValues();
rp.enqueue(target, nExtraMinBranches);
@ -134,12 +134,12 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
for (vtkm::Id branch = 0; branch < nExtraMinBranches; ++branch)
rp.enqueue<ValueType>(target, extraMinBranchIsoValuePortal.Get(branch));
};
if (b->ExtraMinimaBranchIsoValue.GetNumberOfValues())
b->ExtraMinimaBranchIsoValue
if (b->tData.ExtraMinimaBranchIsoValue.GetNumberOfValues())
b->tData.ExtraMinimaBranchIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
resolveMinArray);
// rp.enqueue(target, b->ExtraMinimaBranchOrder);
// rp.enqueue(target, b->ExtraMinimaBranchIsoValue);
// rp.enqueue(target, b->tData.ExtraMinimaBranchOrder);
// rp.enqueue(target, b->tData.ExtraMinimaBranchIsoValue);
}
}
}
@ -159,8 +159,8 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
"Combining local block " << b->GlobalBlockId << " with incoming block "
<< incomingGlobalBlockId);
#endif
vtkm::Id nSelfMaxBranch = b->ExtraMaximaBranchOrder.GetNumberOfValues();
vtkm::Id nSelfMinBranch = b->ExtraMinimaBranchOrder.GetNumberOfValues();
vtkm::Id nSelfMaxBranch = b->tData.ExtraMaximaBranchOrder.GetNumberOfValues();
vtkm::Id nSelfMinBranch = b->tData.ExtraMinimaBranchOrder.GetNumberOfValues();
// dequeue the data from other blocks.
// nExtraMaximaBranches (incoming)
@ -216,7 +216,7 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
vtkm::worklet::contourtree_augmented::PrintHeader(nSelfMaxBranch, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfMaxBranchOrder", b->ExtraMaximaBranchOrder, -1, rs);
"selfMaxBranchOrder", b->tData.ExtraMaximaBranchOrder, -1, rs);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"selfMaxBranchVal", inArray, -1, rs);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, rs.str());
@ -227,7 +227,7 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
vtkm::worklet::scalar_topology::select_top_volume_contours::UpdateOuterSaddle<true>
updateValueOnMaxBranch;
invoke(updateValueOnMaxBranch,
b->ExtraMaximaBranchOrder,
b->tData.ExtraMaximaBranchOrder,
inArray,
incomingMaxBranchOrder,
incomingMaxBranchIsoValue);
@ -238,7 +238,7 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
rs << "After update, block " << b->LocalBlockNo << std::endl;
vtkm::worklet::contourtree_augmented::PrintHeader(nSelfMaxBranch, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfMaxBranchOrder", b->ExtraMaximaBranchOrder, -1, rs);
"selfMaxBranchOrder", b->tData.ExtraMaximaBranchOrder, -1, rs);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"selfMaxBranchVal", inArray, -1, rs);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, rs.str());
@ -246,7 +246,7 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
#endif
};
if (nSelfMaxBranch > 0 && nIncomingMaxBranch > 0)
b->ExtraMaximaBranchIsoValue
b->tData.ExtraMaximaBranchIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
resolveMaxArray);
@ -296,7 +296,7 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
vtkm::worklet::contourtree_augmented::PrintHeader(nSelfMinBranch, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfMinBranchOrder", b->ExtraMinimaBranchOrder, -1, rs);
"selfMinBranchOrder", b->tData.ExtraMinimaBranchOrder, -1, rs);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"selfMinBranchVal", inArray, -1, rs);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, rs.str());
@ -307,7 +307,7 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
vtkm::worklet::scalar_topology::select_top_volume_contours::UpdateOuterSaddle<false>
updateValueOnMinBranch;
invoke(updateValueOnMinBranch,
b->ExtraMinimaBranchOrder,
b->tData.ExtraMinimaBranchOrder,
inArray,
incomingMinBranchOrder,
incomingMinBranchIsoValue);
@ -318,7 +318,7 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
rs << "After update, block " << b->LocalBlockNo << std::endl;
vtkm::worklet::contourtree_augmented::PrintHeader(nSelfMinBranch, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfMinBranchOrder", b->ExtraMinimaBranchOrder, -1, rs);
"selfMinBranchOrder", b->tData.ExtraMinimaBranchOrder, -1, rs);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"selfMinBranchVal", inArray, -1, rs);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, rs.str());
@ -326,7 +326,7 @@ void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
#endif
};
if (nSelfMinBranch > 0 && nIncomingMinBranch > 0)
b->ExtraMinimaBranchIsoValue
b->tData.ExtraMinimaBranchIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
resolveMinArray);

@ -77,12 +77,6 @@ namespace scalar_topology
namespace internal
{
struct IsNegativeDebug
{
VTKM_EXEC_CONT IsNegativeDebug() {}
VTKM_EXEC_CONT bool operator()(vtkm::Id x) const { return x < 0; }
};
SelectTopVolumeContoursBlock::SelectTopVolumeContoursBlock(vtkm::Id localBlockNo, int globalBlockId)
: LocalBlockNo(localBlockNo)
, GlobalBlockId(globalBlockId)
@ -161,7 +155,7 @@ void SelectTopVolumeContoursBlock::SortBranchByVolume(const vtkm::cont::DataSet&
vtkm::cont::ArrayHandle<ValueType> branchSaddleIsoValue;
branchSaddleIsoValue.Allocate(isLowerLeaf.GetNumberOfValues());
this->BranchSaddleEpsilon.Allocate(isLowerLeaf.GetNumberOfValues());
tData.BranchSaddleEpsilon.Allocate(isLowerLeaf.GetNumberOfValues());
vtkm::worklet::scalar_topology::select_top_volume_contours::UpdateInfoByBranchDirectionWorklet<
ValueType>
@ -175,9 +169,9 @@ void SelectTopVolumeContoursBlock::SortBranchByVolume(const vtkm::cont::DataSet&
isUpperLeaf,
inArray,
lowerEndValue,
this->BranchSaddleEpsilon,
tData.BranchSaddleEpsilon,
branchSaddleIsoValue);
this->BranchSaddleIsoValue = branchSaddleIsoValue;
tData.BranchSaddleIsoValue = branchSaddleIsoValue;
};
upperEndValue.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
@ -224,7 +218,7 @@ void SelectTopVolumeContoursBlock::SortBranchByVolume(const vtkm::cont::DataSet&
VTKM_LOG_S(vtkm::cont::LogLevel::Info, resultStream.str());
#endif
vtkm::cont::Algorithm::Copy(branchVolume, this->BranchVolume);
vtkm::cont::Algorithm::Copy(branchVolume, tData.BranchVolume);
const vtkm::Id nBranches = lowerEndSuperarcId.GetNumberOfValues();
vtkm::cont::ArrayHandleIndex branchesIdx(nBranches);
@ -233,7 +227,7 @@ void SelectTopVolumeContoursBlock::SortBranchByVolume(const vtkm::cont::DataSet&
// sort the branch volume
vtkm::cont::Algorithm::SortByKey(branchVolume, sortedBranches, vtkm::SortGreater());
vtkm::cont::Algorithm::Copy(sortedBranches, this->SortedBranchByVolume);
vtkm::cont::Algorithm::Copy(sortedBranches, tData.SortedBranchByVolume);
}
// Select the local top K branches by volume
@ -244,11 +238,11 @@ void SelectTopVolumeContoursBlock::SelectLocalTopVolumeBranch(const vtkm::cont::
// copy the top volume branches into a smaller array
// we skip index 0 because it must be the main branch (which has the highest volume)
vtkm::Id nActualSavedBranches =
std::min(nSavedBranches, this->SortedBranchByVolume.GetNumberOfValues() - 1);
std::min(nSavedBranches, tData.SortedBranchByVolume.GetNumberOfValues() - 1);
vtkm::worklet::contourtree_augmented::IdArrayType topVolumeBranch;
vtkm::cont::Algorithm::CopySubRange(
this->SortedBranchByVolume, 1, nActualSavedBranches, topVolumeBranch);
tData.SortedBranchByVolume, 1, nActualSavedBranches, topVolumeBranch);
auto branchRootByBranch = bdDataset.GetField("BranchRootByBranch")
.GetData()
@ -268,37 +262,37 @@ void SelectTopVolumeContoursBlock::SelectLocalTopVolumeBranch(const vtkm::cont::
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
vtkm::cont::Algorithm::Copy(branchRootByBranch, this->BranchRootByBranch);
vtkm::cont::Algorithm::Copy(branchRootGRId, this->BranchRootGRId);
vtkm::cont::Algorithm::Copy(branchRootByBranch, tData.BranchRootByBranch);
vtkm::cont::Algorithm::Copy(branchRootGRId, tData.BranchRootGRId);
// This seems weird, but we temporarily put the initialization of computing the branch decomposition tree here
this->IsParentBranch.AllocateAndFill(nBranches, false);
tData.IsParentBranch.AllocateAndFill(nBranches, false);
// we permute all branch information to align with the order by volume
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
branchRootGRId, topVolumeBranch, this->TopVolumeBranchRootGRId);
branchRootGRId, topVolumeBranch, tData.TopVolumeBranchRootGRId);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
upperEndGRId, topVolumeBranch, this->TopVolumeBranchUpperEndGRId);
upperEndGRId, topVolumeBranch, tData.TopVolumeBranchUpperEndGRId);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
lowerEndGRId, topVolumeBranch, this->TopVolumeBranchLowerEndGRId);
lowerEndGRId, topVolumeBranch, tData.TopVolumeBranchLowerEndGRId);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
this->BranchVolume, topVolumeBranch, this->TopVolumeBranchVolume);
tData.BranchVolume, topVolumeBranch, tData.TopVolumeBranchVolume);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
this->BranchSaddleEpsilon, topVolumeBranch, this->TopVolumeBranchSaddleEpsilon);
tData.BranchSaddleEpsilon, topVolumeBranch, tData.TopVolumeBranchSaddleEpsilon);
auto resolveArray = [&](const auto& inArray) {
using InArrayHandleType = std::decay_t<decltype(inArray)>;
InArrayHandleType topVolBranchSaddleIsoValue;
vtkm::worklet::contourtree_augmented::PermuteArrayWithRawIndex<InArrayHandleType>(
inArray, topVolumeBranch, topVolBranchSaddleIsoValue);
this->TopVolumeBranchSaddleIsoValue = topVolBranchSaddleIsoValue;
tData.TopVolumeBranchSaddleIsoValue = topVolBranchSaddleIsoValue;
};
this->BranchSaddleIsoValue
tData.BranchSaddleIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(resolveArray);
}
@ -306,390 +300,7 @@ void SelectTopVolumeContoursBlock::SelectLocalTopVolumeBranch(const vtkm::cont::
void SelectTopVolumeContoursBlock::ComputeTopVolumeBranchHierarchy(
const vtkm::cont::DataSet& bdDataSet)
{
using vtkm::worklet::contourtree_augmented::IdArrayType;
vtkm::cont::Invoker invoke;
// we need upper/lower local ends and global ends for hierarchy of branches
auto upperLocalEndIds = bdDataSet.GetField("UpperEndLocalIds")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
auto lowerLocalEndIds = bdDataSet.GetField("LowerEndLocalIds")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
auto globalRegularIds = bdDataSet.GetField("RegularNodeGlobalIds")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
IdArrayType upperEndGRIds =
bdDataSet.GetField("UpperEndGlobalRegularIds").GetData().AsArrayHandle<IdArrayType>();
IdArrayType lowerEndGRIds =
bdDataSet.GetField("LowerEndGlobalRegularIds").GetData().AsArrayHandle<IdArrayType>();
// let's check which top volume branches are known by the block
// We check the branchGRId of top volume branches to see whether there are matches within the block
const vtkm::Id nTopVolBranches = this->TopVolumeBranchLowerEndGRId.GetNumberOfValues();
// sortedBranchOrder: the branch order (in the ascending order of branch root)
// the high-level idea is to sort the branch root global regular ids
// and for each top-volume branch, we use binary search to get the original branch index
// if the top-volume branch does not exist in the block, it will be dropped out
IdArrayType sortedBranchGRId;
IdArrayType sortedBranchOrder;
vtkm::cont::Algorithm::Copy(
vtkm::cont::ArrayHandleIndex(this->BranchRootGRId.GetNumberOfValues()), sortedBranchOrder);
vtkm::cont::Algorithm::Copy(this->BranchRootGRId, sortedBranchGRId);
vtkm::cont::Algorithm::SortByKey(sortedBranchGRId, sortedBranchOrder);
this->TopVolBranchKnownByBlockStencil.Allocate(nTopVolBranches);
this->TopVolBranchGROrder.Allocate(nTopVolBranches);
// We reuse the IdxIfWithinBlockWorklet.
// This worklet searches for given values in a sorted array and returns the stencil & index if the value exists in the array.
// this->TopVolBranchGROrder: the order of the topVolBranch among all known branches if the branch is known by the block.
auto idxIfBranchWithinBlockWorklet =
vtkm::worklet::scalar_topology::select_top_volume_contours::IdxIfWithinBlockWorklet();
invoke(idxIfBranchWithinBlockWorklet,
this->TopVolumeBranchRootGRId,
sortedBranchGRId,
this->TopVolBranchKnownByBlockStencil,
this->TopVolBranchGROrder);
// Dropping out top-volume branches that are not known by the block.
// the index of top-volume branches known by the block among all top-volume branches
IdArrayType topVolBranchKnownByBlockIndex;
vtkm::cont::ArrayHandleIndex topVolBranchesIndex(nTopVolBranches);
vtkm::cont::Algorithm::CopyIf(
topVolBranchesIndex, this->TopVolBranchKnownByBlockStencil, topVolBranchKnownByBlockIndex);
const vtkm::Id nTopVolBranchKnownByBlock = topVolBranchKnownByBlockIndex.GetNumberOfValues();
// filtered this->TopVolBranchGROrder, by removing NO_SUCH_ELEMENT
IdArrayType topVolBranchFilteredGROrder;
// this->TopVolBranchInfoActualIndex: the information index of the top-volume branch
vtkm::cont::Algorithm::CopyIf(
this->TopVolBranchGROrder, this->TopVolBranchKnownByBlockStencil, topVolBranchFilteredGROrder);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
sortedBranchOrder, topVolBranchFilteredGROrder, this->TopVolBranchInfoActualIndex);
// filtered branch saddle epsilons, global lower/upper end GR ids,
IdArrayType topVolFilteredBranchSaddleEpsilon;
IdArrayType topVolFilteredLowerEndGRId;
IdArrayType topVolFilteredUpperEndGRId;
vtkm::cont::Algorithm::CopyIf(this->TopVolumeBranchSaddleEpsilon,
this->TopVolBranchKnownByBlockStencil,
topVolFilteredBranchSaddleEpsilon);
vtkm::cont::Algorithm::CopyIf(this->TopVolumeBranchUpperEndGRId,
this->TopVolBranchKnownByBlockStencil,
topVolFilteredUpperEndGRId);
vtkm::cont::Algorithm::CopyIf(this->TopVolumeBranchLowerEndGRId,
this->TopVolBranchKnownByBlockStencil,
topVolFilteredLowerEndGRId);
// for each top-vol branch known by the block
// we get their upper end and lower end local ids
IdArrayType topVolBranchUpperLocalEnd;
IdArrayType topVolBranchLowerLocalEnd;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
upperLocalEndIds, this->TopVolBranchInfoActualIndex, topVolBranchUpperLocalEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
lowerLocalEndIds, this->TopVolBranchInfoActualIndex, topVolBranchLowerLocalEnd);
IdArrayType topVolLowerLocalEndGRId;
IdArrayType topVolUpperLocalEndGRId;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
globalRegularIds, topVolBranchLowerLocalEnd, topVolLowerLocalEndGRId);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
globalRegularIds, topVolBranchUpperLocalEnd, topVolUpperLocalEndGRId);
// Below is the code to compute the branch hierarchy of top-volume branches
// We need this information because we not only want to visualize the contour
// on top-volume branches, but also on their parent branches.
// Because we use volume as the metric, the parent branch of a top-volume branch
// is either a top-volume branch or the root branch (where both ends are leaf nodes)
vtkm::worklet::scalar_topology::select_top_volume_contours::BranchSaddleIsKnownWorklet
branchSaddleIsKnownWorklet;
// the branch saddle local ID if the saddle end is known by the block
IdArrayType branchSaddleIsKnown;
branchSaddleIsKnown.Allocate(nTopVolBranchKnownByBlock);
invoke(branchSaddleIsKnownWorklet, // worklet
topVolFilteredLowerEndGRId, // input
topVolBranchLowerLocalEnd, // input
topVolLowerLocalEndGRId, // input
topVolFilteredUpperEndGRId, // input
topVolBranchUpperLocalEnd, // input
topVolUpperLocalEndGRId, // input
topVolFilteredBranchSaddleEpsilon, // input
branchSaddleIsKnown); // output
// the order of top volume branches with parents known by the block
IdArrayType topVolChildBranch;
IdArrayType topVolChildBranchSaddle;
vtkm::cont::Algorithm::CopyIf(
topVolBranchKnownByBlockIndex,
branchSaddleIsKnown,
topVolChildBranch,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsNonNegative());
vtkm::cont::Algorithm::CopyIf(
branchSaddleIsKnown,
branchSaddleIsKnown,
topVolChildBranchSaddle,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsNonNegative());
const vtkm::Id nChildBranch = topVolChildBranch.GetNumberOfValues();
// to compute the parent branch, we need to
// 1. for the branch saddle end, collect all superarcs involving it
// 2. get the branch information for selected superarcs
// 3. eliminate branch information for branches sharing the same saddle end
auto superarcs =
bdDataSet.GetField("Superarcs").GetData().AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
auto branchRoots =
bdDataSet.GetField("BranchRoots").GetData().AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
VTKM_ASSERT(superarcs.GetNumberOfValues() == branchRoots.GetNumberOfValues());
// we sort all superarcs by target to allow binary search
IdArrayType superarcsByTarget;
vtkm::worklet::scalar_topology::select_top_volume_contours::SuperarcTargetComparator
superarcComparator(superarcs);
vtkm::cont::Algorithm::Copy(vtkm::cont::ArrayHandleIndex(superarcs.GetNumberOfValues()),
superarcsByTarget);
vtkm::cont::Algorithm::Sort(superarcsByTarget, superarcComparator);
IdArrayType permutedSuperarcs;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
superarcs, superarcsByTarget, permutedSuperarcs);
IdArrayType permutedBranchRoots;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
branchRoots, superarcsByTarget, permutedBranchRoots);
// the branch root of the superarc of the branch saddle supernode
IdArrayType topVolChildBranchSaddleBranchRoot;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
branchRoots, topVolChildBranchSaddle, topVolChildBranchSaddleBranchRoot);
// the GR Ids of the superarc of the branch saddle supernode
IdArrayType topVolChildBranchSaddleGRIds;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
globalRegularIds, topVolChildBranchSaddle, topVolChildBranchSaddleGRIds);
// there is a debate to find all superarcs connect to a supernode
// strategy 1. iterate through saddles and parallelize over superarcs for search
// time complexity: O(nTopVolBranches)
// (nTopVolBranches usually <= 100, based on input parameter setting)
//
// strategy 2. parallelize over all saddles and use binary search to find superarcs
// time complexity: O(log_2(nSuperarcs)) (nSuperarcs can be considerably large)
//
// here, we choose strategy 2 for better extendability to high nTopVolBranches
// but in tests using nTopVolBranches <= 10, strategy 1 is generally faster
// note: after getting the branch root superarc, we use binary search to get the branch order
// because BranchRootByBranch is sorted by branch root (superarc) id
#ifdef DEBUG_PRINT
std::stringstream parentBranchStream;
parentBranchStream << "Debug for Parent Branch, Block " << this->LocalBlockNo << std::endl;
vtkm::worklet::contourtree_augmented::PrintHeader(nChildBranch, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Child Branch Saddle", topVolChildBranchSaddle, -1, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Child Saddle Root", topVolChildBranchSaddleBranchRoot, -1, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Child Saddle GR Id", topVolChildBranchSaddleGRIds, -1, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintHeader(superarcs.GetNumberOfValues(),
parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Permuted Superarcs", permutedSuperarcs, -1, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Permuted Branch roots", permutedBranchRoots, -1, parentBranchStream);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, parentBranchStream.str());
#endif // DEBUG_PRINT
// the corresponding parent branch of child branches
IdArrayType topVolChildBranchParent;
topVolChildBranchParent.AllocateAndFill(nChildBranch,
vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT);
vtkm::worklet::scalar_topology::select_top_volume_contours::GetParentBranchWorklet
getParentBranchWorklet;
invoke(getParentBranchWorklet,
topVolChildBranchSaddle,
topVolChildBranchSaddleBranchRoot,
topVolChildBranchSaddleGRIds,
permutedSuperarcs,
permutedBranchRoots,
this->BranchRootByBranch,
upperEndGRIds,
lowerEndGRIds,
topVolChildBranchParent);
this->TopVolumeBranchParent.AllocateAndFill(
nTopVolBranches, vtkm::Id(vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT));
vtkm::worklet::scalar_topology::select_top_volume_contours::AssignValueByIndex assignParentBranch;
// for each top volume branch, assign the parent branch info id in the block
invoke(
assignParentBranch, topVolChildBranch, topVolChildBranchParent, this->TopVolumeBranchParent);
// for each branch, assign true if it is a parent branch
invoke(assignParentBranch,
topVolChildBranchParent,
vtkm::cont::ArrayHandleConstant<bool>(true, nChildBranch),
this->IsParentBranch);
// sort all top-volume branches based on
// 1. parent branch info id: this->TopVolumeBranchParent
// 2. saddle-end value: this->TopVolumeBranchSaddleIsovalue
// 3. branch root global regular id (anything that can break tie)
auto resolveBranchParent = [&](const auto& inArray) {
using InArrayHandleType = std::decay_t<decltype(inArray)>;
using ValueType = typename InArrayHandleType::ValueType;
vtkm::worklet::scalar_topology::select_top_volume_contours::BranchParentComparator<ValueType>
parentComparator(this->TopVolumeBranchParent, inArray, this->TopVolumeBranchRootGRId);
// sort index for all top volume branches
IdArrayType topVolSortForOuterSaddleIdx;
vtkm::cont::Algorithm::Copy(topVolBranchesIndex, topVolSortForOuterSaddleIdx);
vtkm::cont::Algorithm::Sort(topVolSortForOuterSaddleIdx, parentComparator);
IdArrayType parentPermutation;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
this->TopVolumeBranchParent, topVolSortForOuterSaddleIdx, parentPermutation);
// warning: when parent is NO_SUCH_ELEMENT, parentSaddleEps obtains 0
// However, the corresponding element will be discarded in collecting outer saddles
IdArrayType parentSaddleEpsPermutation;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
this->BranchSaddleEpsilon, parentPermutation, parentSaddleEpsPermutation);
// Some branches have parent=NO_SUCH_ELEMENT (no parent)
// we collect the isovalue of the first and/or the last branches for each parent branch
// we collect the first if branchSaddleEpsilon(parent) < 0
// or the last if branchSaddleEpsilon(parent) > 0
// or both if branchSaddleEpsilon(parent) == 0
IdArrayType IsOuterSaddle;
IsOuterSaddle.Allocate(nTopVolBranches);
vtkm::worklet::scalar_topology::select_top_volume_contours::CollectOuterSaddle
collectOuterSaddleWorklet;
invoke(collectOuterSaddleWorklet, parentSaddleEpsPermutation, parentPermutation, IsOuterSaddle);
// after sorting by index back
// each top volume branch know whether it is the outer saddle of its parent
vtkm::cont::Algorithm::SortByKey(topVolSortForOuterSaddleIdx, IsOuterSaddle);
// collect branches that need contours on extra minima/maxima
// we store the information of the parent branches (on both directions)
IdArrayType extraMaximaParentBranch;
IdArrayType extraMinimaParentBranch;
IdArrayType extraMaximaParentBranchRootGRId;
IdArrayType extraMinimaParentBranchRootGRId;
IdArrayType allBranchGRIdByVolume;
IdArrayType branchGRIdByVolumeIdx;
// we need global branch order including the root branch
// this information should be consistent globally
allBranchGRIdByVolume.Allocate(nTopVolBranches + 1);
vtkm::cont::Algorithm::CopySubRange(
this->TopVolumeBranchRootGRId, 0, nTopVolBranches, allBranchGRIdByVolume, 1);
auto topBranchGRIdWritePortal = allBranchGRIdByVolume.WritePortal();
auto sortedBranchByVolPortal = this->SortedBranchByVolume.ReadPortal();
auto branchGRIdReadPortal = this->BranchRootGRId.ReadPortal();
topBranchGRIdWritePortal.Set(0, branchGRIdReadPortal.Get(sortedBranchByVolPortal.Get(0)));
vtkm::cont::Algorithm::Copy(
vtkm::cont::ArrayHandleIndex(allBranchGRIdByVolume.GetNumberOfValues()),
branchGRIdByVolumeIdx);
vtkm::cont::Algorithm::SortByKey(allBranchGRIdByVolume, branchGRIdByVolumeIdx);
vtkm::cont::Algorithm::CopyIf(
this->TopVolumeBranchParent,
IsOuterSaddle,
extraMaximaParentBranch,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMaxima());
vtkm::cont::Algorithm::CopyIf(
this->TopVolumeBranchParent,
IsOuterSaddle,
extraMinimaParentBranch,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMinima());
if (extraMaximaParentBranch.GetNumberOfValues())
{
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
upperLocalEndIds, extraMaximaParentBranch, this->ExtraMaximaBranchUpperEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
lowerLocalEndIds, extraMaximaParentBranch, this->ExtraMaximaBranchLowerEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
this->BranchRootGRId, extraMaximaParentBranch, extraMaximaParentBranchRootGRId);
InArrayHandleType extraMaximaBranchIsoValue;
vtkm::cont::Algorithm::CopyIf(
this->TopVolumeBranchSaddleIsoValue.AsArrayHandle<InArrayHandleType>(),
IsOuterSaddle,
extraMaximaBranchIsoValue,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMaxima());
this->ExtraMaximaBranchIsoValue = extraMaximaBranchIsoValue;
// a worklet to binary search a number in a sorted array and return the index
vtkm::worklet::scalar_topology::select_top_volume_contours::IdxIfWithinBlockWorklet
getParentBranchOrder;
IdArrayType permutedExtraMaximaBranchOrder;
permutedExtraMaximaBranchOrder.Allocate(extraMaximaParentBranchRootGRId.GetNumberOfValues());
vtkm::cont::ArrayHandleDiscard<vtkm::Id> discard;
discard.Allocate(extraMaximaParentBranchRootGRId.GetNumberOfValues());
invoke(getParentBranchOrder,
extraMaximaParentBranchRootGRId,
allBranchGRIdByVolume,
discard,
permutedExtraMaximaBranchOrder);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
branchGRIdByVolumeIdx, permutedExtraMaximaBranchOrder, this->ExtraMaximaBranchOrder);
}
if (extraMinimaParentBranch.GetNumberOfValues())
{
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
upperLocalEndIds, extraMinimaParentBranch, this->ExtraMinimaBranchUpperEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
lowerLocalEndIds, extraMinimaParentBranch, this->ExtraMinimaBranchLowerEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
this->BranchRootGRId, extraMinimaParentBranch, extraMinimaParentBranchRootGRId);
InArrayHandleType extraMinimaBranchIsoValue;
vtkm::cont::Algorithm::CopyIf(
this->TopVolumeBranchSaddleIsoValue.AsArrayHandle<InArrayHandleType>(),
IsOuterSaddle,
extraMinimaBranchIsoValue,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMinima());
this->ExtraMinimaBranchIsoValue = extraMinimaBranchIsoValue;
vtkm::worklet::scalar_topology::select_top_volume_contours::IdxIfWithinBlockWorklet
getParentBranchOrder;
IdArrayType permutedExtraMinimaBranchOrder;
permutedExtraMinimaBranchOrder.Allocate(extraMinimaParentBranchRootGRId.GetNumberOfValues());
vtkm::cont::ArrayHandleDiscard<vtkm::Id> discard;
discard.Allocate(extraMinimaParentBranchRootGRId.GetNumberOfValues());
invoke(getParentBranchOrder,
extraMinimaParentBranchRootGRId,
allBranchGRIdByVolume,
discard,
permutedExtraMinimaBranchOrder);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
branchGRIdByVolumeIdx, permutedExtraMinimaBranchOrder, this->ExtraMinimaBranchOrder);
}
};
this->TopVolumeBranchSaddleIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
resolveBranchParent);
this->bdtMaker.ComputeTopVolumeBranchHierarchy(bdDataSet, this->tData);
}
@ -701,7 +312,7 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
using vtkm::worklet::contourtree_augmented::IdArrayType;
// if no branch to extract from
if (this->TopVolumeBranchRootGRId.GetNumberOfValues() < 1)
if (tData.TopVolumeBranchRootGRId.GetNumberOfValues() < 1)
return;
// Let's create a mesh dataset to extract all the contours first
@ -711,7 +322,7 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
// usage: identifier of the branch
vtkm::cont::Algorithm::Copy(
bdDataSet.GetField("BranchRootGRId").GetData().AsArrayHandle<IdArrayType>(),
this->BranchRootGRId);
tData.BranchRootGRId);
// branch local upper end and lower end
// size: nBranches
@ -893,7 +504,7 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
IdArrayType topVolBranchWithinBlockId;
vtkm::cont::Algorithm::CopyIf(vtkm::cont::ArrayHandleIndex(nIsoValues),
this->TopVolBranchKnownByBlockStencil,
tData.TopVolBranchKnownByBlockStencil,
topVolBranchWithinBlockId);
auto topVolBranchWithinBlockIdPortal = topVolBranchWithinBlockId.ReadPortal();
@ -901,13 +512,13 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
// filtered branch saddle values
InArrayHandleType isoValues;
vtkm::cont::Algorithm::CopyIf(inArray, this->TopVolBranchKnownByBlockStencil, isoValues);
vtkm::cont::Algorithm::CopyIf(inArray, tData.TopVolBranchKnownByBlockStencil, isoValues);
auto isoValuePortal = isoValues.ReadPortal();
// filtered branch saddle epsilons
IdArrayType topVolBranchSaddleEpsilons;
vtkm::cont::Algorithm::CopyIf(this->TopVolumeBranchSaddleEpsilon,
this->TopVolBranchKnownByBlockStencil,
vtkm::cont::Algorithm::CopyIf(tData.TopVolumeBranchSaddleEpsilon,
tData.TopVolBranchKnownByBlockStencil,
topVolBranchSaddleEpsilons);
auto topVolBranchSaddleEpsilonPortal = topVolBranchSaddleEpsilons.ReadPortal();
@ -917,11 +528,11 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
IdArrayType topVolLocalBranchLowerEnd;
vtkm::cont::ArrayHandle<bool> topVolIsParent;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
upperEndLocalIds, this->TopVolBranchInfoActualIndex, topVolLocalBranchUpperEnd);
upperEndLocalIds, tData.TopVolBranchInfoActualIndex, topVolLocalBranchUpperEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
lowerEndLocalIds, this->TopVolBranchInfoActualIndex, topVolLocalBranchLowerEnd);
lowerEndLocalIds, tData.TopVolBranchInfoActualIndex, topVolLocalBranchLowerEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithRawIndex<vtkm::cont::ArrayHandle<bool>>(
this->IsParentBranch, this->TopVolBranchInfoActualIndex, topVolIsParent);
tData.IsParentBranch, tData.TopVolBranchInfoActualIndex, topVolIsParent);
auto topVolIsParentPortal = topVolIsParent.ReadPortal();
// we compute the superarc of the branch within the block
@ -948,7 +559,7 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
vtkm::worklet::contourtree_augmented::PrintHeader(sortedBranchGRId.GetNumberOfValues(),
branchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Raw Branch GR", this->BranchRootGRId, -1, branchStream);
"Raw Branch GR", tData.BranchRootGRId, -1, branchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Raw Upper End", upperLocalEndIds, -1, branchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
@ -960,7 +571,7 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
vtkm::worklet::contourtree_augmented::PrintHeader(nIsoValues, branchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Top Branch GR", this->TopVolumeBranchRootGRId, -1, branchStream);
"Top Branch GR", tData.TopVolumeBranchRootGRId, -1, branchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Top Branch Stencil", topVolBranchWithinBlockStencil, -1, branchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
@ -975,8 +586,8 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
VTKM_LOG_S(vtkm::cont::LogLevel::Info, branchStream.str());
#endif
const vtkm::Id nExtraMaximaBranch = this->ExtraMaximaBranchLowerEnd.GetNumberOfValues();
const vtkm::Id nExtraMinimaBranch = this->ExtraMinimaBranchLowerEnd.GetNumberOfValues();
const vtkm::Id nExtraMaximaBranch = tData.ExtraMaximaBranchLowerEnd.GetNumberOfValues();
const vtkm::Id nExtraMinimaBranch = tData.ExtraMinimaBranchLowerEnd.GetNumberOfValues();
InArrayHandleType extraMaximaBranchIsoValue;
InArrayHandleType extraMinimaBranchIsoValue;
@ -988,11 +599,11 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
if (nExtraMaximaBranch)
{
extraMaximaBranchIsoValue =
this->ExtraMaximaBranchIsoValue.AsArrayHandle<InArrayHandleType>();
tData.ExtraMaximaBranchIsoValue.AsArrayHandle<InArrayHandleType>();
invoke(branchIsoSuperarcWorklet,
this->ExtraMaximaBranchUpperEnd,
this->ExtraMaximaBranchLowerEnd,
tData.ExtraMaximaBranchUpperEnd,
tData.ExtraMaximaBranchLowerEnd,
extraMaximaBranchIsoValue,
vtkm::cont::ArrayHandleConstant<vtkm::Id>(1, nExtraMaximaBranch),
extraMaximaBranchSuperarcs,
@ -1003,15 +614,15 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
extraMaxStream << "Debug for Extra Maxima Branch, Block " << this->LocalBlockNo << std::endl;
vtkm::worklet::contourtree_augmented::PrintHeader(nExtraMaximaBranch, extraMaxStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Max Branch Upper End", this->ExtraMaximaBranchUpperEnd, -1, extraMaxStream);
"Max Branch Upper End", tData.ExtraMaximaBranchUpperEnd, -1, extraMaxStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Max Branch Lower End", this->ExtraMaximaBranchLowerEnd, -1, extraMaxStream);
"Max Branch Lower End", tData.ExtraMaximaBranchLowerEnd, -1, extraMaxStream);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"Max Branch IsoValue", extraMaximaBranchIsoValue, -1, extraMaxStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Max Branch Superarc", extraMaximaBranchSuperarcs, -1, extraMaxStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Max Branch Order", this->ExtraMaximaBranchOrder, -1, extraMaxStream);
"Max Branch Order", tData.ExtraMaximaBranchOrder, -1, extraMaxStream);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, extraMaxStream.str());
#endif // DEBUG_PRINT
}
@ -1019,11 +630,11 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
if (nExtraMinimaBranch)
{
extraMinimaBranchIsoValue =
this->ExtraMinimaBranchIsoValue.AsArrayHandle<InArrayHandleType>();
tData.ExtraMinimaBranchIsoValue.AsArrayHandle<InArrayHandleType>();
invoke(branchIsoSuperarcWorklet,
this->ExtraMinimaBranchUpperEnd,
this->ExtraMinimaBranchLowerEnd,
tData.ExtraMinimaBranchUpperEnd,
tData.ExtraMinimaBranchLowerEnd,
extraMinimaBranchIsoValue,
vtkm::cont::ArrayHandleConstant<vtkm::Id>(-1, nExtraMinimaBranch),
extraMinimaBranchSuperarcs,
@ -1034,15 +645,15 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
extraMaxStream << "Debug for Extra Maxima Branch, Block " << this->LocalBlockNo << std::endl;
vtkm::worklet::contourtree_augmented::PrintHeader(nExtraMinimaBranch, extraMinStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Max Branch Upper End", this->ExtraMinimaBranchUpperEnd, -1, extraMinStream);
"Max Branch Upper End", tData.ExtraMinimaBranchUpperEnd, -1, extraMinStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Max Branch Lower End", this->ExtraMinimaBranchLowerEnd, -1, extraMinStream);
"Max Branch Lower End", tData.ExtraMinimaBranchLowerEnd, -1, extraMinStream);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"Max Branch IsoValue", extraMinimaBranchIsoValue, -1, extraMinStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Max Branch Superarc", extraMinimaBranchSuperarcs, -1, extraMinStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Max Branch Order", this->ExtraMinimaBranchOrder, -1, extraMinStream);
"Max Branch Order", tData.ExtraMinimaBranchOrder, -1, extraMinStream);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, extraMinStream.str());
#endif // DEBUG_PRINT
}
@ -1051,8 +662,8 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
auto extraMinimaBranchSuperarcPortal = extraMinimaBranchSuperarcs.ReadPortal();
auto extraMaximaBranchIsoValuePortal = extraMaximaBranchIsoValue.ReadPortal();
auto extraMinimaBranchIsoValuePortal = extraMinimaBranchIsoValue.ReadPortal();
auto extraMaximaBranchOrderPortal = this->ExtraMaximaBranchOrder.ReadPortal();
auto extraMinimaBranchOrderPortal = this->ExtraMinimaBranchOrder.ReadPortal();
auto extraMaximaBranchOrderPortal = tData.ExtraMaximaBranchOrder.ReadPortal();
auto extraMinimaBranchOrderPortal = tData.ExtraMinimaBranchOrder.ReadPortal();
const vtkm::Id nContours = nTopVolBranchWithinBlock + nExtraMaximaBranch + nExtraMinimaBranch;
this->IsosurfaceEdgesOffset.AllocateAndFill(nContours, 0);
@ -1295,7 +906,7 @@ void SelectTopVolumeContoursBlock::ExtractIsosurfaceOnSelectedBranch(
<< " " << std::setw(60) << std::left
<< "Number of Meshes On Branches: " << nMeshesOnBranches << std::endl);
};
this->TopVolumeBranchSaddleIsoValue
tData.TopVolumeBranchSaddleIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(resolveArray);
}

@ -55,6 +55,8 @@
#include <vtkm/cont/DataSet.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/Types.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/TopVolumeBranchData.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/BranchDecompositionTreeMaker.h>
namespace vtkm
{
@ -69,65 +71,54 @@ struct SelectTopVolumeContoursBlock
{
SelectTopVolumeContoursBlock(vtkm::Id localBlockNo, int globalBlockId);
void SortBranchByVolume(const vtkm::cont::DataSet& bdDataSet, const vtkm::Id totalVolume);
void SelectLocalTopVolumeBranch(const vtkm::cont::DataSet& bdDataSet,
const vtkm::Id nSavedBranches);
void ComputeTopVolumeBranchHierarchy(const vtkm::cont::DataSet& bdDataSet);
void ExtractIsosurfaceOnSelectedBranch(const vtkm::cont::DataSet& bdDataSet,
const bool isMarchingCubes,
const vtkm::cont::LogLevel timingsLogLevel);
// Block metadata
vtkm::Id LocalBlockNo;
int GlobalBlockId; // TODO/FIXME: Check whether really needed. Possibly only during debugging
vtkm::worklet::contourtree_augmented::IdArrayType BranchRootByBranch;
vtkm::worklet::contourtree_augmented::IdArrayType BranchRootGRId;
vtkm::worklet::contourtree_augmented::IdArrayType BranchVolume;
vtkm::worklet::contourtree_augmented::IdArrayType BranchSaddleEpsilon;
vtkm::worklet::contourtree_augmented::IdArrayType SortedBranchByVolume;
vtkm::cont::ArrayHandle<bool> IsParentBranch;
vtkm::cont::UnknownArrayHandle BranchSaddleIsoValue;
TopVolumeBranchData tData;
// Output Datasets.
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchRoot;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchRootGRId;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchVolume;
// the parent branch of top volume branches (if no parent branch, then NO_SUCH_ELEMENT)
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchParent;
vtkm::cont::UnknownArrayHandle TopVolumeBranchSaddleIsoValue;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchSaddleEpsilon;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchUpperEndGRId;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchLowerEndGRId;
// the factory class to compute the relation of top-volume branches
BranchDecompositionTreeMaker bdtMaker;
// Other top-volume branch information
// whether the top volume branch is known by the block
// size: nTopVolBranches
// value range: [0, 1]
vtkm::worklet::contourtree_augmented::IdArrayType TopVolBranchKnownByBlockStencil;
// the branch order (among all branches) by branch root global regular ids
// size: nTopVolBranches
// value range: {NO_SUCH_ELEMENT} U [0, nBranches - 1]
vtkm::worklet::contourtree_augmented::IdArrayType TopVolBranchGROrder;
// the branch information index (known by the block) of the top volume branch
// size: nTopVolBranchKnownByBlock
// value range: [0, nBranches - 1]
vtkm::worklet::contourtree_augmented::IdArrayType TopVolBranchInfoActualIndex;
// information to extract extra isosurface for extrema
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMaximaBranchUpperEnd;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMaximaBranchLowerEnd;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMaximaBranchOrder;
vtkm::cont::UnknownArrayHandle ExtraMaximaBranchIsoValue;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMinimaBranchUpperEnd;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMinimaBranchLowerEnd;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMinimaBranchOrder;
vtkm::cont::UnknownArrayHandle ExtraMinimaBranchIsoValue;
//vtkm::worklet::contourtree_augmented::IdArrayType BranchRootByBranch;
//vtkm::worklet::contourtree_augmented::IdArrayType BranchRootGRId;
//vtkm::worklet::contourtree_augmented::IdArrayType BranchVolume;
//vtkm::worklet::contourtree_augmented::IdArrayType BranchSaddleEpsilon;
//vtkm::worklet::contourtree_augmented::IdArrayType SortedBranchByVolume;
//vtkm::cont::ArrayHandle<bool> IsParentBranch;
//vtkm::cont::UnknownArrayHandle BranchSaddleIsoValue;
//// Output Datasets.
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchRoot;
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchRootGRId;
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchVolume;
//// the parent branch of top volume branches (if no parent branch, then NO_SUCH_ELEMENT)
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchParent;
//vtkm::cont::UnknownArrayHandle TopVolumeBranchSaddleIsoValue;
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchSaddleEpsilon;
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchUpperEndGRId;
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchLowerEndGRId;
//// Other top-volume branch information
//// whether the top volume branch is known by the block
//// size: nTopVolBranches
//// value range: [0, 1]
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolBranchKnownByBlockStencil;
//// the branch order (among all branches) by branch root global regular ids
//// size: nTopVolBranches
//// value range: {NO_SUCH_ELEMENT} U [0, nBranches - 1]
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolBranchGROrder;
//// the branch information index (known by the block) of the top volume branch
//// size: nTopVolBranchKnownByBlock
//// value range: [0, nBranches - 1]
//vtkm::worklet::contourtree_augmented::IdArrayType TopVolBranchInfoActualIndex;
//// information to extract extra isosurface for extrema
//vtkm::worklet::contourtree_augmented::IdArrayType ExtraMaximaBranchUpperEnd;
//vtkm::worklet::contourtree_augmented::IdArrayType ExtraMaximaBranchLowerEnd;
//vtkm::worklet::contourtree_augmented::IdArrayType ExtraMaximaBranchOrder;
//vtkm::cont::UnknownArrayHandle ExtraMaximaBranchIsoValue;
//vtkm::worklet::contourtree_augmented::IdArrayType ExtraMinimaBranchUpperEnd;
//vtkm::worklet::contourtree_augmented::IdArrayType ExtraMinimaBranchLowerEnd;
//vtkm::worklet::contourtree_augmented::IdArrayType ExtraMinimaBranchOrder;
//vtkm::cont::UnknownArrayHandle ExtraMinimaBranchIsoValue;
// Isosurface output
vtkm::cont::ArrayHandle<vtkm::Vec3f_64> IsosurfaceEdgesFrom;
@ -139,6 +130,17 @@ struct SelectTopVolumeContoursBlock
// Destroy function allowing DIY to own blocks and clean them up after use
static void Destroy(void* b) { delete static_cast<SelectTopVolumeContoursBlock*>(b); }
void SortBranchByVolume(const vtkm::cont::DataSet& bdDataSet, const vtkm::Id totalVolume);
void SelectLocalTopVolumeBranch(const vtkm::cont::DataSet& bdDataSet,
const vtkm::Id nSavedBranches);
void ComputeTopVolumeBranchHierarchy(const vtkm::cont::DataSet& bdDataSet);
void ExtractIsosurfaceOnSelectedBranch(const vtkm::cont::DataSet& bdDataSet,
const bool isMarchingCubes,
const vtkm::cont::LogLevel timingsLogLevel);
};
} // namespace internal

@ -101,11 +101,11 @@ void SelectTopVolumeContoursFunctor::operator()(
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Block " << b->GlobalBlockId << " enqueue to Block " << target.gid);
#endif
auto topVolBranchRootGRIdPortal = b->TopVolumeBranchRootGRId.ReadPortal();
auto topVolBranchVolumePortal = b->TopVolumeBranchVolume.ReadPortal();
auto topVolBranchSaddleEpsilonPortal = b->TopVolumeBranchSaddleEpsilon.ReadPortal();
auto topVolBranchUpperEndPortal = b->TopVolumeBranchUpperEndGRId.ReadPortal();
auto topVolBranchLowerEndPortal = b->TopVolumeBranchLowerEndGRId.ReadPortal();
auto topVolBranchRootGRIdPortal = b->tData.TopVolumeBranchRootGRId.ReadPortal();
auto topVolBranchVolumePortal = b->tData.TopVolumeBranchVolume.ReadPortal();
auto topVolBranchSaddleEpsilonPortal = b->tData.TopVolumeBranchSaddleEpsilon.ReadPortal();
auto topVolBranchUpperEndPortal = b->tData.TopVolumeBranchUpperEndGRId.ReadPortal();
auto topVolBranchLowerEndPortal = b->tData.TopVolumeBranchLowerEndGRId.ReadPortal();
vtkm::Id nBranches = topVolBranchRootGRIdPortal.GetNumberOfValues();
@ -128,11 +128,11 @@ void SelectTopVolumeContoursFunctor::operator()(
for (vtkm::Id branch = 0; branch < nBranches; ++branch)
rp.enqueue<ValueType>(target, topVolBranchSaddleIsoValuePortal.Get(branch));
};
b->TopVolumeBranchSaddleIsoValue
b->tData.TopVolumeBranchSaddleIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(resolveArray);
// rp.enqueue(target, b->TopVolumeBranchRootGRId);
// rp.enqueue(target, b->TopVolumeBranchVolume);
// rp.enqueue(target, b->tData.TopVolumeBranchRootGRId);
// rp.enqueue(target, b->tData.TopVolumeBranchVolume);
}
}
}
@ -267,7 +267,7 @@ void SelectTopVolumeContoursFunctor::operator()(
// Replace with dequeuing ArrayHandles once bug is fixed.
// rp.dequeue<InArrayHandleType>(ingid, incomingTopVolBranchSaddleIsoValue);
vtkm::Id nSelf = b->TopVolumeBranchRootGRId.GetNumberOfValues();
vtkm::Id nSelf = b->tData.TopVolumeBranchRootGRId.GetNumberOfValues();
#ifdef DEBUG_PRINT_COMBINED_HIGH_VOLUME_BRANCH
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
@ -288,15 +288,15 @@ void SelectTopVolumeContoursFunctor::operator()(
vtkm::worklet::contourtree_augmented::PrintHeader(nSelf, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfTopBranchId", b->TopVolumeBranchRootGRId, -1, rs);
"selfTopBranchId", b->tData.TopVolumeBranchRootGRId, -1, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfTopBranchVol", b->TopVolumeBranchVolume, -1, rs);
"selfTopBranchVol", b->tData.TopVolumeBranchVolume, -1, rs);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"selfTopSaddleVal", inArray, -1, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfTopBranchUpperEnd", b->TopVolumeBranchUpperEndGRId, -1, rs);
"selfTopBranchUpperEnd", b->tData.TopVolumeBranchUpperEndGRId, -1, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfTopBranchLowerEnd", b->TopVolumeBranchLowerEndGRId, -1, rs);
"selfTopBranchLowerEnd", b->tData.TopVolumeBranchLowerEndGRId, -1, rs);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, rs.str());
}
#endif
@ -327,15 +327,15 @@ void SelectTopVolumeContoursFunctor::operator()(
vtkm::cont::Algorithm::CopySubRange<ValueType, ValueType>(
incomingTopVolBranchSaddleIsoValue, 0, nIncoming, mergedTopVolBranchSaddleIsoValue, 0);
vtkm::cont::Algorithm::CopySubRange(
b->TopVolumeBranchRootGRId, 0, nSelf, mergedTopVolBranchGRId, nIncoming);
b->tData.TopVolumeBranchRootGRId, 0, nSelf, mergedTopVolBranchGRId, nIncoming);
vtkm::cont::Algorithm::CopySubRange(
b->TopVolumeBranchVolume, 0, nSelf, mergedTopVolBranchVolume, nIncoming);
b->tData.TopVolumeBranchVolume, 0, nSelf, mergedTopVolBranchVolume, nIncoming);
vtkm::cont::Algorithm::CopySubRange(
b->TopVolumeBranchSaddleEpsilon, 0, nSelf, mergedTopVolBranchSaddleEpsilon, nIncoming);
b->tData.TopVolumeBranchSaddleEpsilon, 0, nSelf, mergedTopVolBranchSaddleEpsilon, nIncoming);
vtkm::cont::Algorithm::CopySubRange(
b->TopVolumeBranchUpperEndGRId, 0, nSelf, mergedTopVolBranchUpperEnd, nIncoming);
b->tData.TopVolumeBranchUpperEndGRId, 0, nSelf, mergedTopVolBranchUpperEnd, nIncoming);
vtkm::cont::Algorithm::CopySubRange(
b->TopVolumeBranchLowerEndGRId, 0, nSelf, mergedTopVolBranchLowerEnd, nIncoming);
b->tData.TopVolumeBranchLowerEndGRId, 0, nSelf, mergedTopVolBranchLowerEnd, nIncoming);
vtkm::cont::Algorithm::CopySubRange<ValueType, ValueType>(
inArray, 0, nSelf, mergedTopVolBranchSaddleIsoValue, nIncoming);
@ -439,17 +439,17 @@ void SelectTopVolumeContoursFunctor::operator()(
if (nMergedUnique > this->nSavedBranches)
{
vtkm::cont::Algorithm::CopySubRange(
mergedUniqueBranchGRId, 0, this->nSavedBranches, b->TopVolumeBranchRootGRId);
mergedUniqueBranchGRId, 0, this->nSavedBranches, b->tData.TopVolumeBranchRootGRId);
vtkm::cont::Algorithm::CopySubRange(
mergedUniqueBranchVolume, 0, this->nSavedBranches, b->TopVolumeBranchVolume);
mergedUniqueBranchVolume, 0, this->nSavedBranches, b->tData.TopVolumeBranchVolume);
vtkm::cont::Algorithm::CopySubRange(mergedUniqueBranchSaddleEpsilon,
0,
this->nSavedBranches,
b->TopVolumeBranchSaddleEpsilon);
b->tData.TopVolumeBranchSaddleEpsilon);
vtkm::cont::Algorithm::CopySubRange(
mergedUniqueBranchUpperEnd, 0, this->nSavedBranches, b->TopVolumeBranchUpperEndGRId);
mergedUniqueBranchUpperEnd, 0, this->nSavedBranches, b->tData.TopVolumeBranchUpperEndGRId);
vtkm::cont::Algorithm::CopySubRange(
mergedUniqueBranchLowerEnd, 0, this->nSavedBranches, b->TopVolumeBranchLowerEndGRId);
mergedUniqueBranchLowerEnd, 0, this->nSavedBranches, b->tData.TopVolumeBranchLowerEndGRId);
// InArrayHandleType subRangeUniqueBranchSaddleIsoValue;
inArray.Allocate(this->nSavedBranches);
vtkm::cont::Algorithm::CopySubRange(
@ -458,17 +458,17 @@ void SelectTopVolumeContoursFunctor::operator()(
}
else
{
vtkm::cont::Algorithm::Copy(mergedUniqueBranchGRId, b->TopVolumeBranchRootGRId);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchVolume, b->TopVolumeBranchVolume);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchGRId, b->tData.TopVolumeBranchRootGRId);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchVolume, b->tData.TopVolumeBranchVolume);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchSaddleEpsilon,
b->TopVolumeBranchSaddleEpsilon);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchUpperEnd, b->TopVolumeBranchUpperEndGRId);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchLowerEnd, b->TopVolumeBranchLowerEndGRId);
b->tData.TopVolumeBranchSaddleEpsilon);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchUpperEnd, b->tData.TopVolumeBranchUpperEndGRId);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchLowerEnd, b->tData.TopVolumeBranchLowerEndGRId);
inArray.Allocate(nMergedUnique);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchSaddleIsoValue, inArray);
}
};
b->TopVolumeBranchSaddleIsoValue
b->tData.TopVolumeBranchSaddleIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(resolveArray);
}
}

@ -0,0 +1,527 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
// Copyright (c) 2018, The Regents of the University of California, through
// Lawrence Berkeley National Laboratory (subject to receipt of any required approvals
// from the U.S. Dept. of Energy). All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// (1) Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// (2) Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// (3) Neither the name of the University of California, Lawrence Berkeley National
// Laboratory, U.S. Dept. of Energy nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//
//=======================================================================================
//
// Parallel Peak Pruning v. 2.0
//
// Started June 15, 2017
//
// Copyright Hamish Carr, University of Leeds
//
// BranchDecompositionTreeMaker.h
//
//=======================================================================================
//
// COMMENTS:
//
// This class computes the branch decomposition tree of top-volume branches
//
//=======================================================================================
#ifndef vtk_m_filter_scalar_topology_worklet_BranchDecompositionTreeMaker_h
#define vtk_m_filter_scalar_topology_worklet_BranchDecompositionTreeMaker_h
#ifdef DEBUG_PRINT
#define DEBUG_BRANCH_DECOMPOSITION_TREE_MAKER
#endif
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/TopVolumeBranchData.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/ArrayTransforms.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/BranchParentComparator.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/ClarifyBranchEndSupernodeTypeWorklet.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/GetBranchHierarchyWorklet.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/GetBranchVolumeWorklet.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/LocalIsosurfaceExtractWorklet.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/Predicates.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/UpdateInfoByBranchDirectionWorklet.h>
namespace vtkm
{
namespace filter
{
namespace scalar_topology
{
/// Facture class for augmenting the hierarchical contour tree to enable computations of measures, e.g., volumne
class BranchDecompositionTreeMaker
{ // class BranchDecompositionTreeMaker
public:
void ComputeTopVolumeBranchHierarchy(const vtkm::cont::DataSet& bdDataSet,
TopVolumeBranchData& tData);
private:
/// Used internally to Invoke worklets
vtkm::cont::Invoker invoke;
}; // class BranchDecompositionTreeMaker
/// <summary>
/// Pipeline to compute the hierarchy of top branches by volume
/// </summary>
inline void BranchDecompositionTreeMaker::ComputeTopVolumeBranchHierarchy(
const vtkm::cont::DataSet& bdDataSet,
TopVolumeBranchData& tData)
{
using vtkm::worklet::contourtree_augmented::IdArrayType;
// we need upper/lower local ends and global ends for hierarchy of branches
auto upperLocalEndIds = bdDataSet.GetField("UpperEndLocalIds")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
auto lowerLocalEndIds = bdDataSet.GetField("LowerEndLocalIds")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
auto globalRegularIds = bdDataSet.GetField("RegularNodeGlobalIds")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
IdArrayType upperEndGRIds =
bdDataSet.GetField("UpperEndGlobalRegularIds").GetData().AsArrayHandle<IdArrayType>();
IdArrayType lowerEndGRIds =
bdDataSet.GetField("LowerEndGlobalRegularIds").GetData().AsArrayHandle<IdArrayType>();
// let's check which top volume branches are known by the block
// We check the branchGRId of top volume branches to see whether there are matches within the block
const vtkm::Id nTopVolBranches = tData.TopVolumeBranchLowerEndGRId.GetNumberOfValues();
// sortedBranchOrder: the branch order (in the ascending order of branch root)
// the high-level idea is to sort the branch root global regular ids
// and for each top-volume branch, we use binary search to get the original branch index
// if the top-volume branch does not exist in the block, it will be dropped out
IdArrayType sortedBranchGRId;
IdArrayType sortedBranchOrder;
vtkm::cont::Algorithm::Copy(
vtkm::cont::ArrayHandleIndex(tData.BranchRootGRId.GetNumberOfValues()), sortedBranchOrder);
vtkm::cont::Algorithm::Copy(tData.BranchRootGRId, sortedBranchGRId);
vtkm::cont::Algorithm::SortByKey(sortedBranchGRId, sortedBranchOrder);
tData.TopVolBranchKnownByBlockStencil.Allocate(nTopVolBranches);
tData.TopVolBranchGROrder.Allocate(nTopVolBranches);
// We reuse the IdxIfWithinBlockWorklet.
// This worklet searches for given values in a sorted array and returns the stencil & index if the value exists in the array.
// tData.TopVolBranchGROrder: the order of the topVolBranch among all known branches if the branch is known by the block.
auto idxIfBranchWithinBlockWorklet =
vtkm::worklet::scalar_topology::select_top_volume_contours::IdxIfWithinBlockWorklet();
invoke(idxIfBranchWithinBlockWorklet,
tData.TopVolumeBranchRootGRId,
sortedBranchGRId,
tData.TopVolBranchKnownByBlockStencil,
tData.TopVolBranchGROrder);
// Dropping out top-volume branches that are not known by the block.
// the index of top-volume branches known by the block among all top-volume branches
IdArrayType topVolBranchKnownByBlockIndex;
vtkm::cont::ArrayHandleIndex topVolBranchesIndex(nTopVolBranches);
vtkm::cont::Algorithm::CopyIf(
topVolBranchesIndex, tData.TopVolBranchKnownByBlockStencil, topVolBranchKnownByBlockIndex);
const vtkm::Id nTopVolBranchKnownByBlock = topVolBranchKnownByBlockIndex.GetNumberOfValues();
// filtered tData.TopVolBranchGROrder, by removing NO_SUCH_ELEMENT
IdArrayType topVolBranchFilteredGROrder;
// tData.TopVolBranchInfoActualIndex: the information index of the top-volume branch
vtkm::cont::Algorithm::CopyIf(
tData.TopVolBranchGROrder, tData.TopVolBranchKnownByBlockStencil, topVolBranchFilteredGROrder);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
sortedBranchOrder, topVolBranchFilteredGROrder, tData.TopVolBranchInfoActualIndex);
// filtered branch saddle epsilons, global lower/upper end GR ids,
IdArrayType topVolFilteredBranchSaddleEpsilon;
IdArrayType topVolFilteredLowerEndGRId;
IdArrayType topVolFilteredUpperEndGRId;
vtkm::cont::Algorithm::CopyIf(tData.TopVolumeBranchSaddleEpsilon,
tData.TopVolBranchKnownByBlockStencil,
topVolFilteredBranchSaddleEpsilon);
vtkm::cont::Algorithm::CopyIf(tData.TopVolumeBranchUpperEndGRId,
tData.TopVolBranchKnownByBlockStencil,
topVolFilteredUpperEndGRId);
vtkm::cont::Algorithm::CopyIf(tData.TopVolumeBranchLowerEndGRId,
tData.TopVolBranchKnownByBlockStencil,
topVolFilteredLowerEndGRId);
// for each top-vol branch known by the block
// we get their upper end and lower end local ids
IdArrayType topVolBranchUpperLocalEnd;
IdArrayType topVolBranchLowerLocalEnd;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
upperLocalEndIds, tData.TopVolBranchInfoActualIndex, topVolBranchUpperLocalEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
lowerLocalEndIds, tData.TopVolBranchInfoActualIndex, topVolBranchLowerLocalEnd);
IdArrayType topVolLowerLocalEndGRId;
IdArrayType topVolUpperLocalEndGRId;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
globalRegularIds, topVolBranchLowerLocalEnd, topVolLowerLocalEndGRId);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
globalRegularIds, topVolBranchUpperLocalEnd, topVolUpperLocalEndGRId);
// Below is the code to compute the branch hierarchy of top-volume branches
// We need this information because we not only want to visualize the contour
// on top-volume branches, but also on their parent branches.
// Because we use volume as the metric, the parent branch of a top-volume branch
// is either a top-volume branch or the root branch (where both ends are leaf nodes)
vtkm::worklet::scalar_topology::select_top_volume_contours::BranchSaddleIsKnownWorklet
branchSaddleIsKnownWorklet;
// the branch saddle local ID if the saddle end is known by the block
IdArrayType branchSaddleIsKnown;
branchSaddleIsKnown.Allocate(nTopVolBranchKnownByBlock);
invoke(branchSaddleIsKnownWorklet, // worklet
topVolFilteredLowerEndGRId, // input
topVolBranchLowerLocalEnd, // input
topVolLowerLocalEndGRId, // input
topVolFilteredUpperEndGRId, // input
topVolBranchUpperLocalEnd, // input
topVolUpperLocalEndGRId, // input
topVolFilteredBranchSaddleEpsilon, // input
branchSaddleIsKnown); // output
// the order of top volume branches with parents known by the block
IdArrayType topVolChildBranch;
IdArrayType topVolChildBranchSaddle;
vtkm::cont::Algorithm::CopyIf(
topVolBranchKnownByBlockIndex,
branchSaddleIsKnown,
topVolChildBranch,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsNonNegative());
vtkm::cont::Algorithm::CopyIf(
branchSaddleIsKnown,
branchSaddleIsKnown,
topVolChildBranchSaddle,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsNonNegative());
const vtkm::Id nChildBranch = topVolChildBranch.GetNumberOfValues();
// to compute the parent branch, we need to
// 1. for the branch saddle end, collect all superarcs involving it
// 2. get the branch information for selected superarcs
// 3. eliminate branch information for branches sharing the same saddle end
auto superarcs =
bdDataSet.GetField("Superarcs").GetData().AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
auto branchRoots =
bdDataSet.GetField("BranchRoots").GetData().AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
VTKM_ASSERT(superarcs.GetNumberOfValues() == branchRoots.GetNumberOfValues());
// we sort all superarcs by target to allow binary search
IdArrayType superarcsByTarget;
vtkm::worklet::scalar_topology::select_top_volume_contours::SuperarcTargetComparator
superarcComparator(superarcs);
vtkm::cont::Algorithm::Copy(vtkm::cont::ArrayHandleIndex(superarcs.GetNumberOfValues()),
superarcsByTarget);
vtkm::cont::Algorithm::Sort(superarcsByTarget, superarcComparator);
IdArrayType permutedSuperarcs;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
superarcs, superarcsByTarget, permutedSuperarcs);
IdArrayType permutedBranchRoots;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
branchRoots, superarcsByTarget, permutedBranchRoots);
// the branch root of the superarc of the branch saddle supernode
IdArrayType topVolChildBranchSaddleBranchRoot;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
branchRoots, topVolChildBranchSaddle, topVolChildBranchSaddleBranchRoot);
// the GR Ids of the superarc of the branch saddle supernode
IdArrayType topVolChildBranchSaddleGRIds;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
globalRegularIds, topVolChildBranchSaddle, topVolChildBranchSaddleGRIds);
// there is a debate to find all superarcs connect to a supernode
// strategy 1. iterate through saddles and parallelize over superarcs for search
// time complexity: O(nTopVolBranches)
// (nTopVolBranches usually <= 100, based on input parameter setting)
//
// strategy 2. parallelize over all saddles and use binary search to find superarcs
// time complexity: O(log_2(nSuperarcs)) (nSuperarcs can be considerably large)
//
// here, we choose strategy 2 for better extendability to high nTopVolBranches
// but in tests using nTopVolBranches <= 10, strategy 1 is generally faster
// note: after getting the branch root superarc, we use binary search to get the branch order
// because BranchRootByBranch is sorted by branch root (superarc) id
#ifdef DEBUG_PRINT
std::stringstream parentBranchStream;
vtkm::worklet::contourtree_augmented::PrintHeader(nChildBranch, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Child Branch Saddle", topVolChildBranchSaddle, -1, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Child Saddle Root", topVolChildBranchSaddleBranchRoot, -1, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Child Saddle GR Id", topVolChildBranchSaddleGRIds, -1, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintHeader(superarcs.GetNumberOfValues(),
parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Permuted Superarcs", permutedSuperarcs, -1, parentBranchStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Permuted Branch roots", permutedBranchRoots, -1, parentBranchStream);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, parentBranchStream.str());
#endif // DEBUG_PRINT
// the corresponding parent branch of child branches
IdArrayType topVolChildBranchParent;
topVolChildBranchParent.AllocateAndFill(nChildBranch,
vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT);
vtkm::worklet::scalar_topology::select_top_volume_contours::GetParentBranchWorklet
getParentBranchWorklet;
invoke(getParentBranchWorklet,
topVolChildBranchSaddle,
topVolChildBranchSaddleBranchRoot,
topVolChildBranchSaddleGRIds,
permutedSuperarcs,
permutedBranchRoots,
tData.BranchRootByBranch,
upperEndGRIds,
lowerEndGRIds,
topVolChildBranchParent);
tData.TopVolumeBranchParent.AllocateAndFill(
nTopVolBranches, vtkm::Id(vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT));
vtkm::worklet::scalar_topology::select_top_volume_contours::AssignValueByIndex assignParentBranch;
// for each top volume branch, assign the parent branch info id in the block
invoke(
assignParentBranch, topVolChildBranch, topVolChildBranchParent, tData.TopVolumeBranchParent);
// for each branch, assign true if it is a parent branch
invoke(assignParentBranch,
topVolChildBranchParent,
vtkm::cont::ArrayHandleConstant<bool>(true, nChildBranch),
tData.IsParentBranch);
// sort all top-volume branches based on
// 1. parent branch info id: tData.TopVolumeBranchParent
// 2. saddle-end value: tData.TopVolumeBranchSaddleIsovalue
// 3. branch root global regular id (anything that can break tie)
IdArrayType topVolSortForOuterSaddleIdx;
vtkm::cont::Algorithm::Copy(topVolBranchesIndex, topVolSortForOuterSaddleIdx);
auto resolveBranchParentSorter = [&](const auto& inArray)
{
using InArrayHandleType = std::decay_t<decltype(inArray)>;
using ValueType = typename InArrayHandleType::ValueType;
vtkm::worklet::scalar_topology::select_top_volume_contours::BranchParentComparator<ValueType>
parentComparator(tData.TopVolumeBranchParent, inArray, tData.TopVolumeBranchRootGRId);
// sort index for all top volume branches
vtkm::cont::Algorithm::Sort(topVolSortForOuterSaddleIdx, parentComparator);
};
tData.TopVolumeBranchSaddleIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
resolveBranchParentSorter);
IdArrayType parentPermutation;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
tData.TopVolumeBranchParent, topVolSortForOuterSaddleIdx, parentPermutation);
// warning: when parent is NO_SUCH_ELEMENT, parentSaddleEps obtains 0
// However, the corresponding element will be discarded in collecting outer saddles
IdArrayType parentSaddleEpsPermutation;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
tData.BranchSaddleEpsilon, parentPermutation, parentSaddleEpsPermutation);
// Some branches have parent=NO_SUCH_ELEMENT (no parent)
// we collect the isovalue of the first and/or the last branches for each parent branch
// we collect the first if branchSaddleEpsilon(parent) < 0
// or the last if branchSaddleEpsilon(parent) > 0
// or both if branchSaddleEpsilon(parent) == 0
IdArrayType IsOuterSaddle;
IsOuterSaddle.Allocate(nTopVolBranches);
vtkm::worklet::scalar_topology::select_top_volume_contours::CollectOuterSaddle
collectOuterSaddleWorklet;
invoke(collectOuterSaddleWorklet, parentSaddleEpsPermutation, parentPermutation, IsOuterSaddle);
// after sorting by index back
// each top volume branch know whether it is the outer saddle of its parent
vtkm::cont::Algorithm::SortByKey(topVolSortForOuterSaddleIdx, IsOuterSaddle);
// collect branches that need contours on extra minima/maxima
// we store the information of the parent branches (on both directions)
IdArrayType extraMaximaParentBranch;
IdArrayType extraMinimaParentBranch;
IdArrayType extraMaximaParentBranchRootGRId;
IdArrayType extraMinimaParentBranchRootGRId;
IdArrayType allBranchGRIdByVolume;
IdArrayType branchGRIdByVolumeIdx;
// we need global branch order including the root branch
// this information should be consistent globally
allBranchGRIdByVolume.Allocate(nTopVolBranches + 1);
vtkm::cont::Algorithm::CopySubRange(
tData.TopVolumeBranchRootGRId, 0, nTopVolBranches, allBranchGRIdByVolume, 1);
auto topBranchGRIdWritePortal = allBranchGRIdByVolume.WritePortal();
auto sortedBranchByVolPortal = tData.SortedBranchByVolume.ReadPortal();
auto branchGRIdReadPortal = tData.BranchRootGRId.ReadPortal();
topBranchGRIdWritePortal.Set(0, branchGRIdReadPortal.Get(sortedBranchByVolPortal.Get(0)));
vtkm::cont::Algorithm::Copy(
vtkm::cont::ArrayHandleIndex(allBranchGRIdByVolume.GetNumberOfValues()),
branchGRIdByVolumeIdx);
vtkm::cont::Algorithm::SortByKey(allBranchGRIdByVolume, branchGRIdByVolumeIdx);
vtkm::cont::Algorithm::CopyIf(
tData.TopVolumeBranchParent,
IsOuterSaddle,
extraMaximaParentBranch,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMaxima());
vtkm::cont::Algorithm::CopyIf(
tData.TopVolumeBranchParent,
IsOuterSaddle,
extraMinimaParentBranch,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMinima());
if (extraMaximaParentBranch.GetNumberOfValues())
{
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
upperLocalEndIds, extraMaximaParentBranch, tData.ExtraMaximaBranchUpperEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
lowerLocalEndIds, extraMaximaParentBranch, tData.ExtraMaximaBranchLowerEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
tData.BranchRootGRId, extraMaximaParentBranch, extraMaximaParentBranchRootGRId);
//InArrayHandleType extraMaximaBranchIsoValue;
//vtkm::cont::Algorithm::CopyIf(
// tData.TopVolumeBranchSaddleIsoValue.AsArrayHandle<InArrayHandleType>(),
// IsOuterSaddle,
// extraMaximaBranchIsoValue,
// vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMaxima());
//tData.ExtraMaximaBranchIsoValue = extraMaximaBranchIsoValue;
// a worklet to binary search a number in a sorted array and return the index
vtkm::worklet::scalar_topology::select_top_volume_contours::IdxIfWithinBlockWorklet
getParentBranchOrder;
IdArrayType permutedExtraMaximaBranchOrder;
permutedExtraMaximaBranchOrder.Allocate(extraMaximaParentBranchRootGRId.GetNumberOfValues());
vtkm::cont::ArrayHandleDiscard<vtkm::Id> discard;
discard.Allocate(extraMaximaParentBranchRootGRId.GetNumberOfValues());
invoke(getParentBranchOrder,
extraMaximaParentBranchRootGRId,
allBranchGRIdByVolume,
discard,
permutedExtraMaximaBranchOrder);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
branchGRIdByVolumeIdx, permutedExtraMaximaBranchOrder, tData.ExtraMaximaBranchOrder);
}
if (extraMinimaParentBranch.GetNumberOfValues())
{
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
upperLocalEndIds, extraMinimaParentBranch, tData.ExtraMinimaBranchUpperEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
lowerLocalEndIds, extraMinimaParentBranch, tData.ExtraMinimaBranchLowerEnd);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
tData.BranchRootGRId, extraMinimaParentBranch, extraMinimaParentBranchRootGRId);
//InArrayHandleType extraMinimaBranchIsoValue;
//vtkm::cont::Algorithm::CopyIf(
// tData.TopVolumeBranchSaddleIsoValue.AsArrayHandle<InArrayHandleType>(),
// IsOuterSaddle,
// extraMinimaBranchIsoValue,
// vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMinima());
//tData.ExtraMinimaBranchIsoValue = extraMinimaBranchIsoValue;
vtkm::worklet::scalar_topology::select_top_volume_contours::IdxIfWithinBlockWorklet
getParentBranchOrder;
IdArrayType permutedExtraMinimaBranchOrder;
permutedExtraMinimaBranchOrder.Allocate(extraMinimaParentBranchRootGRId.GetNumberOfValues());
vtkm::cont::ArrayHandleDiscard<vtkm::Id> discard;
discard.Allocate(extraMinimaParentBranchRootGRId.GetNumberOfValues());
invoke(getParentBranchOrder,
extraMinimaParentBranchRootGRId,
allBranchGRIdByVolume,
discard,
permutedExtraMinimaBranchOrder);
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
branchGRIdByVolumeIdx, permutedExtraMinimaBranchOrder, tData.ExtraMinimaBranchOrder);
}
auto resolveExtraContourSaddleValue = [&](const auto& inArray)
{
using InArrayHandleType = std::decay_t<decltype(inArray)>;
using ValueType = typename InArrayHandleType::ValueType;
if (extraMaximaParentBranch.GetNumberOfValues())
{
InArrayHandleType extraMaximaBranchIsoValue;
vtkm::cont::Algorithm::CopyIf(
inArray,
IsOuterSaddle,
extraMaximaBranchIsoValue,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMaxima());
tData.ExtraMaximaBranchIsoValue = extraMaximaBranchIsoValue;
}
if (extraMinimaParentBranch.GetNumberOfValues())
{
InArrayHandleType extraMinimaBranchIsoValue;
vtkm::cont::Algorithm::CopyIf(
inArray,
IsOuterSaddle,
extraMinimaBranchIsoValue,
vtkm::worklet::scalar_topology::select_top_volume_contours::IsExtraMinima());
tData.ExtraMinimaBranchIsoValue = extraMinimaBranchIsoValue;
}
};
tData.TopVolumeBranchSaddleIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
resolveExtraContourSaddleValue);
}
} // namespace scalar_topology
} // namespace filter
} // namespace vtkm
#endif

@ -10,6 +10,7 @@
set(headers
Predicates.h
TopVolumeBranchData.h
ClarifyBranchEndSupernodeTypeWorklet.h
UpdateInfoByBranchDirectionWorklet.h
GetBranchHierarchyWorklet.h
@ -18,6 +19,7 @@ set(headers
BranchVolumeComparator.h
MarchingCubesDataTables.h
LocalIsosurfaceExtractWorklet.h
BranchDecompositionTreeMaker.h
)
#-----------------------------------------------------------------------------

@ -0,0 +1,131 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
// Copyright (c) 2018, The Regents of the University of California, through
// Lawrence Berkeley National Laboratory (subject to receipt of any required approvals
// from the U.S. Dept. of Energy). All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// (1) Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// (2) Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// (3) Neither the name of the University of California, Lawrence Berkeley National
// Laboratory, U.S. Dept. of Energy nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//
//=======================================================================================
//
// Parallel Peak Pruning v. 2.0
//
// Started June 15, 2017
//
// Copyright Hamish Carr, University of Leeds
//
// BranchDecompositionTreeMaker.h
//
//=======================================================================================
//
// COMMENTS:
//
// This class computes the branch decomposition tree of top-volume branches
//
//=======================================================================================
#ifndef vtk_m_filter_scalar_topology_worklet_TopVolumeBranchData_h
#define vtk_m_filter_scalar_topology_worklet_TopVolumeBranchData_h
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/Types.h>
#ifdef DEBUG_PRINT
#define DEBUG_BRANCH_DECOMPOSITION_TREE_MAKER
#endif
namespace vtkm
{
namespace filter
{
namespace scalar_topology
{
/// Data to store all information about top branches by volume
struct TopVolumeBranchData
{ // struct TopVolumeBranchData
vtkm::worklet::contourtree_augmented::IdArrayType BranchRootByBranch;
vtkm::worklet::contourtree_augmented::IdArrayType BranchRootGRId;
vtkm::worklet::contourtree_augmented::IdArrayType BranchVolume;
vtkm::worklet::contourtree_augmented::IdArrayType BranchSaddleEpsilon;
vtkm::worklet::contourtree_augmented::IdArrayType SortedBranchByVolume;
vtkm::cont::ArrayHandle<bool> IsParentBranch;
vtkm::cont::UnknownArrayHandle BranchSaddleIsoValue;
// Output Datasets.
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchRoot;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchRootGRId;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchVolume;
// the parent branch of top volume branches (if no parent branch, then NO_SUCH_ELEMENT)
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchParent;
vtkm::cont::UnknownArrayHandle TopVolumeBranchSaddleIsoValue;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchSaddleEpsilon;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchUpperEndGRId;
vtkm::worklet::contourtree_augmented::IdArrayType TopVolumeBranchLowerEndGRId;
// Other top-volume branch information
// whether the top volume branch is known by the block
// size: nTopVolBranches
// value range: [0, 1]
vtkm::worklet::contourtree_augmented::IdArrayType TopVolBranchKnownByBlockStencil;
// the branch order (among all branches) by branch root global regular ids
// size: nTopVolBranches
// value range: {NO_SUCH_ELEMENT} U [0, nBranches - 1]
vtkm::worklet::contourtree_augmented::IdArrayType TopVolBranchGROrder;
// the branch information index (known by the block) of the top volume branch
// size: nTopVolBranchKnownByBlock
// value range: [0, nBranches - 1]
vtkm::worklet::contourtree_augmented::IdArrayType TopVolBranchInfoActualIndex;
// information to extract extra isosurface for extrema
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMaximaBranchUpperEnd;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMaximaBranchLowerEnd;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMaximaBranchOrder;
vtkm::cont::UnknownArrayHandle ExtraMaximaBranchIsoValue;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMinimaBranchUpperEnd;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMinimaBranchLowerEnd;
vtkm::worklet::contourtree_augmented::IdArrayType ExtraMinimaBranchOrder;
vtkm::cont::UnknownArrayHandle ExtraMinimaBranchIsoValue;
}; // class TopVolumeBranchData
} // namespace scalar_topology
} // namespace filter
} // namespace vtkm
#endif