Merge branch 'distributed-contours' into 'master'

Distributed Isosurface extraction from branch decomposition

See merge request vtk/vtk-m!3226
This commit is contained in:
Mingzhe Li 2024-07-02 01:31:27 -04:00
commit 302d5f6db3
37 changed files with 4808 additions and 75 deletions

@ -669,6 +669,7 @@ int main(int argc, char* argv[])
if (computeHierarchicalVolumetricBranchDecomposition)
{
vtkm::filter::scalar_topology::DistributedBranchDecompositionFilter bd_filter;
bd_filter.SetTimingsLogLevel(timingsLogLevel);
bd_result = bd_filter.Execute(result);
}
currTime = totalTime.GetElapsedTime();
@ -681,8 +682,13 @@ int main(int argc, char* argv[])
{
vtkm::filter::scalar_topology::SelectTopVolumeContoursFilter tp_filter;
tp_filter.SetSavedBranches(numBranches);
tp_filter.SetMarchingCubes(useMarchingCubes);
tp_filter.SetTimingsLogLevel(timingsLogLevel);
tp_result = tp_filter.Execute(bd_result);
}
currTime = totalTime.GetElapsedTime();
vtkm::Float64 topVolBranchTime = currTime - prevTime;
prevTime = currTime;
// Save output
if (saveOutputData)
@ -740,14 +746,19 @@ int main(int argc, char* argv[])
for (vtkm::Id ds_no = 0; print_to_files && ds_no < max_blocks_to_print; ++ds_no)
{
auto ds = tp_result.GetPartition(ds_no);
std::string topVolumeBranchFileName = std::string("TopVolumeBranch_Rank_") +
std::to_string(static_cast<int>(rank)) + std::string("_Block_") +
std::to_string(static_cast<int>(ds_no)) + std::string(".txt");
std::ofstream topVolumeBranchStream(topVolumeBranchFileName.c_str());
auto topVolBranchGRId = ds.GetField("TopVolumeBranchGlobalRegularIds")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>()
.ReadPortal();
auto topVolBranchUpperEnd = ds.GetField("TopVolumeBranchUpperEnd")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>()
.ReadPortal();
auto topVolBranchLowerEnd = ds.GetField("TopVolumeBranchLowerEnd")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>()
.ReadPortal();
auto topVolBranchVolume = ds.GetField("TopVolumeBranchVolume")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>()
@ -761,10 +772,11 @@ int main(int argc, char* argv[])
.AsArrayHandle<vtkm::cont::ArrayHandle<ValueType>>()
.ReadPortal();
vtkm::Id nSelectedBranches = topVolBranchGRId.GetNumberOfValues();
vtkm::Id nSelectedBranches = topVolBranchUpperEnd.GetNumberOfValues();
for (vtkm::Id branch = 0; branch < nSelectedBranches; ++branch)
{
topVolumeBranchStream << std::setw(12) << topVolBranchGRId.Get(branch)
topVolumeBranchStream << std::setw(12) << topVolBranchUpperEnd.Get(branch)
<< std::setw(12) << topVolBranchLowerEnd.Get(branch)
<< std::setw(14) << topVolBranchVolume.Get(branch)
<< std::setw(5) << topVolBranchSaddleEpsilon.Get(branch)
<< std::setw(14) << topVolBranchSaddleIsoValue.Get(branch)
@ -785,6 +797,111 @@ int main(int argc, char* argv[])
isoValuesStream << std::endl;
}
for (vtkm::Id ds_no = 0; ds_no < tp_result.GetNumberOfPartitions(); ++ds_no)
{
auto bd_ds = bd_result.GetPartition(ds_no);
auto ds = tp_result.GetPartition(ds_no);
std::string branchDecompositionVolumeFileName =
std::string("BranchDecompositionVolume_Rank_") +
std::to_string(static_cast<int>(rank)) + std::string("_Block_") +
std::to_string(static_cast<int>(ds_no)) + std::string(".txt");
std::ofstream bdVolStream(branchDecompositionVolumeFileName.c_str());
auto upperEndGRId = bd_ds.GetField("UpperEndGlobalRegularIds")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>()
.ReadPortal();
auto lowerEndGRId = bd_ds.GetField("LowerEndGlobalRegularIds")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>()
.ReadPortal();
auto branchSaddleEpsilon = ds.GetField("BranchSaddleEpsilon")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>()
.ReadPortal();
auto branchVolume = ds.GetField("BranchVolume")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>()
.ReadPortal();
vtkm::Id nBranches = upperEndGRId.GetNumberOfValues();
for (vtkm::Id branch = 0; branch < nBranches; ++branch)
{
bdVolStream << std::setw(12) << upperEndGRId.Get(branch) << std::setw(12)
<< lowerEndGRId.Get(branch) << std::setw(3)
<< branchSaddleEpsilon.Get(branch) << std::setw(18)
<< branchVolume.Get(branch) << std::endl;
}
std::string isosurfaceFileName = std::string("Isosurface_Rank_") +
std::to_string(static_cast<int>(rank)) + std::string("_Block_") +
std::to_string(static_cast<int>(ds_no)) + std::string(".txt");
std::ofstream isosurfaceStream(isosurfaceFileName.c_str());
auto isosurfaceEdgesFrom = ds.GetField("IsosurfaceEdgesFrom")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Vec3f_64>>()
.ReadPortal();
auto isosurfaceEdgesTo = ds.GetField("IsosurfaceEdgesTo")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Vec3f_64>>()
.ReadPortal();
auto isosurfaceEdgesLabels = ds.GetField("IsosurfaceEdgesLabels")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>()
.ReadPortal();
auto isosurfaceEdgesOrders = ds.GetField("IsosurfaceEdgesOrders")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>()
.ReadPortal();
auto isosurfaceEdgesOffset = ds.GetField("IsosurfaceEdgesOffset")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>()
.ReadPortal();
auto isosurfaceIsoValue = ds.GetField("IsosurfaceIsoValue")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<ValueType>>()
.ReadPortal();
vtkm::Id nIsosurfaceEdges = isosurfaceEdgesFrom.GetNumberOfValues();
vtkm::Id isoSurfaceCount = 0;
if (nDims == 2)
for (vtkm::Id edge = 0; edge < nIsosurfaceEdges; ++edge)
{
while (isoSurfaceCount < isosurfaceEdgesLabels.GetNumberOfValues() &&
edge == isosurfaceEdgesOffset.Get(isoSurfaceCount))
{
isosurfaceStream << "Isosurface Info:" << std::setw(5)
<< isosurfaceEdgesLabels.Get(isoSurfaceCount) << std::setw(10)
<< isosurfaceEdgesOrders.Get(isoSurfaceCount) << std::setw(10)
<< isosurfaceIsoValue.Get(isoSurfaceCount) << std::endl;
isoSurfaceCount++;
}
isosurfaceStream << std::setw(6) << isosurfaceEdgesFrom.Get(edge) << std::setw(6)
<< isosurfaceEdgesTo.Get(edge) << std::endl;
}
else if (nDims == 3)
{
VTKM_ASSERT(nIsosurfaceEdges % 3 == 0);
for (vtkm::Id edge = 0; edge < nIsosurfaceEdges; edge += 3)
{
while (isoSurfaceCount < isosurfaceEdgesLabels.GetNumberOfValues() &&
edge == isosurfaceEdgesOffset.Get(isoSurfaceCount))
{
isosurfaceStream << "Isosurface Info:" << std::setw(5)
<< isosurfaceEdgesLabels.Get(isoSurfaceCount) << std::setw(10)
<< isosurfaceEdgesOrders.Get(isoSurfaceCount) << std::setw(10)
<< isosurfaceIsoValue.Get(isoSurfaceCount) << std::endl;
isoSurfaceCount++;
}
isosurfaceStream << std::setw(6) << isosurfaceEdgesFrom.Get(edge) << std::setw(6)
<< isosurfaceEdgesTo.Get(edge) << std::setw(6)
<< isosurfaceEdgesTo.Get(edge + 1) << std::endl;
}
}
}
}
}
else
@ -892,6 +1009,8 @@ int main(int argc, char* argv[])
<< ": " << postFilterSyncTime << " seconds" << std::endl
<< std::setw(42) << std::left << " Branch Decomposition"
<< ": " << branchDecompTime << " seconds" << std::endl
<< std::setw(42) << std::left << " Top Volume Branch Extraction"
<< ": " << topVolBranchTime << " seconds" << std::endl
<< std::setw(42) << std::left << " Save Tree Compiler Data"
<< ": " << saveOutputDataTime << " seconds" << std::endl
<< std::setw(42) << std::left << " Total Time"

@ -21,6 +21,7 @@ set(scalar_topology_sources
internal/ComputeBlockIndices.cxx
internal/ComputeDistributedBranchDecompositionFunctor.cxx
internal/SelectTopVolumeContoursFunctor.cxx
internal/ParentBranchExtremaFunctor.cxx
internal/ExchangeBranchEndsFunctor.cxx
ContourTreeUniform.cxx
ContourTreeUniformAugmented.cxx

@ -1138,11 +1138,17 @@ VTKM_CONT void ContourTreeUniformDistributed::DoPostExecute(
// ******** 3. Augment the hierarchical tree if requested ********
if (this->AugmentHierarchicalTree)
{
master.foreach (
[](DistributedContourTreeBlockData* blockData, const vtkmdiy::Master::ProxyWithLink&) {
blockData->HierarchicalAugmenter.Initialize(
blockData->GlobalBlockId, &blockData->HierarchicalTree, &blockData->AugmentedTree);
});
master.foreach ([globalPointDimensions](DistributedContourTreeBlockData* blockData,
const vtkmdiy::Master::ProxyWithLink&) {
blockData->HierarchicalAugmenter.Initialize(
blockData->GlobalBlockId,
&blockData->HierarchicalTree,
&blockData->AugmentedTree,
blockData->BlockOrigin, // Origin of the data block
blockData->BlockSize, // Extends of the data block
globalPointDimensions // global point dimensions
);
});
timingsStream << " " << std::setw(38) << std::left << "Initalize Hierarchical Trees"
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;

@ -80,6 +80,7 @@ VTKM_CONT vtkm::cont::PartitionedDataSet DistributedBranchDecompositionFilter::D
timingsStream << " " << std::setw(60) << std::left
<< "Create DIY Master and Assigner (Branch Decomposition)"
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;
timer.Start();
// Compute global ids (gids) for our local blocks
@ -116,6 +117,7 @@ VTKM_CONT vtkm::cont::PartitionedDataSet DistributedBranchDecompositionFilter::D
timingsStream << " " << std::setw(60) << std::left
<< "Get DIY Information (Branch Decomposition)"
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;
timer.Start();
@ -237,7 +239,8 @@ VTKM_CONT vtkm::cont::PartitionedDataSet DistributedBranchDecompositionFilter::D
branch_decomposition_master,
assigner,
partners,
vtkm::filter::scalar_topology::internal::ComputeDistributedBranchDecompositionFunctor{});
vtkm::filter::scalar_topology::internal::ComputeDistributedBranchDecompositionFunctor(
this->TimingsLogLevel));
timingsStream << " " << std::setw(60) << std::left
<< "Exchanging best up/down supernode and volume"
@ -314,12 +317,19 @@ VTKM_CONT vtkm::cont::PartitionedDataSet DistributedBranchDecompositionFilter::D
b->VolumetricBranchDecomposer.CollectBranches(ds, b->BranchRoots);
});
timingsStream << " " << std::setw(38) << std::left << "CollectBranchEnds"
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;
timer.Start();
// Now we have collected the branches, we do a global reduction to exchance branch end information
// across all compute ranks
vtkmdiy::reduce(branch_decomposition_master,
assigner,
partners,
vtkm::filter::scalar_topology::internal::ExchangeBranchEndsFunctor{});
auto exchangeBranchEndsFunctor =
vtkm::filter::scalar_topology::internal::ExchangeBranchEndsFunctor(this->TimingsLogLevel);
vtkmdiy::reduce(branch_decomposition_master, assigner, partners, exchangeBranchEndsFunctor);
timingsStream << " " << std::setw(38) << std::left << "ExchangeBranchEnds"
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;
timer.Start();
std::vector<vtkm::cont::DataSet> outputDataSets(input.GetNumberOfPartitions());
// Copy input data set to output
@ -347,6 +357,15 @@ VTKM_CONT vtkm::cont::PartitionedDataSet DistributedBranchDecompositionFilter::D
b->VolumetricBranchDecomposer.LowerEndGRId);
outputDataSets[b->LocalBlockNo].AddField(LowerEndGRIdField);
vtkm::cont::Field UpperEndLocalIdField("UpperEndLocalIds",
vtkm::cont::Field::Association::WholeDataSet,
b->VolumetricBranchDecomposer.UpperEndLocalId);
outputDataSets[b->LocalBlockNo].AddField(UpperEndLocalIdField);
vtkm::cont::Field LowerEndLocalIdField("LowerEndLocalIds",
vtkm::cont::Field::Association::WholeDataSet,
b->VolumetricBranchDecomposer.LowerEndLocalId);
outputDataSets[b->LocalBlockNo].AddField(LowerEndLocalIdField);
vtkm::cont::Field UpperEndIntrinsicVolume(
"UpperEndIntrinsicVolume",
vtkm::cont::Field::Association::WholeDataSet,
@ -383,7 +402,7 @@ VTKM_CONT vtkm::cont::PartitionedDataSet DistributedBranchDecompositionFilter::D
vtkm::cont::Field::Association::WholeDataSet,
b->VolumetricBranchDecomposer.UpperEndValue);
outputDataSets[b->LocalBlockNo].AddField(UpperEndValue);
vtkm::cont::Field BranchRoot("BranchRoot",
vtkm::cont::Field BranchRoot("BranchRootByBranch",
vtkm::cont::Field::Association::WholeDataSet,
b->VolumetricBranchDecomposer.BranchRoot);
outputDataSets[b->LocalBlockNo].AddField(BranchRoot);
@ -391,13 +410,74 @@ VTKM_CONT vtkm::cont::PartitionedDataSet DistributedBranchDecompositionFilter::D
vtkm::cont::Field::Association::WholeDataSet,
b->VolumetricBranchDecomposer.BranchRootGRId);
outputDataSets[b->LocalBlockNo].AddField(BranchRootGRId);
/* To select top volume branches,
we need to carry over the input fields below to the output*/
using vtkm::worklet::contourtree_augmented::IdArrayType;
const vtkm::cont::DataSet& ds = input.GetPartition(b->LocalBlockNo);
// RegularNodeGlobalIds
vtkm::cont::Field RegularNodeGlobalIds("RegularNodeGlobalIds",
vtkm::cont::Field::Association::WholeDataSet,
ds.GetField("RegularNodeGlobalIds").GetData());
outputDataSets[b->LocalBlockNo].AddField(RegularNodeGlobalIds);
// DataValues
vtkm::cont::Field DataValues("DataValues",
vtkm::cont::Field::Association::WholeDataSet,
ds.GetField("DataValues").GetData());
outputDataSets[b->LocalBlockNo].AddField(DataValues);
// Superparents
vtkm::cont::Field Superparents("Superparents",
vtkm::cont::Field::Association::WholeDataSet,
ds.GetField("Superparents").GetData());
outputDataSets[b->LocalBlockNo].AddField(Superparents);
// Supernodes
vtkm::cont::Field Supernodes("Supernodes",
vtkm::cont::Field::Association::WholeDataSet,
ds.GetField("Supernodes").GetData());
outputDataSets[b->LocalBlockNo].AddField(Supernodes);
// Superarcs
vtkm::cont::Field Superarcs("Superarcs",
vtkm::cont::Field::Association::WholeDataSet,
ds.GetField("Superarcs").GetData());
outputDataSets[b->LocalBlockNo].AddField(Superarcs);
// Superchildren
vtkm::cont::Field Superchildren("Superchildren",
vtkm::cont::Field::Association::WholeDataSet,
ds.GetField("Superchildren").GetData());
outputDataSets[b->LocalBlockNo].AddField(Superchildren);
// WhichRound
vtkm::cont::Field WhichRound("WhichRound",
vtkm::cont::Field::Association::WholeDataSet,
ds.GetField("WhichRound").GetData());
outputDataSets[b->LocalBlockNo].AddField(WhichRound);
// WhichIteration
vtkm::cont::Field WhichIteration("WhichIteration",
vtkm::cont::Field::Association::WholeDataSet,
ds.GetField("WhichIteration").GetData());
outputDataSets[b->LocalBlockNo].AddField(WhichIteration);
// Hyperparents
vtkm::cont::Field Hyperparents("Hyperparents",
vtkm::cont::Field::Association::WholeDataSet,
ds.GetField("Hyperparents").GetData());
outputDataSets[b->LocalBlockNo].AddField(Hyperparents);
// Hypernodes
vtkm::cont::Field Hypernodes("Hypernodes",
vtkm::cont::Field::Association::WholeDataSet,
ds.GetField("Hypernodes").GetData());
outputDataSets[b->LocalBlockNo].AddField(Hypernodes);
// Hyperarcs
vtkm::cont::Field Hyperarcs("Hyperarcs",
vtkm::cont::Field::Association::WholeDataSet,
ds.GetField("Hyperarcs").GetData());
outputDataSets[b->LocalBlockNo].AddField(Hyperarcs);
});
timingsStream << " " << std::setw(38) << std::left
<< "Creating Branch Decomposition Output Data"
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;
VTKM_LOG_S(vtkm::cont::LogLevel::Perf,
VTKM_LOG_S(this->TimingsLogLevel,
std::endl
<< "----------- DoExecutePartitions Timings ------------" << std::endl
<< timingsStream.str());

@ -63,11 +63,18 @@ public:
const vtkm::cont::ArrayHandle<vtkm::Id3>&,
const vtkm::cont::ArrayHandle<vtkm::Id3>&,
const vtkm::cont::ArrayHandle<vtkm::Id3>&);
VTKM_CONT void SetTimingsLogLevel(vtkm::cont::LogLevel timingsLogLevel)
{
this->TimingsLogLevel = timingsLogLevel;
}
private:
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet&) override;
VTKM_CONT vtkm::cont::PartitionedDataSet DoExecutePartitions(
const vtkm::cont::PartitionedDataSet& inData) override;
/// Log level to be used for outputting timing information. Default is vtkm::cont::LogLevel::Perf
vtkm::cont::LogLevel TimingsLogLevel = vtkm::cont::LogLevel::Perf;
};
} // namespace scalar_topology

File diff suppressed because it is too large Load Diff

@ -44,7 +44,6 @@
#include <vtkm/filter/Filter.h>
#include <vtkm/filter/scalar_topology/vtkm_filter_scalar_topology_export.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
@ -52,28 +51,47 @@ namespace filter
{
namespace scalar_topology
{
/// \brief Compute branch decompostion from distributed contour tree
/// \brief Compute branch decompostion from distributed contour tree
class VTKM_FILTER_SCALAR_TOPOLOGY_EXPORT SelectTopVolumeContoursFilter : public vtkm::filter::Filter
{
public:
VTKM_CONT SelectTopVolumeContoursFilter() = default;
VTKM_CONT void SetTimingsLogLevel(vtkm::cont::LogLevel timingsLogLevel)
{
this->TimingsLogLevel = timingsLogLevel;
}
VTKM_CONT void SetSavedBranches(const vtkm::Id& numBranches)
{
this->nSavedBranches = numBranches;
}
VTKM_CONT void SetMarchingCubes(const bool& marchingCubes)
{
this->isMarchingCubes = marchingCubes;
}
private:
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet&) override;
VTKM_CONT vtkm::cont::PartitionedDataSet DoExecutePartitions(
const vtkm::cont::PartitionedDataSet& inData) override;
bool isMarchingCubes = false;
vtkm::Id nSavedBranches;
vtkm::worklet::contourtree_augmented::IdArrayType BranchVolume;
vtkm::worklet::contourtree_augmented::IdArrayType BranchSaddleEpsilon;
vtkm::worklet::contourtree_augmented::IdArrayType SortedBranchByVolume;
vtkm::cont::ArrayHandle<vtkm::Id> BranchVolume;
vtkm::cont::ArrayHandle<vtkm::Id> BranchSaddleEpsilon;
vtkm::cont::ArrayHandle<vtkm::Id> SortedBranchByVolume;
vtkm::cont::UnknownArrayHandle BranchSaddleIsoValue;
// the parent branch for top volume branches
// we only care about the parent branch for top volume branches at the moment
// as a result, the index stored in this array follows the descending order of branch volumes
vtkm::cont::ArrayHandle<vtkm::Id> TopVolBranchParent;
/// Log level to be used for outputting timing information. Default is vtkm::cont::LogLevel::Perf
vtkm::cont::LogLevel TimingsLogLevel = vtkm::cont::LogLevel::Perf;
};
} // namespace scalar_topology

@ -13,6 +13,7 @@ set(headers
SelectTopVolumeContoursBlock.h
ComputeBlockIndices.h
ComputeDistributedBranchDecompositionFunctor.h
ParentBranchExtremaFunctor.h
SelectTopVolumeContoursFunctor.h
ExchangeBranchEndsFunctor.h
)

@ -75,7 +75,7 @@ void ComputeDistributedBranchDecompositionFunctor::operator()(
) const
{
// Get our rank and DIY id
//const vtkm::Id rank = vtkm::cont::EnvironmentTracker::GetCommunicator().rank();
const vtkm::Id rank = vtkm::cont::EnvironmentTracker::GetCommunicator().rank();
const auto selfid = rp.gid();
// Aliases to reduce verbosity
@ -110,6 +110,20 @@ void ComputeDistributedBranchDecompositionFunctor::operator()(
vtkm::cont::ArrayHandle<vtkm::Id> incomingBestDownSupernode;
rp.dequeue(ingid, incomingBestDownSupernode);
std::stringstream dataSizeStream;
// Log the amount of exchanged data
dataSizeStream << " " << std::setw(38) << std::left << "Incoming data size"
<< ": " << incomingBestUpSupernode.GetNumberOfValues() << std::endl;
VTKM_LOG_S(this->TimingsLogLevel,
std::endl
<< " ---------------- Compute Branch Decomposition Step ---------------------"
<< std::endl
<< " Rank : " << rank << std::endl
<< " DIY Id : " << selfid << std::endl
<< " Inc Id : " << ingid << std::endl
<< dataSizeStream.str());
vtkm::Id prefixLength = b->FirstSupernodePerIteration.ReadPortal().Get(rp.round() - 1)[0];
#ifdef DEBUG_PRINT

@ -73,10 +73,17 @@ namespace internal
struct ComputeDistributedBranchDecompositionFunctor
{
ComputeDistributedBranchDecompositionFunctor(const vtkm::cont::LogLevel& timingsLogLevel)
: TimingsLogLevel(timingsLogLevel)
{
}
void operator()(BranchDecompositionBlock* b,
const vtkmdiy::ReduceProxy& rp, // communication proxy
const vtkmdiy::RegularSwapPartners& // partners of the current block (unused)
) const;
const vtkm::cont::LogLevel TimingsLogLevel;
};
} // namespace internal

@ -54,6 +54,7 @@
#include <vtkm/filter/scalar_topology/worklet/branch_decomposition/hierarchical_volumetric_branch_decomposer/BranchEndGlobalUpdateWorklet.h>
#include <vtkm/Types.h>
#include <vtkm/cont/Logging.h>
#ifdef DEBUG_PRINT
#define DEBUG_PRINT_COMBINED_BLOCK_IDS
@ -75,6 +76,7 @@ void ExchangeBranchEndsFunctor::operator()(
) const
{
// Get our rank and DIY id
const vtkm::Id rank = vtkm::cont::EnvironmentTracker::GetCommunicator().rank();
const auto selfid = rp.gid();
// Aliases to reduce verbosity
@ -93,6 +95,7 @@ void ExchangeBranchEndsFunctor::operator()(
// Otherwise, we may need to process more than one incoming block
if (ingid != selfid)
{
#ifdef DEBUG_PRINT_COMBINED_BLOCK_IDS
int incomingGlobalBlockId;
rp.dequeue(ingid, incomingGlobalBlockId);
@ -126,6 +129,20 @@ void ExchangeBranchEndsFunctor::operator()(
IdArrayType incomingLowerEndDependentVolume;
rp.dequeue(ingid, incomingLowerEndDependentVolume);
std::stringstream dataSizeStream;
// Log the amount of exchanged data
dataSizeStream << " " << std::setw(38) << std::left << "Incoming branch size"
<< ": " << incomingBranchRootGRId.GetNumberOfValues() << std::endl;
VTKM_LOG_S(this->TimingsLogLevel,
std::endl
<< " ---------------- Exchange Branch Ends Step ---------------------"
<< std::endl
<< " Rank : " << rank << std::endl
<< " DIY Id : " << selfid << std::endl
<< " Inc Id : " << ingid << std::endl
<< dataSizeStream.str());
/// Superarc and Branch IDs are given based on the hierarchical level
/// Shared branches should lie on the smaller ID side of the branch array consecutively
/// We filter out shared branches first
@ -307,7 +324,8 @@ void ExchangeBranchEndsFunctor::operator()(
{
#ifdef DEBUG_PRINT_COMBINED_BLOCK_IDS
rp.enqueue(target, b->GlobalBlockId);
#endif
#endif // DEBUG_PRINT_COMBINED_BLOCK_IDS
rp.enqueue(target, branchDecomposer.BranchRootGRId);
rp.enqueue(target, branchDecomposer.UpperEndGRId);
rp.enqueue(target, branchDecomposer.LowerEndGRId);

@ -73,11 +73,19 @@ namespace internal
struct ExchangeBranchEndsFunctor
{
ExchangeBranchEndsFunctor(vtkm::cont::LogLevel timingsLogLevel = vtkm::cont::LogLevel::Perf)
: TimingsLogLevel(timingsLogLevel)
{
}
VTKM_CONT void operator()(
BranchDecompositionBlock* b,
const vtkmdiy::ReduceProxy& rp, // communication proxy
const vtkmdiy::RegularSwapPartners& // partners of the current block (unused)
) const;
private:
vtkm::cont::LogLevel TimingsLogLevel;
};
} // namespace internal

@ -0,0 +1,355 @@
//============================================================================
// 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.
//
//=============================================================================
//
// This code is an extension of the algorithm presented in the paper:
// Parallel Peak Pruning for Scalable SMP Contour Tree Computation.
// Hamish Carr, Gunther Weber, Christopher Sewell, and James Ahrens.
// Proceedings of the IEEE Symposium on Large Data Analysis and Visualization
// (LDAV), October 2016, Baltimore, Maryland.
//
// The PPP2 algorithm and software were jointly developed by
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
// Oliver Ruebel (LBNL)
//==============================================================================
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/filter/scalar_topology/internal/ParentBranchExtremaFunctor.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/ArrayTransforms.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/GetBranchHierarchyWorklet.h>
#include <vtkm/Types.h>
#include <iomanip>
#ifdef DEBUG_PRINT
#define DEBUG_PRINT_UPDATE_PARENT_BRANCH_ISOVALUE
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/PrintVectors.h>
#endif
namespace vtkm
{
namespace filter
{
namespace scalar_topology
{
namespace internal
{
void ParentBranchIsoValueFunctor::operator()(SelectTopVolumeContoursBlock* b,
const vtkmdiy::ReduceProxy& rp // communication proxy
) const
{
// Get our rank and
const vtkm::Id rank = vtkm::cont::EnvironmentTracker::GetCommunicator().rank();
const auto selfid = rp.gid();
// Aliases to reduce verbosity
using IdArrayType = vtkm::worklet::contourtree_augmented::IdArrayType;
vtkm::cont::Invoker invoke;
if (rp.in_link().size() == 0)
{
for (int cc = 0; cc < rp.out_link().size(); ++cc)
{
auto target = rp.out_link().target(cc);
if (target.gid != selfid)
{
#ifdef DEBUG_PRINT_UPDATE_PARENT_BRANCH_ISOVALUE
rp.enqueue(target, b->GlobalBlockId);
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Block " << b->GlobalBlockId << " enqueue to Block " << target.gid);
#endif
auto extraMaximaBranchOrderPortal = b->ExtraMaximaBranchOrder.ReadPortal();
vtkm::Id nExtraMaxBranches = extraMaximaBranchOrderPortal.GetNumberOfValues();
rp.enqueue(target, nExtraMaxBranches);
auto resolveMaxArray = [&](const auto& inArray) {
using InArrayHandleType = std::decay_t<decltype(inArray)>;
using ValueType = typename InArrayHandleType::ValueType;
// the global order of the branch can be the identity (unique for each branch)
auto extraMaxBranchIsoValuePortal = inArray.ReadPortal();
for (vtkm::Id branch = 0; branch < nExtraMaxBranches; ++branch)
rp.enqueue(target, extraMaximaBranchOrderPortal.Get(branch));
for (vtkm::Id branch = 0; branch < nExtraMaxBranches; ++branch)
rp.enqueue<ValueType>(target, extraMaxBranchIsoValuePortal.Get(branch));
};
if (b->ExtraMaximaBranchIsoValue.GetNumberOfValues())
b->ExtraMaximaBranchIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
resolveMaxArray);
// rp.enqueue(target, b->ExtraMaximaBranchOrder);
// rp.enqueue(target, b->ExtraMaximaBranchIsoValue);
auto extraMinimaBranchOrderPortal = b->ExtraMinimaBranchOrder.ReadPortal();
vtkm::Id nExtraMinBranches = extraMinimaBranchOrderPortal.GetNumberOfValues();
rp.enqueue(target, nExtraMinBranches);
auto resolveMinArray = [&](const auto& inArray) {
using InArrayHandleType = std::decay_t<decltype(inArray)>;
using ValueType = typename InArrayHandleType::ValueType;
// the global order of the branch can be the identity (unique for each branch)
auto extraMinBranchIsoValuePortal = inArray.ReadPortal();
for (vtkm::Id branch = 0; branch < nExtraMinBranches; ++branch)
rp.enqueue(target, extraMinimaBranchOrderPortal.Get(branch));
for (vtkm::Id branch = 0; branch < nExtraMinBranches; ++branch)
rp.enqueue<ValueType>(target, extraMinBranchIsoValuePortal.Get(branch));
};
if (b->ExtraMinimaBranchIsoValue.GetNumberOfValues())
b->ExtraMinimaBranchIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
resolveMinArray);
// rp.enqueue(target, b->ExtraMinimaBranchOrder);
// rp.enqueue(target, b->ExtraMinimaBranchIsoValue);
}
}
}
else
{
for (int i = 0; i < rp.in_link().size(); ++i)
{
int ingid = rp.in_link().target(i).gid;
if (ingid == selfid)
continue;
// copy incoming to the block
#ifdef DEBUG_PRINT_UPDATE_PARENT_BRANCH_ISOVALUE
int incomingGlobalBlockId;
rp.dequeue(ingid, incomingGlobalBlockId);
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Combining local block " << b->GlobalBlockId << " with incoming block "
<< incomingGlobalBlockId);
#endif
vtkm::Id nSelfMaxBranch = b->ExtraMaximaBranchOrder.GetNumberOfValues();
vtkm::Id nSelfMinBranch = b->ExtraMinimaBranchOrder.GetNumberOfValues();
// dequeue the data from other blocks.
// nExtraMaximaBranches (incoming)
// array of incoming maxima branch order
// array of incoming maxima branch isovalue
// nExtraMinimaBranches (incoming)
// array of incoming minima branch order
// array of incoming minima branch isovalue
// TODO/FIXME: This is a workaround for a bug in DIY/vtk-m.
// Replace with dequeuing ArrayHandles once bug is fixed.
vtkm::Id nIncomingMaxBranch;
rp.dequeue(ingid, nIncomingMaxBranch);
auto resolveMaxArray = [&](auto& inArray) {
using InArrayHandleType = std::decay_t<decltype(inArray)>;
using ValueType = typename InArrayHandleType::ValueType;
IdArrayType incomingMaxBranchOrder;
incomingMaxBranchOrder.Allocate(nIncomingMaxBranch);
auto incomingMaxBranchOrderPortal = incomingMaxBranchOrder.WritePortal();
for (vtkm::Id branch = 0; branch < nIncomingMaxBranch; ++branch)
{
vtkm::Id incomingTmpBranchOrder;
rp.dequeue(ingid, incomingTmpBranchOrder);
incomingMaxBranchOrderPortal.Set(branch, incomingTmpBranchOrder);
}
// TODO/FIXME: This is a workaround for a bug in DIY/vtk-m.
// Replace with dequeuing ArrayHandles once bug is fixed.
// rp.dequeue(ingid, incomingMaxBranchOrder);
InArrayHandleType incomingMaxBranchIsoValue;
incomingMaxBranchIsoValue.Allocate(nIncomingMaxBranch);
auto incomingMaxBranchIsoValuePortal = incomingMaxBranchIsoValue.WritePortal();
for (vtkm::Id branch = 0; branch < nIncomingMaxBranch; ++branch)
{
ValueType incomingBranchValue;
rp.dequeue<ValueType>(ingid, incomingBranchValue);
incomingMaxBranchIsoValuePortal.Set(branch, incomingBranchValue);
}
// TODO/FIXME: This is a workaround for a bug in DIY/vtk-m.
// Replace with dequeuing ArrayHandles once bug is fixed.
// rp.dequeue<InArrayHandleType>(ingid, incomingMaxBranchIsoValue);
#ifdef DEBUG_PRINT_UPDATE_PARENT_BRANCH_ISOVALUE
{
std::stringstream rs;
vtkm::worklet::contourtree_augmented::PrintHeader(nIncomingMaxBranch, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"incomingMaxBranchOrder", incomingMaxBranchOrder, -1, rs);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"incomingMaxBranchVal", incomingMaxBranchIsoValue, -1, rs);
vtkm::worklet::contourtree_augmented::PrintHeader(nSelfMaxBranch, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfMaxBranchOrder", b->ExtraMaximaBranchOrder, -1, rs);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"selfMaxBranchVal", inArray, -1, rs);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, rs.str());
}
#endif
vtkm::cont::Algorithm::SortByKey(incomingMaxBranchOrder, incomingMaxBranchIsoValue);
vtkm::worklet::scalar_topology::select_top_volume_contours::UpdateOuterSaddle<true>
updateValueOnMaxBranch;
invoke(updateValueOnMaxBranch,
b->ExtraMaximaBranchOrder,
inArray,
incomingMaxBranchOrder,
incomingMaxBranchIsoValue);
#ifdef DEBUG_PRINT_UPDATE_PARENT_BRANCH_ISOVALUE
{
std::stringstream rs;
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);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"selfMaxBranchVal", inArray, -1, rs);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, rs.str());
}
#endif
};
if (nSelfMaxBranch > 0 && nIncomingMaxBranch > 0)
b->ExtraMaximaBranchIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
resolveMaxArray);
/* Apply the same pipeline for branches with minima to extract */
vtkm::Id nIncomingMinBranch;
rp.dequeue(ingid, nIncomingMinBranch);
auto resolveMinArray = [&](auto& inArray) {
using InArrayHandleType = std::decay_t<decltype(inArray)>;
using ValueType = typename InArrayHandleType::ValueType;
IdArrayType incomingMinBranchOrder;
incomingMinBranchOrder.Allocate(nIncomingMinBranch);
auto incomingMinBranchOrderPortal = incomingMinBranchOrder.WritePortal();
for (vtkm::Id branch = 0; branch < nIncomingMinBranch; ++branch)
{
vtkm::Id incomingTmpBranchOrder;
rp.dequeue(ingid, incomingTmpBranchOrder);
incomingMinBranchOrderPortal.Set(branch, incomingTmpBranchOrder);
}
// TODO/FIXME: This is a workaround for a bug in DIY/vtk-m.
// Replace with dequeuing ArrayHandles once bug is fixed.
// rp.dequeue(ingid, incomingMinBranchOrder);
InArrayHandleType incomingMinBranchIsoValue;
incomingMinBranchIsoValue.Allocate(nIncomingMinBranch);
auto incomingMinBranchIsoValuePortal = incomingMinBranchIsoValue.WritePortal();
for (vtkm::Id branch = 0; branch < nIncomingMinBranch; ++branch)
{
ValueType incomingBranchValue;
rp.dequeue<ValueType>(ingid, incomingBranchValue);
incomingMinBranchIsoValuePortal.Set(branch, incomingBranchValue);
}
// TODO/FIXME: This is a workaround for a bug in DIY/vtk-m.
// Replace with dequeuing ArrayHandles once bug is fixed.
// rp.dequeue<InArrayHandleType>(ingid, incomingMinBranchIsoValue);
#ifdef DEBUG_PRINT_UPDATE_PARENT_BRANCH_ISOVALUE
{
std::stringstream rs;
vtkm::worklet::contourtree_augmented::PrintHeader(nIncomingMinBranch, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"incomingMinBranchOrder", incomingMinBranchOrder, -1, rs);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"incomingMinBranchVal", incomingMinBranchIsoValue, -1, rs);
vtkm::worklet::contourtree_augmented::PrintHeader(nSelfMinBranch, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfMinBranchOrder", b->ExtraMinimaBranchOrder, -1, rs);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"selfMinBranchVal", inArray, -1, rs);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, rs.str());
}
#endif
vtkm::cont::Algorithm::SortByKey(incomingMinBranchOrder, incomingMinBranchIsoValue);
vtkm::worklet::scalar_topology::select_top_volume_contours::UpdateOuterSaddle<false>
updateValueOnMinBranch;
invoke(updateValueOnMinBranch,
b->ExtraMinimaBranchOrder,
inArray,
incomingMinBranchOrder,
incomingMinBranchIsoValue);
#ifdef DEBUG_PRINT_UPDATE_PARENT_BRANCH_ISOVALUE
{
std::stringstream rs;
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);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"selfMinBranchVal", inArray, -1, rs);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, rs.str());
}
#endif
};
if (nSelfMinBranch > 0 && nIncomingMinBranch > 0)
b->ExtraMinimaBranchIsoValue
.CastAndCallForTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(
resolveMinArray);
// The logging is commented because the size of exchange is limited by K,
// the number of top-volume branches, which is usually small
std::stringstream dataSizeStream;
// Log the amount of exchanged data
dataSizeStream << " " << std::setw(38) << std::left << "Incoming branch size"
<< ": " << nIncomingMaxBranch + nIncomingMinBranch << std::endl;
VTKM_LOG_S(this->TimingsLogLevel,
std::endl
<< " ---------------- Exchange Parent Branch Step ---------------------"
<< std::endl
<< " Rank : " << rank << std::endl
<< " DIY Id : " << selfid << std::endl
<< " Inc Id : " << ingid << std::endl
<< dataSizeStream.str());
}
}
}
} // namespace internal
} // namespace scalar_topology
} // namespace filter
} // namespace vtkm

@ -0,0 +1,93 @@
//============================================================================
// 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.
//
//=============================================================================
//
// This code is an extension of the algorithm presented in the paper:
// Parallel Peak Pruning for Scalable SMP Contour Tree Computation.
// Hamish Carr, Gunther Weber, Christopher Sewell, and James Ahrens.
// Proceedings of the IEEE Symposium on Large Data Analysis and Visualization
// (LDAV), October 2016, Baltimore, Maryland.
//
// The PPP2 algorithm and software were jointly developed by
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
// Oliver Ruebel (LBNL)
//==============================================================================
#ifndef vtk_m_filter_scalar_topology_internal_ParentBranchExtremaFunctor_h
#define vtk_m_filter_scalar_topology_internal_ParentBranchExtremaFunctor_h
#include <vtkm/filter/scalar_topology/internal/SelectTopVolumeContoursBlock.h>
// clang-format off
VTKM_THIRDPARTY_PRE_INCLUDE
#include <vtkm/thirdparty/diy/diy.h>
VTKM_THIRDPARTY_POST_INCLUDE
// clang-format on
namespace vtkm
{
namespace filter
{
namespace scalar_topology
{
namespace internal
{
struct ParentBranchIsoValueFunctor
{
ParentBranchIsoValueFunctor(const vtkm::cont::LogLevel& timingsLogLevel)
: TimingsLogLevel(timingsLogLevel)
{
}
void operator()(SelectTopVolumeContoursBlock* b,
const vtkmdiy::ReduceProxy& rp // communication proxy
) const;
const vtkm::cont::LogLevel TimingsLogLevel;
};
} // namespace internal
} // namespace scalar_topology
} // namespace filter
} // namespace vtkm
#endif

@ -69,6 +69,12 @@ 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)
@ -103,13 +109,14 @@ void SelectTopVolumeContoursBlock::SortBranchByVolume(
auto lowerEndDependentVolume = hierarchicalTreeDataSet.GetField("LowerEndDependentVolume")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
auto lowerEndSuperarcId = hierarchicalTreeDataSet.GetField("LowerEndSuperarcId")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
auto upperEndSuperarcId = hierarchicalTreeDataSet.GetField("UpperEndSuperarcId")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
auto branchRoot = hierarchicalTreeDataSet.GetField("BranchRoot")
auto branchRoot = hierarchicalTreeDataSet.GetField("BranchRootByBranch")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();

@ -76,16 +76,58 @@ struct SelectTopVolumeContoursBlock
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;
// 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;
vtkm::cont::ArrayHandle<vtkm::Vec3f_64> IsosurfaceEdgesTo;
vtkm::worklet::contourtree_augmented::IdArrayType IsosurfaceEdgesOffset;
vtkm::worklet::contourtree_augmented::IdArrayType IsosurfaceEdgesLabels;
vtkm::worklet::contourtree_augmented::IdArrayType IsosurfaceEdgesOrders;
vtkm::cont::UnknownArrayHandle IsosurfaceIsoValue;
// Destroy function allowing DIY to own blocks and clean them up after use
static void Destroy(void* b) { delete static_cast<SelectTopVolumeContoursBlock*>(b); }

@ -49,7 +49,7 @@
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
// Oliver Ruebel (LBNL)
//==============================================================================
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/filter/scalar_topology/internal/SelectTopVolumeContoursFunctor.h>
#include <vtkm/filter/scalar_topology/worklet/branch_decomposition/hierarchical_volumetric_branch_decomposer/GetOuterEndWorklet.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/ArrayTransforms.h>
@ -57,6 +57,8 @@
#include <vtkm/Types.h>
#include <iomanip>
#ifdef DEBUG_PRINT
#define DEBUG_PRINT_COMBINED_HIGH_VOLUME_BRANCH
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/PrintVectors.h>
@ -79,7 +81,7 @@ void SelectTopVolumeContoursFunctor::operator()(
if (this->nSavedBranches < 1)
return;
// Get our rank and DIY id
//const vtkm::Id rank = vtkm::cont::EnvironmentTracker::GetCommunicator().rank();
const vtkm::Id rank = vtkm::cont::EnvironmentTracker::GetCommunicator().rank();
const auto selfid = rp.gid();
// Aliases to reduce verbosity
@ -102,6 +104,8 @@ void SelectTopVolumeContoursFunctor::operator()(
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();
vtkm::Id nBranches = topVolBranchRootGRIdPortal.GetNumberOfValues();
@ -112,6 +116,10 @@ void SelectTopVolumeContoursFunctor::operator()(
rp.enqueue(target, topVolBranchVolumePortal.Get(branch));
for (vtkm::Id branch = 0; branch < nBranches; ++branch)
rp.enqueue(target, topVolBranchSaddleEpsilonPortal.Get(branch));
for (vtkm::Id branch = 0; branch < nBranches; ++branch)
rp.enqueue(target, topVolBranchUpperEndPortal.Get(branch));
for (vtkm::Id branch = 0; branch < nBranches; ++branch)
rp.enqueue(target, topVolBranchLowerEndPortal.Get(branch));
auto resolveArray = [&](const auto& inArray) {
using InArrayHandleType = std::decay_t<decltype(inArray)>;
@ -199,6 +207,34 @@ void SelectTopVolumeContoursFunctor::operator()(
// Replace with dequeuing ArrayHandles once bug is fixed.
// rp.dequeue(ingid, incomingTopVolBranchSaddleEpsilon);
IdArrayType incomingTopVolBranchUpperEnd;
incomingTopVolBranchUpperEnd.Allocate(nIncoming);
auto incomingTopVolBranchUpperEndPortal = incomingTopVolBranchUpperEnd.WritePortal();
for (vtkm::Id branch = 0; branch < nIncoming; ++branch)
{
vtkm::Id incomingTmpBranchUpperEnd;
rp.dequeue(ingid, incomingTmpBranchUpperEnd);
incomingTopVolBranchUpperEndPortal.Set(branch, incomingTmpBranchUpperEnd);
}
// TODO/FIXME: This is a workaround for a bug in DIY/vtk-m.
// Replace with dequeuing ArrayHandles once bug is fixed.
// rp.dequeue(ingid, incomingTopVolBranchUpperEnd);
IdArrayType incomingTopVolBranchLowerEnd;
incomingTopVolBranchLowerEnd.Allocate(nIncoming);
auto incomingTopVolBranchLowerEndPortal = incomingTopVolBranchLowerEnd.WritePortal();
for (vtkm::Id branch = 0; branch < nIncoming; ++branch)
{
vtkm::Id incomingTmpBranchLowerEnd;
rp.dequeue(ingid, incomingTmpBranchLowerEnd);
incomingTopVolBranchLowerEndPortal.Set(branch, incomingTmpBranchLowerEnd);
}
// TODO/FIXME: This is a workaround for a bug in DIY/vtk-m.
// Replace with dequeuing ArrayHandles once bug is fixed.
// rp.dequeue(ingid, incomingTopVolBranchLowerEnd);
auto resolveArray = [&](auto& inArray) {
using InArrayHandleType = std::decay_t<decltype(inArray)>;
using ValueType = typename InArrayHandleType::ValueType;
@ -213,6 +249,20 @@ void SelectTopVolumeContoursFunctor::operator()(
incomingTopVolBranchSaddleIsoValuePortal.Set(branch, incomingSaddleValue);
}
std::stringstream dataSizeStream;
// Log the amount of exchanged data
dataSizeStream << " " << std::setw(38) << std::left << "Incoming top volume branch size"
<< ": " << nIncoming << std::endl;
VTKM_LOG_S(this->TimingsLogLevel,
std::endl
<< " ---------------- Select Top Volume Branches Step ---------------------"
<< std::endl
<< " Rank : " << rank << std::endl
<< " DIY Id : " << selfid << std::endl
<< " Inc Id : " << ingid << std::endl
<< dataSizeStream.str());
// TODO/FIXME: This is a workaround for a bug in DIY/vtk-m.
// Replace with dequeuing ArrayHandles once bug is fixed.
// rp.dequeue<InArrayHandleType>(ingid, incomingTopVolBranchSaddleIsoValue);
@ -231,6 +281,10 @@ void SelectTopVolumeContoursFunctor::operator()(
"incomingTopBranchVol", incomingTopVolBranchVolume, -1, rs);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"incomingSaddleVal", incomingTopVolBranchSaddleIsoValue, -1, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"incomingUpperEnd", incomingTopVolBranchUpperEnd, -1, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"incomingLowerEnd", incomingTopVolBranchLowerEnd, -1, rs);
vtkm::worklet::contourtree_augmented::PrintHeader(nSelf, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
@ -239,6 +293,10 @@ void SelectTopVolumeContoursFunctor::operator()(
"selfTopBranchVol", b->TopVolumeBranchVolume, -1, rs);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"selfTopSaddleVal", inArray, -1, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfTopBranchUpperEnd", b->TopVolumeBranchUpperEndGRId, -1, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"selfTopBranchLowerEnd", b->TopVolumeBranchLowerEndGRId, -1, rs);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, rs.str());
}
#endif
@ -246,10 +304,14 @@ void SelectTopVolumeContoursFunctor::operator()(
IdArrayType mergedTopVolBranchGRId;
IdArrayType mergedTopVolBranchVolume;
IdArrayType mergedTopVolBranchSaddleEpsilon;
IdArrayType mergedTopVolBranchUpperEnd;
IdArrayType mergedTopVolBranchLowerEnd;
InArrayHandleType mergedTopVolBranchSaddleIsoValue;
mergedTopVolBranchGRId.Allocate(nIncoming + nSelf);
mergedTopVolBranchVolume.Allocate(nIncoming + nSelf);
mergedTopVolBranchSaddleEpsilon.Allocate(nIncoming + nSelf);
mergedTopVolBranchUpperEnd.Allocate(nIncoming + nSelf);
mergedTopVolBranchLowerEnd.Allocate(nIncoming + nSelf);
mergedTopVolBranchSaddleIsoValue.Allocate(nIncoming + nSelf);
vtkm::cont::Algorithm::CopySubRange(
@ -258,6 +320,10 @@ void SelectTopVolumeContoursFunctor::operator()(
incomingTopVolBranchVolume, 0, nIncoming, mergedTopVolBranchVolume, 0);
vtkm::cont::Algorithm::CopySubRange(
incomingTopVolBranchSaddleEpsilon, 0, nIncoming, mergedTopVolBranchSaddleEpsilon, 0);
vtkm::cont::Algorithm::CopySubRange(
incomingTopVolBranchUpperEnd, 0, nIncoming, mergedTopVolBranchUpperEnd, 0);
vtkm::cont::Algorithm::CopySubRange(
incomingTopVolBranchLowerEnd, 0, nIncoming, mergedTopVolBranchLowerEnd, 0);
vtkm::cont::Algorithm::CopySubRange<ValueType, ValueType>(
incomingTopVolBranchSaddleIsoValue, 0, nIncoming, mergedTopVolBranchSaddleIsoValue, 0);
vtkm::cont::Algorithm::CopySubRange(
@ -266,6 +332,10 @@ void SelectTopVolumeContoursFunctor::operator()(
b->TopVolumeBranchVolume, 0, nSelf, mergedTopVolBranchVolume, nIncoming);
vtkm::cont::Algorithm::CopySubRange(
b->TopVolumeBranchSaddleEpsilon, 0, nSelf, mergedTopVolBranchSaddleEpsilon, nIncoming);
vtkm::cont::Algorithm::CopySubRange(
b->TopVolumeBranchUpperEndGRId, 0, nSelf, mergedTopVolBranchUpperEnd, nIncoming);
vtkm::cont::Algorithm::CopySubRange(
b->TopVolumeBranchLowerEndGRId, 0, nSelf, mergedTopVolBranchLowerEnd, nIncoming);
vtkm::cont::Algorithm::CopySubRange<ValueType, ValueType>(
inArray, 0, nSelf, mergedTopVolBranchSaddleIsoValue, nIncoming);
@ -289,6 +359,12 @@ void SelectTopVolumeContoursFunctor::operator()(
IdArrayType permutedTopVolBranchSaddleEpsilon;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
mergedTopVolBranchSaddleEpsilon, sortedBranchId, permutedTopVolBranchSaddleEpsilon);
IdArrayType permutedTopVolBranchUpperEnd;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
mergedTopVolBranchUpperEnd, sortedBranchId, permutedTopVolBranchUpperEnd);
IdArrayType permutedTopVolBranchLowerEnd;
vtkm::worklet::contourtree_augmented::PermuteArrayWithMaskedIndex<vtkm::Id, IdArrayType>(
mergedTopVolBranchLowerEnd, sortedBranchId, permutedTopVolBranchLowerEnd);
InArrayHandleType permutedTopVolBranchSaddleIsoValue;
vtkm::worklet::contourtree_augmented::PermuteArrayWithRawIndex<InArrayHandleType>(
mergedTopVolBranchSaddleIsoValue, sortedBranchId, permutedTopVolBranchSaddleIsoValue);
@ -301,6 +377,10 @@ void SelectTopVolumeContoursFunctor::operator()(
"permutedTopBranchId", permutedTopVolBranchGRId, -1, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"permutedTopBranchVol", permutedTopVolBranchVolume, -1, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"permutedTopBranchUpperEnd", permutedTopVolBranchUpperEnd, -1, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"permutedTopBranchLowerEnd", permutedTopVolBranchLowerEnd, -1, rs);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"permutedTopSaddleVal", permutedTopVolBranchSaddleIsoValue, -1, rs);
}
@ -318,6 +398,8 @@ void SelectTopVolumeContoursFunctor::operator()(
IdArrayType mergedUniqueBranchGRId;
IdArrayType mergedUniqueBranchVolume;
IdArrayType mergedUniqueBranchSaddleEpsilon;
IdArrayType mergedUniqueBranchUpperEnd;
IdArrayType mergedUniqueBranchLowerEnd;
InArrayHandleType mergedUniqueBranchSaddleIsoValue;
vtkm::cont::Algorithm::CopyIf(
@ -326,6 +408,10 @@ void SelectTopVolumeContoursFunctor::operator()(
permutedTopVolBranchVolume, oneIfUniqueBranch, mergedUniqueBranchVolume);
vtkm::cont::Algorithm::CopyIf(
permutedTopVolBranchSaddleEpsilon, oneIfUniqueBranch, mergedUniqueBranchSaddleEpsilon);
vtkm::cont::Algorithm::CopyIf(
permutedTopVolBranchUpperEnd, oneIfUniqueBranch, mergedUniqueBranchUpperEnd);
vtkm::cont::Algorithm::CopyIf(
permutedTopVolBranchLowerEnd, oneIfUniqueBranch, mergedUniqueBranchLowerEnd);
vtkm::cont::Algorithm::CopyIf(
permutedTopVolBranchSaddleIsoValue, oneIfUniqueBranch, mergedUniqueBranchSaddleIsoValue);
@ -339,6 +425,10 @@ void SelectTopVolumeContoursFunctor::operator()(
"mergedUniqueBranchId", mergedUniqueBranchGRId, -1, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"mergedUniqueBranchVol", mergedUniqueBranchVolume, -1, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"mergedUniqueBranchUpperEnd", mergedUniqueBranchUpperEnd, -1, rs);
vtkm::worklet::contourtree_augmented::PrintIndices(
"mergedUniqueBranchLowerEnd", mergedUniqueBranchLowerEnd, -1, rs);
vtkm::worklet::contourtree_augmented::PrintValues<ValueType>(
"mergedUniqueSaddleVal", mergedUniqueBranchSaddleIsoValue, -1, rs);
}
@ -356,6 +446,10 @@ void SelectTopVolumeContoursFunctor::operator()(
0,
this->nSavedBranches,
b->TopVolumeBranchSaddleEpsilon);
vtkm::cont::Algorithm::CopySubRange(
mergedUniqueBranchUpperEnd, 0, this->nSavedBranches, b->TopVolumeBranchUpperEndGRId);
vtkm::cont::Algorithm::CopySubRange(
mergedUniqueBranchLowerEnd, 0, this->nSavedBranches, b->TopVolumeBranchLowerEndGRId);
// InArrayHandleType subRangeUniqueBranchSaddleIsoValue;
inArray.Allocate(this->nSavedBranches);
vtkm::cont::Algorithm::CopySubRange(
@ -368,6 +462,8 @@ void SelectTopVolumeContoursFunctor::operator()(
vtkm::cont::Algorithm::Copy(mergedUniqueBranchVolume, b->TopVolumeBranchVolume);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchSaddleEpsilon,
b->TopVolumeBranchSaddleEpsilon);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchUpperEnd, b->TopVolumeBranchUpperEndGRId);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchLowerEnd, b->TopVolumeBranchLowerEndGRId);
inArray.Allocate(nMergedUnique);
vtkm::cont::Algorithm::Copy(mergedUniqueBranchSaddleIsoValue, inArray);
}

@ -73,8 +73,9 @@ namespace internal
struct SelectTopVolumeContoursFunctor
{
SelectTopVolumeContoursFunctor(const vtkm::Id& nSB)
SelectTopVolumeContoursFunctor(const vtkm::Id& nSB, const vtkm::cont::LogLevel& timingsLogLevel)
: nSavedBranches(nSB)
, TimingsLogLevel(timingsLogLevel)
{
}
@ -83,6 +84,7 @@ struct SelectTopVolumeContoursFunctor
) const;
const vtkm::Id nSavedBranches;
const vtkm::cont::LogLevel TimingsLogLevel;
};
} // namespace internal

@ -182,6 +182,11 @@ public:
vtkm::worklet::contourtree_augmented::IdArrayType LowerEndIntrinsicVolume;
vtkm::worklet::contourtree_augmented::IdArrayType UpperEndDependentVolume;
vtkm::worklet::contourtree_augmented::IdArrayType LowerEndDependentVolume;
// This information is only used when extracting isosurfaces
// We need the upper and lower end within the block to determine the superarc containing the isovalue
// The information should NOT be exchanged between blocks, since it's local id
vtkm::worklet::contourtree_augmented::IdArrayType UpperEndLocalId;
vtkm::worklet::contourtree_augmented::IdArrayType LowerEndLocalId;
/// routines to compute branch decomposition by volume
/// WARNING: we now have two types of hierarchical tree sharing a data structure:
@ -507,11 +512,19 @@ inline void HierarchicalVolumetricBranchDecomposer::CollapseBranches(
hierarchicalTreeSuperarcs
};
// Get the number of rounds
auto numRoundsArray = hierarchicalTreeDataSet.GetField("NumRounds")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
vtkm::Id numRounds = vtkm::cont::ArrayGetValue(0, numRoundsArray);
using vtkm::worklet::scalar_topology::hierarchical_volumetric_branch_decomposer::
CollapseBranchesWorklet;
this->Invoke(CollapseBranchesWorklet{}, // the worklet
CollapseBranchesWorklet collapseBranchesWorklet(numRounds);
this->Invoke(collapseBranchesWorklet, // the worklet
this->BestUpSupernode, // input
this->BestDownSupernode, // input
hierarchicalTreeSuperarcs, // input
findRegularByGlobal, // input ExecutionObject
findSuperArcBetweenNodes, // input ExecutionObject
hierarchicalTreeRegular2Supernode, // input
@ -770,6 +783,8 @@ inline void HierarchicalVolumetricBranchDecomposer::CollectEndsOfBranches(
vtkm::cont::make_ArrayHandlePermutation(sortedSuperarcs, actualBranchRoots);
auto permutedRegularIds =
vtkm::cont::make_ArrayHandlePermutation(sortedSuperarcs, actualOuterNodeRegularIds);
auto permutedLocalIds =
vtkm::cont::make_ArrayHandlePermutation(sortedSuperarcs, actualOuterNodeLocalIds);
auto permutedDataValues =
vtkm::cont::make_ArrayHandlePermutation(sortedSuperarcs, actualOuterNodeValues);
auto permutedIntrinsicVolumes =
@ -817,6 +832,7 @@ inline void HierarchicalVolumetricBranchDecomposer::CollectEndsOfBranches(
{
vtkm::cont::Algorithm::CopyIf(permutedBranchRoots, oneIfBranchEnd, this->BranchRoot);
vtkm::cont::Algorithm::CopyIf(branchRootGRIds, oneIfBranchEnd, this->BranchRootGRId);
vtkm::cont::Algorithm::CopyIf(permutedLocalIds, oneIfBranchEnd, this->LowerEndLocalId);
vtkm::cont::Algorithm::CopyIf(
actualDirectedSuperarcs, oneIfBranchEnd, this->LowerEndSuperarcId);
vtkm::cont::Algorithm::CopyIf(permutedRegularIds, oneIfBranchEnd, this->LowerEndGRId);
@ -857,6 +873,7 @@ inline void HierarchicalVolumetricBranchDecomposer::CollectEndsOfBranches(
vtkm::cont::Algorithm::CopyIf(
actualDirectedSuperarcs, oneIfBranchEnd, this->UpperEndSuperarcId);
vtkm::cont::Algorithm::CopyIf(permutedRegularIds, oneIfBranchEnd, this->UpperEndGRId);
vtkm::cont::Algorithm::CopyIf(permutedLocalIds, oneIfBranchEnd, this->UpperEndLocalId);
vtkm::cont::Algorithm::CopyIf(
permutedIntrinsicVolumes, oneIfBranchEnd, this->UpperEndIntrinsicVolume);
vtkm::cont::Algorithm::CopyIf(

@ -65,6 +65,7 @@ public:
using ControlSignature = void(
FieldIn bestUpSupernode,
FieldIn bestDownSupernode,
FieldIn superarcs,
// Execution objects from the hierarchical tree to use the FindRegularByGlobal function
ExecObject findRegularByGlobal,
// Execution objects from the hierarchical tree to use the FindSuperArcBetweenNodes, function
@ -72,12 +73,15 @@ public:
WholeArrayIn hierarchicalTreeRegular2supernode,
WholeArrayIn hierarchicalTreeWhichRound,
WholeArrayInOut branchRoot);
using ExecutionSignature = void(InputIndex, _1, _2, _3, _4, _5, _6, _7);
using ExecutionSignature = void(InputIndex, _1, _2, _3, _4, _5, _6, _7, _8);
using InputDomain = _1;
/// Default Constructor
VTKM_EXEC_CONT
CollapseBranchesWorklet() {}
CollapseBranchesWorklet(vtkm::Id numRounds)
: NumRounds(numRounds)
{
}
/// operator() of the workelt
template <typename ExecObjectType1,
@ -88,6 +92,7 @@ public:
const vtkm::Id& supernode, // iteration index
const vtkm::Id& bestUpSupernodeId, // bestUpSupernode[supernode]
const vtkm::Id& bestDownSupernodeId, // bestDownSupernode[supernode]
const vtkm::Id& superarcsId, // hierarchicalTree.superarcs[supernode]
const ExecObjectType1& findRegularByGlobal, // Execution object to call FindRegularByGlobal
const ExecObjectType2&
findSuperArcBetweenNodes, // Execution object to call FindSuperArcBetweenNodes
@ -104,6 +109,18 @@ public:
// If it does exist and is an upwards superarc, then the current supernode must have an ascending arc to it, and we're done
// Also do the same for the best down, then for each supernode, point the higher numbered at the lower
// ADDED 19/07/2023
// If there are any attachment points left in the hierarchical tree, there is an extra edge case we need to deal with.
// It occurs when a supernode is simultaneously the target of an ascending superarc and a descending one
// What we do is to test for this here: if we are an attachment point, we omit connecting the best up and down
// ADDED 19/07/2023
// test for attachment points
if ((hierarchicalTreeWhichRoundPortal.Get(supernode) != this->NumRounds) &&
(vtkm::worklet::contourtree_augmented::NoSuchElement(superarcsId)))
{
return;
}
// if there is no best up, we're at an upper leaf and will not connect up two superarcs anyway, so we can skip the supernode
if (vtkm::worklet::contourtree_augmented::NoSuchElement(bestUpSupernodeId))
{
@ -233,6 +250,8 @@ public:
*/
} // operator()()
private:
vtkm::Id NumRounds;
}; // CollapseBranchesWorklet

@ -111,7 +111,7 @@ public:
using ControlSignature = void(
FieldIn superarcId, // (input) actual ID of superarc
WholeArrayIn branchRoots, // (array input) branch root (superarc) IDs of all superarcs
FieldOut branchEndIndicator // (output) 1 if
FieldOut branchEndIndicator // (output) 1 if the superarc is the last of a branch in the array
);
using ExecutionSignature = _3(_1, _2);
using InputDomain = _1;

@ -102,6 +102,7 @@
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/hierarchical_augmenter/AttachmentSuperparentAndIndexComparator.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/hierarchical_augmenter/CopyBaseRegularStructureWorklet.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/hierarchical_augmenter/CreateSuperarcsWorklet.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/hierarchical_augmenter/FillEmptyIterationWorklet.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/hierarchical_augmenter/FindSuperparentForNecessaryNodesWorklet.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/hierarchical_augmenter/HierarchicalAugmenterInOutData.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/hierarchical_augmenter/IsAscendingDecorator.h>
@ -127,6 +128,11 @@ template <typename FieldType>
class HierarchicalAugmenter
{ // class HierarchicalAugmenter
public:
/// base mesh variable needs to determine whether a vertex is inside or outside of the block
vtkm::Id3 MeshBlockOrigin;
vtkm::Id3 MeshBlockSize;
vtkm::Id3 MeshGlobalSize;
/// the tree that it hypersweeps over
vtkm::worklet::contourtree_distributed::HierarchicalContourTree<FieldType>* BaseTree;
/// the tree that it is building
@ -198,7 +204,10 @@ public:
void Initialize(
vtkm::Id blockId,
vtkm::worklet::contourtree_distributed::HierarchicalContourTree<FieldType>* inBaseTree,
vtkm::worklet::contourtree_distributed::HierarchicalContourTree<FieldType>* inAugmentedTree);
vtkm::worklet::contourtree_distributed::HierarchicalContourTree<FieldType>* inAugmentedTree,
vtkm::Id3 meshBlockOrigin,
vtkm::Id3 meshBockSize,
vtkm::Id3 meshGlobalSize);
/// routine to prepare the set of attachment points to transfer
void PrepareOutAttachmentPoints(vtkm::Id round);
@ -225,7 +234,7 @@ public:
void CopyBaseRegularStructure();
// subroutines for CopySuperstructure
/// gets a list of all the old supernodes to transfer at this level (ie except attachment points
/// gets a list of all the old supernodes to transfer at this level (i.e., except attachment points
void RetrieveOldSupernodes(vtkm::Id roundNumber);
/// resizes the arrays for the level
void ResizeArrays(vtkm::Id roundNumber);
@ -249,12 +258,18 @@ template <typename FieldType>
void HierarchicalAugmenter<FieldType>::Initialize(
vtkm::Id blockId,
vtkm::worklet::contourtree_distributed::HierarchicalContourTree<FieldType>* baseTree,
vtkm::worklet::contourtree_distributed::HierarchicalContourTree<FieldType>* augmentedTree)
vtkm::worklet::contourtree_distributed::HierarchicalContourTree<FieldType>* augmentedTree,
vtkm::Id3 meshBlockOrigin,
vtkm::Id3 meshBockSize,
vtkm::Id3 meshGlobalSize)
{ // Initialize()
// copy the parameters for use
this->BlockId = blockId;
this->BaseTree = baseTree;
this->AugmentedTree = augmentedTree;
this->MeshBlockOrigin = meshBlockOrigin;
this->MeshBlockSize = meshBockSize;
this->MeshGlobalSize = meshGlobalSize;
// now construct a list of all attachment points on the block
// to do this, we construct an index array with all supernode ID's that satisfy:
@ -728,12 +743,13 @@ void HierarchicalAugmenter<FieldType>::CopyBaseRegularStructure()
vtkm::worklet::contourtree_augmented::IdArrayType tempRegularNodesNeeded;
// create the worklet
vtkm::worklet::contourtree_distributed::hierarchical_augmenter::
FindSuperparentForNecessaryNodesWorklet findSuperparentForNecessaryNodesWorklet;
FindSuperparentForNecessaryNodesWorklet findSuperparentForNecessaryNodesWorklet(
this->MeshBlockOrigin, this->MeshBlockSize, this->MeshGlobalSize);
// Get a FindRegularByGlobal and FindSuperArcForUnknownNode execution object for our worklet
auto findRegularByGlobal = this->AugmentedTree->GetFindRegularByGlobal();
auto findSuperArcForUnknownNode = this->AugmentedTree->GetFindSuperArcForUnknownNode();
// excute the worklet
// execute the worklet
this->Invoke(findSuperparentForNecessaryNodesWorklet, // the worklet to call
// inputs
this->BaseTree->RegularNodeGlobalIds, // input domain
@ -831,6 +847,11 @@ void HierarchicalAugmenter<FieldType>::CopyBaseRegularStructure()
);
}
// Reset the number of regular nodes in round 0
vtkm::Id regularNodesInRound0 =
numTotalRegular - this->AugmentedTree->NumRegularNodesInRound.ReadPortal().Get(1);
this->AugmentedTree->NumRegularNodesInRound.WritePortal().Set(0, regularNodesInRound0);
// Finally, we resort the regular node sort order
{
vtkm::worklet::contourtree_distributed::PermuteComparator // hierarchical_contour_tree::
@ -1218,6 +1239,7 @@ void HierarchicalAugmenter<FieldType>::CreateSuperarcs(vtkm::Id roundNumber)
vtkm::cont::make_ArrayHandleView(this->AugmentedTree->Super2Hypernode,
numSupernodesAlready,
this->SupernodeSorter.GetNumberOfValues());
// invoke the worklet
this->Invoke(createSuperarcsWorklet, // the worklet
this->SupernodeSorter, // input domain
@ -1297,6 +1319,19 @@ void HierarchicalAugmenter<FieldType>::CreateSuperarcs(vtkm::Id roundNumber)
// But there might be *NO* supernodes in the round, so we check first
vtkm::Id iterationArraySize =
vtkm::cont::ArrayGetValue(roundNumber, this->AugmentedTree->NumIterations);
// This was added because in rare cases there are no supernodes transferred in an iteration, for example because there
// are no available upper leaves to prune. If this is case, we are guaranteed that there will be available lower leaves
// so the next iteration will have a non-zero number. We had a major bug from this, and it's cropped back up in the.
// Hierarchical Augmentation, so I'm expanding the comment just in case.
// Mingzhe: for any empty iteration, augmentedTree->FirstSupernodePerIteration[round] will be 0
// Fill the 0 out (except when it is leading) by its following number as necessary
// There should never be two consecutive zeros, so running it in parallel should be safe
vtkm::worklet::contourtree_distributed::hierarchical_augmenter::FillEmptyIterationWorklet
fillEmptyIterationWorklet;
this->Invoke(fillEmptyIterationWorklet,
this->AugmentedTree->FirstSupernodePerIteration[roundNumber]);
if (iterationArraySize > 0)
{ // at least one iteration
vtkm::Id lastSupernodeThisLevel = this->AugmentedTree->Supernodes.GetNumberOfValues() - 1;

@ -110,6 +110,15 @@ public:
if (ingid != selfid)
{ // Receive and augment
rp.dequeue(ingid, blockData->HierarchicalAugmenter.InData);
vtkm::Id exchangeSize =
blockData->HierarchicalAugmenter.InData.Superparents.GetNumberOfValues();
exchangeSize =
std::max(exchangeSize,
blockData->HierarchicalAugmenter.InData.GlobalRegularIds.GetNumberOfValues());
timingsStream << " " << std::setw(38) << std::left << "Retrieved Attachment Points"
<< ": " << exchangeSize << std::endl;
blockData->HierarchicalAugmenter.RetrieveInAttachmentPoints();
}
}

@ -81,6 +81,7 @@
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/hierarchical_contour_tree/FindSuperArcForUnknownNode.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/hierarchical_contour_tree/InitalizeSuperchildrenWorklet.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/hierarchical_contour_tree/PermuteComparator.h>
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/LocalIsosurfaceExtractWorklet.h>
namespace vtkm
{
@ -1024,9 +1025,18 @@ void HierarchicalContourTree<FieldType>::AddToVTKMDataSet(vtkm::cont::DataSet& d
vtkm::cont::Field superarcsField(
"Superarcs", vtkm::cont::Field::Association::WholeDataSet, this->Superarcs);
ds.AddField(superarcsField);
vtkm::cont::Field superchildrenField(
"Superchildren", vtkm::cont::Field::Association::WholeDataSet, this->Superchildren);
ds.AddField(superchildrenField);
vtkm::cont::Field hyperparentsField(
"Hyperparents", vtkm::cont::Field::Association::WholeDataSet, this->Hyperparents);
ds.AddField(hyperparentsField);
vtkm::cont::Field hypernodesField(
"Hypernodes", vtkm::cont::Field::Association::WholeDataSet, this->Hypernodes);
ds.AddField(hypernodesField);
vtkm::cont::Field hyperarcsField(
"Hyperarcs", vtkm::cont::Field::Association::WholeDataSet, this->Hyperarcs);
ds.AddField(hyperarcsField);
vtkm::cont::Field super2HypernodeField(
"Super2Hypernode", vtkm::cont::Field::Association::WholeDataSet, this->Super2Hypernode);
ds.AddField(super2HypernodeField);
@ -1054,6 +1064,13 @@ void HierarchicalContourTree<FieldType>::AddToVTKMDataSet(vtkm::cont::DataSet& d
ds.AddField(firstSupernodePerIterationOffsetsField);
// TODO/FIXME: It seems we may only need the counts for the first iteration, so check, which
// information we actually need.
// Add the number of rounds as an array of length 1
vtkm::cont::ArrayHandle<vtkm::Id> tempNumRounds;
tempNumRounds.Allocate(1);
vtkm::worklet::contourtree_augmented::IdArraySetValue(0, this->NumRounds, tempNumRounds);
vtkm::cont::Field numRoundsField(
"NumRounds", vtkm::cont::Field::Association::WholeDataSet, tempNumRounds);
ds.AddField(numRoundsField);
}
} // namespace contourtree_distributed

@ -200,7 +200,6 @@ private:
}; // class HierarchicalHyperSweeper
template <typename SweepValueType, typename ContourTreeFieldType>
HierarchicalHyperSweeper<SweepValueType, ContourTreeFieldType>::HierarchicalHyperSweeper(
vtkm::Id blockId,
@ -360,6 +359,7 @@ void HierarchicalHyperSweeper<SweepValueType, ContourTreeFieldType>::LocalHyperS
// TODO/FIXME: Use portal? Or is there a more efficient way?
auto firstSupernodePerIterationPortal =
this->HierarchicalTree.FirstSupernodePerIteration[round].ReadPortal();
vtkm::Id firstSupernode = firstSupernodePerIterationPortal.Get(iteration);
vtkm::Id lastSupernode = firstSupernodePerIterationPortal.Get(iteration + 1);
@ -424,7 +424,6 @@ void HierarchicalHyperSweeper<SweepValueType, ContourTreeFieldType>::
vtkm::Id lastSupernode)
{ // ComputeSuperarcDependentWeights()
vtkm::Id numSupernodesToProcess = lastSupernode - firstSupernode;
// 2. Use sorted prefix sum to compute the total weight to contribute to the super/hypertarget
// Same as std::partial_sum(sweepValues.begin() + firstSupernode, sweepValues.begin() + lastSupernode, valuePrefixSum.begin() + firstSupernode);
{
@ -442,7 +441,6 @@ void HierarchicalHyperSweeper<SweepValueType, ContourTreeFieldType>::
vtkm::cont::Algorithm::ScanInclusive(dependentValuesView, // input
valuePrefixSumView); // result of partial sum
}
// Since the prefix sum is over *all* supernodes in the iteration, we need to break it into segments
// There are two cases we have to worry about:
// a. Hyperarcs made up of multiple supernodes

@ -22,6 +22,7 @@ set(headers
SetSuperparentSetDecorator.h
AttachmentAndSupernodeComparator.h
ResizeArraysBuildNewSupernodeIdsWorklet.h
FillEmptyIterationWorklet.h
CreateSuperarcsWorklet.h
HierarchicalAugmenterInOutData.h
)

@ -175,7 +175,6 @@ public:
// strip the ascending flag from the superparent.
vtkm::Id superparentOldSuperId =
vtkm::worklet::contourtree_augmented::MaskedIndex(superparentSetVal);
// setting the superarc is done the usual way. Our sort routine has ended up
// with the supernodes arranged in either ascending or descending order
// inwards along the parent superarc (as expressed by the superparent Id).
@ -237,8 +236,12 @@ public:
(superarcAscends ? vtkm::worklet::contourtree_augmented::IS_ASCENDING : 0x00);
} // not last in the segment
// The following single line sets the first supernode for the iteration for each round
// Why does it execute separately for each supernode? This will kill speed with all the write collisions
// Commented out so that the location of the error is apparent
// It looks like this was set separately in ResizeArrays(), so it's also redundant!!!!
// set the first supernode in the first iteration to the beginning of the round
augmentedTreeFirstSupernodePerIterationPortal.Set(0, this->NumSupernodesAlready);
// augmentedTreeFirstSupernodePerIterationPortal.Set(0, this->NumSupernodesAlready);
// NOTE: This part has been moved out of the worklet and is performed using standard vtkm copy constructs

@ -0,0 +1,95 @@
//============================================================================
// 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.
//
//=============================================================================
// The PPP2 algorithm and software were jointly developed by
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
// Oliver Ruebel (LBNL)
//==============================================================================
#ifndef vtk_m_worklet_contourtree_distributed_hierarchical_augmenter_fill_empty_iteration_worklet_h
#define vtk_m_worklet_contourtree_distributed_hierarchical_augmenter_fill_empty_iteration_worklet_h
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/Types.h>
#include <vtkm/worklet/WorkletMapField.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace hierarchical_augmenter
{
// Worklet for a rare case where an iteration has no supernode
// need to update the FirstSupernodePerIteration array to avoid crash
class FillEmptyIterationWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(
WholeArrayInOut augmentedTreeFirstSupernodePerIteration // input/output
);
using ExecutionSignature = void(InputIndex, _1);
using InputDomain = _1;
VTKM_EXEC_CONT
FillEmptyIterationWorklet() {}
/// operator() of the worklet
template <typename InOutFieldPortalType>
VTKM_EXEC void operator()(const vtkm::Id& inputIndex,
InOutFieldPortalType& firstSupernodePerIteration) const
{
if (inputIndex == 0 || inputIndex == firstSupernodePerIteration.GetNumberOfValues() - 1)
return;
if (firstSupernodePerIteration.Get(inputIndex) == 0)
{
vtkm::Id nextSupernode = firstSupernodePerIteration.Get(inputIndex + 1);
firstSupernodePerIteration.Set(inputIndex, nextSupernode);
}
} // operator()()
}; // FillEmptyIterationWorklet
} // namespace hierarchical_augmenter
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -83,7 +83,14 @@ public:
/// Default Constructor
VTKM_EXEC_CONT
FindSuperparentForNecessaryNodesWorklet() {}
FindSuperparentForNecessaryNodesWorklet(vtkm::Id3 meshBlockOrigin,
vtkm::Id3 meshBlockSize,
vtkm::Id3 meshGlobalSize)
: MeshBlockOrigin(meshBlockOrigin)
, MeshBlockSize(meshBlockSize)
, MeshGlobalSize(meshGlobalSize)
{
}
/// operator() of the workelt
template <typename InFieldPortalType,
@ -111,6 +118,17 @@ public:
// first check to see if it is already present (newRegularId set on input)
vtkm::Id newRegularId = findRegularByGlobal.FindRegularByGlobal(globalRegularId);
// WARNING: Mingzhe: the code commented out below comes from one of Oliver's fixes
// However, the code fails to work with isosurface extraction code.
// Many regular vertices are missing from the array with the code below
// Explicitly check whether the vertex belongs to the base block. If it doesn't, we ignore it
/* if (!this->IsInMesh(globalRegularId))
{
// Set to NO_SUCH_ELEMENT by default. By doing this in the worklet we an avoid having to
// initialize the output arrays first and we can use FieldIn instead of FieldInOut
regularSuperparentsValue = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
regularNodesNeededValue = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
} else */
// if it fails this test, then it's already in tree
if (vtkm::worklet::contourtree_augmented::NoSuchElement(newRegularId))
{ // not yet in tree
@ -200,7 +218,79 @@ public:
*/
} // operator()()
}; // FindSuperparentForNecessaryNodesWorklet
private:
// Mesh data
vtkm::Id3 MeshBlockOrigin;
vtkm::Id3 MeshBlockSize;
vtkm::Id3 MeshGlobalSize;
VTKM_EXEC
bool IsInMesh(vtkm::Id globalId) const
{ // IsInMesh()
if (this->MeshGlobalSize[2] > 1) // 3D
{
// convert from global ID to global coords
vtkm::Id globalSliceSize = this->MeshGlobalSize[0] * this->MeshGlobalSize[1];
vtkm::Id globalSlice = globalId / globalSliceSize;
vtkm::Id globalRow = globalId / this->MeshGlobalSize[0];
vtkm::Id globalCol = globalId % this->MeshGlobalSize[0];
// test validity
if (globalSlice < this->MeshBlockOrigin[2])
{
return false;
}
if (globalSlice >= this->MeshBlockOrigin[2] + this->MeshBlockSize[2])
{
return false;
}
if (globalRow < this->MeshBlockOrigin[1])
{
return false;
}
if (globalRow >= this->MeshBlockOrigin[1] + this->MeshBlockSize[1])
{
return false;
}
if (globalCol < this->MeshBlockOrigin[0])
{
return false;
}
if (globalCol >= this->MeshBlockOrigin[0] + this->MeshBlockSize[0])
{
return false;
}
// it's in the block - return true
return true;
} // end if 3D
else // 2D mesh
{
// convert from global ID to global coords
vtkm::Id globalRow = globalId / this->MeshGlobalSize[0];
vtkm::Id globalCol = globalId % this->MeshGlobalSize[0];
// test validity
if (globalRow < this->MeshBlockOrigin[1])
{
return false;
}
if (globalRow >= this->MeshBlockOrigin[1] + this->MeshBlockSize[1])
{
return false;
}
if (globalCol < this->MeshBlockOrigin[0])
{
return false;
}
if (globalCol >= this->MeshBlockOrigin[0] + this->MeshBlockSize[0])
{
return false;
}
// it's in the block - return true
return true;
}
} // IsInMesh()
}; // FindSuperparentForNecessaryNodesWorklet
} // namespace hierarchical_augmenter
} // namespace contourtree_distributed

@ -118,6 +118,16 @@ public:
// the hyperparent which we need to search along
vtkm::Id hyperparent = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
// sanity check: if above / below does not satisfy the condition, return NO_SUCH_ELEMENT
FieldType aboveValue = this->DataValues.Get(above);
FieldType belowValue = this->DataValues.Get(below);
vtkm::Id aboveGlobalId = this->RegularNodeGlobalIds.Get(above);
vtkm::Id belowGlobalId = this->RegularNodeGlobalIds.Get(below);
if (nodeValue > aboveValue || (nodeValue == aboveValue && nodeGlobalId > aboveGlobalId))
return vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
if (nodeValue < belowValue || (nodeValue == belowValue && nodeGlobalId < belowGlobalId))
return vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
// to find the superarc, we will first have to convert the above / below to a pair of super/hypernodes
vtkm::Id aboveSuperparent = this->Superparents.Get(above);
vtkm::Id belowSuperparent = this->Superparents.Get(below);

@ -0,0 +1,236 @@
//============================================================================
// 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.
//
//=============================================================================
//
// This code is an extension of the algorithm presented in the paper:
// Parallel Peak Pruning for Scalable SMP Contour Tree Computation.
// Hamish Carr, Gunther Weber, Christopher Sewell, and James Ahrens.
// Proceedings of the IEEE Symposium on Large Data Analysis and Visualization
// (LDAV), October 2016, Baltimore, Maryland.
//
// The PPP2 algorithm and software were jointly developed by
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
// Oliver Ruebel (LBNL)
//==============================================================================
#ifndef vtk_m_filter_scalar_topology_worklet_branch_decomposition_select_top_volume_contours_BranchParentComparator_h
#define vtk_m_filter_scalar_topology_worklet_branch_decomposition_select_top_volume_contours_BranchParentComparator_h
#include <vtkm/worklet/WorkletMapField.h>
namespace vtkm
{
namespace worklet
{
namespace scalar_topology
{
namespace select_top_volume_contours
{
using IdArrayType = vtkm::worklet::contourtree_augmented::IdArrayType;
// Implementation of BranchParentComparator
template <typename ValueType>
class BranchParentComparatorImpl
{
public:
using ValueArrayType = typename vtkm::cont::ArrayHandle<ValueType>;
using IdPortalType = typename IdArrayType::ReadPortalType;
using ValuePortalType = typename ValueArrayType::ReadPortalType;
// constructor
VTKM_CONT
BranchParentComparatorImpl(const IdArrayType& branchParent,
const ValueArrayType& saddleIsoValue,
const IdArrayType& branchRootGRId,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
: branchParentPortal(branchParent.PrepareForInput(device, token))
, saddleIsoValuePortal(saddleIsoValue.PrepareForInput(device, token))
, branchRootGRIdPortal(branchRootGRId.PrepareForInput(device, token))
{ // constructor
} // constructor
// () operator - gets called to do comparison
VTKM_EXEC
bool operator()(const vtkm::Id& i, const vtkm::Id& j) const
{ // operator()
vtkm::Id parentI = this->branchParentPortal.Get(i);
vtkm::Id parentJ = this->branchParentPortal.Get(j);
// primary sort on branch parent
if (parentI < parentJ)
return true;
if (parentI > parentJ)
return false;
ValueType valueI = this->saddleIsoValuePortal.Get(i);
ValueType valueJ = this->saddleIsoValuePortal.Get(j);
// secondary sort on branch saddle isovalue
if (valueI < valueJ)
return true;
if (valueI > valueJ)
return false;
vtkm::Id rootI = this->branchRootGRIdPortal.Get(i);
vtkm::Id rootJ = this->branchRootGRIdPortal.Get(j);
return (rootI < rootJ);
} // operator()
private:
IdPortalType branchParentPortal;
ValuePortalType saddleIsoValuePortal;
IdPortalType branchRootGRIdPortal;
}; // BranchParentComparatorImpl
/// <summary>
/// Comparator of branch parent. Lower parent comes first
/// </summary>
template <typename ValueType>
class BranchParentComparator : public vtkm::cont::ExecutionObjectBase
{
using ValueArrayType = typename vtkm::cont::ArrayHandle<ValueType>;
public:
// constructor
VTKM_CONT
BranchParentComparator(const IdArrayType& branchParent,
const ValueArrayType& saddleIsoValue,
const IdArrayType& branchRootGRId)
: BranchParent(branchParent)
, SaddleIsoValue(saddleIsoValue)
, BranchRootGRId(branchRootGRId)
{
}
VTKM_CONT BranchParentComparatorImpl<ValueType> PrepareForExecution(
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token) const
{
return BranchParentComparatorImpl<ValueType>(
this->BranchParent, this->SaddleIsoValue, this->BranchRootGRId, device, token);
}
private:
IdArrayType BranchParent;
ValueArrayType SaddleIsoValue;
IdArrayType BranchRootGRId;
}; // BranchParentComparator
// Implementation of SuperarcTargetComparator
class SuperarcTargetComparatorImpl
{
public:
using IdPortalType = typename IdArrayType::ReadPortalType;
// constructor
VTKM_CONT
SuperarcTargetComparatorImpl(const IdArrayType& superarcTarget,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
: superarcPortal(superarcTarget.PrepareForInput(device, token))
{ // constructor
} // constructor
// () operator - gets called to do comparison
VTKM_EXEC
bool operator()(const vtkm::Id& i, const vtkm::Id& j) const
{ // operator()
VTKM_ASSERT(i < superarcPortal.GetNumberOfValues() && i >= 0);
VTKM_ASSERT(j < superarcPortal.GetNumberOfValues() && j >= 0);
vtkm::Id superarcI = this->superarcPortal.Get(i);
vtkm::Id superarcJ = this->superarcPortal.Get(j);
bool isNullI = vtkm::worklet::contourtree_augmented::NoSuchElement(superarcI);
bool isNullJ = vtkm::worklet::contourtree_augmented::NoSuchElement(superarcJ);
// let the NULL superarc always go first
if (isNullI)
return true;
if (isNullJ)
return false;
vtkm::Id targetI = vtkm::worklet::contourtree_augmented::MaskedIndex(superarcI);
vtkm::Id targetJ = vtkm::worklet::contourtree_augmented::MaskedIndex(superarcJ);
// primary sort on the superarc target
return (targetI < targetJ);
} // operator()
private:
IdPortalType superarcPortal;
}; // SuperarcTargetComparatorImpl
/// <summary>
/// Comparator of superarc target. The NULL superarc always comes first.
/// </summary>
class SuperarcTargetComparator : public vtkm::cont::ExecutionObjectBase
{
public:
// constructor
VTKM_CONT
SuperarcTargetComparator(const IdArrayType& superarcTarget)
: SuperarcTarget(superarcTarget)
{
}
VTKM_CONT SuperarcTargetComparatorImpl PrepareForExecution(vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token) const
{
return SuperarcTargetComparatorImpl(this->SuperarcTarget, device, token);
}
private:
IdArrayType SuperarcTarget;
}; // SuperarcTargetComparator
} // namespace select_top_volume_contours
} // namespace scalar_topology
} // namespace worklet
} // namespace vtkm
#endif

@ -9,10 +9,15 @@
##============================================================================
set(headers
Predicates.h
ClarifyBranchEndSupernodeTypeWorklet.h
UpdateInfoByBranchDirectionWorklet.h
GetBranchHierarchyWorklet.h
GetBranchVolumeWorklet.h
BranchParentComparator.h
BranchVolumeComparator.h
MarchingCubesDataTables.h
LocalIsosurfaceExtractWorklet.h
)
#-----------------------------------------------------------------------------

@ -0,0 +1,401 @@
//============================================================================
// 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.
//
//=============================================================================
//
// This code is an extension of the algorithm presented in the paper:
// Parallel Peak Pruning for Scalable SMP Contour Tree Computation.
// Hamish Carr, Gunther Weber, Christopher Sewell, and James Ahrens.
// Proceedings of the IEEE Symposium on Large Data Analysis and Visualization
// (LDAV), October 2016, Baltimore, Maryland.
//
// The PPP2 algorithm and software were jointly developed by
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
// Oliver Ruebel (LBNL)
//==============================================================================
#ifndef vtk_m_filter_scalar_topology_worklet_select_top_volume_contours_GetBranchHierarchyWorklet_h
#define vtk_m_filter_scalar_topology_worklet_select_top_volume_contours_GetBranchHierarchyWorklet_h
#include <vtkm/worklet/WorkletMapField.h>
namespace vtkm
{
namespace worklet
{
namespace scalar_topology
{
namespace select_top_volume_contours
{
constexpr vtkm::IdComponent MAX_CONNECTIVITY_3D = static_cast<vtkm::IdComponent>(14);
using IdArrayType = vtkm::worklet::contourtree_augmented::IdArrayType;
/// <summary>
/// worklet to check whether the saddle end of branch is known by the block
/// if true, we return the saddle end supernode id
/// if false (or main branch), we return NO_SUCH_ELEMENT
/// </summary>
class BranchSaddleIsKnownWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(
FieldIn lowerEndGRId, // (input) branch lower end global regular id
FieldIn lowerLocalEnd, // (input) branch local lower end
FieldIn lowerLocalEndGRId, // (input) branch local lower end global regular id
FieldIn upperEndGRId, // (input) branch upper end global regular id
FieldIn upperLocalEnd, // (input) branch local upper end
FieldIn upperLocalEndGRId, // (input) branch local upper end global regular id
FieldIn branchSaddleEps, // (input) branch saddle epsilon
FieldOut branchSaddle // (output) the branch saddle (if known by the block)
);
using ExecutionSignature = _8(_1, _2, _3, _4, _5, _6, _7);
using InputDomain = _1;
/// Constructor
VTKM_EXEC_CONT
BranchSaddleIsKnownWorklet() {}
/// The functor checks the direction of the branch
VTKM_EXEC vtkm::Id operator()(const vtkm::Id& lowerEndGRId,
const vtkm::Id& lowerLocalEnd,
const vtkm::Id& lowerLocalEndGRId,
const vtkm::Id& upperEndGRId,
const vtkm::Id& upperLocalEnd,
const vtkm::Id& upperLocalEndGRId,
const vtkm::Id& branchSaddleEps) const
{
// if main branch
if (branchSaddleEps == 0)
return vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
// if the branch is a minimum-saddle branch
if (branchSaddleEps > 0)
return lowerEndGRId == lowerLocalEndGRId
? lowerLocalEnd
: vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
// if the branch is a maximum-saddle branch
if (branchSaddleEps < 0)
return upperEndGRId == upperLocalEndGRId
? upperLocalEnd
: vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
// in case of fallout, should never reach
return vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
}
}; // BranchSaddleIsKnownWorklet
/// <summary>
/// worklet to compute the parent branch of branches
/// </summary>
class GetParentBranchWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(
FieldIn branchSaddle, // (input) branch saddle supernode id
FieldIn saddleBranchRoot, // (input) the branch root of the superarc starting from the saddle
FieldIn saddleGRId, // (input) branch saddle supernode global regular id
WholeArrayIn superarcs, // (array input) all superarc targets in ascending order
WholeArrayIn branchRoots, // (array input) all branchRoots of superarcs
WholeArrayIn branchRootByBranch, // (array input) branch roots of branches in ascending order
WholeArrayIn upperEndGRIds, // (array input) upper local end of branches
WholeArrayIn lowerEndGRIds, // (array input) lower local end of branches
FieldOut parentBranch // (output) the information index of the parent branch
);
using ExecutionSignature = _9(_1, _2, _3, _4, _5, _6, _7, _8);
using InputDomain = _1;
/// Constructor
VTKM_EXEC_CONT
GetParentBranchWorklet() {}
template <typename IdArrayPortalType>
VTKM_EXEC vtkm::Id GetSuperarcEndPoint(const vtkm::Id& branchSaddle,
const IdArrayPortalType& sortedSuperarcs,
const bool isStart) const
{
VTKM_ASSERT(vtkm::worklet::contourtree_augmented::NoSuchElement(sortedSuperarcs.Get(0)));
using vtkm::worklet::contourtree_augmented::MaskedIndex;
vtkm::Id nSuperarcs = sortedSuperarcs.GetNumberOfValues();
vtkm::Id endpoint = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
vtkm::Id head = 1;
vtkm::Id tail = nSuperarcs - 1;
while (head <= tail)
{
vtkm::Id mid = (head + tail) >> 1;
vtkm::Id midSuperarc = MaskedIndex(sortedSuperarcs.Get(mid));
if (midSuperarc > branchSaddle)
tail = mid - 1;
else if (midSuperarc < branchSaddle)
head = mid + 1;
else if (isStart &&
(mid == 1 || (mid > 1 && MaskedIndex(sortedSuperarcs.Get(mid - 1)) < branchSaddle)))
{
endpoint = mid;
break;
}
else if (!isStart &&
(mid == nSuperarcs - 1 ||
(mid < nSuperarcs - 1 && MaskedIndex(sortedSuperarcs.Get(mid + 1)) > branchSaddle)))
{
endpoint = mid;
break;
}
else if (isStart)
tail = mid - 1;
else
head = mid + 1;
}
VTKM_ASSERT(endpoint >= 1);
return endpoint;
}
template <typename IdArrayPortalType>
VTKM_EXEC vtkm::Id GetBranchRootIdx(const vtkm::Id& branchRoot,
const IdArrayPortalType& branchRootByBranch) const
{
vtkm::Id nBranchRoot = branchRootByBranch.GetNumberOfValues();
vtkm::Id head = 0;
vtkm::Id tail = nBranchRoot - 1;
while (head <= tail)
{
vtkm::Id mid = (head + tail) >> 1;
vtkm::Id midBranchRoot = branchRootByBranch.Get(mid);
if (midBranchRoot == branchRoot)
{
return mid;
}
else if (midBranchRoot > branchRoot)
tail = mid - 1;
else
head = mid + 1;
}
// should always find the branch root index
// if not, report error
VTKM_ASSERT(false && "Cannot find the branch root known by the block!");
return vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
}
template <typename IdArrayPortalType>
VTKM_EXEC vtkm::Id operator()(const vtkm::Id& branchSaddle,
const vtkm::Id& saddleBranchRoot,
const vtkm::Id& saddleGRId,
const IdArrayPortalType& sortedSuperarcs,
const IdArrayPortalType& permutedBranchRoots,
const IdArrayPortalType& branchRootByBranch,
const IdArrayPortalType& upperEndGRIds,
const IdArrayPortalType& lowerEndGRIds) const
{
// there are at most MAX_CONNECTIVITY_3D superarcs connected to the branchSaddle
vtkm::Id candidateBranchRoot[MAX_CONNECTIVITY_3D];
vtkm::Id nCandidate = 1;
candidateBranchRoot[0] = saddleBranchRoot;
const vtkm::Id superarcStartIdx = GetSuperarcEndPoint(branchSaddle, sortedSuperarcs, true);
const vtkm::Id superarcEndIdx = GetSuperarcEndPoint(branchSaddle, sortedSuperarcs, false);
VTKM_ASSERT(superarcEndIdx >= superarcStartIdx);
VTKM_ASSERT(superarcEndIdx - superarcStartIdx + 2 <= MAX_CONNECTIVITY_3D);
for (vtkm::Id superarc = superarcStartIdx; superarc <= superarcEndIdx; superarc++)
{
candidateBranchRoot[nCandidate++] = permutedBranchRoots.Get(superarc);
}
for (vtkm::Id branchRoot = 0; branchRoot < nCandidate; branchRoot++)
{
// NOTE: we ALWAYS exclude the virtual superarc, which does not belong to any branch
if (candidateBranchRoot[branchRoot] == permutedBranchRoots.Get(0))
continue;
const vtkm::Id branchIdx =
GetBranchRootIdx(candidateBranchRoot[branchRoot], branchRootByBranch);
if (upperEndGRIds.Get(branchIdx) != saddleGRId && lowerEndGRIds.Get(branchIdx) != saddleGRId)
return branchIdx;
}
// Unfortunately, it seems possible that the parent branch cannot be found
// in which case NO_SUCH_ELEMENT is returned
// VTKM_ASSERT(false && "Cannot find the parent branch!");
return vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
}
}; // GetParentBranchWorklet
/// <summary>
/// worklet to assign values to arrayhandle with given index
/// this is different from permutation: we do not want to change the size of valueOut
/// we also don't want to touch the default values in valueOut
/// index - value is one to one
/// </summary>
class AssignValueByIndex : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn index, // (input) index
FieldIn value, // (input) value
WholeArrayOut valueOut // (array output) valueOut[index] = value
);
using ExecutionSignature = void(_1, _2, _3);
using InputDomain = _1;
/// Constructor
VTKM_EXEC_CONT
AssignValueByIndex() {}
template <typename ValueType, typename ValueArrayPortalType>
VTKM_EXEC void operator()(const vtkm::Id& index,
const ValueType& value,
ValueArrayPortalType& valueOut) const
{
if (vtkm::worklet::contourtree_augmented::NoSuchElement(index))
return;
valueOut.Set(index, value);
}
}; // AssignValueByIndex
/// <summary>
/// worklet to get the outer saddles of parent branches from branch-decomposition tree
/// This is to visualize the isosurface belong to the parent branch
/// that is symmetrical to the outer-most child branch
/// we collect the first saddle isovalue if branchSaddleEpsilon(parent) < 0
/// or the last saddle isovalue if branchSaddleEpsilon(parent) > 0
/// or both if branchSaddleEpsilon(parent) == 0
/// </summary>
class CollectOuterSaddle : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(
FieldIn parentSaddleEpsilon, // parent saddle epsilon
WholeArrayIn branchParent, // (array input) parent branch root ID (local)
FieldOut IsOuterSaddle // (output) whether the branch is an outer saddle of the parent
);
using ExecutionSignature = _3(InputIndex, _1, _2);
using InputDomain = _1;
using IdArrayPortalType = typename IdArrayType::ReadPortalType;
/// Constructor
VTKM_EXEC_CONT
CollectOuterSaddle() {}
VTKM_EXEC vtkm::Id operator()(const vtkm::Id& inputIndex,
const vtkm::Id& parentSaddleEpsilon,
const IdArrayPortalType& branchParent) const
{
const vtkm::Id selfParent = branchParent.Get(inputIndex);
vtkm::Id isOuterSaddle = 0;
if (vtkm::worklet::contourtree_augmented::NoSuchElement(selfParent))
{
return isOuterSaddle;
}
const bool isFirst = (inputIndex == 0) || (branchParent.Get(inputIndex - 1) != selfParent);
const bool isLast = (inputIndex == branchParent.GetNumberOfValues() - 1) ||
(branchParent.Get(inputIndex + 1) != selfParent);
if (isFirst && parentSaddleEpsilon <= 0)
{
isOuterSaddle |= 1;
}
if (isLast && parentSaddleEpsilon >= 0)
{
isOuterSaddle |= 2;
}
return isOuterSaddle;
}
}; // CollectOuterSaddle
/// <summary>
/// worklet to update the value of outer saddles for parent branches
/// </summary>
template <bool isMaximum>
class UpdateOuterSaddle : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(
FieldIn branchOrder, // (input) the order of the (top-volume) branch by volume
FieldInOut branchValue, // (input/output) the isovalue to extract
WholeArrayIn incomingOrders, // (array input) (sorted) orders of branches from the other block
WholeArrayIn
incomingValues // (array input) isovalues to extract on branches from the other block
);
using ExecutionSignature = void(_1, _2, _3, _4);
using InputDomain = _1;
using IdArrayPortalType = typename IdArrayType::ReadPortalType;
/// Constructor
VTKM_EXEC_CONT
UpdateOuterSaddle() {}
template <typename ValueType, typename ValuePortalType>
VTKM_EXEC void operator()(const vtkm::Id& branchOrder,
ValueType& branchValue,
const IdArrayPortalType& incomingOrders,
const ValuePortalType& incomingValues) const
{
vtkm::Id head = 0;
vtkm::Id tail = incomingOrders.GetNumberOfValues() - 1;
while (head <= tail)
{
vtkm::Id mid = (head + tail) >> 1;
vtkm::Id midOrder = incomingOrders.Get(mid);
if (midOrder == branchOrder)
{
const ValueType midValue = incomingValues.Get(mid);
if (isMaximum && midValue > branchValue)
branchValue = midValue;
else if (!isMaximum && midValue < branchValue)
branchValue = midValue;
return;
}
else if (midOrder > branchOrder)
tail = mid - 1;
else
head = mid + 1;
}
}
}; // UpdateOuterSaddle
} // namespace select_top_volume_contours
} // namespace scalar_topology
} // namespace worklet
} // namespace vtkm
#endif

@ -108,18 +108,19 @@ public:
{
if (isLowerLeaf && isUpperLeaf)
return totalVolume;
// if the branch is a minimum-saddle branch
// if the upper end superarc direction is pointing up, then dependent; otherwise, reverse
if (isLowerLeaf)
return contourtree_augmented::IsAscending(upperDirection)
? upperDependent
: totalVolume - upperDependent + upperIntrinsic;
: totalVolume - upperDependent + upperIntrinsic - 1;
// if the branch is a maximum-saddle branch
// if the lower end superarc direction is pointing down, then true; otherwise, false
if (isUpperLeaf)
return !contourtree_augmented::IsAscending(lowerDirection)
? lowerDependent
: totalVolume - lowerDependent + lowerIntrinsic;
: totalVolume - lowerDependent + lowerIntrinsic - 1;
// in case of fallout, should never reach
return 0;

@ -0,0 +1,751 @@
//============================================================================
// 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.
//
//=============================================================================
//
// This code is an extension of the algorithm presented in the paper:
// Parallel Peak Pruning for Scalable SMP Contour Tree Computation.
// Hamish Carr, Gunther Weber, Christopher Sewell, and James Ahrens.
// Proceedings of the IEEE Symposium on Large Data Analysis and Visualization
// (LDAV), October 2016, Baltimore, Maryland.
//
// The PPP2 algorithm and software were jointly developed by
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
// Oliver Ruebel (LBNL)
//==============================================================================
#ifndef vtk_m_filter_scalar_topology_worklet_select_top_volume_contours_local_isosurface_extract_worklet_h
#define vtk_m_filter_scalar_topology_worklet_select_top_volume_contours_local_isosurface_extract_worklet_h
#include <vtkm/filter/scalar_topology/worklet/select_top_volume_contours/MarchingCubesDataTables.h>
#include <vtkm/worklet/WorkletMapField.h>
namespace vtkm
{
namespace worklet
{
namespace scalar_topology
{
namespace select_top_volume_contours
{
constexpr vtkm::IdComponent MAX_MARCHING_CUBE_TRIANGLES = static_cast<vtkm::IdComponent>(5);
constexpr vtkm::IdComponent MAX_LINEAR_INTERPOLATION_TRIANGLES = static_cast<vtkm::IdComponent>(12);
/// Worklet to check whether the global regular id in inside the block
/// The global regular Ids in block should be sorted beforehand
class IdxIfWithinBlockWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(
FieldIn regularId, // (input) global regular id
WholeArrayIn idsInBlock, // (array input) all global regular ids within the local block
FieldOut inBlockIndicator, // (output) 1 if the regularId is inside the block
FieldOut inBlockIdx // (output) the index of regularId in idsInBlock
);
using ExecutionSignature = void(_1, _2, _3, _4);
using InputDomain = _1;
/// Constructor
VTKM_EXEC_CONT
IdxIfWithinBlockWorklet() {}
/// The functor uses binary search to locate regularId in idsInBlock
/// if the search fails, return NO_SUCH_ELEMENT; otherwise, return the location
/// idsInBlock should be sorted
template <typename InIdPortalType>
VTKM_EXEC void operator()(const vtkm::Id& regularId,
const InIdPortalType& idsInBlock,
vtkm::Id& inBlockIndicator,
vtkm::Id& inBlockIdx) const
{
vtkm::Id head = 0;
vtkm::Id tail = idsInBlock.GetNumberOfValues() - 1;
inBlockIndicator = 0;
inBlockIdx = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
while (head <= tail)
{
vtkm::Id mid = (head + tail) >> 1;
vtkm::Id midValue = idsInBlock.Get(mid);
if (regularId == midValue)
{
inBlockIdx = mid;
inBlockIndicator = 1;
return;
}
else if (regularId > midValue)
head = mid + 1;
else
tail = mid - 1;
}
}
}; // IdxIfWithinBlockWorklet
/// Worklet for debug, upon remove when release
class DebugSearchWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature =
void(FieldIn regularId, // (input) global regular id
WholeArrayIn idsInBlock, // (array input) all global regular ids within the local block
FieldOut foundId);
using ExecutionSignature = _3(InputIndex, _1, _2);
using InputDomain = _1;
/// Constructor
VTKM_EXEC_CONT
DebugSearchWorklet(const vtkm::Id& superarcSize)
: SuperarcSize(superarcSize)
{
}
template <typename InIdPortalType>
VTKM_EXEC vtkm::Id operator()(const vtkm::Id& inputIndex,
const vtkm::Id& regularId,
const InIdPortalType& idsInBlock) const
{
vtkm::Id head = 0;
vtkm::Id tail = idsInBlock.GetNumberOfValues() - 1;
while (head <= tail)
{
vtkm::Id mid = (head + tail) >> 1;
vtkm::Id midValue = idsInBlock.Get(mid);
if (regularId == midValue)
{
if (inputIndex < SuperarcSize)
return inputIndex;
break;
}
else if (regularId > midValue)
head = mid + 1;
else
tail = mid - 1;
}
return vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
}
private:
const vtkm::Id SuperarcSize;
}; // DebugSearchWorklet
/// Worklet for getting the polarity case of a cell compared to the isovalue.
/// Only consider 2D and 3D data.
/// The output for each cell is an integer ([0, 7] if 2D, or [0, 255] if 3D)
/// indicating the polarity at each vertex of the cell compared to the isovalue.
template <typename ValueType>
class GetCellCasesWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(
FieldIn localIdx, // (input) local point index
WholeArrayIn dataValues, // (array input) data values within block
WholeArrayIn vertexOffset, // (array input) vertex offset look-up table
FieldOut caseCell // (output) the polarity case (in binary) of the cell
);
using ExecutionSignature = _4(_1, _2, _3);
using InputDomain = _1;
using IdArrayPortalType = typename vtkm::cont::ArrayHandle<vtkm::Id>::ReadPortalType;
using ValueArrayPortalType = typename vtkm::cont::ArrayHandle<ValueType>::ReadPortalType;
/// <summary>
/// Constructor
/// </summary>
/// <param name="ptDimensions">dimension of points in the grid</param>
/// <param name="branchSaddleEpsilon">the direction for tiebreaking when comparing values</param>
/// <param name="isoValue">isovalue for the isosurface to extract</param>
/// <returns></returns>
VTKM_EXEC_CONT
GetCellCasesWorklet(const vtkm::Id3 ptDimensions,
const vtkm::Id branchSaddleEpsilon,
const ValueType isoValue)
: PointDimensions(ptDimensions)
, BranchSaddleEpsilon(branchSaddleEpsilon)
, IsoValue(isoValue)
{
CellDimensions[0] = ptDimensions[0] - 1;
CellDimensions[1] = ptDimensions[1] - 1;
CellDimensions[2] = ptDimensions[2] - 1;
}
/// <summary>
/// Computes the polarity case of cells
/// </summary>
/// <param name="localIndex">the local index of the point in the local grid</param>
/// <param name="dataValuesPortal">all data values on the local grid points</param>
/// <returns>integer indicating the polarity case of the cell originating at the input point</returns>
VTKM_EXEC vtkm::Id operator()(const vtkm::Id localIndex,
const ValueArrayPortalType& dataValuesPortal,
const IdArrayPortalType& vertexOffset) const
{
const vtkm::Id nPoints = PointDimensions[0] * PointDimensions[1] * PointDimensions[2];
VTKM_ASSERT(dataValuesPortal.GetNumberOfValues() == nPoints);
if (CellDimensions[2] <= 0)
{
// the 2D local coordinate of the input point
vtkm::Id2 localPt(localIndex % CellDimensions[0], localIndex / CellDimensions[0]);
vtkm::Id caseCell = 0;
// iterate over all points of the cell
for (vtkm::Id i = 0; i < nVertices2d; i++)
{
vtkm::Id currPtIdx = i * 2;
vtkm::Id currPt = vertexOffset.Get(currPtIdx) + localPt[0] +
(vertexOffset.Get(currPtIdx + 1) + localPt[1]) * PointDimensions[0];
VTKM_ASSERT(currPt < nPoints);
// when point value == IsoValue
// the index is 1 only if the branch is lower-end
if (dataValuesPortal.Get(currPt) > IsoValue ||
(dataValuesPortal.Get(currPt) == IsoValue && BranchSaddleEpsilon < 0))
caseCell |= vtkm::Id(1) << i;
}
return caseCell;
}
else
{
// the 3D local coordinate of the input point
vtkm::Id3 localPt(localIndex % CellDimensions[0],
(localIndex / CellDimensions[0]) % CellDimensions[1],
localIndex / (CellDimensions[0] * CellDimensions[1]));
vtkm::Id caseCell = 0;
// iterate over all points of the cell
for (vtkm::Id i = 0; i < nVertices3d; i++)
{
vtkm::Id currPtIdx = i * 3;
vtkm::Id currPt = vertexOffset.Get(currPtIdx) + localPt[0] +
(vertexOffset.Get(currPtIdx + 1) + localPt[1]) * PointDimensions[0] +
(vertexOffset.Get(currPtIdx + 2) + localPt[2]) *
(PointDimensions[0] * PointDimensions[1]);
VTKM_ASSERT(currPt < nPoints);
// when point value == IsoValue
// the index is 1 only if the branch is lower-end
if (dataValuesPortal.Get(currPt) > IsoValue ||
(dataValuesPortal.Get(currPt) == IsoValue && BranchSaddleEpsilon < 0))
caseCell |= vtkm::Id(1) << i;
}
return caseCell;
}
}
private:
vtkm::Id3 PointDimensions;
vtkm::Id BranchSaddleEpsilon;
ValueType IsoValue;
vtkm::Id3 CellDimensions;
}; // GetCellCasesWorklet
/// Worklet for getting the superarc of a branch given an isovalue
class GetSuperarcByIsoValueWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature =
void(FieldIn upperEndLocalId, // (input) upper end of the branch
FieldIn lowerEndLocalId, // (input) lower end of the branch
FieldIn isoValue, // (input) isoValue
FieldIn branchSaddleEpsilon, // (input) whether the branch is on top or at the bottom
FieldOut superarc, // (output) local superarc that intersects the isosurface
ExecObject findSuperarcByNode);
using ExecutionSignature = _5(_1, _2, _3, _4, _6);
using InputDomain = _1;
/// <summary>
/// Constructor
/// </summary>
/// <param name="totNumPoints">total number of points within the local grid</param>
/// <hint>We only need a number that is larger than any grid index</hint>
VTKM_EXEC_CONT
GetSuperarcByIsoValueWorklet(const vtkm::Id totNumPoints)
: TotalNumPoints(totNumPoints)
{
}
/// <summary>
/// Implementation of GetSuperarcByIsoValueWorklet.
/// Check vtkm::worklet::contourtree_distributed::FindSuperArcForUnknownNode
/// for the execution object description.
/// </summary>
/// <typeparam name="ValueType">data value type</typeparam>
/// <typeparam name="findSuperarcType">execution object type of findSuperarc</typeparam>
/// <param name="upperEndLocalId">local id of the upper end vertex of the branch</param>
/// <param name="lowerEndLocalId">local id of the lower end vertex of the branch</param>
/// <param name="isoValue">isovalue</param>
/// <param name="branchSaddleEpsilon">the direction for tiebreaking when comparing values</param>
/// <param name="findSuperarc">execution object</param>
/// <returns></returns>
template <typename ValueType, typename findSuperarcType>
VTKM_EXEC vtkm::Id operator()(const vtkm::Id upperEndLocalId,
const vtkm::Id lowerEndLocalId,
const ValueType isoValue,
const vtkm::Id branchSaddleEpsilon,
const findSuperarcType& findSuperarc) const
{
VTKM_ASSERT(branchSaddleEpsilon != 0);
if (branchSaddleEpsilon < 0)
return findSuperarc.FindSuperArcForUnknownNode(
-1, isoValue, upperEndLocalId, lowerEndLocalId);
return findSuperarc.FindSuperArcForUnknownNode(
TotalNumPoints, isoValue, upperEndLocalId, lowerEndLocalId);
}
private:
vtkm::Id TotalNumPoints;
}; // GetSuperarcByIsoValueWorklet
/// Worklet for calculating the edges to be drawn in the cell
/// NOTE: this worklet can only work on 2D and 3D data
template <typename ValueType>
class GetEdgesInCellWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(
FieldIn edgeOffset, // (input) offset of output edge in the output array
FieldIn caseCell, // (input) the marching cube case of the cell
WholeArrayIn localIds, // (array input) local ids of points
WholeArrayIn dataValues, // (array input) data values within block
WholeArrayIn vertexOffset, // (array input) vertex offset look-up table
WholeArrayIn edgeTable, // (array input) edge-in-cell look-up table
WholeArrayIn numBoundTable, // (array input) number of boundaries look-up table
WholeArrayIn boundaryTable, // (array input) edge-of-boundary look-up table
WholeArrayIn labelEdgeTable, // (array input) label edge (only for 3D) look-up table
WholeArrayOut edgesFrom, // (array output) array of start-points of edges on the isosurface
WholeArrayOut edgesTo, // (array output) array of end-points of edges on the isosurface
WholeArrayOut
isValidEdges, // (array output) whether the edge plan to draw belongs to the branch
ExecObject
findSuperarcForNode // (execution object) detector for the superarc of interpolated nodes
);
using ExecutionSignature =
void(InputIndex, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13);
using InputDomain = _1;
using IdArrayReadPortalType = typename vtkm::cont::ArrayHandle<vtkm::Id>::ReadPortalType;
using IdArrayWritePortalType = typename vtkm::cont::ArrayHandle<vtkm::Id>::WritePortalType;
using ValueArrayPortalType = typename vtkm::cont::ArrayHandle<ValueType>::ReadPortalType;
using EdgePointArrayPortalType =
typename vtkm::cont::ArrayHandle<vtkm::Vec3f_64>::WritePortalType;
/// Constructor
/// ptDimensions: dimension of points in the grid
/// branchSuperarc: the superarc on the given branch intersecting the isosurface
/// isoValue: isovalue for the isosurface to extract
VTKM_EXEC_CONT
GetEdgesInCellWorklet(const vtkm::Id3 ptDimensions,
const vtkm::Id3 globalPointIndexStart,
const ValueType isoValue,
const vtkm::Id branchSuperarc,
const vtkm::Id branchSaddleEpsilon,
const vtkm::Id totNumPoints,
const bool marchingCubes)
: PointDimensions(ptDimensions)
, GlobalPointIndexStart(globalPointIndexStart)
, IsoValue(isoValue)
, BranchSuperarc(branchSuperarc)
, BranchSaddleEpsilon(branchSaddleEpsilon)
, TotalNumPoints(totNumPoints)
, isMarchingCubes(marchingCubes)
{
CellDimensions[0] = ptDimensions[0] - 1;
CellDimensions[1] = ptDimensions[1] - 1;
CellDimensions[2] = ptDimensions[2] - 1;
}
// cell index: the point index within the local cell
VTKM_EXEC vtkm::Id CellIndexToNodeIndex2D(const vtkm::Id2& localPt,
const vtkm::Id cellIndex,
const IdArrayReadPortalType& vertOffset) const
{
return vertOffset.Get(cellIndex * 2) + localPt[0] +
(vertOffset.Get(cellIndex * 2 + 1) + localPt[1]) * PointDimensions[0];
}
// cell index: the point index within the local cell
VTKM_EXEC vtkm::Vec3f_64 CellIndexToNodeCoord2D(const vtkm::Id2& localPt,
const vtkm::Id cellIndex,
const IdArrayReadPortalType& vertOffset) const
{
return vtkm::Vec3f_64(
static_cast<vtkm::Float64>(vertOffset.Get(cellIndex * 2) + localPt[0]),
static_cast<vtkm::Float64>(vertOffset.Get(cellIndex * 2 + 1) + localPt[1]),
static_cast<vtkm::Float64>(0));
}
// cell index: the point index within the local cell
VTKM_EXEC vtkm::Id CellIndexToNodeIndex3D(const vtkm::Id3& localPt,
const vtkm::Id cellIndex,
const IdArrayReadPortalType& vertOffset) const
{
return vertOffset.Get(cellIndex * 3) + localPt[0] +
(vertOffset.Get(cellIndex * 3 + 1) + localPt[1]) * PointDimensions[0] +
(vertOffset.Get(cellIndex * 3 + 2) + localPt[2]) * (PointDimensions[0] * PointDimensions[1]);
}
// cell index: the point index within the local cell
VTKM_EXEC vtkm::Vec3f_64 CellIndexToNodeCoord3D(const vtkm::Id3& localPt,
const vtkm::Id cellIndex,
const IdArrayReadPortalType& vertOffset) const
{
return vtkm::Vec3f_64(
static_cast<vtkm::Float64>(vertOffset.Get(cellIndex * 3) + localPt[0]),
static_cast<vtkm::Float64>(vertOffset.Get(cellIndex * 3 + 1) + localPt[1]),
static_cast<vtkm::Float64>(vertOffset.Get(cellIndex * 3 + 2) + localPt[2]));
}
// Implementation to draw isosurface edges
// all hard-coded numbers in this function depends on the dimension of the data
// The number of vertices/lines/faces of a cell is fixed for a certain dimension
// The number of cases for the marching cube algorithm are also hard-coded
// Check MarchingCubesDataTables.h for more details
template <typename FindSuperarcExecType>
VTKM_EXEC void operator()(
const vtkm::Id localIndex, // refers to the index in the grid
const vtkm::Id edgeOffset,
const vtkm::Id caseCell,
const IdArrayReadPortalType& localIdsPortal, // refers to the index in (superarc etc.) arrays
const ValueArrayPortalType& dataValuesPortal,
const IdArrayReadPortalType& vertexOffset,
const IdArrayReadPortalType& edgeTable,
const IdArrayReadPortalType& numBoundTable,
const IdArrayReadPortalType& boundaryTable,
const IdArrayReadPortalType& labelEdgeTable,
EdgePointArrayPortalType& edgesFromPortal,
EdgePointArrayPortalType& edgesToPortal,
IdArrayWritePortalType& isValidEdgesPortal,
const FindSuperarcExecType& findSuperarcForNode) const
{
const vtkm::Id nPoints = PointDimensions[0] * PointDimensions[1] * PointDimensions[2];
// 2D
if (CellDimensions[2] <= 0)
{
const vtkm::Id2 localPt(localIndex % CellDimensions[0], localIndex / CellDimensions[0]);
VTKM_ASSERT(localIdsPortal.GetNumberOfValues() == nPoints);
VTKM_ASSERT(dataValuesPortal.GetNumberOfValues() == nPoints);
const vtkm::Id numEdges = numBoundTable.Get(caseCell);
if (numEdges < 1)
return;
for (vtkm::Id edgeIndex = 0; edgeIndex < numEdges; edgeIndex++)
{
const vtkm::Id lineForCaseOffset = caseCell * nLineTableElemSize2d; // 8;
const vtkm::Id lineOffset = lineForCaseOffset + edgeIndex * 2;
// lineFrom and lineTo are two edges where the isosurface edge intersects
const vtkm::Id lineFrom = boundaryTable.Get(lineOffset);
const vtkm::Id lineTo = boundaryTable.Get(lineOffset + 1);
// We need to assure that both lineFrom and lineTo belong to the branch
// all 0 and 1 in the variables below refer to the two vertices of the line
const vtkm::Id lineFromVert0 =
CellIndexToNodeIndex2D(localPt, edgeTable.Get(lineFrom * 2), vertexOffset);
const vtkm::Id lineFromVert1 =
CellIndexToNodeIndex2D(localPt, edgeTable.Get(lineFrom * 2 + 1), vertexOffset);
VTKM_ASSERT(lineFromVert0 < nPoints);
VTKM_ASSERT(lineFromVert1 < nPoints);
const vtkm::Id lineFromVert0LocalId = localIdsPortal.Get(lineFromVert0);
const vtkm::Id lineFromVert1LocalId = localIdsPortal.Get(lineFromVert1);
const ValueType lineFromVert0Value = dataValuesPortal.Get(lineFromVert0);
const ValueType lineFromVert1Value = dataValuesPortal.Get(lineFromVert1);
// due to simulation of simplicity
// vert0 < vert1 if their values are equal
const vtkm::Id lowVertFrom =
lineFromVert0Value <= lineFromVert1Value ? lineFromVert0LocalId : lineFromVert1LocalId;
const vtkm::Id highVertFrom =
lineFromVert0Value > lineFromVert1Value ? lineFromVert0LocalId : lineFromVert1LocalId;
const vtkm::Id lineToVert0 =
CellIndexToNodeIndex2D(localPt, edgeTable.Get(lineTo * 2), vertexOffset);
const vtkm::Id lineToVert1 =
CellIndexToNodeIndex2D(localPt, edgeTable.Get(lineTo * 2 + 1), vertexOffset);
VTKM_ASSERT(lineToVert0 < nPoints);
VTKM_ASSERT(lineToVert1 < nPoints);
const vtkm::Id lineToVert0LocalId = localIdsPortal.Get(lineToVert0);
const vtkm::Id lineToVert1LocalId = localIdsPortal.Get(lineToVert1);
const ValueType lineToVert0Value = dataValuesPortal.Get(lineToVert0);
const ValueType lineToVert1Value = dataValuesPortal.Get(lineToVert1);
// due to simulation of simplicity
// vert0 < vert1 if their values are equal
const vtkm::Id lowVertTo =
lineToVert0Value <= lineToVert1Value ? lineToVert0LocalId : lineToVert1LocalId;
const vtkm::Id highVertTo =
lineToVert0Value > lineToVert1Value ? lineToVert0LocalId : lineToVert1LocalId;
vtkm::Id lineFromSuperarc = -1;
vtkm::Id lineToSuperarc = -1;
// We always extract the isosurface above/below the isovalue by 0+
VTKM_ASSERT(BranchSaddleEpsilon != 0);
// lower end of branch is leaf
// the actual isovalue should be IsoValue-eps
// eps is 0+ (infinitely small)
if (BranchSaddleEpsilon < 0)
{
lineFromSuperarc =
findSuperarcForNode.FindSuperArcForUnknownNode(-1, IsoValue, highVertFrom, lowVertFrom);
lineToSuperarc =
findSuperarcForNode.FindSuperArcForUnknownNode(-1, IsoValue, highVertTo, lowVertTo);
}
// upper end of branch is leaf
// the actual isovalue should be IsoValue+eps
// eps is 0+ (infinitely small)
else if (BranchSaddleEpsilon > 0)
{
lineFromSuperarc = findSuperarcForNode.FindSuperArcForUnknownNode(
TotalNumPoints, IsoValue, highVertFrom, lowVertFrom);
lineToSuperarc = findSuperarcForNode.FindSuperArcForUnknownNode(
TotalNumPoints, IsoValue, highVertTo, lowVertTo);
}
// we only draw the line if both lineFrom and lineTo belongs to the branch of query
if (lineFromSuperarc != BranchSuperarc || lineToSuperarc != BranchSuperarc)
{
isValidEdgesPortal.Set(edgeOffset + edgeIndex, 0);
continue;
}
isValidEdgesPortal.Set(edgeOffset + edgeIndex, 1);
// Now let's draw the line
vtkm::Vec3f_64 lineFromVert0Coord =
CellIndexToNodeCoord2D(localPt, edgeTable.Get(lineFrom * 2), vertexOffset);
vtkm::Vec3f_64 lineFromVert1Coord =
CellIndexToNodeCoord2D(localPt, edgeTable.Get(lineFrom * 2 + 1), vertexOffset);
vtkm::Vec3f_64 lineToVert0Coord =
CellIndexToNodeCoord2D(localPt, edgeTable.Get(lineTo * 2), vertexOffset);
vtkm::Vec3f_64 lineToVert1Coord =
CellIndexToNodeCoord2D(localPt, edgeTable.Get(lineTo * 2 + 1), vertexOffset);
vtkm::Vec3f_64 fromPt(lineFromVert0Coord);
vtkm::Vec3f_64 toPt(lineToVert0Coord);
vtkm::Float64 fromRatio =
vtkm::Float64(IsoValue - lineFromVert0Value) / (lineFromVert1Value - lineFromVert0Value);
vtkm::Float64 toRatio =
vtkm::Float64(IsoValue - lineToVert0Value) / (lineToVert1Value - lineToVert0Value);
VTKM_ASSERT(fromRatio >= 0.0 && fromRatio <= 1.0);
VTKM_ASSERT(toRatio >= 0.0 && toRatio <= 1.0);
fromPt += (lineFromVert1Coord - lineFromVert0Coord) * fromRatio;
toPt += (lineToVert1Coord - lineToVert0Coord) * toRatio;
edgesFromPortal.Set(edgeOffset + edgeIndex, fromPt + GlobalPointIndexStart);
edgesToPortal.Set(edgeOffset + edgeIndex, toPt + GlobalPointIndexStart);
}
}
else // 3D
{
vtkm::Id3 localPt(localIndex % CellDimensions[0],
(localIndex / CellDimensions[0]) % CellDimensions[1],
localIndex / (CellDimensions[0] * CellDimensions[1]));
const vtkm::Id numTriangles = numBoundTable.Get(caseCell);
if (numTriangles < 1)
return;
// we check a specific edge to know the superarc of the triangle
// the edge label of the triangle is stored in labelEdgeTable in MarchingCubesDataTables.h
// there are at most 5 triangles to draw in each 3D cell (for marching cubes)
// for linear interpolation, there are at most 12 triangles
if (isMarchingCubes)
VTKM_ASSERT(numTriangles <= MAX_MARCHING_CUBE_TRIANGLES);
else
VTKM_ASSERT(numTriangles <= MAX_LINEAR_INTERPOLATION_TRIANGLES);
vtkm::Id triangleSuperarc[MAX_LINEAR_INTERPOLATION_TRIANGLES + 1];
vtkm::Id triangleLabelIdx = 0;
const vtkm::Id nLabelEdgeElemSize =
isMarchingCubes ? nLabelEdgeTableMC3dElemSize : nLabelEdgeTableLT3dElemSize;
vtkm::Id labelPtr = caseCell * nLabelEdgeElemSize;
while (labelEdgeTable.Get(labelPtr) != -1)
{
vtkm::Id labelCount = labelEdgeTable.Get(labelPtr++);
vtkm::Id labelEdge = labelEdgeTable.Get(labelPtr++);
// compute the superarc of the labelEdge belong to the branch
const vtkm::Id labelEdgeVert0 =
CellIndexToNodeIndex3D(localPt, edgeTable.Get(labelEdge * 2), vertexOffset);
const vtkm::Id labelEdgeVert1 =
CellIndexToNodeIndex3D(localPt, edgeTable.Get(labelEdge * 2 + 1), vertexOffset);
VTKM_ASSERT(labelEdgeVert0 < nPoints);
VTKM_ASSERT(labelEdgeVert1 < nPoints);
const vtkm::Id labelEdgeVert0LocalId = localIdsPortal.Get(labelEdgeVert0);
const vtkm::Id labelEdgeVert1LocalId = localIdsPortal.Get(labelEdgeVert1);
const ValueType labelEdgeVert0Value = dataValuesPortal.Get(labelEdgeVert0);
const ValueType labelEdgeVert1Value = dataValuesPortal.Get(labelEdgeVert1);
// due to simulation of simplicity
// vert0 < vert1 if their values are equal
const vtkm::Id lowVert = labelEdgeVert0Value <= labelEdgeVert1Value ? labelEdgeVert0LocalId
: labelEdgeVert1LocalId;
const vtkm::Id highVert =
labelEdgeVert0Value > labelEdgeVert1Value ? labelEdgeVert0LocalId : labelEdgeVert1LocalId;
vtkm::Id labelEdgeSuperarc = -1;
// We always extract the isosurface above/below the isovalue by 0+
VTKM_ASSERT(BranchSaddleEpsilon != 0);
// lower end of branch is leaf
// the actual isovalue should be IsoValue-(0+)
if (BranchSaddleEpsilon < 0)
{
labelEdgeSuperarc =
findSuperarcForNode.FindSuperArcForUnknownNode(-1, IsoValue, highVert, lowVert);
}
// upper end of branch is leaf
// the actual isovalue should be IsoValue+(0+)
else if (BranchSaddleEpsilon > 0)
{
labelEdgeSuperarc = findSuperarcForNode.FindSuperArcForUnknownNode(
TotalNumPoints, IsoValue, highVert, lowVert);
}
for (vtkm::Id i = 0; i < labelCount; i++)
triangleSuperarc[triangleLabelIdx++] = labelEdgeSuperarc;
}
VTKM_ASSERT(triangleLabelIdx == numTriangles);
const vtkm::Id nTriTableElemSize =
isMarchingCubes ? nTriTableMC3dElemSize : nTriTableLT3dElemSize;
for (vtkm::Id triIndex = 0; triIndex < numTriangles; triIndex++)
{
const vtkm::Id lineFroms[3] = {
boundaryTable.Get(caseCell * nTriTableElemSize + triIndex * 3),
boundaryTable.Get(caseCell * nTriTableElemSize + triIndex * 3 + 1),
boundaryTable.Get(caseCell * nTriTableElemSize + triIndex * 3 + 2)
};
const vtkm::Id lineTos[3] = {
boundaryTable.Get(caseCell * nTriTableElemSize + triIndex * 3 + 1),
boundaryTable.Get(caseCell * nTriTableElemSize + triIndex * 3 + 2),
boundaryTable.Get(caseCell * nTriTableElemSize + triIndex * 3)
};
const vtkm::Id labelEdgeSuperarc = triangleSuperarc[triIndex];
// we only draw the triangle if the triangle lies on the branch of query
if (labelEdgeSuperarc != BranchSuperarc)
{
isValidEdgesPortal.Set(edgeOffset + triIndex * 3, 0);
isValidEdgesPortal.Set(edgeOffset + triIndex * 3 + 1, 0);
isValidEdgesPortal.Set(edgeOffset + triIndex * 3 + 2, 0);
continue;
}
isValidEdgesPortal.Set(edgeOffset + triIndex * 3, 1);
isValidEdgesPortal.Set(edgeOffset + triIndex * 3 + 1, 1);
isValidEdgesPortal.Set(edgeOffset + triIndex * 3 + 2, 1);
for (vtkm::Id edgeIndex = 0; edgeIndex < 3; edgeIndex++)
{
// lineFrom and lineTo are two edges where the edge of the triangle intersects
const vtkm::Id lineFrom = lineFroms[edgeIndex];
const vtkm::Id lineTo = lineTos[edgeIndex];
// Now let's draw the line
vtkm::Vec3f_64 lineFromVert0Coord =
CellIndexToNodeCoord3D(localPt, edgeTable.Get(lineFrom * 2), vertexOffset);
vtkm::Vec3f_64 lineFromVert1Coord =
CellIndexToNodeCoord3D(localPt, edgeTable.Get(lineFrom * 2 + 1), vertexOffset);
vtkm::Vec3f_64 lineToVert0Coord =
CellIndexToNodeCoord3D(localPt, edgeTable.Get(lineTo * 2), vertexOffset);
vtkm::Vec3f_64 lineToVert1Coord =
CellIndexToNodeCoord3D(localPt, edgeTable.Get(lineTo * 2 + 1), vertexOffset);
vtkm::Vec3f_64 fromPt(lineFromVert0Coord);
vtkm::Vec3f_64 toPt(lineToVert0Coord);
const vtkm::Id lineFromVert0 =
CellIndexToNodeIndex3D(localPt, edgeTable.Get(lineFrom * 2), vertexOffset);
const vtkm::Id lineFromVert1 =
CellIndexToNodeIndex3D(localPt, edgeTable.Get(lineFrom * 2 + 1), vertexOffset);
VTKM_ASSERT(lineFromVert0 < nPoints);
VTKM_ASSERT(lineFromVert1 < nPoints);
const ValueType lineFromVert0Value = dataValuesPortal.Get(lineFromVert0);
const ValueType lineFromVert1Value = dataValuesPortal.Get(lineFromVert1);
const vtkm::Id lineToVert0 =
CellIndexToNodeIndex3D(localPt, edgeTable.Get(lineTo * 2), vertexOffset);
const vtkm::Id lineToVert1 =
CellIndexToNodeIndex3D(localPt, edgeTable.Get(lineTo * 2 + 1), vertexOffset);
VTKM_ASSERT(lineToVert0 < nPoints);
VTKM_ASSERT(lineToVert1 < nPoints);
const ValueType lineToVert0Value = dataValuesPortal.Get(lineToVert0);
const ValueType lineToVert1Value = dataValuesPortal.Get(lineToVert1);
vtkm::Float64 fromRatio = vtkm::Float64(IsoValue - lineFromVert0Value) /
(lineFromVert1Value - lineFromVert0Value);
vtkm::Float64 toRatio =
vtkm::Float64(IsoValue - lineToVert0Value) / (lineToVert1Value - lineToVert0Value);
VTKM_ASSERT(fromRatio >= 0.0 && fromRatio <= 1.0);
VTKM_ASSERT(toRatio >= 0.0 && toRatio <= 1.0);
fromPt += (lineFromVert1Coord - lineFromVert0Coord) * fromRatio;
toPt += (lineToVert1Coord - lineToVert0Coord) * toRatio;
edgesFromPortal.Set(edgeOffset + triIndex * 3 + edgeIndex,
fromPt + GlobalPointIndexStart);
edgesToPortal.Set(edgeOffset + triIndex * 3 + edgeIndex, toPt + GlobalPointIndexStart);
}
}
}
}
private:
vtkm::Id3 PointDimensions;
vtkm::Id3 GlobalPointIndexStart;
ValueType IsoValue;
vtkm::Id BranchSuperarc;
vtkm::Id BranchSaddleEpsilon;
vtkm::Id TotalNumPoints;
bool isMarchingCubes;
vtkm::Id3 CellDimensions;
}; // GetEdgesInCellWorklet
} // namespace select_top_volume_contours
} // namespace scalar_topology
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,945 @@
//============================================================================
// 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.
//
//=============================================================================
//
// This code is an extension of the algorithm presented in the paper:
// Parallel Peak Pruning for Scalable SMP Contour Tree Computation.
// Hamish Carr, Gunther Weber, Christopher Sewell, and James Ahrens.
// Proceedings of the IEEE Symposium on Large Data Analysis and Visualization
// (LDAV), October 2016, Baltimore, Maryland.
//
// The PPP2 algorithm and software were jointly developed by
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
// Oliver Ruebel (LBNL)
//==============================================================================
#ifndef vtk_m_filter_scalar_topology_worklet_select_top_volume_contours_marching_cubes_data_tables_h
#define vtk_m_filter_scalar_topology_worklet_select_top_volume_contours_marching_cubes_data_tables_h
#include <vtkm/Types.h>
namespace vtkm
{
namespace worklet
{
namespace scalar_topology
{
namespace select_top_volume_contours
{
// Edges include the diagonal of the triangulation of the mesh
const vtkm::Id nVertices2d = 4;
const vtkm::Id nEdges2d = 5;
const vtkm::Id nCases2d = 16;
const vtkm::Id nLineTableElemSize2d = 8;
const vtkm::cont::ArrayHandle<vtkm::Id> vertexOffset2d =
vtkm::cont::make_ArrayHandle<vtkm::Id>({ 0, 0, 1, 0, 1, 1, 0, 1 });
const vtkm::cont::ArrayHandle<vtkm::Id> edgeTable2d =
vtkm::cont::make_ArrayHandle<vtkm::Id>({ 0, 1, 1, 2, 3, 2, 0, 3, 0, 2 });
const vtkm::cont::ArrayHandle<vtkm::Id> numLinesTable2d =
vtkm::cont::make_ArrayHandle<vtkm::Id>({ 0, 2, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 2, 0 });
// size: nCase2d * nLineTableElemSize2d
const vtkm::cont::ArrayHandle<vtkm::Id> lineTable2d = vtkm::cont::make_ArrayHandle<vtkm::Id>({
#define X -1
X, X, X, X, X, X, X, X, 3, 4, 4, 0, X, X, X, X, 0, 1, X, X, X, X, X, X, 3, 4, 4, 1, X, X, X, X,
2, 4, 4, 1, X, X, X, X, 3, 2, 0, 1, X, X, X, X, 2, 4, 4, 0, X, X, X, X, 3, 2, X, X, X, X, X, X,
3, 2, X, X, X, X, X, X, 2, 4, 4, 0, X, X, X, X, 3, 2, 0, 1, X, X, X, X, 2, 4, 4, 1, X, X, X, X,
3, 4, 4, 1, X, X, X, X, 0, 1, X, X, X, X, X, X, 3, 4, 4, 0, X, X, X, X, X, X, X, X, X, X, X, X
#undef X
});
const vtkm::Id nVertices3d = 8;
const vtkm::Id nEdgesMC3d = 12;
const vtkm::Id nEdgesLT3d = 19;
const vtkm::Id nCasesMC3d = 256;
const vtkm::Id nCasesLT3d = 256;
// size: nVertices3d * nDims (3)
const vtkm::cont::ArrayHandle<vtkm::Id> vertexOffset3d = vtkm::cont::make_ArrayHandle<vtkm::Id>(
{ 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1 });
// size: nEdgesMC3d * 2 (vertices per edge)
const vtkm::cont::ArrayHandle<vtkm::Id> edgeTableMC3d = vtkm::cont::make_ArrayHandle<vtkm::Id>(
{ 0, 1, 1, 2, 3, 2, 0, 3, 4, 5, 5, 6, 7, 6, 4, 7, 0, 4, 1, 5, 2, 6, 3, 7 });
// size: nEdgesLT3d * 2
const vtkm::cont::ArrayHandle<vtkm::Id> edgeTableLT3d = vtkm::cont::make_ArrayHandle<vtkm::Id>(
{ 0, 1, 1, 2, 3, 2, 0, 3, 4, 5, 5, 6, 7, 6, 4, 7, 0, 4, 1,
5, 2, 6, 3, 7, 0, 2, 4, 6, 0, 5, 3, 6, 0, 7, 1, 6, 0, 6 });
// size: nCasesMC3d
const vtkm::cont::ArrayHandle<vtkm::Id> numTrianglesTableMC3d =
vtkm::cont::make_ArrayHandle<vtkm::Id>({
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 2, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 3,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 3, 2, 3, 3, 2, 3, 4, 4, 3, 3, 4, 4, 3, 4, 5, 5, 2,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 3, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 4,
2, 3, 3, 4, 3, 4, 2, 3, 3, 4, 4, 5, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 3, 2, 4, 5, 5, 4, 5, 2, 4, 1,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 3, 2, 3, 3, 4, 3, 4, 4, 5, 3, 2, 4, 3, 4, 3, 5, 2,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 4, 3, 4, 4, 3, 4, 5, 5, 4, 4, 3, 5, 2, 5, 4, 2, 1,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 2, 3, 3, 2, 3, 4, 4, 5, 4, 5, 5, 2, 4, 3, 5, 4, 3, 2, 4, 1,
3, 4, 4, 5, 4, 5, 3, 4, 4, 5, 5, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 2, 1, 3, 2, 4, 1, 2, 1, 1, 0,
});
// size: nCasesMC3d
const vtkm::cont::ArrayHandle<vtkm::Id> numTrianglesTableLT3d =
vtkm::cont::make_ArrayHandle<vtkm::Id>(
{ 0, 6, 2, 8, 2, 8, 4, 8, 2, 8, 4, 10, 4, 8, 6, 8, 2, 8, 4, 10, 4, 10,
6, 10, 4, 10, 6, 12, 6, 10, 8, 10, 2, 8, 4, 8, 4, 10, 6, 8, 4, 10, 6, 10,
6, 10, 8, 8, 4, 8, 6, 8, 6, 10, 8, 8, 6, 10, 8, 10, 8, 10, 10, 8, 6, 12,
8, 10, 8, 10, 8, 8, 8, 10, 10, 8, 8, 8, 8, 6, 8, 10, 10, 8, 10, 8, 10, 6,
10, 8, 12, 6, 10, 6, 10, 4, 8, 10, 8, 8, 10, 8, 8, 6, 10, 8, 10, 6, 10, 6,
8, 4, 8, 8, 8, 6, 10, 6, 8, 4, 10, 6, 10, 4, 10, 4, 8, 2, 2, 8, 4, 10,
4, 10, 6, 10, 4, 8, 6, 10, 6, 8, 8, 8, 4, 8, 6, 10, 6, 10, 8, 10, 6, 8,
8, 10, 8, 8, 10, 8, 4, 10, 6, 10, 6, 12, 8, 10, 6, 10, 8, 10, 8, 10, 10, 8,
6, 8, 8, 8, 8, 10, 10, 8, 8, 8, 10, 8, 10, 8, 12, 6, 8, 10, 10, 8, 10, 8,
10, 6, 8, 8, 10, 6, 8, 6, 8, 4, 8, 8, 10, 6, 10, 6, 10, 4, 8, 6, 10, 4,
8, 4, 8, 2, 10, 8, 10, 6, 12, 6, 10, 4, 10, 6, 10, 4, 10, 4, 8, 2, 8, 6,
8, 4, 10, 4, 8, 2, 8, 4, 8, 2, 8, 2, 6, 0 });
const vtkm::Id nTriTableMC3dElemSize = 16; // (at most 5 triangles, each with 3 vertices)
const vtkm::Id nTriTableLT3dElemSize = 37; // (at most 12 triangles, each with 3 vertices)
// size: nCasesMC3d * nTriTableMCElemSize
const vtkm::cont::ArrayHandle<vtkm::Id> triTableMC3d = vtkm::cont::make_ArrayHandle<vtkm::Id>({
#define X -1
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 8, 3, X, X, X, X, X,
X, X, X, X, X, X, X, X, 0, 1, 9, X, X, X, X, X, X, X, X, X, X, X, X, X,
1, 8, 3, 9, 8, 1, X, X, X, X, X, X, X, X, X, X, 1, 2, 10, X, X, X, X, X,
X, X, X, X, X, X, X, X, 0, 8, 3, 1, 2, 10, X, X, X, X, X, X, X, X, X, X,
9, 2, 10, 0, 2, 9, X, X, X, X, X, X, X, X, X, X, 2, 8, 3, 2, 10, 8, 10, 9,
8, X, X, X, X, X, X, X, 3, 11, 2, X, X, X, X, X, X, X, X, X, X, X, X, X,
0, 11, 2, 8, 11, 0, X, X, X, X, X, X, X, X, X, X, 1, 9, 0, 2, 3, 11, X, X,
X, X, X, X, X, X, X, X, 1, 11, 2, 1, 9, 11, 9, 8, 11, X, X, X, X, X, X, X,
3, 10, 1, 11, 10, 3, X, X, X, X, X, X, X, X, X, X, 0, 10, 1, 0, 8, 10, 8, 11,
10, X, X, X, X, X, X, X, 3, 9, 0, 3, 11, 9, 11, 10, 9, X, X, X, X, X, X, X,
9, 8, 10, 10, 8, 11, X, X, X, X, X, X, X, X, X, X, 4, 7, 8, X, X, X, X, X,
X, X, X, X, X, X, X, X, 4, 3, 0, 7, 3, 4, X, X, X, X, X, X, X, X, X, X,
0, 1, 9, 8, 4, 7, X, X, X, X, X, X, X, X, X, X, 4, 1, 9, 4, 7, 1, 7, 3,
1, X, X, X, X, X, X, X, 1, 2, 10, 8, 4, 7, X, X, X, X, X, X, X, X, X, X,
3, 4, 7, 3, 0, 4, 1, 2, 10, X, X, X, X, X, X, X, 9, 2, 10, 9, 0, 2, 8, 4,
7, X, X, X, X, X, X, X, 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, X, X, X, X,
8, 4, 7, 3, 11, 2, X, X, X, X, X, X, X, X, X, X, 11, 4, 7, 11, 2, 4, 2, 0,
4, X, X, X, X, X, X, X, 9, 0, 1, 8, 4, 7, 2, 3, 11, X, X, X, X, X, X, X,
4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, X, X, X, X, 3, 10, 1, 3, 11, 10, 7, 8,
4, X, X, X, X, X, X, X, 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, X, X, X, X,
4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, X, X, X, X, 4, 7, 11, 4, 11, 9, 9, 11,
10, X, X, X, X, X, X, X, 9, 5, 4, X, X, X, X, X, X, X, X, X, X, X, X, X,
9, 5, 4, 0, 8, 3, X, X, X, X, X, X, X, X, X, X, 0, 5, 4, 1, 5, 0, X, X,
X, X, X, X, X, X, X, X, 8, 5, 4, 8, 3, 5, 3, 1, 5, X, X, X, X, X, X, X,
1, 2, 10, 9, 5, 4, X, X, X, X, X, X, X, X, X, X, 3, 0, 8, 1, 2, 10, 4, 9,
5, X, X, X, X, X, X, X, 5, 2, 10, 5, 4, 2, 4, 0, 2, X, X, X, X, X, X, X,
2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, X, X, X, X, 9, 5, 4, 2, 3, 11, X, X,
X, X, X, X, X, X, X, X, 0, 11, 2, 0, 8, 11, 4, 9, 5, X, X, X, X, X, X, X,
0, 5, 4, 0, 1, 5, 2, 3, 11, X, X, X, X, X, X, X, 2, 1, 5, 2, 5, 8, 2, 8,
11, 4, 8, 5, X, X, X, X, 10, 3, 11, 10, 1, 3, 9, 5, 4, X, X, X, X, X, X, X,
4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, X, X, X, X, 5, 4, 0, 5, 0, 11, 5, 11,
10, 11, 0, 3, X, X, X, X, 5, 4, 8, 5, 8, 10, 10, 8, 11, X, X, X, X, X, X, X,
9, 7, 8, 5, 7, 9, X, X, X, X, X, X, X, X, X, X, 9, 3, 0, 9, 5, 3, 5, 7,
3, X, X, X, X, X, X, X, 0, 7, 8, 0, 1, 7, 1, 5, 7, X, X, X, X, X, X, X,
1, 5, 3, 3, 5, 7, X, X, X, X, X, X, X, X, X, X, 9, 7, 8, 9, 5, 7, 10, 1,
2, X, X, X, X, X, X, X, 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, X, X, X, X,
8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, X, X, X, X, 2, 10, 5, 2, 5, 3, 3, 5,
7, X, X, X, X, X, X, X, 7, 9, 5, 7, 8, 9, 3, 11, 2, X, X, X, X, X, X, X,
9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, X, X, X, X, 2, 3, 11, 0, 1, 8, 1, 7,
8, 1, 5, 7, X, X, X, X, 11, 2, 1, 11, 1, 7, 7, 1, 5, X, X, X, X, X, X, X,
9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, X, X, X, X, 5, 7, 0, 5, 0, 9, 7, 11,
0, 1, 0, 10, 11, 10, 0, X, 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, X,
11, 10, 5, 7, 11, 5, X, X, X, X, X, X, X, X, X, X, 10, 6, 5, X, X, X, X, X,
X, X, X, X, X, X, X, X, 0, 8, 3, 5, 10, 6, X, X, X, X, X, X, X, X, X, X,
9, 0, 1, 5, 10, 6, X, X, X, X, X, X, X, X, X, X, 1, 8, 3, 1, 9, 8, 5, 10,
6, X, X, X, X, X, X, X, 1, 6, 5, 2, 6, 1, X, X, X, X, X, X, X, X, X, X,
1, 6, 5, 1, 2, 6, 3, 0, 8, X, X, X, X, X, X, X, 9, 6, 5, 9, 0, 6, 0, 2,
6, X, X, X, X, X, X, X, 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, X, X, X, X,
2, 3, 11, 10, 6, 5, X, X, X, X, X, X, X, X, X, X, 11, 0, 8, 11, 2, 0, 10, 6,
5, X, X, X, X, X, X, X, 0, 1, 9, 2, 3, 11, 5, 10, 6, X, X, X, X, X, X, X,
5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, X, X, X, X, 6, 3, 11, 6, 5, 3, 5, 1,
3, X, X, X, X, X, X, X, 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, X, X, X, X,
3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, X, X, X, X, 6, 5, 9, 6, 9, 11, 11, 9,
8, X, X, X, X, X, X, X, 5, 10, 6, 4, 7, 8, X, X, X, X, X, X, X, X, X, X,
4, 3, 0, 4, 7, 3, 6, 5, 10, X, X, X, X, X, X, X, 1, 9, 0, 5, 10, 6, 8, 4,
7, X, X, X, X, X, X, X, 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, X, X, X, X,
6, 1, 2, 6, 5, 1, 4, 7, 8, X, X, X, X, X, X, X, 1, 2, 5, 5, 2, 6, 3, 0,
4, 3, 4, 7, X, X, X, X, 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, X, X, X, X,
7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, X, 3, 11, 2, 7, 8, 4, 10, 6,
5, X, X, X, X, X, X, X, 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, X, X, X, X,
0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, X, X, X, X, 9, 2, 1, 9, 11, 2, 9, 4,
11, 7, 11, 4, 5, 10, 6, X, 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, X, X, X, X,
5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, X, 0, 5, 9, 0, 6, 5, 0, 3,
6, 11, 6, 3, 8, 4, 7, X, 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, X, X, X, X,
10, 4, 9, 6, 4, 10, X, X, X, X, X, X, X, X, X, X, 4, 10, 6, 4, 9, 10, 0, 8,
3, X, X, X, X, X, X, X, 10, 0, 1, 10, 6, 0, 6, 4, 0, X, X, X, X, X, X, X,
8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, X, X, X, X, 1, 4, 9, 1, 2, 4, 2, 6,
4, X, X, X, X, X, X, X, 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, X, X, X, X,
0, 2, 4, 4, 2, 6, X, X, X, X, X, X, X, X, X, X, 8, 3, 2, 8, 2, 4, 4, 2,
6, X, X, X, X, X, X, X, 10, 4, 9, 10, 6, 4, 11, 2, 3, X, X, X, X, X, X, X,
0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, X, X, X, X, 3, 11, 2, 0, 1, 6, 0, 6,
4, 6, 1, 10, X, X, X, X, 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, X,
9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, X, X, X, X, 8, 11, 1, 8, 1, 0, 11, 6,
1, 9, 1, 4, 6, 4, 1, X, 3, 11, 6, 3, 6, 0, 0, 6, 4, X, X, X, X, X, X, X,
6, 4, 8, 11, 6, 8, X, X, X, X, X, X, X, X, X, X, 7, 10, 6, 7, 8, 10, 8, 9,
10, X, X, X, X, X, X, X, 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, X, X, X, X,
10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, X, X, X, X, 10, 6, 7, 10, 7, 1, 1, 7,
3, X, X, X, X, X, X, X, 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, X, X, X, X,
2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, X, 7, 8, 0, 7, 0, 6, 6, 0,
2, X, X, X, X, X, X, X, 7, 3, 2, 6, 7, 2, X, X, X, X, X, X, X, X, X, X,
2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, X, X, X, X, 2, 0, 7, 2, 7, 11, 0, 9,
7, 6, 7, 10, 9, 10, 7, X, 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, X,
11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, X, X, X, X, 8, 9, 6, 8, 6, 7, 9, 1,
6, 11, 6, 3, 1, 3, 6, X, 0, 9, 1, 11, 6, 7, X, X, X, X, X, X, X, X, X, X,
7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, X, X, X, X, 7, 11, 6, X, X, X, X, X,
X, X, X, X, X, X, X, X, 7, 6, 11, X, X, X, X, X, X, X, X, X, X, X, X, X,
3, 0, 8, 11, 7, 6, X, X, X, X, X, X, X, X, X, X, 0, 1, 9, 11, 7, 6, X, X,
X, X, X, X, X, X, X, X, 8, 1, 9, 8, 3, 1, 11, 7, 6, X, X, X, X, X, X, X,
10, 1, 2, 6, 11, 7, X, X, X, X, X, X, X, X, X, X, 1, 2, 10, 3, 0, 8, 6, 11,
7, X, X, X, X, X, X, X, 2, 9, 0, 2, 10, 9, 6, 11, 7, X, X, X, X, X, X, X,
6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, X, X, X, X, 7, 2, 3, 6, 2, 7, X, X,
X, X, X, X, X, X, X, X, 7, 0, 8, 7, 6, 0, 6, 2, 0, X, X, X, X, X, X, X,
2, 7, 6, 2, 3, 7, 0, 1, 9, X, X, X, X, X, X, X, 1, 6, 2, 1, 8, 6, 1, 9,
8, 8, 7, 6, X, X, X, X, 10, 7, 6, 10, 1, 7, 1, 3, 7, X, X, X, X, X, X, X,
10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, X, X, X, X, 0, 3, 7, 0, 7, 10, 0, 10,
9, 6, 10, 7, X, X, X, X, 7, 6, 10, 7, 10, 8, 8, 10, 9, X, X, X, X, X, X, X,
6, 8, 4, 11, 8, 6, X, X, X, X, X, X, X, X, X, X, 3, 6, 11, 3, 0, 6, 0, 4,
6, X, X, X, X, X, X, X, 8, 6, 11, 8, 4, 6, 9, 0, 1, X, X, X, X, X, X, X,
9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, X, X, X, X, 6, 8, 4, 6, 11, 8, 2, 10,
1, X, X, X, X, X, X, X, 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, X, X, X, X,
4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, X, X, X, X, 10, 9, 3, 10, 3, 2, 9, 4,
3, 11, 3, 6, 4, 6, 3, X, 8, 2, 3, 8, 4, 2, 4, 6, 2, X, X, X, X, X, X, X,
0, 4, 2, 4, 6, 2, X, X, X, X, X, X, X, X, X, X, 1, 9, 0, 2, 3, 4, 2, 4,
6, 4, 3, 8, X, X, X, X, 1, 9, 4, 1, 4, 2, 2, 4, 6, X, X, X, X, X, X, X,
8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, X, X, X, X, 10, 1, 0, 10, 0, 6, 6, 0,
4, X, X, X, X, X, X, X, 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, X,
10, 9, 4, 6, 10, 4, X, X, X, X, X, X, X, X, X, X, 4, 9, 5, 7, 6, 11, X, X,
X, X, X, X, X, X, X, X, 0, 8, 3, 4, 9, 5, 11, 7, 6, X, X, X, X, X, X, X,
5, 0, 1, 5, 4, 0, 7, 6, 11, X, X, X, X, X, X, X, 11, 7, 6, 8, 3, 4, 3, 5,
4, 3, 1, 5, X, X, X, X, 9, 5, 4, 10, 1, 2, 7, 6, 11, X, X, X, X, X, X, X,
6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, X, X, X, X, 7, 6, 11, 5, 4, 10, 4, 2,
10, 4, 0, 2, X, X, X, X, 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, X,
7, 2, 3, 7, 6, 2, 5, 4, 9, X, X, X, X, X, X, X, 9, 5, 4, 0, 8, 6, 0, 6,
2, 6, 8, 7, X, X, X, X, 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, X, X, X, X,
6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, X, 9, 5, 4, 10, 1, 6, 1, 7,
6, 1, 3, 7, X, X, X, X, 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, X,
4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, X, 7, 6, 10, 7, 10, 8, 5, 4,
10, 4, 8, 10, X, X, X, X, 6, 9, 5, 6, 11, 9, 11, 8, 9, X, X, X, X, X, X, X,
3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, X, X, X, X, 0, 11, 8, 0, 5, 11, 0, 1,
5, 5, 6, 11, X, X, X, X, 6, 11, 3, 6, 3, 5, 5, 3, 1, X, X, X, X, X, X, X,
1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, X, X, X, X, 0, 11, 3, 0, 6, 11, 0, 9,
6, 5, 6, 9, 1, 2, 10, X, 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, X,
6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, X, X, X, X, 5, 8, 9, 5, 2, 8, 5, 6,
2, 3, 8, 2, X, X, X, X, 9, 5, 6, 9, 6, 0, 0, 6, 2, X, X, X, X, X, X, X,
1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, X, 1, 5, 6, 2, 1, 6, X, X,
X, X, X, X, X, X, X, X, 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, X,
10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, X, X, X, X, 0, 3, 8, 5, 6, 10, X, X,
X, X, X, X, X, X, X, X, 10, 5, 6, X, X, X, X, X, X, X, X, X, X, X, X, X,
11, 5, 10, 7, 5, 11, X, X, X, X, X, X, X, X, X, X, 11, 5, 10, 11, 7, 5, 8, 3,
0, X, X, X, X, X, X, X, 5, 11, 7, 5, 10, 11, 1, 9, 0, X, X, X, X, X, X, X,
10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, X, X, X, X, 11, 1, 2, 11, 7, 1, 7, 5,
1, X, X, X, X, X, X, X, 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, X, X, X, X,
9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, X, X, X, X, 7, 5, 2, 7, 2, 11, 5, 9,
2, 3, 2, 8, 9, 8, 2, X, 2, 5, 10, 2, 3, 5, 3, 7, 5, X, X, X, X, X, X, X,
8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, X, X, X, X, 9, 0, 1, 5, 10, 3, 5, 3,
7, 3, 10, 2, X, X, X, X, 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, X,
1, 3, 5, 3, 7, 5, X, X, X, X, X, X, X, X, X, X, 0, 8, 7, 0, 7, 1, 1, 7,
5, X, X, X, X, X, X, X, 9, 0, 3, 9, 3, 5, 5, 3, 7, X, X, X, X, X, X, X,
9, 8, 7, 5, 9, 7, X, X, X, X, X, X, X, X, X, X, 5, 8, 4, 5, 10, 8, 10, 11,
8, X, X, X, X, X, X, X, 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, X, X, X, X,
0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, X, X, X, X, 10, 11, 4, 10, 4, 5, 11, 3,
4, 9, 4, 1, 3, 1, 4, X, 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, X, X, X, X,
0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, X, 0, 2, 5, 0, 5, 9, 2, 11,
5, 4, 5, 8, 11, 8, 5, X, 9, 4, 5, 2, 11, 3, X, X, X, X, X, X, X, X, X, X,
2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, X, X, X, X, 5, 10, 2, 5, 2, 4, 4, 2,
0, X, X, X, X, X, X, X, 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, X,
5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, X, X, X, X, 8, 4, 5, 8, 5, 3, 3, 5,
1, X, X, X, X, X, X, X, 0, 4, 5, 1, 0, 5, X, X, X, X, X, X, X, X, X, X,
8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, X, X, X, X, 9, 4, 5, X, X, X, X, X,
X, X, X, X, X, X, X, X, 4, 11, 7, 4, 9, 11, 9, 10, 11, X, X, X, X, X, X, X,
0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, X, X, X, X, 1, 10, 11, 1, 11, 4, 1, 4,
0, 7, 4, 11, X, X, X, X, 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, X,
4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, X, X, X, X, 9, 7, 4, 9, 11, 7, 9, 1,
11, 2, 11, 1, 0, 8, 3, X, 11, 7, 4, 11, 4, 2, 2, 4, 0, X, X, X, X, X, X, X,
11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, X, X, X, X, 2, 9, 10, 2, 7, 9, 2, 3,
7, 7, 4, 9, X, X, X, X, 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, X,
3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, X, 1, 10, 2, 8, 7, 4, X, X,
X, X, X, X, X, X, X, X, 4, 9, 1, 4, 1, 7, 7, 1, 3, X, X, X, X, X, X, X,
4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, X, X, X, X, 4, 0, 3, 7, 4, 3, X, X,
X, X, X, X, X, X, X, X, 4, 8, 7, X, X, X, X, X, X, X, X, X, X, X, X, X,
9, 10, 8, 10, 11, 8, X, X, X, X, X, X, X, X, X, X, 3, 0, 9, 3, 9, 11, 11, 9,
10, X, X, X, X, X, X, X, 0, 1, 10, 0, 10, 8, 8, 10, 11, X, X, X, X, X, X, X,
3, 1, 10, 11, 3, 10, X, X, X, X, X, X, X, X, X, X, 1, 2, 11, 1, 11, 9, 9, 11,
8, X, X, X, X, X, X, X, 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, X, X, X, X,
0, 2, 11, 8, 0, 11, X, X, X, X, X, X, X, X, X, X, 3, 2, 11, X, X, X, X, X,
X, X, X, X, X, X, X, X, 2, 3, 8, 2, 8, 10, 10, 8, 9, X, X, X, X, X, X, X,
9, 10, 2, 0, 9, 2, X, X, X, X, X, X, X, X, X, X, 2, 3, 8, 2, 8, 10, 0, 1,
8, 1, 10, 8, X, X, X, X, 1, 10, 2, X, X, X, X, X, X, X, X, X, X, X, X, X,
1, 3, 8, 9, 1, 8, X, X, X, X, X, X, X, X, X, X, 0, 9, 1, X, X, X, X, X,
X, X, X, X, X, X, X, X, 0, 3, 8, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X
#undef X
});
// size: nCasesLT3d * nTriTableLT3dElemSize
const vtkm::cont::ArrayHandle<vtkm::Id> triTableLT3d = vtkm::cont::make_ArrayHandle<vtkm::Id>({
#define X -1
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 18, 0, 14, 18, 3, 12, 18, 3, 16,
18, 8, 14, 18, 8, 16, 18, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, 0, 1, 17, 0, 9, 17, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 12, 18, 17, 12, 1, 17, 14, 18, 17,
14, 9, 17, 3, 12, 18, 3, 16, 18, 8, 14, 18, 8, 16, 18, X, X, X, X, X, X, X, X, X,
X, X, X, X, 12, 1, 10, 12, 2, 10, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10, 0,
14, 18, 3, 18, 10, 3, 2, 10, 3, 16, 18, 8, 14, 18, 8, 16, 18, X, X, X, X, X, X, X,
X, X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 9, 17, 12, 2, 10, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 18, 17, 10, 14, 18,
17, 14, 9, 17, 3, 18, 10, 3, 2, 10, 3, 16, 18, 8, 14, 18, 8, 16, 18, X, X, X, X, X,
X, X, X, X, X, X, X, X, 3, 2, 15, 3, 11, 15, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 18,
0, 14, 18, 12, 18, 15, 12, 2, 15, 16, 18, 15, 16, 11, 15, 8, 14, 18, 8, 16, 18, X, X, X,
X, X, X, X, X, X, X, X, X, X, 0, 1, 17, 0, 9, 17, 3, 2, 15, 3, 11, 15, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 12,
18, 17, 12, 1, 17, 14, 18, 17, 14, 9, 17, 12, 18, 15, 12, 2, 15, 16, 18, 15, 16, 11, 15, 8,
14, 18, 8, 16, 18, X, X, X, X, X, X, X, 12, 1, 10, 3, 12, 10, 3, 15, 10, 3, 11, 15,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, 0, 18, 10, 0, 1, 10, 0, 14, 18, 18, 15, 10, 16, 18, 15, 16, 11, 15, 8, 14, 18, 8, 16,
18, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 9, 17, 3,
12, 10, 3, 15, 10, 3, 11, 15, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, 18, 17, 10, 14, 18, 17, 14, 9, 17, 18, 15, 10, 16, 18, 15, 16, 11, 15, 8, 14, 18,
8, 16, 18, X, X, X, X, X, X, X, X, X, X, X, X, X, 8, 4, 13, 8, 7, 13, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, 0, 12, 18, 0, 14, 18, 3, 12, 18, 3, 16, 18, 14, 18, 13, 14, 4, 13, 16,
18, 13, 16, 7, 13, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 1, 17, 0, 9, 17,
8, 4, 13, 8, 7, 13, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, 12, 18, 17, 12, 1, 17, 14, 18, 17, 14, 9, 17, 3, 12, 18, 3, 16,
18, 14, 18, 13, 14, 4, 13, 16, 18, 13, 16, 7, 13, X, X, X, X, X, X, X, 12, 1, 10, 12,
2, 10, 8, 4, 13, 8, 7, 13, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10, 0, 14, 18, 3, 18, 10, 3, 2, 10,
3, 16, 18, 14, 18, 13, 14, 4, 13, 16, 18, 13, 16, 7, 13, X, X, X, X, X, X, X, 0, 12,
10, 0, 17, 10, 0, 9, 17, 12, 2, 10, 8, 4, 13, 8, 7, 13, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, 18, 17, 10, 14, 18, 17, 14, 9, 17, 3, 18, 10, 3,
2, 10, 3, 16, 18, 14, 18, 13, 14, 4, 13, 16, 18, 13, 16, 7, 13, X, X, X, X, X, X, X,
3, 2, 15, 3, 11, 15, 8, 4, 13, 8, 7, 13, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 18, 0, 14, 18, 12, 18, 15, 12, 2,
15, 16, 18, 15, 16, 11, 15, 14, 18, 13, 14, 4, 13, 16, 18, 13, 16, 7, 13, X, X, X, X, X,
X, X, 0, 1, 17, 0, 9, 17, 3, 2, 15, 3, 11, 15, 8, 4, 13, 8, 7, 13, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 12, 18, 17, 12, 1, 17, 14, 18, 17,
14, 9, 17, 12, 18, 15, 12, 2, 15, 16, 18, 15, 16, 11, 15, 14, 18, 13, 14, 4, 13, 16, 18, 13,
16, 7, 13, X, 12, 1, 10, 3, 12, 10, 3, 15, 10, 3, 11, 15, 8, 4, 13, 8, 7, 13, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10, 0,
14, 18, 18, 15, 10, 16, 18, 15, 16, 11, 15, 14, 18, 13, 14, 4, 13, 16, 18, 13, 16, 7, 13, X,
X, X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 9, 17, 3, 12, 10, 3, 15, 10, 3, 11, 15,
8, 4, 13, 8, 7, 13, X, X, X, X, X, X, X, X, X, X, X, X, X, 18, 17, 10, 14, 18,
17, 14, 9, 17, 18, 15, 10, 16, 18, 15, 16, 11, 15, 14, 18, 13, 14, 4, 13, 16, 18, 13, 16, 7,
13, X, X, X, X, X, X, X, 14, 9, 5, 14, 4, 5, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 18,
0, 18, 5, 0, 9, 5, 3, 12, 18, 3, 16, 18, 8, 18, 5, 8, 4, 5, 8, 16, 18, X, X, X,
X, X, X, X, X, X, X, X, X, X, 0, 1, 17, 0, 14, 5, 0, 17, 5, 14, 4, 5, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 12,
18, 17, 12, 1, 17, 18, 17, 5, 3, 12, 18, 3, 16, 18, 8, 18, 5, 8, 4, 5, 8, 16, 18, X,
X, X, X, X, X, X, X, X, X, X, X, X, 12, 1, 10, 14, 9, 5, 12, 2, 10, 14, 4, 5,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, 0, 18, 10, 0, 1, 10, 0, 18, 5, 0, 9, 5, 3, 18, 10, 3, 2, 10, 3, 16, 18, 8, 18,
5, 8, 4, 5, 8, 16, 18, X, X, X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 14, 5, 0,
17, 5, 12, 2, 10, 14, 4, 5, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, 18, 17, 10, 18, 17, 5, 3, 18, 10, 3, 2, 10, 3, 16, 18, 8, 18, 5, 8, 4, 5,
8, 16, 18, X, X, X, X, X, X, X, X, X, X, X, X, X, 14, 9, 5, 3, 2, 15, 3, 11,
15, 14, 4, 5, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, 0, 12, 18, 0, 18, 5, 0, 9, 5, 12, 18, 15, 12, 2, 15, 16, 18, 15, 16,
11, 15, 8, 18, 5, 8, 4, 5, 8, 16, 18, X, X, X, X, X, X, X, 0, 1, 17, 0, 14, 5,
0, 17, 5, 3, 2, 15, 3, 11, 15, 14, 4, 5, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, 12, 18, 17, 12, 1, 17, 18, 17, 5, 12, 18, 15, 12, 2, 15, 16, 18,
15, 16, 11, 15, 8, 18, 5, 8, 4, 5, 8, 16, 18, X, X, X, X, X, X, X, 12, 1, 10, 14,
9, 5, 3, 12, 10, 3, 15, 10, 3, 11, 15, 14, 4, 5, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10, 0, 18, 5, 0, 9, 5, 18, 15, 10,
16, 18, 15, 16, 11, 15, 8, 18, 5, 8, 4, 5, 8, 16, 18, X, X, X, X, X, X, X, 0, 12,
10, 0, 17, 10, 0, 14, 5, 0, 17, 5, 3, 12, 10, 3, 15, 10, 3, 11, 15, 14, 4, 5, X, X,
X, X, X, X, X, X, X, X, X, X, X, 18, 17, 10, 18, 17, 5, 18, 15, 10, 16, 18, 15, 16,
11, 15, 8, 18, 5, 8, 4, 5, 8, 16, 18, X, X, X, X, X, X, X, X, X, X, X, X, X,
14, 9, 5, 8, 14, 5, 8, 13, 5, 8, 7, 13, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 18, 0, 18, 5, 0, 9, 5, 3, 12,
18, 3, 16, 18, 18, 13, 5, 16, 18, 13, 16, 7, 13, X, X, X, X, X, X, X, X, X, X, X,
X, X, 0, 1, 17, 0, 14, 5, 0, 17, 5, 8, 14, 5, 8, 13, 5, 8, 7, 13, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 12, 18, 17, 12, 1, 17, 18, 17, 5,
3, 12, 18, 3, 16, 18, 18, 13, 5, 16, 18, 13, 16, 7, 13, X, X, X, X, X, X, X, X, X,
X, X, X, X, 12, 1, 10, 14, 9, 5, 12, 2, 10, 8, 14, 5, 8, 13, 5, 8, 7, 13, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10, 0,
18, 5, 0, 9, 5, 3, 18, 10, 3, 2, 10, 3, 16, 18, 18, 13, 5, 16, 18, 13, 16, 7, 13, X,
X, X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 14, 5, 0, 17, 5, 12, 2, 10, 8, 14, 5,
8, 13, 5, 8, 7, 13, X, X, X, X, X, X, X, X, X, X, X, X, X, 18, 17, 10, 18, 17,
5, 3, 18, 10, 3, 2, 10, 3, 16, 18, 18, 13, 5, 16, 18, 13, 16, 7, 13, X, X, X, X, X,
X, X, X, X, X, X, X, X, 14, 9, 5, 3, 2, 15, 3, 11, 15, 8, 14, 5, 8, 13, 5, 8,
7, 13, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 18,
0, 18, 5, 0, 9, 5, 12, 18, 15, 12, 2, 15, 16, 18, 15, 16, 11, 15, 18, 13, 5, 16, 18, 13,
16, 7, 13, X, X, X, X, X, X, X, 0, 1, 17, 0, 14, 5, 0, 17, 5, 3, 2, 15, 3, 11,
15, 8, 14, 5, 8, 13, 5, 8, 7, 13, X, X, X, X, X, X, X, X, X, X, X, X, X, 12,
18, 17, 12, 1, 17, 18, 17, 5, 12, 18, 15, 12, 2, 15, 16, 18, 15, 16, 11, 15, 18, 13, 5, 16,
18, 13, 16, 7, 13, X, X, X, X, X, X, X, 12, 1, 10, 14, 9, 5, 3, 12, 10, 3, 15, 10,
3, 11, 15, 8, 14, 5, 8, 13, 5, 8, 7, 13, X, X, X, X, X, X, X, X, X, X, X, X,
X, 0, 18, 10, 0, 1, 10, 0, 18, 5, 0, 9, 5, 18, 15, 10, 16, 18, 15, 16, 11, 15, 18, 13,
5, 16, 18, 13, 16, 7, 13, X, X, X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 14, 5, 0,
17, 5, 3, 12, 10, 3, 15, 10, 3, 11, 15, 8, 14, 5, 8, 13, 5, 8, 7, 13, X, X, X, X,
X, X, X, 18, 17, 10, 18, 17, 5, 18, 15, 10, 16, 18, 15, 16, 11, 15, 18, 13, 5, 16, 18, 13,
16, 7, 13, X, X, X, X, X, X, X, X, X, X, X, X, X, 18, 17, 10, 18, 17, 5, 18, 15,
10, 18, 15, 6, 18, 13, 5, 18, 13, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 14, 5, 0, 17, 5, 3, 12, 10, 3, 15, 10, 3,
16, 6, 3, 15, 6, 8, 14, 5, 8, 13, 5, 8, 16, 6, 8, 13, 6, X, 0, 18, 10, 0, 1, 10,
0, 18, 5, 0, 9, 5, 18, 15, 10, 18, 15, 6, 18, 13, 5, 18, 13, 6, X, X, X, X, X, X,
X, X, X, X, X, X, X, 12, 1, 10, 14, 9, 5, 3, 12, 10, 3, 15, 10, 3, 16, 6, 3, 15,
6, 8, 14, 5, 8, 13, 5, 8, 16, 6, 8, 13, 6, X, X, X, X, X, X, X, 12, 18, 17, 12,
1, 17, 18, 17, 5, 12, 18, 15, 12, 2, 15, 18, 15, 6, 18, 13, 5, 18, 13, 6, X, X, X, X,
X, X, X, X, X, X, X, X, X, 0, 1, 17, 0, 14, 5, 0, 17, 5, 3, 2, 15, 3, 16, 6,
3, 15, 6, 8, 14, 5, 8, 13, 5, 8, 16, 6, 8, 13, 6, X, X, X, X, X, X, X, 0, 12,
18, 0, 18, 5, 0, 9, 5, 12, 18, 15, 12, 2, 15, 18, 15, 6, 18, 13, 5, 18, 13, 6, X, X,
X, X, X, X, X, X, X, X, X, X, X, 14, 9, 5, 3, 2, 15, 3, 16, 6, 3, 15, 6, 8,
14, 5, 8, 13, 5, 8, 16, 6, 8, 13, 6, X, X, X, X, X, X, X, X, X, X, X, X, X,
18, 17, 10, 18, 17, 5, 3, 18, 10, 3, 2, 10, 3, 18, 6, 3, 11, 6, 18, 13, 5, 18, 13, 6,
X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 14, 5, 0, 17,
5, 12, 2, 10, 16, 11, 6, 8, 14, 5, 8, 13, 5, 8, 16, 6, 8, 13, 6, X, X, X, X, X,
X, X, 0, 18, 10, 0, 1, 10, 0, 18, 5, 0, 9, 5, 3, 18, 10, 3, 2, 10, 3, 18, 6, 3,
11, 6, 18, 13, 5, 18, 13, 6, X, X, X, X, X, X, X, 12, 1, 10, 14, 9, 5, 12, 2, 10,
16, 11, 6, 8, 14, 5, 8, 13, 5, 8, 16, 6, 8, 13, 6, X, X, X, X, X, X, X, X, X,
X, X, X, X, 12, 18, 17, 12, 1, 17, 18, 17, 5, 3, 12, 18, 3, 18, 6, 3, 11, 6, 18, 13,
5, 18, 13, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 1, 17, 0, 14, 5, 0,
17, 5, 16, 11, 6, 8, 14, 5, 8, 13, 5, 8, 16, 6, 8, 13, 6, X, X, X, X, X, X, X,
X, X, X, X, X, X, 0, 12, 18, 0, 18, 5, 0, 9, 5, 3, 12, 18, 3, 18, 6, 3, 11, 6,
18, 13, 5, 18, 13, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 14, 9, 5, 16, 11,
6, 8, 14, 5, 8, 13, 5, 8, 16, 6, 8, 13, 6, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, 18, 17, 10, 18, 17, 5, 18, 15, 10, 18, 15, 6, 8, 18, 5, 8,
4, 5, 8, 18, 6, 8, 7, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 10,
0, 17, 10, 0, 14, 5, 0, 17, 5, 3, 12, 10, 3, 15, 10, 3, 16, 6, 3, 15, 6, 14, 4, 5,
16, 7, 6, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10, 0, 18, 5, 0, 9, 5, 18, 15,
10, 18, 15, 6, 8, 18, 5, 8, 4, 5, 8, 18, 6, 8, 7, 6, X, X, X, X, X, X, X, 12,
1, 10, 14, 9, 5, 3, 12, 10, 3, 15, 10, 3, 16, 6, 3, 15, 6, 14, 4, 5, 16, 7, 6, X,
X, X, X, X, X, X, X, X, X, X, X, X, 12, 18, 17, 12, 1, 17, 18, 17, 5, 12, 18, 15,
12, 2, 15, 18, 15, 6, 8, 18, 5, 8, 4, 5, 8, 18, 6, 8, 7, 6, X, X, X, X, X, X,
X, 0, 1, 17, 0, 14, 5, 0, 17, 5, 3, 2, 15, 3, 16, 6, 3, 15, 6, 14, 4, 5, 16, 7,
6, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 18, 0, 18, 5, 0, 9, 5, 12,
18, 15, 12, 2, 15, 18, 15, 6, 8, 18, 5, 8, 4, 5, 8, 18, 6, 8, 7, 6, X, X, X, X,
X, X, X, 14, 9, 5, 3, 2, 15, 3, 16, 6, 3, 15, 6, 14, 4, 5, 16, 7, 6, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 18, 17, 10, 18, 17, 5, 3, 18,
10, 3, 2, 10, 3, 18, 6, 3, 11, 6, 8, 18, 5, 8, 4, 5, 8, 18, 6, 8, 7, 6, X, X,
X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 14, 5, 0, 17, 5, 12, 2, 10, 16, 11, 6, 14,
4, 5, 16, 7, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10,
0, 18, 5, 0, 9, 5, 3, 18, 10, 3, 2, 10, 3, 18, 6, 3, 11, 6, 8, 18, 5, 8, 4, 5,
8, 18, 6, 8, 7, 6, X, 12, 1, 10, 14, 9, 5, 12, 2, 10, 16, 11, 6, 14, 4, 5, 16, 7,
6, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 12, 18, 17, 12,
1, 17, 18, 17, 5, 3, 12, 18, 3, 18, 6, 3, 11, 6, 8, 18, 5, 8, 4, 5, 8, 18, 6, 8,
7, 6, X, X, X, X, X, X, X, 0, 1, 17, 0, 14, 5, 0, 17, 5, 16, 11, 6, 14, 4, 5,
16, 7, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12,
18, 0, 18, 5, 0, 9, 5, 3, 12, 18, 3, 18, 6, 3, 11, 6, 8, 18, 5, 8, 4, 5, 8, 18,
6, 8, 7, 6, X, X, X, X, X, X, X, 14, 9, 5, 16, 11, 6, 14, 4, 5, 16, 7, 6, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
18, 17, 10, 14, 18, 17, 14, 9, 17, 18, 15, 10, 18, 15, 6, 14, 18, 13, 14, 4, 13, 18, 13, 6,
X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 9, 17, 3, 12,
10, 3, 15, 10, 3, 16, 6, 3, 15, 6, 8, 4, 13, 8, 16, 6, 8, 13, 6, X, X, X, X, X,
X, X, 0, 18, 10, 0, 1, 10, 0, 14, 18, 18, 15, 10, 18, 15, 6, 14, 18, 13, 14, 4, 13, 18,
13, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 12, 1, 10, 3, 12, 10, 3, 15, 10,
3, 16, 6, 3, 15, 6, 8, 4, 13, 8, 16, 6, 8, 13, 6, X, X, X, X, X, X, X, X, X,
X, X, X, X, 12, 18, 17, 12, 1, 17, 14, 18, 17, 14, 9, 17, 12, 18, 15, 12, 2, 15, 18, 15,
6, 14, 18, 13, 14, 4, 13, 18, 13, 6, X, X, X, X, X, X, X, 0, 1, 17, 0, 9, 17, 3,
2, 15, 3, 16, 6, 3, 15, 6, 8, 4, 13, 8, 16, 6, 8, 13, 6, X, X, X, X, X, X, X,
X, X, X, X, X, X, 0, 12, 18, 0, 14, 18, 12, 18, 15, 12, 2, 15, 18, 15, 6, 14, 18, 13,
14, 4, 13, 18, 13, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 3, 2, 15, 3, 16,
6, 3, 15, 6, 8, 4, 13, 8, 16, 6, 8, 13, 6, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, 18, 17, 10, 14, 18, 17, 14, 9, 17, 3, 18, 10, 3, 2, 10, 3,
18, 6, 3, 11, 6, 14, 18, 13, 14, 4, 13, 18, 13, 6, X, X, X, X, X, X, X, 0, 12, 10,
0, 17, 10, 0, 9, 17, 12, 2, 10, 16, 11, 6, 8, 4, 13, 8, 16, 6, 8, 13, 6, X, X, X,
X, X, X, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10, 0, 14, 18, 3, 18, 10, 3, 2,
10, 3, 18, 6, 3, 11, 6, 14, 18, 13, 14, 4, 13, 18, 13, 6, X, X, X, X, X, X, X, 12,
1, 10, 12, 2, 10, 16, 11, 6, 8, 4, 13, 8, 16, 6, 8, 13, 6, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, 12, 18, 17, 12, 1, 17, 14, 18, 17, 14, 9, 17,
3, 12, 18, 3, 18, 6, 3, 11, 6, 14, 18, 13, 14, 4, 13, 18, 13, 6, X, X, X, X, X, X,
X, 0, 1, 17, 0, 9, 17, 16, 11, 6, 8, 4, 13, 8, 16, 6, 8, 13, 6, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 18, 0, 14, 18, 3, 12, 18, 3,
18, 6, 3, 11, 6, 14, 18, 13, 14, 4, 13, 18, 13, 6, X, X, X, X, X, X, X, X, X, X,
X, X, X, 16, 11, 6, 8, 4, 13, 8, 16, 6, 8, 13, 6, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 18, 17, 10, 14, 18, 17, 14, 9,
17, 18, 15, 10, 18, 15, 6, 8, 14, 18, 8, 18, 6, 8, 7, 6, X, X, X, X, X, X, X, X,
X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 9, 17, 3, 12, 10, 3, 15, 10, 3, 16, 6, 3,
15, 6, 16, 7, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10,
0, 14, 18, 18, 15, 10, 18, 15, 6, 8, 14, 18, 8, 18, 6, 8, 7, 6, X, X, X, X, X, X,
X, X, X, X, X, X, X, 12, 1, 10, 3, 12, 10, 3, 15, 10, 3, 16, 6, 3, 15, 6, 16, 7,
6, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 12, 18, 17, 12,
1, 17, 14, 18, 17, 14, 9, 17, 12, 18, 15, 12, 2, 15, 18, 15, 6, 8, 14, 18, 8, 18, 6, 8,
7, 6, X, X, X, X, X, X, X, 0, 1, 17, 0, 9, 17, 3, 2, 15, 3, 16, 6, 3, 15, 6,
16, 7, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12,
18, 0, 14, 18, 12, 18, 15, 12, 2, 15, 18, 15, 6, 8, 14, 18, 8, 18, 6, 8, 7, 6, X, X,
X, X, X, X, X, X, X, X, X, X, X, 3, 2, 15, 3, 16, 6, 3, 15, 6, 16, 7, 6, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
18, 17, 10, 14, 18, 17, 14, 9, 17, 3, 18, 10, 3, 2, 10, 3, 18, 6, 3, 11, 6, 8, 14, 18,
8, 18, 6, 8, 7, 6, X, X, X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 9, 17, 12, 2,
10, 16, 11, 6, 16, 7, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, 0, 18, 10, 0, 1, 10, 0, 14, 18, 3, 18, 10, 3, 2, 10, 3, 18, 6, 3, 11, 6, 8,
14, 18, 8, 18, 6, 8, 7, 6, X, X, X, X, X, X, X, 12, 1, 10, 12, 2, 10, 16, 11, 6,
16, 7, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, 12, 18, 17, 12, 1, 17, 14, 18, 17, 14, 9, 17, 3, 12, 18, 3, 18, 6, 3, 11,
6, 8, 14, 18, 8, 18, 6, 8, 7, 6, X, X, X, X, X, X, X, 0, 1, 17, 0, 9, 17, 16,
11, 6, 16, 7, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, 0, 12, 18, 0, 14, 18, 3, 12, 18, 3, 18, 6, 3, 11, 6, 8, 14, 18,
8, 18, 6, 8, 7, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 16, 11, 6, 16, 7,
6, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, 16, 11, 6, 16, 7, 6, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 18,
0, 14, 18, 3, 12, 18, 3, 18, 6, 3, 11, 6, 8, 14, 18, 8, 18, 6, 8, 7, 6, X, X, X,
X, X, X, X, X, X, X, X, X, X, 0, 1, 17, 0, 9, 17, 16, 11, 6, 16, 7, 6, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 12,
18, 17, 12, 1, 17, 14, 18, 17, 14, 9, 17, 3, 12, 18, 3, 18, 6, 3, 11, 6, 8, 14, 18, 8,
18, 6, 8, 7, 6, X, X, X, X, X, X, X, 12, 1, 10, 12, 2, 10, 16, 11, 6, 16, 7, 6,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, 0, 18, 10, 0, 1, 10, 0, 14, 18, 3, 18, 10, 3, 2, 10, 3, 18, 6, 3, 11, 6, 8, 14,
18, 8, 18, 6, 8, 7, 6, X, X, X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 9, 17, 12,
2, 10, 16, 11, 6, 16, 7, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, 18, 17, 10, 14, 18, 17, 14, 9, 17, 3, 18, 10, 3, 2, 10, 3, 18, 6, 3, 11, 6,
8, 14, 18, 8, 18, 6, 8, 7, 6, X, X, X, X, X, X, X, 3, 2, 15, 3, 16, 6, 3, 15,
6, 16, 7, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, 0, 12, 18, 0, 14, 18, 12, 18, 15, 12, 2, 15, 18, 15, 6, 8, 14, 18, 8,
18, 6, 8, 7, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 1, 17, 0, 9, 17,
3, 2, 15, 3, 16, 6, 3, 15, 6, 16, 7, 6, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, 12, 18, 17, 12, 1, 17, 14, 18, 17, 14, 9, 17, 12, 18, 15, 12, 2,
15, 18, 15, 6, 8, 14, 18, 8, 18, 6, 8, 7, 6, X, X, X, X, X, X, X, 12, 1, 10, 3,
12, 10, 3, 15, 10, 3, 16, 6, 3, 15, 6, 16, 7, 6, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10, 0, 14, 18, 18, 15, 10, 18, 15, 6,
8, 14, 18, 8, 18, 6, 8, 7, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12,
10, 0, 17, 10, 0, 9, 17, 3, 12, 10, 3, 15, 10, 3, 16, 6, 3, 15, 6, 16, 7, 6, X, X,
X, X, X, X, X, X, X, X, X, X, X, 18, 17, 10, 14, 18, 17, 14, 9, 17, 18, 15, 10, 18,
15, 6, 8, 14, 18, 8, 18, 6, 8, 7, 6, X, X, X, X, X, X, X, X, X, X, X, X, X,
16, 11, 6, 8, 4, 13, 8, 16, 6, 8, 13, 6, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 18, 0, 14, 18, 3, 12, 18, 3, 18,
6, 3, 11, 6, 14, 18, 13, 14, 4, 13, 18, 13, 6, X, X, X, X, X, X, X, X, X, X, X,
X, X, 0, 1, 17, 0, 9, 17, 16, 11, 6, 8, 4, 13, 8, 16, 6, 8, 13, 6, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 12, 18, 17, 12, 1, 17, 14, 18, 17,
14, 9, 17, 3, 12, 18, 3, 18, 6, 3, 11, 6, 14, 18, 13, 14, 4, 13, 18, 13, 6, X, X, X,
X, X, X, X, 12, 1, 10, 12, 2, 10, 16, 11, 6, 8, 4, 13, 8, 16, 6, 8, 13, 6, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10, 0,
14, 18, 3, 18, 10, 3, 2, 10, 3, 18, 6, 3, 11, 6, 14, 18, 13, 14, 4, 13, 18, 13, 6, X,
X, X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 9, 17, 12, 2, 10, 16, 11, 6, 8, 4, 13,
8, 16, 6, 8, 13, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 18, 17, 10, 14, 18,
17, 14, 9, 17, 3, 18, 10, 3, 2, 10, 3, 18, 6, 3, 11, 6, 14, 18, 13, 14, 4, 13, 18, 13,
6, X, X, X, X, X, X, X, 3, 2, 15, 3, 16, 6, 3, 15, 6, 8, 4, 13, 8, 16, 6, 8,
13, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 18,
0, 14, 18, 12, 18, 15, 12, 2, 15, 18, 15, 6, 14, 18, 13, 14, 4, 13, 18, 13, 6, X, X, X,
X, X, X, X, X, X, X, X, X, X, 0, 1, 17, 0, 9, 17, 3, 2, 15, 3, 16, 6, 3, 15,
6, 8, 4, 13, 8, 16, 6, 8, 13, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 12,
18, 17, 12, 1, 17, 14, 18, 17, 14, 9, 17, 12, 18, 15, 12, 2, 15, 18, 15, 6, 14, 18, 13, 14,
4, 13, 18, 13, 6, X, X, X, X, X, X, X, 12, 1, 10, 3, 12, 10, 3, 15, 10, 3, 16, 6,
3, 15, 6, 8, 4, 13, 8, 16, 6, 8, 13, 6, X, X, X, X, X, X, X, X, X, X, X, X,
X, 0, 18, 10, 0, 1, 10, 0, 14, 18, 18, 15, 10, 18, 15, 6, 14, 18, 13, 14, 4, 13, 18, 13,
6, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 9, 17, 3,
12, 10, 3, 15, 10, 3, 16, 6, 3, 15, 6, 8, 4, 13, 8, 16, 6, 8, 13, 6, X, X, X, X,
X, X, X, 18, 17, 10, 14, 18, 17, 14, 9, 17, 18, 15, 10, 18, 15, 6, 14, 18, 13, 14, 4, 13,
18, 13, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 14, 9, 5, 16, 11, 6, 14, 4,
5, 16, 7, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, 0, 12, 18, 0, 18, 5, 0, 9, 5, 3, 12, 18, 3, 18, 6, 3, 11, 6, 8,
18, 5, 8, 4, 5, 8, 18, 6, 8, 7, 6, X, X, X, X, X, X, X, 0, 1, 17, 0, 14, 5,
0, 17, 5, 16, 11, 6, 14, 4, 5, 16, 7, 6, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, 12, 18, 17, 12, 1, 17, 18, 17, 5, 3, 12, 18, 3, 18, 6, 3, 11,
6, 8, 18, 5, 8, 4, 5, 8, 18, 6, 8, 7, 6, X, X, X, X, X, X, X, 12, 1, 10, 14,
9, 5, 12, 2, 10, 16, 11, 6, 14, 4, 5, 16, 7, 6, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10, 0, 18, 5, 0, 9, 5, 3, 18, 10,
3, 2, 10, 3, 18, 6, 3, 11, 6, 8, 18, 5, 8, 4, 5, 8, 18, 6, 8, 7, 6, X, 0, 12,
10, 0, 17, 10, 0, 14, 5, 0, 17, 5, 12, 2, 10, 16, 11, 6, 14, 4, 5, 16, 7, 6, X, X,
X, X, X, X, X, X, X, X, X, X, X, 18, 17, 10, 18, 17, 5, 3, 18, 10, 3, 2, 10, 3,
18, 6, 3, 11, 6, 8, 18, 5, 8, 4, 5, 8, 18, 6, 8, 7, 6, X, X, X, X, X, X, X,
14, 9, 5, 3, 2, 15, 3, 16, 6, 3, 15, 6, 14, 4, 5, 16, 7, 6, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 18, 0, 18, 5, 0, 9, 5, 12, 18,
15, 12, 2, 15, 18, 15, 6, 8, 18, 5, 8, 4, 5, 8, 18, 6, 8, 7, 6, X, X, X, X, X,
X, X, 0, 1, 17, 0, 14, 5, 0, 17, 5, 3, 2, 15, 3, 16, 6, 3, 15, 6, 14, 4, 5, 16,
7, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 12, 18, 17, 12, 1, 17, 18, 17, 5,
12, 18, 15, 12, 2, 15, 18, 15, 6, 8, 18, 5, 8, 4, 5, 8, 18, 6, 8, 7, 6, X, X, X,
X, X, X, X, 12, 1, 10, 14, 9, 5, 3, 12, 10, 3, 15, 10, 3, 16, 6, 3, 15, 6, 14, 4,
5, 16, 7, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10, 0,
18, 5, 0, 9, 5, 18, 15, 10, 18, 15, 6, 8, 18, 5, 8, 4, 5, 8, 18, 6, 8, 7, 6, X,
X, X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 14, 5, 0, 17, 5, 3, 12, 10, 3, 15, 10,
3, 16, 6, 3, 15, 6, 14, 4, 5, 16, 7, 6, X, X, X, X, X, X, X, 18, 17, 10, 18, 17,
5, 18, 15, 10, 18, 15, 6, 8, 18, 5, 8, 4, 5, 8, 18, 6, 8, 7, 6, X, X, X, X, X,
X, X, X, X, X, X, X, X, 14, 9, 5, 16, 11, 6, 8, 14, 5, 8, 13, 5, 8, 16, 6, 8,
13, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 18,
0, 18, 5, 0, 9, 5, 3, 12, 18, 3, 18, 6, 3, 11, 6, 18, 13, 5, 18, 13, 6, X, X, X,
X, X, X, X, X, X, X, X, X, X, 0, 1, 17, 0, 14, 5, 0, 17, 5, 16, 11, 6, 8, 14,
5, 8, 13, 5, 8, 16, 6, 8, 13, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 12,
18, 17, 12, 1, 17, 18, 17, 5, 3, 12, 18, 3, 18, 6, 3, 11, 6, 18, 13, 5, 18, 13, 6, X,
X, X, X, X, X, X, X, X, X, X, X, X, 12, 1, 10, 14, 9, 5, 12, 2, 10, 16, 11, 6,
8, 14, 5, 8, 13, 5, 8, 16, 6, 8, 13, 6, X, X, X, X, X, X, X, X, X, X, X, X,
X, 0, 18, 10, 0, 1, 10, 0, 18, 5, 0, 9, 5, 3, 18, 10, 3, 2, 10, 3, 18, 6, 3, 11,
6, 18, 13, 5, 18, 13, 6, X, X, X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 14, 5, 0,
17, 5, 12, 2, 10, 16, 11, 6, 8, 14, 5, 8, 13, 5, 8, 16, 6, 8, 13, 6, X, X, X, X,
X, X, X, 18, 17, 10, 18, 17, 5, 3, 18, 10, 3, 2, 10, 3, 18, 6, 3, 11, 6, 18, 13, 5,
18, 13, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 14, 9, 5, 3, 2, 15, 3, 16,
6, 3, 15, 6, 8, 14, 5, 8, 13, 5, 8, 16, 6, 8, 13, 6, X, X, X, X, X, X, X, X,
X, X, X, X, X, 0, 12, 18, 0, 18, 5, 0, 9, 5, 12, 18, 15, 12, 2, 15, 18, 15, 6, 18,
13, 5, 18, 13, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 1, 17, 0, 14, 5,
0, 17, 5, 3, 2, 15, 3, 16, 6, 3, 15, 6, 8, 14, 5, 8, 13, 5, 8, 16, 6, 8, 13, 6,
X, X, X, X, X, X, X, 12, 18, 17, 12, 1, 17, 18, 17, 5, 12, 18, 15, 12, 2, 15, 18, 15,
6, 18, 13, 5, 18, 13, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 12, 1, 10, 14,
9, 5, 3, 12, 10, 3, 15, 10, 3, 16, 6, 3, 15, 6, 8, 14, 5, 8, 13, 5, 8, 16, 6, 8,
13, 6, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10, 0, 18, 5, 0, 9, 5, 18, 15, 10,
18, 15, 6, 18, 13, 5, 18, 13, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12,
10, 0, 17, 10, 0, 14, 5, 0, 17, 5, 3, 12, 10, 3, 15, 10, 3, 16, 6, 3, 15, 6, 8, 14,
5, 8, 13, 5, 8, 16, 6, 8, 13, 6, X, 18, 17, 10, 18, 17, 5, 18, 15, 10, 18, 15, 6, 18,
13, 5, 18, 13, 6, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
18, 17, 10, 18, 17, 5, 18, 15, 10, 16, 18, 15, 16, 11, 15, 18, 13, 5, 16, 18, 13, 16, 7, 13,
X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 14, 5, 0, 17,
5, 3, 12, 10, 3, 15, 10, 3, 11, 15, 8, 14, 5, 8, 13, 5, 8, 7, 13, X, X, X, X, X,
X, X, 0, 18, 10, 0, 1, 10, 0, 18, 5, 0, 9, 5, 18, 15, 10, 16, 18, 15, 16, 11, 15, 18,
13, 5, 16, 18, 13, 16, 7, 13, X, X, X, X, X, X, X, 12, 1, 10, 14, 9, 5, 3, 12, 10,
3, 15, 10, 3, 11, 15, 8, 14, 5, 8, 13, 5, 8, 7, 13, X, X, X, X, X, X, X, X, X,
X, X, X, X, 12, 18, 17, 12, 1, 17, 18, 17, 5, 12, 18, 15, 12, 2, 15, 16, 18, 15, 16, 11,
15, 18, 13, 5, 16, 18, 13, 16, 7, 13, X, X, X, X, X, X, X, 0, 1, 17, 0, 14, 5, 0,
17, 5, 3, 2, 15, 3, 11, 15, 8, 14, 5, 8, 13, 5, 8, 7, 13, X, X, X, X, X, X, X,
X, X, X, X, X, X, 0, 12, 18, 0, 18, 5, 0, 9, 5, 12, 18, 15, 12, 2, 15, 16, 18, 15,
16, 11, 15, 18, 13, 5, 16, 18, 13, 16, 7, 13, X, X, X, X, X, X, X, 14, 9, 5, 3, 2,
15, 3, 11, 15, 8, 14, 5, 8, 13, 5, 8, 7, 13, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, 18, 17, 10, 18, 17, 5, 3, 18, 10, 3, 2, 10, 3, 16, 18, 18,
13, 5, 16, 18, 13, 16, 7, 13, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 10,
0, 17, 10, 0, 14, 5, 0, 17, 5, 12, 2, 10, 8, 14, 5, 8, 13, 5, 8, 7, 13, X, X, X,
X, X, X, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10, 0, 18, 5, 0, 9, 5, 3, 18,
10, 3, 2, 10, 3, 16, 18, 18, 13, 5, 16, 18, 13, 16, 7, 13, X, X, X, X, X, X, X, 12,
1, 10, 14, 9, 5, 12, 2, 10, 8, 14, 5, 8, 13, 5, 8, 7, 13, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, 12, 18, 17, 12, 1, 17, 18, 17, 5, 3, 12, 18,
3, 16, 18, 18, 13, 5, 16, 18, 13, 16, 7, 13, X, X, X, X, X, X, X, X, X, X, X, X,
X, 0, 1, 17, 0, 14, 5, 0, 17, 5, 8, 14, 5, 8, 13, 5, 8, 7, 13, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 18, 0, 18, 5, 0, 9, 5, 3,
12, 18, 3, 16, 18, 18, 13, 5, 16, 18, 13, 16, 7, 13, X, X, X, X, X, X, X, X, X, X,
X, X, X, 14, 9, 5, 8, 14, 5, 8, 13, 5, 8, 7, 13, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 18, 17, 10, 18, 17, 5, 18, 15,
10, 16, 18, 15, 16, 11, 15, 8, 18, 5, 8, 4, 5, 8, 16, 18, X, X, X, X, X, X, X, X,
X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 14, 5, 0, 17, 5, 3, 12, 10, 3, 15, 10, 3,
11, 15, 14, 4, 5, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10,
0, 18, 5, 0, 9, 5, 18, 15, 10, 16, 18, 15, 16, 11, 15, 8, 18, 5, 8, 4, 5, 8, 16, 18,
X, X, X, X, X, X, X, 12, 1, 10, 14, 9, 5, 3, 12, 10, 3, 15, 10, 3, 11, 15, 14, 4,
5, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 12, 18, 17, 12,
1, 17, 18, 17, 5, 12, 18, 15, 12, 2, 15, 16, 18, 15, 16, 11, 15, 8, 18, 5, 8, 4, 5, 8,
16, 18, X, X, X, X, X, X, X, 0, 1, 17, 0, 14, 5, 0, 17, 5, 3, 2, 15, 3, 11, 15,
14, 4, 5, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12,
18, 0, 18, 5, 0, 9, 5, 12, 18, 15, 12, 2, 15, 16, 18, 15, 16, 11, 15, 8, 18, 5, 8, 4,
5, 8, 16, 18, X, X, X, X, X, X, X, 14, 9, 5, 3, 2, 15, 3, 11, 15, 14, 4, 5, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
18, 17, 10, 18, 17, 5, 3, 18, 10, 3, 2, 10, 3, 16, 18, 8, 18, 5, 8, 4, 5, 8, 16, 18,
X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 14, 5, 0, 17,
5, 12, 2, 10, 14, 4, 5, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, 0, 18, 10, 0, 1, 10, 0, 18, 5, 0, 9, 5, 3, 18, 10, 3, 2, 10, 3, 16, 18, 8,
18, 5, 8, 4, 5, 8, 16, 18, X, X, X, X, X, X, X, 12, 1, 10, 14, 9, 5, 12, 2, 10,
14, 4, 5, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, 12, 18, 17, 12, 1, 17, 18, 17, 5, 3, 12, 18, 3, 16, 18, 8, 18, 5, 8, 4,
5, 8, 16, 18, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 1, 17, 0, 14, 5, 0,
17, 5, 14, 4, 5, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, 0, 12, 18, 0, 18, 5, 0, 9, 5, 3, 12, 18, 3, 16, 18, 8, 18, 5,
8, 4, 5, 8, 16, 18, X, X, X, X, X, X, X, X, X, X, X, X, X, 14, 9, 5, 14, 4,
5, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, 18, 17, 10, 14, 18, 17, 14, 9, 17, 18, 15, 10, 16, 18, 15, 16,
11, 15, 14, 18, 13, 14, 4, 13, 16, 18, 13, 16, 7, 13, X, X, X, X, X, X, X, 0, 12, 10,
0, 17, 10, 0, 9, 17, 3, 12, 10, 3, 15, 10, 3, 11, 15, 8, 4, 13, 8, 7, 13, X, X, X,
X, X, X, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10, 0, 14, 18, 18, 15, 10, 16, 18,
15, 16, 11, 15, 14, 18, 13, 14, 4, 13, 16, 18, 13, 16, 7, 13, X, X, X, X, X, X, X, 12,
1, 10, 3, 12, 10, 3, 15, 10, 3, 11, 15, 8, 4, 13, 8, 7, 13, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, 12, 18, 17, 12, 1, 17, 14, 18, 17, 14, 9, 17,
12, 18, 15, 12, 2, 15, 16, 18, 15, 16, 11, 15, 14, 18, 13, 14, 4, 13, 16, 18, 13, 16, 7, 13,
X, 0, 1, 17, 0, 9, 17, 3, 2, 15, 3, 11, 15, 8, 4, 13, 8, 7, 13, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 18, 0, 14, 18, 12, 18, 15, 12,
2, 15, 16, 18, 15, 16, 11, 15, 14, 18, 13, 14, 4, 13, 16, 18, 13, 16, 7, 13, X, X, X, X,
X, X, X, 3, 2, 15, 3, 11, 15, 8, 4, 13, 8, 7, 13, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 18, 17, 10, 14, 18, 17, 14, 9,
17, 3, 18, 10, 3, 2, 10, 3, 16, 18, 14, 18, 13, 14, 4, 13, 16, 18, 13, 16, 7, 13, X, X,
X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 9, 17, 12, 2, 10, 8, 4, 13, 8, 7, 13, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10,
0, 14, 18, 3, 18, 10, 3, 2, 10, 3, 16, 18, 14, 18, 13, 14, 4, 13, 16, 18, 13, 16, 7, 13,
X, X, X, X, X, X, X, 12, 1, 10, 12, 2, 10, 8, 4, 13, 8, 7, 13, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 12, 18, 17, 12,
1, 17, 14, 18, 17, 14, 9, 17, 3, 12, 18, 3, 16, 18, 14, 18, 13, 14, 4, 13, 16, 18, 13, 16,
7, 13, X, X, X, X, X, X, X, 0, 1, 17, 0, 9, 17, 8, 4, 13, 8, 7, 13, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12,
18, 0, 14, 18, 3, 12, 18, 3, 16, 18, 14, 18, 13, 14, 4, 13, 16, 18, 13, 16, 7, 13, X, X,
X, X, X, X, X, X, X, X, X, X, X, 8, 4, 13, 8, 7, 13, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
18, 17, 10, 14, 18, 17, 14, 9, 17, 18, 15, 10, 16, 18, 15, 16, 11, 15, 8, 14, 18, 8, 16, 18,
X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 10, 0, 17, 10, 0, 9, 17, 3, 12,
10, 3, 15, 10, 3, 11, 15, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, 0, 18, 10, 0, 1, 10, 0, 14, 18, 18, 15, 10, 16, 18, 15, 16, 11, 15, 8, 14, 18, 8,
16, 18, X, X, X, X, X, X, X, X, X, X, X, X, X, 12, 1, 10, 3, 12, 10, 3, 15, 10,
3, 11, 15, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, 12, 18, 17, 12, 1, 17, 14, 18, 17, 14, 9, 17, 12, 18, 15, 12, 2, 15, 16, 18,
15, 16, 11, 15, 8, 14, 18, 8, 16, 18, X, X, X, X, X, X, X, 0, 1, 17, 0, 9, 17, 3,
2, 15, 3, 11, 15, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, 0, 12, 18, 0, 14, 18, 12, 18, 15, 12, 2, 15, 16, 18, 15, 16, 11, 15,
8, 14, 18, 8, 16, 18, X, X, X, X, X, X, X, X, X, X, X, X, X, 3, 2, 15, 3, 11,
15, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, 18, 17, 10, 14, 18, 17, 14, 9, 17, 3, 18, 10, 3, 2, 10, 3,
16, 18, 8, 14, 18, 8, 16, 18, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 10,
0, 17, 10, 0, 9, 17, 12, 2, 10, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, 0, 18, 10, 0, 1, 10, 0, 14, 18, 3, 18, 10, 3, 2,
10, 3, 16, 18, 8, 14, 18, 8, 16, 18, X, X, X, X, X, X, X, X, X, X, X, X, X, 12,
1, 10, 12, 2, 10, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, 12, 18, 17, 12, 1, 17, 14, 18, 17, 14, 9, 17,
3, 12, 18, 3, 16, 18, 8, 14, 18, 8, 16, 18, X, X, X, X, X, X, X, X, X, X, X, X,
X, 0, 1, 17, 0, 9, 17, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 12, 18, 0, 14, 18, 3, 12, 18, 3,
16, 18, 8, 14, 18, 8, 16, 18, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X
#undef X
});
const vtkm::Id nLabelEdgeTableMC3dElemSize = 9; // (at most 4 label edges)
const vtkm::Id nLabelEdgeTableLT3dElemSize = 13; // (at most 6 tetrahedra)
// size: nCasesMC3d * nLabelEdgeTableMC3dElemSize
const vtkm::cont::ArrayHandle<vtkm::Id> labelEdgeTableMC3d =
vtkm::cont::make_ArrayHandle<vtkm::Id>({
#define X -1
X, X, X, X, X, X, X, X, X, 1, 0, X, X, X, X, X, X, X, 1, 0, X, X, X, X, X, X, X, 2, 1, X, X, X,
X, X, X, X, 1, 1, X, X, X, X, X, X, X, 1, 0, 1, 1, X, X, X, X, X, 2, 0, X, X, X, X, X, X, X, 3,
2, X, X, X, X, X, X, X, 1, 2, X, X, X, X, X, X, X, 2, 0, X, X, X, X, X, X, X, 1, 0, 1, 2, X, X,
X, X, X, 3, 1, X, X, X, X, X, X, X, 2, 1, X, X, X, X, X, X, X, 3, 0, X, X, X, X, X, X, X, 3, 0,
X, X, X, X, X, X, X, 2, 8, X, X, X, X, X, X, X, 1, 4, X, X, X, X, X, X, X, 2, 0, X, X, X, X, X,
X, X, 1, 0, 1, 4, X, X, X, X, X, 3, 1, X, X, X, X, X, X, X, 1, 1, 1, 4, X, X, X, X, X, 2, 0, 1,
1, X, X, X, X, X, 2, 0, 1, 4, X, X, X, X, X, 4, 2, X, X, X, X, X, X, X, 1, 4, 1, 2, X, X, X, X,
X, 3, 0, X, X, X, X, X, X, X, 1, 0, 1, 4, 1, 2, X, X, X, 4, 1, X, X, X, X, X, X, X, 2, 1, 1, 4,
X, X, X, X, X, 4, 0, X, X, X, X, X, X, X, 1, 4, 3, 0, X, X, X, X, X, 3, 4, X, X, X, X, X, X, X,
1, 4, X, X, X, X, X, X, X, 1, 4, 1, 0, X, X, X, X, X, 2, 0, X, X, X, X, X, X, X, 3, 1, X, X, X,
X, X, X, X, 1, 1, 1, 4, X, X, X, X, X, 1, 0, 1, 1, 1, 4, X, X, X, 3, 0, X, X, X, X, X, X, X, 4,
2, X, X, X, X, X, X, X, 1, 4, 1, 2, X, X, X, X, X, 2, 0, 1, 4, X, X, X, X, X, 2, 0, 1, 2, X, X,
X, X, X, 4, 1, X, X, X, X, X, X, X, 2, 1, 1, 4, X, X, X, X, X, 1, 4, 3, 0, X, X, X, X, X, 4, 0,
X, X, X, X, X, X, X, 3, 4, X, X, X, X, X, X, X, 2, 5, X, X, X, X, X, X, X, 3, 0, X, X, X, X, X,
X, X, 3, 0, X, X, X, X, X, X, X, 2, 1, X, X, X, X, X, X, X, 2, 5, 1, 1, X, X, X, X, X, 1, 1, 3,
0, X, X, X, X, X, 4, 0, X, X, X, X, X, X, X, 3, 2, X, X, X, X, X, X, X, 2, 5, 1, 2, X, X, X, X,
X, 4, 0, X, X, X, X, X, X, X, 1, 2, 3, 0, X, X, X, X, X, 3, 1, X, X, X, X, X, X, X, 2, 5, 2, 1,
X, X, X, X, X, 5, 0, X, X, X, X, X, X, X, 5, 0, X, X, X, X, X, X, X, 2, 5, X, X, X, X, X, X, X,
1, 5, X, X, X, X, X, X, X, 1, 0, 1, 5, X, X, X, X, X, 1, 0, 1, 5, X, X, X, X, X, 2, 1, 1, 5, X,
X, X, X, X, 2, 1, X, X, X, X, X, X, X, 2, 1, 1, 0, X, X, X, X, X, 3, 0, X, X, X, X, X, X, X, 4,
2, X, X, X, X, X, X, X, 1, 2, 1, 5, X, X, X, X, X, 2, 0, 1, 5, X, X, X, X, X, 1, 0, 1, 2, 1, 5,
X, X, X, 1, 5, 3, 1, X, X, X, X, X, 3, 1, X, X, X, X, X, X, X, 4, 0, X, X, X, X, X, X, X, 4, 0,
X, X, X, X, X, X, X, 3, 5, X, X, X, X, X, X, X, 1, 5, 1, 4, X, X, X, X, X, 2, 0, 1, 5, X, X, X,
X, X, 1, 0, 1, 5, 1, 4, X, X, X, 1, 5, 3, 1, X, X, X, X, X, 2, 1, 1, 4, X, X, X, X, X, 2, 1, 2,
0, X, X, X, X, X, 1, 4, 3, 0, X, X, X, X, X, 5, 2, X, X, X, X, X, X, X, 1, 2, 1, 4, 1, 5, X, X,
X, 1, 5, 3, 0, X, X, X, X, X, 1, 0, 1, 4, 1, 2, 1, 5, X, 4, 1, 1, 5, X, X, X, X, X, 1, 4, 3, 1,
X, X, X, X, X, 5, 0, X, X, X, X, X, X, X, 4, 0, 1, 4, X, X, X, X, X, 4, 4, X, X, X, X, X, X, X,
2, 4, X, X, X, X, X, X, X, 2, 4, 1, 0, X, X, X, X, X, 3, 0, X, X, X, X, X, X, X, 4, 1, X, X, X,
X, X, X, X, 3, 1, X, X, X, X, X, X, X, 1, 0, 3, 1, X, X, X, X, X, 2, 0, X, X, X, X, X, X, X, 3,
2, X, X, X, X, X, X, X, 2, 4, 1, 2, X, X, X, X, X, 2, 0, 2, 4, X, X, X, X, X, 1, 2, 3, 0, X, X,
X, X, X, 5, 1, X, X, X, X, X, X, X, 4, 1, X, X, X, X, X, X, X, 5, 0, X, X, X, X, X, X, X, 3, 0,
X, X, X, X, X, X, X, 2, 4, X, X, X, X, X, X, X, 3, 6, X, X, X, X, X, X, X, 4, 0, X, X, X, X, X,
X, X, 4, 0, X, X, X, X, X, X, X, 3, 1, X, X, X, X, X, X, X, 4, 1, X, X, X, X, X, X, X, 5, 0, X,
X, X, X, X, X, X, 3, 0, X, X, X, X, X, X, X, 2, 2, X, X, X, X, X, X, X, 1, 2, 3, 6, X, X, X, X,
X, 5, 0, X, X, X, X, X, X, X, 4, 0, 1, 2, X, X, X, X, X, 4, 1, X, X, X, X, X, X, X, 5, 1, X, X,
X, X, X, X, X, 1, 0, 1, 6, X, X, X, X, X, 4, 0, X, X, X, X, X, X, X, 1, 6, X, X, X, X, X, X, X,
1, 6, X, X, X, X, X, X, X, 1, 0, 1, 6, X, X, X, X, X, 1, 0, 1, 6, X, X, X, X, X, 2, 1, 1, 6, X,
X, X, X, X, 1, 1, 1, 6, X, X, X, X, X, 1, 1, 1, 0, 1, 6, X, X, X, 2, 0, 1, 6, X, X, X, X, X, 1,
6, 3, 2, X, X, X, X, X, 2, 2, X, X, X, X, X, X, X, 3, 0, X, X, X, X, X, X, X, 2, 2, 1, 0, X, X,
X, X, X, 4, 1, X, X, X, X, X, X, X, 3, 1, X, X, X, X, X, X, X, 4, 0, X, X, X, X, X, X, X, 4, 0,
X, X, X, X, X, X, X, 3, 6, X, X, X, X, X, X, X, 2, 4, X, X, X, X, X, X, X, 3, 0, X, X, X, X, X,
X, X, 2, 4, 1, 0, X, X, X, X, X, 4, 1, X, X, X, X, X, X, X, 2, 4, 1, 1, X, X, X, X, X, 1, 1, 3,
0, X, X, X, X, X, 2, 4, 2, 0, X, X, X, X, X, 5, 2, X, X, X, X, X, X, X, 3, 2, X, X, X, X, X, X,
X, 2, 0, X, X, X, X, X, X, X, 1, 0, 3, 2, X, X, X, X, X, 3, 1, X, X, X, X, X, X, X, 4, 1, X, X,
X, X, X, X, X, 3, 0, X, X, X, X, X, X, X, 5, 0, X, X, X, X, X, X, X, 2, 4, X, X, X, X, X, X, X,
1, 4, 1, 6, X, X, X, X, X, 1, 0, 1, 4, 1, 6, X, X, X, 2, 0, 1, 6, X, X, X, X, X, 1, 6, 3, 1, X,
X, X, X, X, 1, 4, 1, 1, 1, 6, X, X, X, 1, 6, 1, 1, 1, 0, 1, 4, X, 1, 6, 3, 0, X, X, X, X, X, 4,
2, 1, 6, X, X, X, X, X, 2, 2, 1, 4, X, X, X, X, X, 1, 4, 3, 0, X, X, X, X, X, 2, 2, 2, 0, X, X,
X, X, X, 5, 1, X, X, X, X, X, X, X, 1, 4, 3, 1, X, X, X, X, X, 4, 0, 1, 4, X, X, X, X, X, 5, 0,
X, X, X, X, X, X, X, 4, 4, X, X, X, X, X, X, X, 3, 5, X, X, X, X, X, X, X, 4, 0, X, X, X, X, X,
X, X, 4, 0, X, X, X, X, X, X, X, 3, 1, X, X, X, X, X, X, X, 1, 1, 3, 5, X, X, X, X, X, 4, 0, 1,
1, X, X, X, X, X, 5, 0, X, X, X, X, X, X, X, 4, 2, X, X, X, X, X, X, X, 4, 2, X, X, X, X, X, X,
X, 3, 0, X, X, X, X, X, X, X, 5, 0, X, X, X, X, X, X, X, 2, 1, X, X, X, X, X, X, X, 5, 1, X, X,
X, X, X, X, X, 4, 0, X, X, X, X, X, X, X, 1, 0, 1, 5, X, X, X, X, X, 1, 5, X, X, X, X, X, X, X,
2, 5, X, X, X, X, X, X, X, 2, 5, 1, 0, X, X, X, X, X, 2, 5, 1, 0, X, X, X, X, X, 2, 5, 2, 1, X,
X, X, X, X, 3, 1, X, X, X, X, X, X, X, 1, 0, 3, 1, X, X, X, X, X, 4, 0, X, X, X, X, X, X, X, 5,
2, X, X, X, X, X, X, X, 3, 2, X, X, X, X, X, X, X, 4, 0, X, X, X, X, X, X, X, 1, 0, 3, 2, X, X,
X, X, X, 5, 1, X, X, X, X, X, X, X, 2, 1, X, X, X, X, X, X, X, 3, 0, X, X, X, X, X, X, X, 3, 0,
X, X, X, X, X, X, X, 2, 5, X, X, X, X, X, X, X, 3, 4, X, X, X, X, X, X, X, 4, 0, X, X, X, X, X,
X, X, 1, 0, 3, 4, X, X, X, X, X, 5, 1, X, X, X, X, X, X, X, 4, 1, X, X, X, X, X, X, X, 5, 0, X,
X, X, X, X, X, X, 5, 0, X, X, X, X, X, X, X, 1, 4, 1, 2, X, X, X, X, X, 4, 2, X, X, X, X, X, X,
X, 3, 0, X, X, X, X, X, X, X, 4, 2, 1, 0, X, X, X, X, X, 4, 1, X, X, X, X, X, X, X, 3, 1, X, X,
X, X, X, X, X, 2, 0, X, X, X, X, X, X, X, 4, 0, X, X, X, X, X, X, X, 1, 4, X, X, X, X, X, X, X,
3, 4, X, X, X, X, X, X, X, 1, 0, 3, 4, X, X, X, X, X, 4, 0, X, X, X, X, X, X, X, 5, 1, X, X, X,
X, X, X, X, 4, 1, X, X, X, X, X, X, X, 4, 1, 1, 0, X, X, X, X, X, 3, 0, X, X, X, X, X, X, X, 4,
2, X, X, X, X, X, X, X, 4, 2, X, X, X, X, X, X, X, 5, 0, X, X, X, X, X, X, X, 5, 0, X, X, X, X,
X, X, X, 1, 1, 1, 4, X, X, X, X, X, 3, 1, X, X, X, X, X, X, X, 4, 0, X, X, X, X, X, X, X, 2, 0,
X, X, X, X, X, X, X, 1, 4, X, X, X, X, X, X, X, 2, 8, X, X, X, X, X, X, X, 3, 0, X, X, X, X, X,
X, X, 3, 0, X, X, X, X, X, X, X, 2, 1, X, X, X, X, X, X, X, 3, 1, X, X, X, X, X, X, X, 4, 0, X,
X, X, X, X, X, X, 2, 0, X, X, X, X, X, X, X, 1, 2, X, X, X, X, X, X, X, 3, 2, X, X, X, X, X, X,
X, 2, 0, X, X, X, X, X, X, X, 4, 0, X, X, X, X, X, X, X, 1, 1, X, X, X, X, X, X, X, 2, 1, X, X,
X, X, X, X, X, 1, 0, X, X, X, X, X, X, X, 1, 0, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X
#undef X
});
// size: nCasesLT3d * nLabelEdgeTableLT3dElemSize
// (TODO/FIXME: it can be improved to be shortened a little bit)
const vtkm::cont::ArrayHandle<vtkm::Id> labelEdgeTableLT3d =
vtkm::cont::make_ArrayHandle<vtkm::Id>({
#define X -1
X, X, X, X, X, X, X, X, X, X, X, X, X, 6, 18, X, X, X, X, X, X, X, X, X, X, X,
2, 0, X, X, X, X, X, X, X, X, X, X, X, 2, 12, 2, 14, 4, 18, X, X, X, X, X, X, X,
2, 12, X, X, X, X, X, X, X, X, X, X, X, 2, 0, 1, 18, 2, 3, 3, 18, X, X, X, X, X,
3, 0, 1, 12, X, X, X, X, X, X, X, X, X, 1, 18, 2, 14, 2, 3, 3, 18, X, X, X, X, X,
2, 3, X, X, X, X, X, X, X, X, X, X, X, 2, 18, 2, 12, 2, 16, 2, 18, X, X, X, X, X,
2, 0, 2, 3, X, X, X, X, X, X, X, X, X, 2, 12, 2, 14, 2, 12, 2, 16, 2, 18, X, X, X,
1, 12, 3, 3, X, X, X, X, X, X, X, X, X, 2, 0, 2, 18, 2, 16, 2, 18, X, X, X, X, X,
3, 0, 3, 3, X, X, X, X, X, X, X, X, X, 1, 18, 2, 14, 1, 18, 2, 16, 2, 18, X, X, X,
2, 8, X, X, X, X, X, X, X, X, X, X, X, 4, 18, 2, 14, 2, 16, X, X, X, X, X, X, X,
2, 0, 2, 8, X, X, X, X, X, X, X, X, X, 2, 12, 2, 14, 2, 18, 2, 14, 2, 16, X, X, X,
2, 12, 2, 8, X, X, X, X, X, X, X, X, X, 2, 0, 1, 18, 2, 3, 1, 18, 2, 14, 2, 16, X,
3, 0, 1, 12, 2, 8, X, X, X, X, X, X, X, 1, 18, 2, 14, 2, 3, 1, 18, 2, 14, 2, 16, X,
2, 3, 2, 8, X, X, X, X, X, X, X, X, X, 2, 18, 2, 12, 2, 16, 2, 14, 2, 16, X, X, X,
2, 0, 2, 3, 2, 8, X, X, X, X, X, X, X, 2, 12, 2, 14, 2, 12, 2, 16, 2, 14, 2, 16, X,
1, 12, 3, 3, 2, 8, X, X, X, X, X, X, X, 2, 0, 2, 18, 2, 16, 2, 14, 2, 16, X, X, X,
3, 0, 3, 3, 2, 8, X, X, X, X, X, X, X, 1, 18, 2, 14, 1, 18, 2, 16, 2, 14, 2, 16, X,
2, 14, X, X, X, X, X, X, X, X, X, X, X, 1, 18, 2, 0, 2, 18, 2, 8, 1, 18, X, X, X,
3, 0, 1, 14, X, X, X, X, X, X, X, X, X, 2, 12, 3, 18, 2, 8, 1, 18, X, X, X, X, X,
1, 12, 1, 14, 1, 12, 1, 14, X, X, X, X, X, 4, 0, 2, 3, 1, 18, 2, 8, 1, 18, X, X, X,
4, 0, 1, 12, 1, 14, X, X, X, X, X, X, X, 2, 18, 2, 3, 1, 18, 2, 8, 1, 18, X, X, X,
1, 14, 2, 3, 1, 14, X, X, X, X, X, X, X, 1, 18, 2, 0, 2, 12, 2, 16, 2, 8, 1, 18, X,
3, 0, 2, 3, 1, 14, X, X, X, X, X, X, X, 2, 12, 1, 18, 2, 12, 2, 16, 2, 8, 1, 18, X,
1, 12, 1, 14, 3, 3, 1, 14, X, X, X, X, X, 4, 0, 1, 18, 2, 16, 2, 8, 1, 18, X, X, X,
4, 0, 3, 3, 1, 14, X, X, X, X, X, X, X, 3, 18, 2, 16, 2, 8, 1, 18, X, X, X, X, X,
1, 14, 3, 8, X, X, X, X, X, X, X, X, X, 1, 18, 2, 0, 3, 18, 2, 16, X, X, X, X, X,
3, 0, 3, 8, X, X, X, X, X, X, X, X, X, 2, 12, 4, 18, 2, 16, X, X, X, X, X, X, X,
1, 12, 1, 14, 1, 12, 3, 8, X, X, X, X, X, 4, 0, 2, 3, 2, 18, 2, 16, X, X, X, X, X,
4, 0, 1, 12, 3, 8, X, X, X, X, X, X, X, 2, 18, 2, 3, 2, 18, 2, 16, X, X, X, X, X,
1, 14, 2, 3, 3, 8, X, X, X, X, X, X, X, 1, 18, 2, 0, 2, 12, 2, 16, 1, 18, 2, 16, X,
3, 0, 2, 3, 3, 8, X, X, X, X, X, X, X, 2, 12, 1, 18, 2, 12, 2, 16, 1, 18, 2, 16, X,
1, 12, 1, 14, 3, 3, 3, 8, X, X, X, X, X, 4, 0, 1, 18, 2, 16, 1, 18, 2, 16, X, X, X,
4, 0, 3, 3, 3, 8, X, X, X, X, X, X, X, 3, 18, 2, 16, 1, 18, 2, 16, X, X, X, X, X,
6, 18, X, X, X, X, X, X, X, X, X, X, X, 4, 0, 4, 3, 4, 8, X, X, X, X, X, X, X,
4, 0, 4, 18, X, X, X, X, X, X, X, X, X, 1, 12, 1, 14, 4, 3, 4, 8, X, X, X, X, X,
2, 12, 1, 18, 2, 12, 3, 18, X, X, X, X, X, 3, 0, 3, 3, 4, 8, X, X, X, X, X, X, X,
1, 18, 2, 0, 2, 12, 3, 18, X, X, X, X, X, 1, 14, 3, 3, 4, 8, X, X, X, X, X, X, X,
2, 18, 4, 3, 2, 18, X, X, X, X, X, X, X, 4, 0, 1, 12, 1, 16, 4, 8, X, X, X, X, X,
4, 0, 4, 3, 2, 18, X, X, X, X, X, X, X, 1, 12, 1, 14, 1, 12, 1, 16, 4, 8, X, X, X,
2, 12, 2, 18, 2, 3, 2, 18, X, X, X, X, X, 3, 0, 1, 16, 4, 8, X, X, X, X, X, X, X,
1, 18, 2, 0, 1, 18, 2, 3, 2, 18, X, X, X, 1, 14, 1, 16, 4, 8, X, X, X, X, X, X, X,
4, 18, 4, 8, X, X, X, X, X, X, X, X, X, 4, 0, 4, 3, 1, 14, 1, 16, X, X, X, X, X,
4, 0, 2, 18, 4, 8, X, X, X, X, X, X, X, 1, 12, 1, 14, 4, 3, 1, 14, 1, 16, X, X, X,
2, 12, 1, 18, 2, 12, 1, 18, 4, 8, X, X, X, 3, 0, 3, 3, 1, 14, 1, 16, X, X, X, X, X,
1, 18, 2, 0, 2, 12, 1, 18, 4, 8, X, X, X, 1, 14, 3, 3, 1, 14, 1, 16, X, X, X, X, X,
2, 18, 4, 3, 4, 8, X, X, X, X, X, X, X, 4, 0, 1, 12, 1, 16, 1, 14, 1, 16, X, X, X,
4, 0, 4, 3, 4, 8, X, X, X, X, X, X, X, 1, 12, 1, 14, 1, 12, 1, 16, 1, 14, 1, 16, X,
2, 12, 2, 18, 2, 3, 4, 8, X, X, X, X, X, 3, 0, 1, 16, 1, 14, 1, 16, X, X, X, X, X,
1, 18, 2, 0, 1, 18, 2, 3, 4, 8, X, X, X, 1, 14, 1, 16, 1, 14, 1, 16, X, X, X, X, X,
1, 18, 2, 14, 2, 18, 2, 14, 1, 18, X, X, X, 3, 0, 4, 3, 3, 8, X, X, X, X, X, X, X,
2, 0, 3, 18, 2, 14, 1, 18, X, X, X, X, X, 1, 12, 4, 3, 3, 8, X, X, X, X, X, X, X,
2, 12, 2, 14, 2, 12, 1, 18, 2, 14, 1, 18, X, 2, 0, 3, 3, 3, 8, X, X, X, X, X, X, X,
2, 18, 2, 12, 1, 18, 2, 14, 1, 18, X, X, X, 3, 3, 3, 8, X, X, X, X, X, X, X, X, X,
1, 18, 2, 14, 4, 3, 2, 14, 1, 18, X, X, X, 3, 0, 1, 12, 1, 16, 3, 8, X, X, X, X, X,
2, 0, 1, 18, 4, 3, 2, 14, 1, 18, X, X, X, 2, 12, 1, 16, 3, 8, X, X, X, X, X, X, X,
2, 12, 2, 14, 1, 18, 2, 3, 2, 14, 1, 18, X, 2, 0, 1, 16, 3, 8, X, X, X, X, X, X, X,
3, 18, 2, 3, 2, 14, 1, 18, X, X, X, X, X, 1, 16, 3, 8, X, X, X, X, X, X, X, X, X,
1, 18, 2, 14, 3, 18, 2, 8, X, X, X, X, X, 3, 0, 4, 3, 1, 16, X, X, X, X, X, X, X,
2, 0, 4, 18, 2, 8, X, X, X, X, X, X, X, 1, 12, 4, 3, 1, 16, X, X, X, X, X, X, X,
2, 12, 2, 14, 2, 12, 2, 18, 2, 8, X, X, X, 2, 0, 3, 3, 1, 16, X, X, X, X, X, X, X,
2, 18, 2, 12, 2, 18, 2, 8, X, X, X, X, X, 3, 3, 1, 16, X, X, X, X, X, X, X, X, X,
1, 18, 2, 14, 4, 3, 1, 18, 2, 8, X, X, X, 3, 0, 1, 12, 2, 16, X, X, X, X, X, X, X,
2, 0, 1, 18, 4, 3, 1, 18, 2, 8, X, X, X, 2, 12, 2, 16, X, X, X, X, X, X, X, X, X,
2, 12, 2, 14, 1, 18, 2, 3, 1, 18, 2, 8, X, 2, 0, 2, 16, X, X, X, X, X, X, X, X, X,
3, 18, 2, 3, 1, 18, 2, 8, X, X, X, X, X, 2, 16, X, X, X, X, X, X, X, X, X, X, X,
2, 16, X, X, X, X, X, X, X, X, X, X, X, 3, 18, 2, 3, 1, 18, 2, 8, X, X, X, X, X,
2, 0, 2, 16, X, X, X, X, X, X, X, X, X, 2, 12, 2, 14, 1, 18, 2, 3, 1, 18, 2, 8, X,
2, 12, 2, 16, X, X, X, X, X, X, X, X, X, 2, 0, 1, 18, 4, 3, 1, 18, 2, 8, X, X, X,
3, 0, 1, 12, 2, 16, X, X, X, X, X, X, X, 1, 18, 2, 14, 4, 3, 1, 18, 2, 8, X, X, X,
3, 3, 1, 16, X, X, X, X, X, X, X, X, X, 2, 18, 2, 12, 2, 18, 2, 8, X, X, X, X, X,
2, 0, 3, 3, 1, 16, X, X, X, X, X, X, X, 2, 12, 2, 14, 2, 12, 2, 18, 2, 8, X, X, X,
1, 12, 4, 3, 1, 16, X, X, X, X, X, X, X, 2, 0, 4, 18, 2, 8, X, X, X, X, X, X, X,
3, 0, 4, 3, 1, 16, X, X, X, X, X, X, X, 1, 18, 2, 14, 3, 18, 2, 8, X, X, X, X, X,
1, 16, 3, 8, X, X, X, X, X, X, X, X, X, 3, 18, 2, 3, 2, 14, 1, 18, X, X, X, X, X,
2, 0, 1, 16, 3, 8, X, X, X, X, X, X, X, 2, 12, 2, 14, 1, 18, 2, 3, 2, 14, 1, 18, X,
2, 12, 1, 16, 3, 8, X, X, X, X, X, X, X, 2, 0, 1, 18, 4, 3, 2, 14, 1, 18, X, X, X,
3, 0, 1, 12, 1, 16, 3, 8, X, X, X, X, X, 1, 18, 2, 14, 4, 3, 2, 14, 1, 18, X, X, X,
3, 3, 3, 8, X, X, X, X, X, X, X, X, X, 2, 18, 2, 12, 1, 18, 2, 14, 1, 18, X, X, X,
2, 0, 3, 3, 3, 8, X, X, X, X, X, X, X, 2, 12, 2, 14, 2, 12, 1, 18, 2, 14, 1, 18, X,
1, 12, 4, 3, 3, 8, X, X, X, X, X, X, X, 2, 0, 3, 18, 2, 14, 1, 18, X, X, X, X, X,
3, 0, 4, 3, 3, 8, X, X, X, X, X, X, X, 1, 18, 2, 14, 2, 18, 2, 14, 1, 18, X, X, X,
1, 14, 1, 16, 1, 14, 1, 16, X, X, X, X, X, 1, 18, 2, 0, 1, 18, 2, 3, 4, 8, X, X, X,
3, 0, 1, 16, 1, 14, 1, 16, X, X, X, X, X, 2, 12, 2, 18, 2, 3, 4, 8, X, X, X, X, X,
1, 12, 1, 14, 1, 12, 1, 16, 1, 14, 1, 16, X, 4, 0, 4, 3, 4, 8, X, X, X, X, X, X, X,
4, 0, 1, 12, 1, 16, 1, 14, 1, 16, X, X, X, 2, 18, 4, 3, 4, 8, X, X, X, X, X, X, X,
1, 14, 3, 3, 1, 14, 1, 16, X, X, X, X, X, 1, 18, 2, 0, 2, 12, 1, 18, 4, 8, X, X, X,
3, 0, 3, 3, 1, 14, 1, 16, X, X, X, X, X, 2, 12, 1, 18, 2, 12, 1, 18, 4, 8, X, X, X,
1, 12, 1, 14, 4, 3, 1, 14, 1, 16, X, X, X, 4, 0, 2, 18, 4, 8, X, X, X, X, X, X, X,
4, 0, 4, 3, 1, 14, 1, 16, X, X, X, X, X, 4, 18, 4, 8, X, X, X, X, X, X, X, X, X,
1, 14, 1, 16, 4, 8, X, X, X, X, X, X, X, 1, 18, 2, 0, 1, 18, 2, 3, 2, 18, X, X, X,
3, 0, 1, 16, 4, 8, X, X, X, X, X, X, X, 2, 12, 2, 18, 2, 3, 2, 18, X, X, X, X, X,
1, 12, 1, 14, 1, 12, 1, 16, 4, 8, X, X, X, 4, 0, 4, 3, 2, 18, X, X, X, X, X, X, X,
4, 0, 1, 12, 1, 16, 4, 8, X, X, X, X, X, 2, 18, 4, 3, 2, 18, X, X, X, X, X, X, X,
1, 14, 3, 3, 4, 8, X, X, X, X, X, X, X, 1, 18, 2, 0, 2, 12, 3, 18, X, X, X, X, X,
3, 0, 3, 3, 4, 8, X, X, X, X, X, X, X, 2, 12, 1, 18, 2, 12, 3, 18, X, X, X, X, X,
1, 12, 1, 14, 4, 3, 4, 8, X, X, X, X, X, 4, 0, 4, 18, X, X, X, X, X, X, X, X, X,
4, 0, 4, 3, 4, 8, X, X, X, X, X, X, X, 6, 18, X, X, X, X, X, X, X, X, X, X, X,
3, 18, 2, 16, 1, 18, 2, 16, X, X, X, X, X, 4, 0, 3, 3, 3, 8, X, X, X, X, X, X, X,
4, 0, 1, 18, 2, 16, 1, 18, 2, 16, X, X, X, 1, 12, 1, 14, 3, 3, 3, 8, X, X, X, X, X,
2, 12, 1, 18, 2, 12, 2, 16, 1, 18, 2, 16, X, 3, 0, 2, 3, 3, 8, X, X, X, X, X, X, X,
1, 18, 2, 0, 2, 12, 2, 16, 1, 18, 2, 16, X, 1, 14, 2, 3, 3, 8, X, X, X, X, X, X, X,
2, 18, 2, 3, 2, 18, 2, 16, X, X, X, X, X, 4, 0, 1, 12, 3, 8, X, X, X, X, X, X, X,
4, 0, 2, 3, 2, 18, 2, 16, X, X, X, X, X, 1, 12, 1, 14, 1, 12, 3, 8, X, X, X, X, X,
2, 12, 4, 18, 2, 16, X, X, X, X, X, X, X, 3, 0, 3, 8, X, X, X, X, X, X, X, X, X,
1, 18, 2, 0, 3, 18, 2, 16, X, X, X, X, X, 1, 14, 3, 8, X, X, X, X, X, X, X, X, X,
3, 18, 2, 16, 2, 8, 1, 18, X, X, X, X, X, 4, 0, 3, 3, 1, 14, X, X, X, X, X, X, X,
4, 0, 1, 18, 2, 16, 2, 8, 1, 18, X, X, X, 1, 12, 1, 14, 3, 3, 1, 14, X, X, X, X, X,
2, 12, 1, 18, 2, 12, 2, 16, 2, 8, 1, 18, X, 3, 0, 2, 3, 1, 14, X, X, X, X, X, X, X,
1, 18, 2, 0, 2, 12, 2, 16, 2, 8, 1, 18, X, 1, 14, 2, 3, 1, 14, X, X, X, X, X, X, X,
2, 18, 2, 3, 1, 18, 2, 8, 1, 18, X, X, X, 4, 0, 1, 12, 1, 14, X, X, X, X, X, X, X,
4, 0, 2, 3, 1, 18, 2, 8, 1, 18, X, X, X, 1, 12, 1, 14, 1, 12, 1, 14, X, X, X, X, X,
2, 12, 3, 18, 2, 8, 1, 18, X, X, X, X, X, 3, 0, 1, 14, X, X, X, X, X, X, X, X, X,
1, 18, 2, 0, 2, 18, 2, 8, 1, 18, X, X, X, 2, 14, X, X, X, X, X, X, X, X, X, X, X,
1, 18, 2, 14, 1, 18, 2, 16, 2, 14, 2, 16, X, 3, 0, 3, 3, 2, 8, X, X, X, X, X, X, X,
2, 0, 2, 18, 2, 16, 2, 14, 2, 16, X, X, X, 1, 12, 3, 3, 2, 8, X, X, X, X, X, X, X,
2, 12, 2, 14, 2, 12, 2, 16, 2, 14, 2, 16, X, 2, 0, 2, 3, 2, 8, X, X, X, X, X, X, X,
2, 18, 2, 12, 2, 16, 2, 14, 2, 16, X, X, X, 2, 3, 2, 8, X, X, X, X, X, X, X, X, X,
1, 18, 2, 14, 2, 3, 1, 18, 2, 14, 2, 16, X, 3, 0, 1, 12, 2, 8, X, X, X, X, X, X, X,
2, 0, 1, 18, 2, 3, 1, 18, 2, 14, 2, 16, X, 2, 12, 2, 8, X, X, X, X, X, X, X, X, X,
2, 12, 2, 14, 2, 18, 2, 14, 2, 16, X, X, X, 2, 0, 2, 8, X, X, X, X, X, X, X, X, X,
4, 18, 2, 14, 2, 16, X, X, X, X, X, X, X, 2, 8, X, X, X, X, X, X, X, X, X, X, X,
1, 18, 2, 14, 1, 18, 2, 16, 2, 18, X, X, X, 3, 0, 3, 3, X, X, X, X, X, X, X, X, X,
2, 0, 2, 18, 2, 16, 2, 18, X, X, X, X, X, 1, 12, 3, 3, X, X, X, X, X, X, X, X, X,
2, 12, 2, 14, 2, 12, 2, 16, 2, 18, X, X, X, 2, 0, 2, 3, X, X, X, X, X, X, X, X, X,
2, 18, 2, 12, 2, 16, 2, 18, X, X, X, X, X, 2, 3, X, X, X, X, X, X, X, X, X, X, X,
1, 18, 2, 14, 2, 3, 3, 18, X, X, X, X, X, 3, 0, 1, 12, X, X, X, X, X, X, X, X, X,
2, 0, 1, 18, 2, 3, 3, 18, X, X, X, X, X, 2, 12, X, X, X, X, X, X, X, X, X, X, X,
2, 12, 2, 14, 4, 18, X, X, X, X, X, X, X, 2, 0, X, X, X, X, X, X, X, X, X, X, X,
6, 18, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X
#undef X
});
} // namespace select_top_volume_contours
} // namespace scalar_topology
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,103 @@
//============================================================================
// 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.
//
//=============================================================================
//
// This code is an extension of the algorithm presented in the paper:
// Parallel Peak Pruning for Scalable SMP Contour Tree Computation.
// Hamish Carr, Gunther Weber, Christopher Sewell, and James Ahrens.
// Proceedings of the IEEE Symposium on Large Data Analysis and Visualization
// (LDAV), October 2016, Baltimore, Maryland.
//
// The PPP2 algorithm and software were jointly developed by
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
// Oliver Ruebel (LBNL)
//==============================================================================
#ifndef vtk_m_filter_scalar_topology_worklet_select_top_volume_contours_predicates_h
#define vtk_m_filter_scalar_topology_worklet_select_top_volume_contours_predicates_h
#include <vtkm/Types.h>
namespace vtkm
{
namespace worklet
{
namespace scalar_topology
{
namespace select_top_volume_contours
{
constexpr vtkm::Id BRANCH_SADDLE = static_cast<vtkm::Id>(1); // 1 << 0
constexpr vtkm::Id BRANCH_COVER = static_cast<vtkm::Id>(2); // 1 << 1
constexpr vtkm::Id MAXIMA_CONTOUR = static_cast<vtkm::Id>(4); // 1 << 2
struct IsNonNegative
{
VTKM_EXEC_CONT
IsNonNegative() {}
VTKM_EXEC_CONT
bool operator()(const vtkm::Id x) const { return x >= 0; }
};
struct IsExtraMinima
{
VTKM_EXEC_CONT
IsExtraMinima() {}
VTKM_EXEC_CONT
bool operator()(const vtkm::Id x) const { return (x & vtkm::Id(1)) != 0; }
};
struct IsExtraMaxima
{
VTKM_EXEC_CONT
IsExtraMaxima() {}
VTKM_EXEC_CONT
bool operator()(const vtkm::Id x) const { return (x & vtkm::Id(2)) != 0; }
};
} // namespace select_top_volume_contours
} // namespace scalar_topology
} // namespace worklet
} // namespace vtkm
#endif