mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-16 17:22:55 +00:00
Ported distributed contour tree prototype to vtk-m
This commit is contained in:
parent
ea3f101953
commit
f433790a17
@ -854,7 +854,7 @@ int main(int argc, char* argv[])
|
||||
ctaug_ns::EdgePairArray saddlePeak;
|
||||
ctaug_ns::ProcessContourTree::CollectSortedSuperarcs(
|
||||
filter.GetContourTree(), filter.GetSortOrder(), saddlePeak);
|
||||
ctaug_ns::PrintEdgePairArray(saddlePeak);
|
||||
ctaug_ns::PrintEdgePairArrayColumnLayout(saddlePeak, std::cout);
|
||||
}
|
||||
|
||||
#ifdef WITH_MPI
|
||||
|
@ -50,7 +50,7 @@
|
||||
## Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
|
||||
## Oliver Ruebel (LBNL)
|
||||
##==============================================================================
|
||||
cmake_minimum_required(VERSION 3.8...3.15 FATAL_ERROR)
|
||||
cmake_minimum_required(VERSION 3.12...3.15 FATAL_ERROR)
|
||||
|
||||
# Find the VTK-m package
|
||||
find_package(VTKm REQUIRED QUIET)
|
||||
@ -60,11 +60,11 @@ find_package(VTKm REQUIRED QUIET)
|
||||
####################################
|
||||
if (VTKm_ENABLE_MPI)
|
||||
add_executable(ContourTree_Distributed ContourTreeApp.cxx)
|
||||
target_link_libraries(ContourTree_Distributed vtkm_filter MPI::MPI_CXX)
|
||||
target_link_libraries(ContourTree_Distributed vtkm_filter vtkm_io MPI::MPI_CXX)
|
||||
vtkm_add_target_information(ContourTree_Distributed
|
||||
MODIFY_CUDA_FLAGS
|
||||
DEVICE_SOURCES ContourTreeApp.cxx)
|
||||
target_compile_definitions(ContourTree_Distributed PRIVATE)
|
||||
target_compile_definitions(ContourTree_Distributed PRIVATE "WITH_MPI")
|
||||
|
||||
option (VTKM_EXAMPLE_CONTOURTREE_ENABLE_DEBUG_PRINT Off)
|
||||
mark_as_advanced(VTKM_EXAMPLE_CONTOURTREE_ENABLE_DEBUG_PRINT)
|
||||
|
@ -65,9 +65,12 @@
|
||||
#include <vtkm/cont/DataSet.h>
|
||||
#include <vtkm/cont/DataSetBuilderUniform.h>
|
||||
#include <vtkm/cont/DataSetFieldAdd.h>
|
||||
#include <vtkm/cont/DeviceAdapterTag.h>
|
||||
#include <vtkm/cont/Initialize.h>
|
||||
#include <vtkm/cont/RuntimeDeviceTracker.h>
|
||||
#include <vtkm/cont/Timer.h>
|
||||
#include <vtkm/io/BOVDataSetReader.h>
|
||||
|
||||
#include <vtkm/filter/ContourTreeUniformDistributed.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/PrintVectors.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/ProcessContourTree.h>
|
||||
@ -90,11 +93,12 @@ VTKM_THIRDPARTY_POST_INCLUDE
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#define PRESPLIT_FILE
|
||||
using ValueType = vtkm::Float32;
|
||||
|
||||
namespace ctaug_ns = vtkm::worklet::contourtree_augmented;
|
||||
@ -126,7 +130,7 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
return (it - this->mCLOptions.begin());
|
||||
return static_cast<vtkm::Id>(it - this->mCLOptions.begin());
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,8 +170,6 @@ int main(int argc, char* argv[])
|
||||
int rank, size;
|
||||
MPI_Comm_rank(comm, &rank);
|
||||
MPI_Comm_size(comm, &size);
|
||||
int numBlocks = size;
|
||||
int blocksPerRank = 1;
|
||||
|
||||
// initialize vtkm-m (e.g., logging via -v and device via the -d option)
|
||||
vtkm::cont::InitializeOptions vtkm_initialize_options =
|
||||
@ -217,33 +219,54 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rank == 0 && (argc < 2 || parser.hasOption("--help") || parser.hasOption("-h")))
|
||||
int numBlocks = size;
|
||||
int blocksPerRank = 1;
|
||||
if (parser.hasOption("--numBlocks"))
|
||||
{
|
||||
std::cout << "ContourTreeAugmented <options> <fileName>" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "<fileName> Name of the input data file." << std::endl;
|
||||
std::cout << "The file is expected to be ASCII with either: " << std::endl;
|
||||
std::cout << " - xdim ydim integers for 2D or" << std::endl;
|
||||
std::cout << " - xdim ydim zdim integers for 3D" << std::endl;
|
||||
std::cout << "followed by vector data last dimension varying fastest" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "----------------------------- VTKM Options -----------------------------"
|
||||
<< std::endl;
|
||||
std::cout << vtkm_config.Usage << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "------------------------- Contour Tree Options -------------------------"
|
||||
<< std::endl;
|
||||
std::cout << "Options: (Bool options are give via int, i.e. =0 for False and =1 for True)"
|
||||
<< std::endl;
|
||||
std::cout << "--mc Use marching cubes interpolation for contour tree calculation. "
|
||||
"(Default=False)"
|
||||
<< std::endl;
|
||||
#ifdef ENABLE_SET_NUM_THREADS
|
||||
std::cout << "--numThreads Specifiy the number of threads to use. Available only with TBB."
|
||||
<< std::endl;
|
||||
#endif
|
||||
std::cout << std::endl;
|
||||
numBlocks = std::stoi(parser.getOption("--numBlocks"));
|
||||
if (numBlocks % size == 0)
|
||||
blocksPerRank = numBlocks / size;
|
||||
else
|
||||
{
|
||||
std::cerr << "Error: Number of blocks must be divisible by number of ranks." << std::endl;
|
||||
MPI_Finalize();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc < 2 || parser.hasOption("--help") || parser.hasOption("-h"))
|
||||
{
|
||||
if (rank == 0)
|
||||
{
|
||||
std::cout << "ContourTreeAugmented <options> <fileName>" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "<fileName> Name of the input data file." << std::endl;
|
||||
std::cout << "The file is expected to be ASCII with either: " << std::endl;
|
||||
std::cout << " - xdim ydim integers for 2D or" << std::endl;
|
||||
std::cout << " - xdim ydim zdim integers for 3D" << std::endl;
|
||||
std::cout << "followed by vector data last dimension varying fastest" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "----------------------------- VTKM Options -----------------------------"
|
||||
<< std::endl;
|
||||
std::cout << vtkm_config.Usage << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "------------------------- Contour Tree Options -------------------------"
|
||||
<< std::endl;
|
||||
std::cout << "Options: (Bool options are give via int, i.e. =0 for False and =1 for True)"
|
||||
<< std::endl;
|
||||
std::cout
|
||||
<< "--mc Use marching cubes interpolation for contour tree calculation. "
|
||||
"(Default=False)"
|
||||
<< std::endl;
|
||||
#ifdef ENABLE_SET_NUM_THREADS
|
||||
std::cout
|
||||
<< "--numThreads Specifiy the number of threads to use. Available only with TBB."
|
||||
<< std::endl;
|
||||
#endif
|
||||
std::cout << "--numBlocks Number of blocks to load. (Default=number of MPI ranks.)"
|
||||
<< std::endl;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
MPI_Finalize();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@ -265,11 +288,11 @@ int main(int argc, char* argv[])
|
||||
vtkm::Float64 startUpTime = currTime - prevTime;
|
||||
prevTime = currTime;
|
||||
|
||||
// Redirect stdout to file if we are using MPI with Debugging
|
||||
#ifdef DEBUG_PRINT
|
||||
// Redirect stdout to file if we are using MPI with Debugging
|
||||
//#ifdef DEBUG_PRINT
|
||||
// From https://www.unix.com/302983597-post2.html
|
||||
char* cstr_filename = new char[15];
|
||||
snprintf(cstr_filename, sizeof(filename), "cout_%d.log", rank);
|
||||
char cstr_filename[255];
|
||||
std::snprintf(cstr_filename, sizeof(cstr_filename), "cout_%d.log", rank);
|
||||
int out = open(cstr_filename, O_RDWR | O_CREAT | O_APPEND, 0600);
|
||||
if (-1 == out)
|
||||
{
|
||||
@ -277,13 +300,15 @@ int main(int argc, char* argv[])
|
||||
return 255;
|
||||
}
|
||||
|
||||
snprintf(cstr_filename, sizeof(cstr_filename), "cerr_%d.log", rank);
|
||||
/*
|
||||
std::snprintf(cstr_filename, sizeof(cstr_filename), "cerr_%d.log", rank);
|
||||
int err = open(cstr_filename, O_RDWR | O_CREAT | O_APPEND, 0600);
|
||||
if (-1 == err)
|
||||
{
|
||||
perror("opening cerr.log");
|
||||
return 255;
|
||||
}
|
||||
*/
|
||||
|
||||
int save_out = dup(fileno(stdout));
|
||||
int save_err = dup(fileno(stderr));
|
||||
@ -293,37 +318,240 @@ int main(int argc, char* argv[])
|
||||
perror("cannot redirect stdout");
|
||||
return 255;
|
||||
}
|
||||
if (-1 == dup2(err, fileno(stderr)))
|
||||
//if (-1 == dup2(err, fileno(stderr)))
|
||||
if (-1 == dup2(out, fileno(stderr)))
|
||||
{
|
||||
perror("cannot redirect stderr");
|
||||
return 255;
|
||||
}
|
||||
|
||||
delete[] cstr_filename;
|
||||
#endif
|
||||
//#endif
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// Read the input data
|
||||
///////////////////////////////////////////////
|
||||
std::ifstream inFile(filename);
|
||||
if (inFile.bad())
|
||||
return 0;
|
||||
vtkm::Float64 dataReadTime = 0;
|
||||
vtkm::Float64 buildDatasetTime = 0;
|
||||
std::vector<vtkm::Float32>::size_type nDims = 0;
|
||||
|
||||
// Read the dimensions of the mesh, i.e,. number of elementes in x, y, and z
|
||||
std::vector<std::size_t> dims;
|
||||
std::string line;
|
||||
getline(inFile, line);
|
||||
std::istringstream linestream(line);
|
||||
std::size_t dimVertices;
|
||||
while (linestream >> dimVertices)
|
||||
#ifdef PRESPLIT_FILE
|
||||
// Multi-block dataset for multi-block DIY-paralle processing
|
||||
vtkm::cont::PartitionedDataSet useDataSet;
|
||||
|
||||
// Domain decomposition information for DIY/contour tree
|
||||
vtkm::Id3 globalSize;
|
||||
vtkm::Id3 blocksPerDim;
|
||||
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockIndices;
|
||||
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockOrigins;
|
||||
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockSizes;
|
||||
localBlockIndices.Allocate(blocksPerRank);
|
||||
localBlockOrigins.Allocate(blocksPerRank);
|
||||
localBlockSizes.Allocate(blocksPerRank);
|
||||
auto localBlockIndicesPortal = localBlockIndices.WritePortal();
|
||||
auto localBlockOriginsPortal = localBlockOrigins.WritePortal();
|
||||
auto localBlockSizesPortal = localBlockSizes.WritePortal();
|
||||
|
||||
for (int blockNo = 0; blockNo < blocksPerRank; ++blockNo)
|
||||
{
|
||||
dims.push_back(dimVertices);
|
||||
// Translate pattern into filename for this block
|
||||
char block_filename[256];
|
||||
snprintf(block_filename,
|
||||
sizeof(block_filename),
|
||||
filename.c_str(),
|
||||
static_cast<int>(rank * blocksPerRank + blockNo));
|
||||
std::cout << "Reading file " << block_filename << std::endl;
|
||||
|
||||
// Open file
|
||||
std::ifstream inFile(block_filename);
|
||||
if (!inFile.is_open() || inFile.bad())
|
||||
{
|
||||
std::cerr << "Error: Couldn't open file " << block_filename << std::endl;
|
||||
MPI_Finalize();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Read header with dimensions
|
||||
std::string line;
|
||||
std::string tag;
|
||||
vtkm::Id dimVertices;
|
||||
|
||||
getline(inFile, line);
|
||||
std::istringstream global_extents_stream(line);
|
||||
global_extents_stream >> tag;
|
||||
if (tag != "#GLOBAL_EXTENTS")
|
||||
{
|
||||
std::cerr << "Error: Expected #GLOBAL_EXTENTS, got " << tag << std::endl;
|
||||
MPI_Finalize();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::vector<vtkm::Id> global_extents;
|
||||
while (global_extents_stream >> dimVertices)
|
||||
global_extents.push_back(dimVertices);
|
||||
|
||||
// Swap dimensions so that they are from fastest to slowest growing
|
||||
// dims[0] -> col; dims[1] -> row, dims[2] ->slice
|
||||
std::swap(global_extents[0], global_extents[1]);
|
||||
|
||||
if (blockNo == 0)
|
||||
{ // First block: Set globalSize
|
||||
globalSize =
|
||||
vtkm::Id3{ static_cast<vtkm::Id>(global_extents[0]),
|
||||
static_cast<vtkm::Id>(global_extents[1]),
|
||||
static_cast<vtkm::Id>(global_extents.size() > 2 ? global_extents[2] : 1) };
|
||||
}
|
||||
else
|
||||
{ // All other blocks: Consistency check of globalSize
|
||||
if (globalSize !=
|
||||
vtkm::Id3{ static_cast<vtkm::Id>(global_extents[0]),
|
||||
static_cast<vtkm::Id>(global_extents[1]),
|
||||
static_cast<vtkm::Id>(global_extents.size() > 2 ? global_extents[2] : 1) })
|
||||
{
|
||||
std::cerr << "Error: Global extents mismatch between blocks!" << std::endl;
|
||||
MPI_Finalize();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
getline(inFile, line);
|
||||
std::istringstream offset_stream(line);
|
||||
offset_stream >> tag;
|
||||
if (tag != "#OFFSET")
|
||||
{
|
||||
std::cerr << "Error: Expected #OFFSET, got " << tag << std::endl;
|
||||
MPI_Finalize();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
std::vector<vtkm::Id> offset;
|
||||
while (offset_stream >> dimVertices)
|
||||
offset.push_back(dimVertices);
|
||||
// Swap dimensions so that they are from fastest to slowest growing
|
||||
// dims[0] -> col; dims[1] -> row, dims[2] ->slice
|
||||
std::swap(offset[0], offset[1]);
|
||||
|
||||
getline(inFile, line);
|
||||
std::istringstream linestream(line);
|
||||
std::vector<vtkm::Id> dims;
|
||||
while (linestream >> dimVertices)
|
||||
{
|
||||
dims.push_back(dimVertices);
|
||||
}
|
||||
|
||||
std::cout << dims.size() << " " << global_extents.size() << " " << offset.size() << std::endl;
|
||||
if (dims.size() != global_extents.size() || dims.size() != offset.size())
|
||||
{
|
||||
std::cerr << "Error: Dimension mismatch" << std::endl;
|
||||
MPI_Finalize();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
// Swap dimensions so that they are from fastest to slowest growing
|
||||
// dims[0] -> col; dims[1] -> row, dims[2] ->slice
|
||||
std::swap(dims[0], dims[1]);
|
||||
|
||||
// Compute the number of vertices, i.e., xdim * ydim * zdim
|
||||
nDims = static_cast<unsigned short>(dims.size());
|
||||
std::size_t numVertices = static_cast<std::size_t>(
|
||||
std::accumulate(dims.begin(), dims.end(), std::size_t(1), std::multiplies<std::size_t>()));
|
||||
|
||||
// Check for fatal input errors
|
||||
// Check that the number of dimensiosn is either 2D or 3D
|
||||
bool invalidNumDimensions = (nDims < 2 || nDims > 3);
|
||||
// Log any errors if found on rank 0
|
||||
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Error,
|
||||
invalidNumDimensions && (rank == 0),
|
||||
"The input mesh is " << nDims
|
||||
<< "D. "
|
||||
"The input data must be either 2D or 3D.");
|
||||
|
||||
// If we found any errors in the setttings than finalize MPI and exit the execution
|
||||
if (invalidNumDimensions)
|
||||
{
|
||||
MPI_Finalize();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Read data
|
||||
std::vector<ValueType> values(numVertices);
|
||||
if (filename.compare(filename.length() - 5, 5, ".bdem") == 0)
|
||||
{
|
||||
inFile.read(reinterpret_cast<char*>(values.data()),
|
||||
static_cast<std::streamsize>(numVertices * sizeof(ValueType)));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (std::size_t vertex = 0; vertex < numVertices; ++vertex)
|
||||
{
|
||||
inFile >> values[vertex];
|
||||
}
|
||||
}
|
||||
|
||||
// Create vtk-m data set
|
||||
vtkm::cont::DataSetBuilderUniform dsb;
|
||||
vtkm::cont::DataSet ds;
|
||||
if (nDims == 2)
|
||||
{
|
||||
const vtkm::Id2 v_dims{
|
||||
static_cast<vtkm::Id>(dims[0]),
|
||||
static_cast<vtkm::Id>(dims[1]),
|
||||
};
|
||||
const vtkm::Vec<ValueType, 2> v_origin{ static_cast<ValueType>(offset[0]),
|
||||
static_cast<ValueType>(offset[1]) };
|
||||
const vtkm::Vec<ValueType, 2> v_spacing{ 1, 1 };
|
||||
ds = dsb.Create(v_dims, v_origin, v_spacing);
|
||||
}
|
||||
else
|
||||
{
|
||||
VTKM_ASSERT(nDims == 3);
|
||||
const vtkm::Id3 v_dims{ static_cast<vtkm::Id>(dims[0]),
|
||||
static_cast<vtkm::Id>(dims[1]),
|
||||
static_cast<vtkm::Id>(dims[2]) };
|
||||
const vtkm::Vec<ValueType, 3> v_origin{ static_cast<ValueType>(offset[0]),
|
||||
static_cast<ValueType>(offset[1]),
|
||||
static_cast<ValueType>(offset[2]) };
|
||||
vtkm::Vec<ValueType, 3> v_spacing(1, 1, 1);
|
||||
ds = dsb.Create(v_dims, v_origin, v_spacing);
|
||||
}
|
||||
ds.AddPointField("values", values);
|
||||
// and add to partition
|
||||
useDataSet.AppendPartition(ds);
|
||||
|
||||
// FIXME: Hack: Approximate block index (better to put this into file)
|
||||
localBlockIndicesPortal.Set(
|
||||
blockNo,
|
||||
vtkm::Id3{ static_cast<vtkm::Id>(
|
||||
std::ceil(static_cast<float>(offset[0]) / static_cast<float>(dims[0]))),
|
||||
static_cast<vtkm::Id>(
|
||||
std::ceil(static_cast<float>(offset[1]) / static_cast<float>(dims[1]))),
|
||||
static_cast<vtkm::Id>(nDims == 3 ? std::ceil(static_cast<float>(offset[2]) /
|
||||
static_cast<float>(dims[2]))
|
||||
: 0) });
|
||||
localBlockOriginsPortal.Set(blockNo,
|
||||
vtkm::Id3{ static_cast<vtkm::Id>(offset[0]),
|
||||
static_cast<vtkm::Id>(offset[1]),
|
||||
static_cast<vtkm::Id>(nDims == 3 ? offset[2] : 0) });
|
||||
localBlockSizesPortal.Set(blockNo,
|
||||
vtkm::Id3{ static_cast<vtkm::Id>(dims[0]),
|
||||
static_cast<vtkm::Id>(dims[1]),
|
||||
static_cast<vtkm::Id>(nDims == 3 ? dims[2] : 0) });
|
||||
|
||||
if (blockNo == 0)
|
||||
{
|
||||
// FIXME: Hack: Approximate blocks per dim
|
||||
blocksPerDim = vtkm::Id3{
|
||||
static_cast<vtkm::Id>(
|
||||
std::ceil(static_cast<float>(global_extents[0]) / static_cast<float>(dims[0]))),
|
||||
static_cast<vtkm::Id>(
|
||||
std::ceil(static_cast<float>(global_extents[1]) / static_cast<float>(dims[1]))),
|
||||
static_cast<vtkm::Id>(nDims == 3 ? std::ceil(static_cast<float>(global_extents[2]) /
|
||||
static_cast<float>(dims[2]))
|
||||
: 1)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the number of vertices, i.e., xdim * ydim * zdim
|
||||
unsigned short nDims = static_cast<unsigned short>(dims.size());
|
||||
std::size_t numVertices = static_cast<std::size_t>(
|
||||
std::accumulate(dims.begin(), dims.end(), std::size_t(1), std::multiplies<std::size_t>()));
|
||||
currTime = totalTime.GetElapsedTime();
|
||||
dataReadTime = currTime - prevTime;
|
||||
prevTime = currTime;
|
||||
|
||||
// Print the mesh metadata
|
||||
if (rank == 0)
|
||||
@ -331,50 +559,106 @@ int main(int argc, char* argv[])
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
|
||||
std::endl
|
||||
<< " ---------------- Input Mesh Properties --------------" << std::endl
|
||||
<< " Number of dimensions: " << nDims << std::endl
|
||||
<< " Number of mesh vertices: " << numVertices << std::endl);
|
||||
<< " Number of dimensions: " << nDims << std::endl);
|
||||
}
|
||||
|
||||
// Check for fatal input errors
|
||||
// Check the the number of dimensiosn is either 2D or 3D
|
||||
bool invalidNumDimensions = (nDims < 2 || nDims > 3);
|
||||
// Check if marching cubes is enabled for non 3D data
|
||||
bool invalidMCOption = (useMarchingCubes && nDims != 3);
|
||||
// Log any errors if found on rank 0
|
||||
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Error,
|
||||
invalidNumDimensions && (rank == 0),
|
||||
"The input mesh is " << nDims
|
||||
<< "D. "
|
||||
"The input data must be either 2D or 3D.");
|
||||
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Error,
|
||||
invalidMCOption && (rank == 0),
|
||||
"The input mesh is "
|
||||
<< nDims << "D. "
|
||||
<< "Contour tree using marching cubes is only supported for 3D data.");
|
||||
// If we found any errors in the setttings than finalize MPI and exit the execution
|
||||
if (invalidNumDimensions || invalidMCOption)
|
||||
#else
|
||||
vtkm::cont::DataSet inDataSet;
|
||||
std::vector<ValueType> values;
|
||||
std::vector<vtkm::Id> dims;
|
||||
|
||||
if (filename.compare(filename.length() - 3, 3, "bov") == 0)
|
||||
{
|
||||
std::cout << "Reading BOV file" << std::endl;
|
||||
vtkm::io::BOVDataSetReader reader(filename);
|
||||
inDataSet = reader.ReadDataSet();
|
||||
nDims = 3;
|
||||
currTime = totalTime.GetElapsedTime();
|
||||
dataReadTime = currTime - prevTime;
|
||||
prevTime = currTime;
|
||||
// Copy the data into the values array so we can construct a multiblock dataset
|
||||
// TODO All we should need to do to implement BOV support is to copy the values
|
||||
// in the values vector and copy the dimensions in the dims vector
|
||||
vtkm::Id nRows, nCols, nSlices;
|
||||
vtkm::worklet::contourtree_augmented::GetRowsColsSlices temp;
|
||||
temp(inDataSet.GetCellSet(), nRows, nCols, nSlices);
|
||||
dims[0] = nRows;
|
||||
dims[1] = nCols;
|
||||
dims[2] = nSlices;
|
||||
auto tempField = inDataSet.GetField("values").GetData();
|
||||
values.resize(static_cast<std::size_t>(tempField.GetNumberOfValues()));
|
||||
auto tempFieldHandle = tempField.AsVirtual<ValueType>().ReadPortal();
|
||||
for (vtkm::Id i = 0; i < tempField.GetNumberOfValues(); i++)
|
||||
{
|
||||
values[static_cast<std::size_t>(i)] = static_cast<ValueType>(tempFieldHandle.Get(i));
|
||||
}
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Error,
|
||||
"BOV reader not yet support in MPI mode by this example");
|
||||
MPI_Finalize();
|
||||
return EXIT_SUCCESS;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Read data
|
||||
std::vector<ValueType> values(numVertices);
|
||||
for (std::size_t vertex = 0; vertex < numVertices; ++vertex)
|
||||
else // Read ASCII data input
|
||||
{
|
||||
inFile >> values[vertex];
|
||||
std::cout << "Reading ASCII file" << std::endl;
|
||||
std::ifstream inFile(filename);
|
||||
if (inFile.bad())
|
||||
return 0;
|
||||
|
||||
// Read the dimensions of the mesh, i.e,. number of elementes in x, y, and z
|
||||
std::string line;
|
||||
getline(inFile, line);
|
||||
std::istringstream linestream(line);
|
||||
vtkm::Id dimVertices;
|
||||
while (linestream >> dimVertices)
|
||||
{
|
||||
dims.push_back(dimVertices);
|
||||
}
|
||||
|
||||
// Compute the number of vertices, i.e., xdim * ydim * zdim
|
||||
nDims = static_cast<unsigned short>(dims.size());
|
||||
std::size_t numVertices = static_cast<std::size_t>(
|
||||
std::accumulate(dims.begin(), dims.end(), std::size_t(1), std::multiplies<std::size_t>()));
|
||||
|
||||
// Check the the number of dimensiosn is either 2D or 3D
|
||||
bool invalidNumDimensions = (nDims < 2 || nDims > 3);
|
||||
// Log any errors if found on rank 0
|
||||
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Error,
|
||||
invalidNumDimensions && (rank == 0),
|
||||
"The input mesh is " << nDims << "D. The input data must be either 2D or 3D.");
|
||||
// If we found any errors in the setttings than finalize MPI and exit the execution
|
||||
if (invalidNumDimensions)
|
||||
{
|
||||
MPI_Finalize();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Read data
|
||||
values.resize(numVertices);
|
||||
for (std::size_t vertex = 0; vertex < numVertices; ++vertex)
|
||||
{
|
||||
inFile >> values[vertex];
|
||||
}
|
||||
|
||||
// finish reading the data
|
||||
inFile.close();
|
||||
|
||||
currTime = totalTime.GetElapsedTime();
|
||||
dataReadTime = currTime - prevTime;
|
||||
prevTime = currTime;
|
||||
|
||||
} // END ASCII Read
|
||||
|
||||
// Print the mesh metadata
|
||||
if (rank == 0)
|
||||
{
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
|
||||
std::endl
|
||||
<< " ---------------- Input Mesh Properties --------------" << std::endl
|
||||
<< " Number of dimensions: " << nDims);
|
||||
}
|
||||
|
||||
// finish reading the data
|
||||
inFile.close();
|
||||
|
||||
currTime = totalTime.GetElapsedTime();
|
||||
vtkm::Float64 dataReadTime = currTime - prevTime;
|
||||
prevTime = currTime;
|
||||
|
||||
vtkm::cont::DataSetBuilderUniform dsb;
|
||||
// Create a multi-block dataset for multi-block DIY-paralle processing
|
||||
vtkm::cont::PartitionedDataSet inDataSet; // Partitioned variant of the input dataset
|
||||
vtkm::cont::PartitionedDataSet useDataSet; // Partitioned variant of the input dataset
|
||||
vtkm::Id3 blocksPerDim =
|
||||
nDims == 3 ? vtkm::Id3(1, 1, numBlocks) : vtkm::Id3(1, numBlocks, 1); // Decompose the data into
|
||||
vtkm::Id3 globalSize = nDims == 3 ? vtkm::Id3(static_cast<vtkm::Id>(dims[0]),
|
||||
@ -428,6 +712,7 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
vtkm::Id currBlockSize = (vtkm::Id)((blockEnd - blockStart) / blockSliceSize);
|
||||
|
||||
vtkm::cont::DataSetBuilderUniform dsb;
|
||||
vtkm::cont::DataSet ds;
|
||||
|
||||
// 2D data
|
||||
@ -468,31 +753,59 @@ int main(int argc, char* argv[])
|
||||
std::vector<vtkm::Float32> subValues((values.begin() + blockStart),
|
||||
(values.begin() + blockEnd));
|
||||
|
||||
//vtkm::cont::DataSetFieldAdd dsf;
|
||||
ds.AddPointField("values", subValues);
|
||||
inDataSet.AppendPartition(ds);
|
||||
useDataSet.AppendPartition(ds);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Check if marching cubes is enabled for non 3D data
|
||||
bool invalidMCOption = (useMarchingCubes && nDims != 3);
|
||||
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Error,
|
||||
invalidMCOption && (rank == 0),
|
||||
"The input mesh is "
|
||||
<< nDims << "D. "
|
||||
<< "Contour tree using marching cubes is only supported for 3D data.");
|
||||
|
||||
// If we found any errors in the setttings than finalize MPI and exit the execution
|
||||
if (invalidMCOption)
|
||||
{
|
||||
MPI_Finalize();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
currTime = totalTime.GetElapsedTime();
|
||||
vtkm::Float64 buildDatasetTime = currTime - prevTime;
|
||||
buildDatasetTime = currTime - prevTime;
|
||||
prevTime = currTime;
|
||||
|
||||
// Convert the mesh of values into contour tree, pairs of vertex ids
|
||||
vtkm::filter::ContourTreeUniformDistributed filter(useMarchingCubes);
|
||||
|
||||
filter.SetSpatialDecomposition(
|
||||
blocksPerDim, globalSize, localBlockIndices, localBlockOrigins, localBlockSizes);
|
||||
vtkm::filter::ContourTreeUniformDistributed filter(blocksPerDim,
|
||||
globalSize,
|
||||
localBlockIndices,
|
||||
localBlockOrigins,
|
||||
localBlockSizes,
|
||||
useMarchingCubes);
|
||||
filter.SetActiveField("values");
|
||||
|
||||
// Execute the contour tree analysis. NOTE: If MPI is used the result will be
|
||||
// a vtkm::cont::PartitionedDataSet instead of a vtkm::cont::DataSet
|
||||
auto result = filter.Execute(inDataSet);
|
||||
auto result = filter.Execute(useDataSet);
|
||||
|
||||
currTime = totalTime.GetElapsedTime();
|
||||
vtkm::Float64 computeContourTreeTime = currTime - prevTime;
|
||||
prevTime = currTime;
|
||||
|
||||
//std::cout << std::flush; close(out);
|
||||
//std::cerr << std::flush; close(err);
|
||||
std::cout << std::flush;
|
||||
std::cerr << std::flush;
|
||||
close(out);
|
||||
|
||||
dup2(save_out, fileno(stdout));
|
||||
dup2(save_err, fileno(stderr));
|
||||
|
||||
close(save_out);
|
||||
close(save_err);
|
||||
|
||||
// Force a simple round-robin on the ranks for the summary prints. Its not perfect for MPI but
|
||||
// it works well enough to sort the summaries from the ranks for small-scale debugging.
|
||||
if (rank > 0)
|
||||
|
@ -57,7 +57,11 @@
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/ContourTree.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/MultiBlockContourTreeHelper.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/DataSetMesh.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/BoundaryTree.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/HierarchicalContourTree.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/InteriorForest.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/SpatialDecomposition.h>
|
||||
|
||||
#include <vtkm/filter/FilterField.h>
|
||||
|
||||
@ -90,15 +94,6 @@ public:
|
||||
using SupportedTypes = vtkm::TypeListScalarAll;
|
||||
///
|
||||
/// Create the contour tree filter
|
||||
/// @param[in] useMarchingCubes Boolean indicating whether marching cubes (true) or freudenthal (false)
|
||||
/// connectivity should be used. Valid only for 3D input data. Default is false.
|
||||
VTKM_CONT
|
||||
ContourTreeUniformDistributed(bool useMarchingCubes = false);
|
||||
|
||||
///
|
||||
/// Define the spatial decomposition of the data in case we run in parallel with a multi-block dataset
|
||||
///
|
||||
/// Note: Only used when running on a multi-block dataset.
|
||||
/// @param[in] blocksPerDim Number of data blocks used in each data dimension
|
||||
/// @param[in] globalSize Global extends of the input mesh (i.e., number of mesh points in each dimension)
|
||||
/// @param[in] localBlockIndices Array with the (x,y,z) index of each local data block with
|
||||
@ -107,19 +102,42 @@ public:
|
||||
/// local data block
|
||||
/// @param[in] localBlockSizes Array with the sizes (i.e., extends in number of mesh points) of each
|
||||
/// local data block
|
||||
/// @param[in] useMarchingCubes Boolean indicating whether marching cubes (true) or freudenthal (false)
|
||||
/// connectivity should be used. Valid only for 3D input data. Default is false.
|
||||
VTKM_CONT
|
||||
void SetSpatialDecomposition(vtkm::Id3 blocksPerDim,
|
||||
vtkm::Id3 globalSize,
|
||||
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockIndices,
|
||||
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockOrigins,
|
||||
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockSizes);
|
||||
ContourTreeUniformDistributed(
|
||||
vtkm::Id3 blocksPerDim, // TODO/FIXME: Possibly pass SpatialDecomposition object instead
|
||||
vtkm::Id3 globalSize,
|
||||
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockIndices,
|
||||
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockOrigins,
|
||||
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockSizes,
|
||||
bool useMarchingCubes = false);
|
||||
|
||||
template <typename DerivedPolicy>
|
||||
VTKM_CONT vtkm::cont::PartitionedDataSet PrepareForExecution(
|
||||
const vtkm::cont::PartitionedDataSet& input,
|
||||
const vtkm::filter::PolicyBase<DerivedPolicy>& policy);
|
||||
|
||||
/// Output field "saddlePeak" wich is pairs of vertex ids indicating saddle and peak of contour
|
||||
template <typename T, typename StorageType, typename DerivedPolicy>
|
||||
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& input,
|
||||
const vtkm::cont::ArrayHandle<T, StorageType>& field,
|
||||
const vtkm::filter::FieldMetadata& fieldMeta,
|
||||
vtkm::filter::PolicyBase<DerivedPolicy> policy);
|
||||
VTKM_CONT void ComputeLocalTree(const vtkm::Id blockIndex,
|
||||
const vtkm::cont::DataSet& input,
|
||||
const vtkm::cont::ArrayHandle<T, StorageType>& field,
|
||||
const vtkm::filter::FieldMetadata& fieldMeta,
|
||||
vtkm::filter::PolicyBase<DerivedPolicy> policy);
|
||||
|
||||
/// Implement per block contour tree computation after the MeshType has been discovered
|
||||
template <typename T,
|
||||
typename StorageType,
|
||||
typename DerivedPolicy,
|
||||
typename MeshType,
|
||||
typename MeshBoundaryExecType>
|
||||
VTKM_CONT void ComputeLocalTreeImpl(const vtkm::Id blockIndex,
|
||||
const vtkm::cont::DataSet& input,
|
||||
const vtkm::cont::ArrayHandle<T, StorageType>& field,
|
||||
const vtkm::filter::FieldMetadata& fieldMeta,
|
||||
vtkm::filter::PolicyBase<DerivedPolicy> policy,
|
||||
MeshType& mesh,
|
||||
MeshBoundaryExecType& meshBoundaryExecObject);
|
||||
|
||||
//@{
|
||||
/// when operating on vtkm::cont::MultiBlock we want to
|
||||
@ -153,16 +171,24 @@ private:
|
||||
/// Use marching cubes connectivity for computing the contour tree
|
||||
bool UseMarchingCubes;
|
||||
|
||||
/// The contour tree computed by the filter
|
||||
vtkm::worklet::contourtree_augmented::ContourTree ContourTreeData;
|
||||
/// Information about the spatial decomposition
|
||||
vtkm::worklet::contourtree_distributed::SpatialDecomposition MultiBlockSpatialDecomposition;
|
||||
|
||||
/// Intermediate results (one per local data block)...
|
||||
/// ... local mesh information needed at end of fan out
|
||||
std::vector<vtkm::worklet::contourtree_augmented::DataSetMesh> LocalMeshes;
|
||||
/// ... local contour trees etc. computed during fan in and used during fan out
|
||||
std::vector<vtkm::worklet::contourtree_augmented::ContourTree> LocalContourTrees;
|
||||
std::vector<vtkm::worklet::contourtree_distributed::BoundaryTree> LocalBoundaryTrees;
|
||||
std::vector<vtkm::worklet::contourtree_distributed::InteriorForest> LocalInteriorForests;
|
||||
|
||||
/// The hierarchical trees computed by the filter (array with one entry per block)
|
||||
// TODO/FIXME: We need to find a way to store the final hieararchical trees somewhere.
|
||||
// Currently we cannot do this here as it is a template on FieldType
|
||||
//
|
||||
//std::vector<vtkm::worklet::contourtree_distributed::HierarchicalContourTree> HierarchicalContourTrees;
|
||||
/// Number of iterations used to compute the contour tree
|
||||
vtkm::Id NumIterations;
|
||||
/// Array with the sorted order of the mesh vertices
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType MeshSortOrder;
|
||||
|
||||
/// Helper object to help with the parallel merge when running with DIY in parallel with MulitBlock data
|
||||
std::unique_ptr<vtkm::worklet::contourtree_distributed::MultiBlockContourTreeHelper>
|
||||
MultiBlockTreeHelper;
|
||||
};
|
||||
|
||||
} // namespace filter
|
||||
|
@ -59,14 +59,20 @@
|
||||
// single-node augmented contour tree includes
|
||||
#include <vtkm/filter/ContourTreeUniformDistributed.h>
|
||||
#include <vtkm/worklet/ContourTreeUniformAugmented.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/DataSetMesh.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/meshtypes/ContourTreeMesh.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/meshtypes/mesh_boundary/MeshBoundaryContourTreeMesh.h>
|
||||
|
||||
// distributed contour tree includes
|
||||
#include <vtkm/worklet/contourtree_distributed/BoundaryRestrictedAugmentedContourTree.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/BoundaryRestrictedAugmentedContourTreeMaker.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/ContourTreeBlockData.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/MergeBlockFunctor.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/BoundaryTree.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/BoundaryTreeMaker.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/ComputeDistributedContourTreeFunctor.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/DistributedContourTreeBlockData.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/HierarchicalContourTree.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/InteriorForest.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/PrintGraph.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/SpatialDecomposition.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/TreeGrafter.h>
|
||||
|
||||
// DIY includes
|
||||
// clang-format off
|
||||
@ -82,6 +88,20 @@ namespace filter
|
||||
{
|
||||
namespace contourtree_distributed_detail
|
||||
{
|
||||
struct ComputeLocalTree
|
||||
{
|
||||
template <typename T, typename Storage, typename DerivedPolicy>
|
||||
void operator()(const vtkm::cont::ArrayHandle<T, Storage>& field,
|
||||
ContourTreeUniformDistributed* self,
|
||||
const vtkm::Id blockIndex,
|
||||
const vtkm::cont::DataSet& inputData,
|
||||
const vtkm::filter::FieldMetadata& fieldMeta,
|
||||
vtkm::filter::PolicyBase<DerivedPolicy> policy)
|
||||
{
|
||||
self->ComputeLocalTree(blockIndex, inputData, field, fieldMeta, policy);
|
||||
}
|
||||
};
|
||||
|
||||
//----Helper struct to call DoPostExecute. This is used to be able to
|
||||
// wrap the PostExecute work in a functor so that we can use VTK-M's
|
||||
// vtkm::cont::CastAndCall to infer the FieldType template parameters
|
||||
@ -104,42 +124,71 @@ struct PostExecuteCaller
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
ContourTreeUniformDistributed::ContourTreeUniformDistributed(bool useMarchingCubes)
|
||||
: vtkm::filter::FilterField<ContourTreeUniformDistributed>()
|
||||
, UseMarchingCubes(useMarchingCubes)
|
||||
, MultiBlockTreeHelper(nullptr)
|
||||
{
|
||||
this->SetOutputFieldName("resultData");
|
||||
}
|
||||
|
||||
void ContourTreeUniformDistributed::SetSpatialDecomposition(
|
||||
ContourTreeUniformDistributed::ContourTreeUniformDistributed(
|
||||
vtkm::Id3 blocksPerDim,
|
||||
vtkm::Id3 globalSize,
|
||||
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockIndices,
|
||||
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockOrigins,
|
||||
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockSizes)
|
||||
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockSizes,
|
||||
bool useMarchingCubes)
|
||||
: vtkm::filter::FilterField<ContourTreeUniformDistributed>()
|
||||
, UseMarchingCubes(useMarchingCubes)
|
||||
, MultiBlockSpatialDecomposition(blocksPerDim,
|
||||
globalSize,
|
||||
localBlockIndices,
|
||||
localBlockOrigins,
|
||||
localBlockSizes)
|
||||
, LocalMeshes(static_cast<std::size_t>(localBlockSizes.GetNumberOfValues()))
|
||||
, LocalContourTrees(static_cast<std::size_t>(localBlockSizes.GetNumberOfValues()))
|
||||
, LocalBoundaryTrees(static_cast<std::size_t>(localBlockSizes.GetNumberOfValues()))
|
||||
, LocalInteriorForests(static_cast<std::size_t>(localBlockSizes.GetNumberOfValues()))
|
||||
{
|
||||
if (this->MultiBlockTreeHelper)
|
||||
this->SetOutputFieldName("resultData");
|
||||
}
|
||||
|
||||
template <typename DerivedPolicy>
|
||||
vtkm::cont::PartitionedDataSet ContourTreeUniformDistributed::PrepareForExecution(
|
||||
const vtkm::cont::PartitionedDataSet& input,
|
||||
const vtkm::filter::PolicyBase<DerivedPolicy>& policy)
|
||||
{
|
||||
// Time execution
|
||||
vtkm::cont::Timer timer;
|
||||
timer.Start();
|
||||
|
||||
for (vtkm::Id blockNo = 0; blockNo < input.GetNumberOfPartitions(); ++blockNo)
|
||||
{
|
||||
this->MultiBlockTreeHelper.reset();
|
||||
auto dataset = input.GetPartition(blockNo);
|
||||
auto field = dataset.GetField(this->GetActiveFieldName(), this->GetActiveFieldAssociation());
|
||||
vtkm::filter::FieldMetadata metaData(field);
|
||||
|
||||
vtkm::filter::FilterTraits<ContourTreeUniformDistributed> traits;
|
||||
vtkm::cont::CastAndCall(vtkm::filter::ApplyPolicyFieldActive(field, policy, traits),
|
||||
vtkm::filter::contourtree_distributed_detail::ComputeLocalTree{},
|
||||
this,
|
||||
blockNo,
|
||||
dataset,
|
||||
metaData,
|
||||
policy);
|
||||
}
|
||||
this->MultiBlockTreeHelper =
|
||||
std::unique_ptr<vtkm::worklet::contourtree_distributed::MultiBlockContourTreeHelper>(
|
||||
new vtkm::worklet::contourtree_distributed::MultiBlockContourTreeHelper(
|
||||
blocksPerDim, globalSize, localBlockIndices, localBlockOrigins, localBlockSizes));
|
||||
|
||||
// Print timing statistics
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Perf,
|
||||
std::endl
|
||||
<< " " << std::setw(38) << std::left << "Contour Tree Filter PrepareForExecution"
|
||||
<< ": " << timer.GetElapsedTime() << " seconds");
|
||||
|
||||
return input; // TODO/FIXME: What to return?
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T, typename StorageType, typename DerivedPolicy>
|
||||
vtkm::cont::DataSet ContourTreeUniformDistributed::DoExecute(
|
||||
void ContourTreeUniformDistributed::ComputeLocalTree(
|
||||
const vtkm::Id blockIndex,
|
||||
const vtkm::cont::DataSet& input,
|
||||
const vtkm::cont::ArrayHandle<T, StorageType>& field,
|
||||
const vtkm::filter::FieldMetadata& fieldMeta,
|
||||
vtkm::filter::PolicyBase<DerivedPolicy> policy)
|
||||
{
|
||||
vtkm::cont::Timer timer;
|
||||
timer.Start();
|
||||
|
||||
// Check that the field is Ok
|
||||
if (fieldMeta.IsPointField() == false)
|
||||
{
|
||||
@ -151,58 +200,159 @@ vtkm::cont::DataSet ContourTreeUniformDistributed::DoExecute(
|
||||
const auto& cells = input.GetCellSet();
|
||||
vtkm::filter::ApplyPolicyCellSet(cells, policy, *this)
|
||||
.CastAndCall(vtkm::worklet::contourtree_augmented::GetPointDimensions(), meshSize);
|
||||
// TODO blockIndex needs to change if we have multiple blocks per MPI rank and DoExecute is called for multiple blocks
|
||||
std::size_t blockIndex = 0;
|
||||
|
||||
// We always need to compute the fully augemented contour tree for our local data block
|
||||
unsigned int compRegularStruct = 1;
|
||||
// Create the mesh we need for the contour tree computation so that we have access to it
|
||||
// afterwards to compute the BRACT for each data block as well
|
||||
if (meshSize[2] == 1) // 2D mesh
|
||||
{
|
||||
vtkm::worklet::contourtree_augmented::DataSetMeshTriangulation2DFreudenthal mesh(
|
||||
vtkm::Id2{ meshSize[0], meshSize[1] });
|
||||
this->LocalMeshes[static_cast<std::size_t>(blockIndex)] = mesh;
|
||||
auto meshBoundaryExecObject = mesh.GetMeshBoundaryExecutionObject();
|
||||
this->ComputeLocalTreeImpl(
|
||||
blockIndex, input, field, fieldMeta, policy, mesh, meshBoundaryExecObject);
|
||||
}
|
||||
else if (this->UseMarchingCubes) // 3D marching cubes mesh
|
||||
{
|
||||
vtkm::worklet::contourtree_augmented::DataSetMeshTriangulation3DMarchingCubes mesh(meshSize);
|
||||
this->LocalMeshes[static_cast<std::size_t>(blockIndex)] = mesh;
|
||||
auto meshBoundaryExecObject = mesh.GetMeshBoundaryExecutionObject();
|
||||
this->ComputeLocalTreeImpl(
|
||||
blockIndex, input, field, fieldMeta, policy, mesh, meshBoundaryExecObject);
|
||||
}
|
||||
else // Regular 3D mesh
|
||||
{
|
||||
vtkm::worklet::contourtree_augmented::DataSetMeshTriangulation3DFreudenthal mesh(meshSize);
|
||||
this->LocalMeshes[static_cast<std::size_t>(blockIndex)] = mesh;
|
||||
auto meshBoundaryExecObject = mesh.GetMeshBoundaryExecutionObject();
|
||||
this->ComputeLocalTreeImpl(
|
||||
blockIndex, input, field, fieldMeta, policy, mesh, meshBoundaryExecObject);
|
||||
}
|
||||
} // ContourTreeUniformDistributed::ComputeLocalTree
|
||||
|
||||
// Run the worklet
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T,
|
||||
typename StorageType,
|
||||
typename DerivedPolicy,
|
||||
typename MeshType,
|
||||
typename MeshBoundaryExecType>
|
||||
void ContourTreeUniformDistributed::ComputeLocalTreeImpl(
|
||||
const vtkm::Id blockIndex,
|
||||
const vtkm::cont::DataSet&, // input,
|
||||
const vtkm::cont::ArrayHandle<T, StorageType>& field,
|
||||
const vtkm::filter::FieldMetadata&, // fieldMeta,
|
||||
vtkm::filter::PolicyBase<DerivedPolicy>, // policy,
|
||||
MeshType& mesh,
|
||||
MeshBoundaryExecType& meshBoundaryExecObject)
|
||||
{
|
||||
// We always need to compute the fully augmented contour tree for our local data block
|
||||
const unsigned int compRegularStruct = 1;
|
||||
|
||||
// Set up the worklet
|
||||
vtkm::worklet::ContourTreeAugmented worklet;
|
||||
worklet.Run(field,
|
||||
MultiBlockTreeHelper ? MultiBlockTreeHelper->LocalContourTrees[blockIndex]
|
||||
: this->ContourTreeData,
|
||||
MultiBlockTreeHelper ? MultiBlockTreeHelper->LocalSortOrders[blockIndex]
|
||||
: this->MeshSortOrder,
|
||||
mesh,
|
||||
this->LocalContourTrees[static_cast<std::size_t>(blockIndex)],
|
||||
this->LocalMeshes[static_cast<std::size_t>(blockIndex)].SortOrder,
|
||||
this->NumIterations,
|
||||
meshSize,
|
||||
this->UseMarchingCubes,
|
||||
compRegularStruct);
|
||||
compRegularStruct,
|
||||
meshBoundaryExecObject);
|
||||
|
||||
// If we run in parallel but with only one global block, then we need set our outputs correctly
|
||||
// here to match the expected behavior in parallel
|
||||
if (this->MultiBlockTreeHelper)
|
||||
{
|
||||
if (this->MultiBlockTreeHelper->GetGlobalNumberOfBlocks() == 1)
|
||||
{
|
||||
// Copy the contour tree and mesh sort order to the output
|
||||
this->ContourTreeData = this->MultiBlockTreeHelper->LocalContourTrees[0];
|
||||
this->MeshSortOrder = this->MultiBlockTreeHelper->LocalSortOrders[0];
|
||||
// In parallel we need the sorted values as output resulti
|
||||
// Construct the sorted values by permutting the input field
|
||||
auto fieldPermutted = vtkm::cont::make_ArrayHandlePermutation(this->MeshSortOrder, field);
|
||||
vtkm::cont::ArrayHandle<T> sortedValues;
|
||||
vtkm::cont::Algorithm::Copy(fieldPermutted, sortedValues);
|
||||
// Create the result object
|
||||
vtkm::cont::DataSet result;
|
||||
vtkm::cont::Field rfield(
|
||||
this->GetOutputFieldName(), vtkm::cont::Field::Association::WHOLE_MESH, sortedValues);
|
||||
result.AddField(rfield);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// Now we compute the BRACT for our data block. We do this here because we know the MeshType
|
||||
// here and we don't need to store the mesh separately any more since it is stored in the BRACT
|
||||
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Perf,
|
||||
std::endl
|
||||
<< " " << std::setw(38) << std::left << "Contour Tree Filter DoExecute"
|
||||
<< ": " << timer.GetElapsedTime() << " seconds");
|
||||
// Get the mesh information needed to create an IdRelabeler to relable local to global ids
|
||||
// Create an IdRelabeler since we are using a DataSetMesh type here, we don't need
|
||||
// the IdRelabeler for the BRACT construction when we are using a ContourTreeMesh.
|
||||
auto localToGlobalIdRelabeler = vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler(
|
||||
this->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal().Get(blockIndex),
|
||||
this->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal().Get(blockIndex),
|
||||
this->MultiBlockSpatialDecomposition.GlobalSize);
|
||||
// Initialize the BoundaryTreeMaker
|
||||
auto boundaryTreeMaker =
|
||||
vtkm::worklet::contourtree_distributed::BoundaryTreeMaker<MeshType, MeshBoundaryExecType>(
|
||||
&mesh, // The input mesh
|
||||
meshBoundaryExecObject, // The mesh boundary
|
||||
this->LocalContourTrees[static_cast<std::size_t>(blockIndex)], // The contour tree
|
||||
&this->LocalBoundaryTrees[static_cast<std::size_t>(
|
||||
blockIndex)], // The boundary tree (a.k.a BRACT) to be computed
|
||||
&this->LocalInteriorForests[static_cast<std::size_t>(
|
||||
blockIndex)] // The interior forest (a.k.a. Residue) to be computed
|
||||
);
|
||||
// Execute the BRACT construction, including the compute of the InteriorForest
|
||||
boundaryTreeMaker.Construct(&localToGlobalIdRelabeler);
|
||||
|
||||
// Construct the expected result for serial execution. Note, in serial the result currently
|
||||
// not actually being used, but in parallel we need the sorted mesh values as output
|
||||
// This part is being hit when we run in serial or parallel with more then one rank
|
||||
return CreateResultFieldPoint(input, ContourTreeData.Arcs, this->GetOutputFieldName());
|
||||
} // ContourTreeUniformDistributed::DoExecute
|
||||
|
||||
// Print BRACT for debug
|
||||
vtkm::Id rank = vtkm::cont::EnvironmentTracker::GetCommunicator().rank();
|
||||
char buffer[256];
|
||||
std::snprintf(buffer,
|
||||
sizeof(buffer),
|
||||
"Rank_%d_Block_%d_Initial_BRACT.gv",
|
||||
static_cast<int>(rank),
|
||||
static_cast<int>(blockIndex));
|
||||
std::ofstream os(buffer);
|
||||
os << this->LocalBoundaryTrees[static_cast<std::size_t>(blockIndex)].PrintGlobalDot(
|
||||
"Before Fan In",
|
||||
mesh,
|
||||
field,
|
||||
this->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal().Get(blockIndex),
|
||||
this->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal().Get(blockIndex),
|
||||
this->MultiBlockSpatialDecomposition.GlobalSize)
|
||||
<< std::endl;
|
||||
|
||||
// TODO: Fix calling conventions so dot print works here
|
||||
// At this point, I'm reasonably certain that the contour tree has been computed regardless of data push/pull
|
||||
// So although it might be logical to print things out earlier, I'll do it here
|
||||
// save the regular structure
|
||||
// TODO: Oliver Fix and renable the following print calls
|
||||
/*
|
||||
std::string regularStructureFileName = std::string("Rank_") + std::to_string(static_cast<int>(rank)) + std::string("_Block_") + std::to_string(static_cast<int>(blockIndex)) + std::string("_Initial_Step_0_Contour_Tree_Regular_Structure.gv");
|
||||
std::ofstream regularStructureFile(regularStructureFileName);
|
||||
regularStructureFile << worklet::contourtree_distributed::ContourTreeDotGraphPrint<T, MeshType, vtkm::worklet::contourtree_augmented::IdArrayType>
|
||||
( std::string("Block ") + std::to_string(static_cast<std::size_t>(blockIndex)) + " Initial Step 0 Contour Tree Regular Structure",
|
||||
this->LocalMeshes[static_cast<std::size_t>(blockIndex)],
|
||||
this->LocalContourTrees[static_cast<std::size_t>(blockIndex)],
|
||||
worklet::contourtree_distributed::SHOW_REGULAR_STRUCTURE|worklet::contourtree_distributed::SHOW_ALL_IDS);
|
||||
*/
|
||||
/*
|
||||
std::string superStructureFileName = std::string("Rank_") + std::to_string(static_cast<int>(rank)) + std::string("_Block_") + std::to_string(static_cast<int>(blockIndex)) + std::string("_Initial_Step_1_Contour_Tree_Super_Structure.gv");
|
||||
std::ofstream superStructureFile(superStructureFileName);
|
||||
vtkm::Id ctPrintSettings = worklet::contourtree_distributed::SHOW_SUPER_STRUCTURE|worklet::contourtree_distributed::SHOW_HYPER_STRUCTURE|worklet::contourtree_distributed::SHOW_ALL_IDS|worklet::contourtree_distributed::SHOW_ALL_SUPERIDS|worklet::contourtree_distributed::SHOW_ALL_HYPERIDS;
|
||||
std::string ctPrintLabel = std::string("Block ") + std::to_string(static_cast<size_t>(blockIndex)) + " Initial Step 1 Contour Tree Super Structure";
|
||||
superStructureFile << vtkm::worklet::contourtree_distributed::ContourTreeDotGraphPrint<T, StorageType, MeshType, vtkm::worklet::contourtree_augmented::IdArrayType>
|
||||
( ctPrintLabel,
|
||||
dynamic_cast<MeshType&>(this->LocalMeshes[static_cast<std::size_t>(blockIndex)]),
|
||||
&localToGlobalIdRelabeler,
|
||||
field,
|
||||
this->LocalContourTrees[static_cast<std::size_t>(blockIndex)],
|
||||
ctPrintSettings);
|
||||
|
||||
// save the Boundary Tree as a dot file
|
||||
std::string boundaryTreeFileName = std::string("Rank_") + std::to_string(static_cast<int>(rank)) + std::string("_Block_") + std::to_string(static_cast<size_t>(blockIndex)) + std::string("_Initial_Step_3_Boundary_Tree.gv");
|
||||
std::ofstream boundaryTreeFile(boundaryTreeFileName);
|
||||
boundaryTreeFile << vtkm::worklet::contourtree_distributed::BoundaryTreeDotGraphPrint
|
||||
( std::string("Block ") + std::to_string(static_cast<size_t>(blockIndex)) + std::string(" Initial Step 3 Boundary Tree"),
|
||||
dynamic_cast<MeshType&>(this->LocalMeshes[static_cast<std::size_t>(blockIndex)]),
|
||||
meshBoundaryExecObject,
|
||||
this->LocalBoundaryTrees[static_cast<std::size_t>(blockIndex)],
|
||||
&localToGlobalIdRelabeler,
|
||||
field);
|
||||
|
||||
// and save the Interior Forest as another dot file
|
||||
std::string interiorForestFileName = std::string("Rank_") + std::to_string(static_cast<int>(rank)) + std::string("_Block_") + std::to_string(static_cast<int>(blockIndex)) + std::string("_Initial_Step_4_Interior_Forest.gv");
|
||||
std::ofstream interiorForestFile(interiorForestFileName);
|
||||
interiorForestFile << worklet::contourtree_distributed::InteriorForestDotGraphPrint
|
||||
( std::string("Block ") + std::to_string(rank) + " Initial Step 4 Interior Forest",
|
||||
this->LocalInteriorForests[static_cast<std::size_t>(blockIndex)],
|
||||
this->LocalContourTrees[static_cast<std::size_t>(blockIndex)],
|
||||
this->LocalBoundaryTrees[static_cast<std::size_t>(blockIndex)],
|
||||
dynamic_cast<MeshType&>(this->LocalMeshes[static_cast<std::size_t>(blockIndex)]),
|
||||
meshBoundaryExecObject,
|
||||
&localToGlobalIdRelabeler,
|
||||
field);
|
||||
*/
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename DerivedPolicy>
|
||||
@ -210,93 +360,109 @@ inline VTKM_CONT void ContourTreeUniformDistributed::PreExecute(
|
||||
const vtkm::cont::PartitionedDataSet& input,
|
||||
const vtkm::filter::PolicyBase<DerivedPolicy>&)
|
||||
{
|
||||
if (this->MultiBlockTreeHelper)
|
||||
if (vtkm::worklet::contourtree_distributed::SpatialDecomposition::GetGlobalNumberOfBlocks(
|
||||
input) != this->MultiBlockSpatialDecomposition.GetGlobalNumberOfBlocks())
|
||||
{
|
||||
if (this->MultiBlockTreeHelper->GetGlobalNumberOfBlocks(input) !=
|
||||
this->MultiBlockTreeHelper->GetGlobalNumberOfBlocks())
|
||||
{
|
||||
throw vtkm::cont::ErrorFilterExecution(
|
||||
"Global number of block in MultiBlock dataset does not match the SpatialDecomposition");
|
||||
}
|
||||
if (this->MultiBlockTreeHelper->GetLocalNumberOfBlocks() != input.GetNumberOfPartitions())
|
||||
{
|
||||
throw vtkm::cont::ErrorFilterExecution(
|
||||
"Global number of block in MultiBlock dataset does not match the SpatialDecomposition");
|
||||
}
|
||||
throw vtkm::cont::ErrorFilterExecution(
|
||||
"Global number of blocks in MultiBlock dataset does not match the SpatialDecomposition");
|
||||
}
|
||||
if (this->MultiBlockSpatialDecomposition.GetLocalNumberOfBlocks() !=
|
||||
input.GetNumberOfPartitions())
|
||||
{
|
||||
throw vtkm::cont::ErrorFilterExecution(
|
||||
"Local number of blocks in MultiBlock dataset does not match the SpatialDecomposition");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T, typename StorageType, typename DerivedPolicy>
|
||||
template <typename FieldType, typename StorageType, typename DerivedPolicy>
|
||||
VTKM_CONT void ContourTreeUniformDistributed::DoPostExecute(
|
||||
const vtkm::cont::PartitionedDataSet& input,
|
||||
vtkm::cont::PartitionedDataSet& output,
|
||||
const vtkm::filter::FieldMetadata& fieldMeta,
|
||||
const vtkm::cont::ArrayHandle<T, StorageType>&, // dummy parameter to get the type
|
||||
vtkm::filter::PolicyBase<DerivedPolicy> policy)
|
||||
vtkm::cont::PartitionedDataSet&, // temporarily commented out: output,
|
||||
const vtkm::filter::FieldMetadata&, // dummy parameter for field meta data
|
||||
const vtkm::cont::ArrayHandle<FieldType, StorageType>&, // dummy parameter to get the type
|
||||
vtkm::filter::PolicyBase<DerivedPolicy>) // dummy parameter for policy
|
||||
{
|
||||
(void)fieldMeta; // avoid unused parameter warning
|
||||
(void)policy; // avoid unused parameter warning
|
||||
|
||||
auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator();
|
||||
vtkm::Id size = comm.size();
|
||||
vtkm::Id rank = comm.rank();
|
||||
|
||||
std::vector<vtkm::worklet::contourtree_augmented::ContourTreeMesh<T>*> localContourTreeMeshes;
|
||||
localContourTreeMeshes.resize(static_cast<std::size_t>(input.GetNumberOfPartitions()));
|
||||
// TODO need to allocate and free these ourselves. May need to update detail::MultiBlockContourTreeHelper::ComputeLocalContourTreeMesh
|
||||
std::vector<vtkm::worklet::contourtree_distributed::ContourTreeBlockData<T>*> localDataBlocks;
|
||||
localDataBlocks.resize(static_cast<size_t>(input.GetNumberOfPartitions()));
|
||||
std::vector<vtkmdiy::Link*> localLinks; // dummy links needed to make DIY happy
|
||||
localLinks.resize(static_cast<size_t>(input.GetNumberOfPartitions()));
|
||||
// TODO Check setting. In parallel we should need to augment the tree in order to be able to do the merging
|
||||
unsigned int compRegularStruct = 1;
|
||||
std::vector<vtkm::worklet::contourtree_distributed::DistributedContourTreeBlockData<FieldType>*>
|
||||
localDataBlocks(static_cast<size_t>(input.GetNumberOfPartitions()), nullptr);
|
||||
for (std::size_t bi = 0; bi < static_cast<std::size_t>(input.GetNumberOfPartitions()); bi++)
|
||||
{
|
||||
// create the local contour tree mesh
|
||||
localLinks[bi] = new vtkmdiy::Link;
|
||||
// Create the local data block structure and set extents
|
||||
localDataBlocks[bi] =
|
||||
new vtkm::worklet::contourtree_distributed::DistributedContourTreeBlockData<FieldType>();
|
||||
localDataBlocks[bi]->BlockIndex = static_cast<vtkm::Id>(bi);
|
||||
localDataBlocks[bi]->BlockOrigin =
|
||||
this->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal().Get(
|
||||
static_cast<vtkm::Id>(bi));
|
||||
localDataBlocks[bi]->BlockSize =
|
||||
this->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal().Get(
|
||||
static_cast<vtkm::Id>(bi));
|
||||
|
||||
// Save local tree information for fan out FIXME: Try to avoid copy
|
||||
localDataBlocks[bi]->ContourTrees.push_back(this->LocalContourTrees[bi]);
|
||||
localDataBlocks[bi]->InteriorForests.push_back(this->LocalInteriorForests[bi]);
|
||||
|
||||
// ... Compute arrays needed for constructing contour tree mesh
|
||||
const auto sortOrder = this->LocalMeshes[bi].SortOrder;
|
||||
// ... Compute the global mesh index for the partially augmented contour tree. I.e., here we
|
||||
// don't need the global mesh index for all nodes, but only for the augmented nodes from the
|
||||
// tree. We, hence, permute the sortOrder by contourTree.augmentednodes and then compute the
|
||||
// GlobalMeshIndex by tranforming those indices with our IdRelabler
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType localGlobalMeshIndex;
|
||||
vtkm::cont::ArrayHandlePermutation<vtkm::worklet::contourtree_augmented::IdArrayType,
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType>
|
||||
permutedSortOrder(this->LocalBoundaryTrees[bi].VertexIndex, sortOrder);
|
||||
auto transformedIndex = vtkm::cont::make_ArrayHandleTransform(
|
||||
permutedSortOrder,
|
||||
vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler(
|
||||
this->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal().Get(
|
||||
static_cast<vtkm::Id>(bi)),
|
||||
this->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal().Get(
|
||||
static_cast<vtkm::Id>(bi)),
|
||||
this->MultiBlockSpatialDecomposition.GlobalSize));
|
||||
vtkm::cont::Algorithm::Copy(transformedIndex, localGlobalMeshIndex);
|
||||
|
||||
// ... get data values
|
||||
auto currBlock = input.GetPartition(static_cast<vtkm::Id>(bi));
|
||||
auto currField =
|
||||
currBlock.GetField(this->GetActiveFieldName(), this->GetActiveFieldAssociation());
|
||||
//const vtkm::cont::ArrayHandle<T,StorageType> &fieldData = currField.GetData().Cast<vtkm::cont::ArrayHandle<T,StorageType> >();
|
||||
vtkm::cont::ArrayHandle<T> fieldData;
|
||||
vtkm::cont::ArrayCopy(currField.GetData().AsVirtual<T>(), fieldData);
|
||||
auto currContourTreeMesh = vtkm::worklet::contourtree_distributed::MultiBlockContourTreeHelper::
|
||||
ComputeLocalContourTreeMesh<T>(
|
||||
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal()
|
||||
.Get(static_cast<vtkm::Id>(bi)),
|
||||
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal().Get(
|
||||
static_cast<vtkm::Id>(bi)),
|
||||
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.GlobalSize,
|
||||
fieldData,
|
||||
MultiBlockTreeHelper->LocalContourTrees[bi],
|
||||
MultiBlockTreeHelper->LocalSortOrders[bi],
|
||||
compRegularStruct);
|
||||
localContourTreeMeshes[bi] = currContourTreeMesh;
|
||||
// create the local data block structure
|
||||
localDataBlocks[bi] = new vtkm::worklet::contourtree_distributed::ContourTreeBlockData<T>();
|
||||
localDataBlocks[bi]->NumVertices = currContourTreeMesh->NumVertices;
|
||||
// FIXME: Commented out to avoid compile error, full fix to follow in subsequent merge request
|
||||
// localDataBlocks[bi]->SortOrder = currContourTreeMesh->SortOrder;
|
||||
localDataBlocks[bi]->SortedValue = currContourTreeMesh->SortedValues;
|
||||
localDataBlocks[bi]->GlobalMeshIndex = currContourTreeMesh->GlobalMeshIndex;
|
||||
localDataBlocks[bi]->Neighbours = currContourTreeMesh->Neighbours;
|
||||
localDataBlocks[bi]->FirstNeighbour = currContourTreeMesh->FirstNeighbour;
|
||||
localDataBlocks[bi]->MaxNeighbours = currContourTreeMesh->MaxNeighbours;
|
||||
localDataBlocks[bi]->BlockOrigin =
|
||||
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal().Get(
|
||||
static_cast<vtkm::Id>(bi));
|
||||
localDataBlocks[bi]->BlockSize =
|
||||
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal().Get(
|
||||
static_cast<vtkm::Id>(bi));
|
||||
localDataBlocks[bi]->GlobalSize =
|
||||
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.GlobalSize;
|
||||
// We need to augment at least with the boundary vertices when running in parallel
|
||||
localDataBlocks[bi]->ComputeRegularStructure = compRegularStruct;
|
||||
}
|
||||
// Setup vtkmdiy to do global binary reduction of neighbouring blocks. See also RecuctionOperation struct for example
|
||||
vtkm::cont::ArrayHandle<FieldType> fieldData;
|
||||
vtkm::cont::ArrayCopy(currField.GetData().template AsVirtual<FieldType>(), fieldData);
|
||||
|
||||
// ... compute and store the actual mesh
|
||||
localDataBlocks[bi]->ContourTreeMeshes.emplace_back(this->LocalBoundaryTrees[bi].VertexIndex,
|
||||
this->LocalBoundaryTrees[bi].Superarcs,
|
||||
sortOrder,
|
||||
fieldData,
|
||||
localGlobalMeshIndex);
|
||||
|
||||
// ... save for debugging in text and .gv/.dot format
|
||||
char buffer[256];
|
||||
std::snprintf(buffer,
|
||||
sizeof(buffer),
|
||||
"Rank_%d_Block_%d_Initial_Step_3_BRACT_Mesh.txt",
|
||||
static_cast<int>(rank),
|
||||
static_cast<int>(bi));
|
||||
localDataBlocks[bi]->ContourTreeMeshes.back().Save(buffer);
|
||||
|
||||
// save the corresponding .gv file
|
||||
std::string boundaryTreeMeshFileName = std::string("Rank_") +
|
||||
std::to_string(static_cast<int>(rank)) + std::string("_Block_") +
|
||||
std::to_string(static_cast<int>(bi)) + std::string("_Initial_Step_5_BRACT_Mesh.gv");
|
||||
std::ofstream boundaryTreeMeshFile(boundaryTreeMeshFileName);
|
||||
boundaryTreeMeshFile
|
||||
<< vtkm::worklet::contourtree_distributed::ContourTreeMeshDotGraphPrint<FieldType>(
|
||||
std::string("Block ") + std::to_string(static_cast<int>(rank)) +
|
||||
std::string(" Initial Step 5 BRACT Mesh"),
|
||||
localDataBlocks[bi]->ContourTreeMeshes.back(),
|
||||
worklet::contourtree_distributed::SHOW_CONTOUR_TREE_MESH_ALL);
|
||||
}
|
||||
|
||||
// Setup vtkmdiy to do global binary reduction of neighbouring blocks. See also RecuctionOperation struct for example
|
||||
// Create the vtkmdiy master
|
||||
vtkmdiy::Master master(comm,
|
||||
1, // Use 1 thread, VTK-M will do the treading
|
||||
@ -305,7 +471,7 @@ VTKM_CONT void ContourTreeUniformDistributed::DoPostExecute(
|
||||
|
||||
// Compute the gids for our local blocks
|
||||
const vtkm::worklet::contourtree_distributed::SpatialDecomposition& spatialDecomp =
|
||||
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition;
|
||||
this->MultiBlockSpatialDecomposition;
|
||||
auto localBlockIndicesPortal = spatialDecomp.LocalBlockIndices.ReadPortal();
|
||||
std::vector<vtkm::Id> vtkmdiyLocalBlockGids(static_cast<size_t>(input.GetNumberOfPartitions()));
|
||||
for (vtkm::Id bi = 0; bi < input.GetNumberOfPartitions(); bi++)
|
||||
@ -325,9 +491,12 @@ VTKM_CONT void ContourTreeUniformDistributed::DoPostExecute(
|
||||
vtkmdiy::RegularDecomposer<vtkmdiy::DiscreteBounds>::coords_to_gid(tempCoords, tempDivisions);
|
||||
}
|
||||
|
||||
std::vector<vtkmdiy::Link*> localLinks(static_cast<std::vector<vtkmdiy::Link>::size_type>(
|
||||
input.GetNumberOfPartitions())); // dummy links needed to make DIY happy
|
||||
// Add my local blocks to the vtkmdiy master.
|
||||
for (std::size_t bi = 0; bi < static_cast<std::size_t>(input.GetNumberOfPartitions()); bi++)
|
||||
{
|
||||
localLinks[bi] = new vtkmdiy::Link;
|
||||
master.add(static_cast<int>(vtkmdiyLocalBlockGids[bi]), // block id
|
||||
localDataBlocks[bi],
|
||||
localLinks[bi]);
|
||||
@ -348,87 +517,168 @@ VTKM_CONT void ContourTreeUniformDistributed::DoPostExecute(
|
||||
static_cast<int>(vtkmdiyLocalBlockGids[static_cast<size_t>(bi)]));
|
||||
}
|
||||
|
||||
// Fix the vtkmdiy links. TODO Remove changes to the vtkmdiy in VTKM when we update to the new VTK-M
|
||||
// Fix the vtkmdiy links.
|
||||
vtkmdiy::fix_links(master, assigner);
|
||||
|
||||
// partners for merge over regular block grid
|
||||
vtkmdiy::RegularMergePartners partners(
|
||||
vtkmdiy::RegularSwapPartners partners(
|
||||
decomposer, // domain decomposition
|
||||
2, // raix of k-ary reduction. TODO check this value
|
||||
true // contiguous: true=distance doubling , false=distnace halving TODO check this value
|
||||
);
|
||||
// reduction
|
||||
vtkmdiy::reduce(
|
||||
master, assigner, partners, &vtkm::worklet::contourtree_distributed::MergeBlockFunctor<T>);
|
||||
const vtkm::worklet::contourtree_distributed::ComputeDistributedContourTreeFunctor<FieldType>
|
||||
computeDistributedContourTreeFunctor{ this->MultiBlockSpatialDecomposition.GlobalSize };
|
||||
vtkmdiy::reduce(master, assigner, partners, computeDistributedContourTreeFunctor);
|
||||
|
||||
comm.barrier(); // Be safe!
|
||||
|
||||
if (rank == 0)
|
||||
{
|
||||
// Now run the contour tree algorithm on the last block to compute the final tree
|
||||
vtkm::Id currNumIterations;
|
||||
vtkm::worklet::contourtree_augmented::ContourTree currContourTree;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType currSortOrder;
|
||||
vtkm::worklet::ContourTreeAugmented worklet;
|
||||
vtkm::cont::ArrayHandle<T> currField;
|
||||
// Construct the contour tree mesh from the last block
|
||||
vtkm::worklet::contourtree_augmented::ContourTreeMesh<T> contourTreeMeshOut;
|
||||
contourTreeMeshOut.NumVertices = localDataBlocks[0]->NumVertices;
|
||||
// FIXME: Commented out to avoid compile error, full fix to follow in subsequent merge request
|
||||
// contourTreeMeshOut.SortOrder = localDataBlocks[0]->SortOrder;
|
||||
contourTreeMeshOut.SortedValues = localDataBlocks[0]->SortedValue;
|
||||
contourTreeMeshOut.GlobalMeshIndex = localDataBlocks[0]->GlobalMeshIndex;
|
||||
contourTreeMeshOut.Neighbours = localDataBlocks[0]->Neighbours;
|
||||
contourTreeMeshOut.FirstNeighbour = localDataBlocks[0]->FirstNeighbour;
|
||||
contourTreeMeshOut.MaxNeighbours = localDataBlocks[0]->MaxNeighbours;
|
||||
// Construct the mesh boundary exectuion object needed for boundary augmentation
|
||||
vtkm::Id3 minIdx(0, 0, 0);
|
||||
vtkm::Id3 maxIdx = this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.GlobalSize;
|
||||
maxIdx[0] = maxIdx[0] - 1;
|
||||
maxIdx[1] = maxIdx[1] - 1;
|
||||
maxIdx[2] = maxIdx[2] > 0 ? (maxIdx[2] - 1) : 0;
|
||||
auto meshBoundaryExecObj = contourTreeMeshOut.GetMeshBoundaryExecutionObject(
|
||||
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.GlobalSize, minIdx, maxIdx);
|
||||
// Run the worklet to compute the final contour tree
|
||||
worklet.Run(
|
||||
contourTreeMeshOut.SortedValues, // Unused param. Provide something to keep API happy
|
||||
contourTreeMeshOut,
|
||||
this->ContourTreeData,
|
||||
this->MeshSortOrder,
|
||||
currNumIterations,
|
||||
compRegularStruct,
|
||||
meshBoundaryExecObj);
|
||||
master.foreach ([&](vtkm::worklet::contourtree_distributed::DistributedContourTreeBlockData<
|
||||
FieldType>* b,
|
||||
const vtkmdiy::Master::ProxyWithLink&) {
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
|
||||
"Fan In Complete" << std::endl
|
||||
<< "# of CTs: " << b->ContourTrees.size() << std::endl
|
||||
<< "# of CTMs: " << b->ContourTreeMeshes.size() << std::endl
|
||||
<< "# of IFs: " << b->InteriorForests.size() << std::endl);
|
||||
|
||||
// Set the final mesh sort order we need to use
|
||||
this->MeshSortOrder = contourTreeMeshOut.GlobalMeshIndex;
|
||||
// Remeber the number of iterations for the output
|
||||
this->NumIterations = currNumIterations;
|
||||
char buffer[256];
|
||||
std::snprintf(buffer,
|
||||
sizeof(buffer),
|
||||
"AfterFanInResults_Rank%d_Block%d.txt",
|
||||
static_cast<int>(rank),
|
||||
static_cast<int>(b->BlockIndex));
|
||||
std::ofstream os(buffer);
|
||||
os << "Contour Trees" << std::endl;
|
||||
os << "=============" << std::endl;
|
||||
for (const auto& ct : b->ContourTrees)
|
||||
ct.PrintContent(os);
|
||||
os << std::endl;
|
||||
os << "Contour Tree Meshes" << std::endl;
|
||||
os << "===================" << std::endl;
|
||||
for (const auto& cm : b->ContourTreeMeshes)
|
||||
cm.PrintContent(os);
|
||||
os << std::endl;
|
||||
os << "Interior Forests" << std::endl;
|
||||
os << "===================" << std::endl;
|
||||
for (const auto& info : b->InteriorForests)
|
||||
info.PrintContent(os);
|
||||
os << std::endl;
|
||||
|
||||
// Return the sorted values of the contour tree as the result
|
||||
// TODO the result we return for the parallel and serial case are different right now. This should be made consistent. However, only in the parallel case are we useing the result output
|
||||
vtkm::cont::DataSet temp;
|
||||
vtkm::cont::Field rfield(this->GetOutputFieldName(),
|
||||
vtkm::cont::Field::Association::WHOLE_MESH,
|
||||
contourTreeMeshOut.SortedValues);
|
||||
temp.AddField(rfield);
|
||||
output = vtkm::cont::PartitionedDataSet(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->ContourTreeData = MultiBlockTreeHelper->LocalContourTrees[0];
|
||||
this->MeshSortOrder = MultiBlockTreeHelper->LocalSortOrders[0];
|
||||
// Fan out
|
||||
auto nRounds = b->ContourTrees.size() - 1;
|
||||
|
||||
// Free allocated temporary pointers
|
||||
for (std::size_t bi = 0; bi < static_cast<std::size_t>(input.GetNumberOfPartitions()); bi++)
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Fan out. nRounds=" << nRounds);
|
||||
vtkm::worklet::contourtree_distributed::HierarchicalContourTree<FieldType> hierarchicalTree;
|
||||
hierarchicalTree.Initialize(
|
||||
static_cast<vtkm::Id>(nRounds), b->ContourTrees[nRounds], b->ContourTreeMeshes[nRounds - 1]);
|
||||
|
||||
// TODO: GET THIS COMPILING
|
||||
// save the corresponding .gv file
|
||||
// std::string hierarchicalTreeFileName = std::string("Rank_") + std::to_string(static_cast<int>(rank)) + std::string("_Block_") + std::to_string(static_cast<int>(b->BlockIndex)) + "_Round_" + std::to_string(nRounds) + "_Hierarchical_Tree.gv";
|
||||
// std::ofstream hierarchicalTreeFile(hierarchicalTreeFileName);
|
||||
// hierarchicalTreeFile << vtkm::worklet::contourtree_distributed::HierarchicalContourTreeDotGraphPrint<FieldType>
|
||||
// ( std::string("Block ") + std::to_string(static_cast<int>(b->BlockIndex)) + " Round " + std::to_string(nRounds) + " Hierarchical Tree", hierarchicalTree,
|
||||
// vtkm::worklet::contourtree_distributed::SHOW_SUPER_STRUCTURE|vtkm::worklet::contourtree_distributed::SHOW_HYPER_STRUCTURE|vtkm::worklet::contourtree_distributed::SHOW_ALL_IDS|vtkm::worklet::contourtree_distributed::SHOW_ALL_SUPERIDS|vtkm::worklet::contourtree_distributed::SHOW_ALL_HYPERIDS
|
||||
// );
|
||||
|
||||
for (auto round = nRounds - 1; round > 0; round--)
|
||||
{
|
||||
delete localContourTreeMeshes[bi];
|
||||
delete localDataBlocks[bi];
|
||||
// delete localLinks[bi];
|
||||
vtkm::worklet::contourtree_distributed::
|
||||
TreeGrafter<vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>, FieldType>
|
||||
grafter(&(b->ContourTreeMeshes[round - 1]),
|
||||
b->ContourTrees[round],
|
||||
&(b->InteriorForests[round]));
|
||||
grafter.GraftInteriorForests(static_cast<vtkm::Id>(round),
|
||||
hierarchicalTree,
|
||||
b->ContourTreeMeshes[round - 1].SortedValues);
|
||||
// TODO: GET THIS COMPILING
|
||||
// save the corresponding .gv file
|
||||
// std::string hierarchicalTreeFileName = std::string("Rank_") + std::to_string(static_cast<int>(rank)) + std::string("_Block_") + std::to_string(static_cast<int>(b->BlockIndex)) + "_Round_" + std::to_string(nRounds) + "_Hierarchical_Tree.gv";
|
||||
// std::ofstream hierarchicalTreeFile(hierarchicalTreeFileName);
|
||||
// hierarchicalTreeFile << vtkm::worklet::contourtree_distributed::HierarchicalContourTreeDotGraphPrint<FieldType>
|
||||
// ( std::string("Block ") + std::to_string(static_cast<int>(b->BlockIndex)) + " Round " + std::to_string(nRounds) + " Hierarchical Tree", hierarchicalTree,
|
||||
// vtkm::worklet::contourtree_distributed::SHOW_SUPER_STRUCTURE|vtkm::worklet::contourtree_distributed::SHOW_HYPER_STRUCTURE|vtkm::worklet::contourtree_distributed::SHOW_ALL_IDS|vtkm::worklet::contourtree_distributed::SHOW_ALL_SUPERIDS|vtkm::worklet::contourtree_distributed::SHOW_ALL_HYPERIDS
|
||||
// );
|
||||
}
|
||||
}
|
||||
localContourTreeMeshes.clear();
|
||||
localDataBlocks.clear();
|
||||
localLinks.clear();
|
||||
|
||||
// bottom level
|
||||
vtkm::worklet::contourtree_distributed::
|
||||
TreeGrafter<vtkm::worklet::contourtree_augmented::DataSetMesh, FieldType>
|
||||
grafter(&(this->LocalMeshes[static_cast<std::size_t>(b->BlockIndex)]),
|
||||
b->ContourTrees[0],
|
||||
&(b->InteriorForests[0]));
|
||||
auto currBlock = input.GetPartition(b->BlockIndex);
|
||||
auto currField =
|
||||
currBlock.GetField(this->GetActiveFieldName(), this->GetActiveFieldAssociation());
|
||||
vtkm::cont::ArrayHandle<FieldType> fieldData;
|
||||
vtkm::cont::ArrayCopy(currField.GetData().template AsVirtual<FieldType>(), fieldData);
|
||||
auto localToGlobalIdRelabeler = vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler(
|
||||
this->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal().Get(b->BlockIndex),
|
||||
this->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal().Get(b->BlockIndex),
|
||||
this->MultiBlockSpatialDecomposition.GlobalSize);
|
||||
grafter.GraftInteriorForests(0, hierarchicalTree, fieldData, &localToGlobalIdRelabeler);
|
||||
|
||||
// TODO: GET THIS COMPILING
|
||||
// save the corresponding .gv file
|
||||
// std::string hierarchicalTreeFileName = std::string("Rank_") + std::to_string(static_cast<int>(rank)) + std::string("_Block_") + std::to_string(static_cast<int>(b->BlockIndex)) + "_Round_" + std::to_string(nRounds) + "_Hierarchical_Tree.gv";
|
||||
// std::ofstream hierarchicalTreeFile(hierarchicalTreeFileName);
|
||||
// hierarchicalTreeFile << vtkm::worklet::contourtree_distributed::HierarchicalContourTreeDotGraphPrint<FieldType>
|
||||
// ( std::string("Block ") + std::to_string(static_cast<int>(b->BlockIndex)) + " Round " + std::to_string(nRounds) + " Hierarchical Tree", hierarchicalTree,
|
||||
// vtkm::worklet::contourtree_distributed::SHOW_SUPER_STRUCTURE|vtkm::worklet::contourtree_distributed::SHOW_HYPER_STRUCTURE|vtkm::worklet::contourtree_distributed::SHOW_ALL_IDS|vtkm::worklet::contourtree_distributed::SHOW_ALL_SUPERIDS|vtkm::worklet::contourtree_distributed::SHOW_ALL_HYPERIDS
|
||||
// );
|
||||
});
|
||||
|
||||
// FIXME: The following is still old code and needs to be changed!!!
|
||||
|
||||
#if 0
|
||||
// Now run the contour tree algorithm on the last block to compute the final tree
|
||||
vtkm::Id currNumIterations;
|
||||
vtkm::worklet::contourtree_augmented::ContourTree currContourTree;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType currSortOrder;
|
||||
vtkm::worklet::ContourTreeAugmented worklet;
|
||||
vtkm::cont::ArrayHandle<T> currField;
|
||||
// Construct the mesh boundary exectuion object needed for boundary augmentation
|
||||
vtkm::Id3 minIdx(0, 0, 0);
|
||||
vtkm::Id3 maxIdx = this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.GlobalSize;
|
||||
maxIdx[0] = maxIdx[0] - 1;
|
||||
maxIdx[1] = maxIdx[1] - 1;
|
||||
maxIdx[2] = maxIdx[2] > 0 ? (maxIdx[2] - 1) : 0;
|
||||
// TODO Check setting. In parallel we should need to augment the tree in order to be able to do the merging
|
||||
const unsigned int computeRegularStructure = 1;
|
||||
auto meshBoundaryExecObj = localDataBlocks[0]->ContourTreeMeshes.back().GetMeshBoundaryExecutionObject(
|
||||
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.GlobalSize[0],
|
||||
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.GlobalSize[1],
|
||||
minIdx,
|
||||
maxIdx);
|
||||
// Run the worklet to compute the final contour tree
|
||||
worklet.Run(
|
||||
localDataBlocks[0]->ContourTreeMeshes.back().SortedValues, // Unused param. Provide something to keep API happy
|
||||
localDataBlocks[0]->ContourTreeMeshes.back(),
|
||||
this->ContourTreeData,
|
||||
this->MeshSortOrder,
|
||||
currNumIterations,
|
||||
computeRegularStructure,
|
||||
meshBoundaryExecObj);
|
||||
|
||||
// Set the final mesh sort order we need to use
|
||||
this->MeshSortOrder = localDataBlocks[0]->ContourTreeMeshes.back().GlobalMeshIndex;
|
||||
// Remeber the number of iterations for the output
|
||||
this->NumIterations = currNumIterations;
|
||||
|
||||
// Return the sorted values of the contour tree as the result
|
||||
// TODO the result we return for the parallel and serial case are different right now. This should be made consistent. However, only in the parallel case are we useing the result output
|
||||
vtkm::cont::DataSet temp;
|
||||
vtkm::cont::Field rfield(this->GetOutputFieldName(),
|
||||
vtkm::cont::Field::Association::WHOLE_MESH,
|
||||
localDataBlocks[0]->ContourTreeMeshes.back().SortedValues);
|
||||
temp.AddField(rfield);
|
||||
output = vtkm::cont::PartitionedDataSet(temp);
|
||||
/* Not necessary?
|
||||
this->ContourTreeData = MultiBlockTreeHelper->LocalContourTrees[0];
|
||||
this->MeshSortOrder = MultiBlockTreeHelper->LocalSortOrders[0];
|
||||
*/
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -439,36 +689,32 @@ inline VTKM_CONT void ContourTreeUniformDistributed::PostExecute(
|
||||
vtkm::cont::PartitionedDataSet& result,
|
||||
const vtkm::filter::PolicyBase<DerivedPolicy>& policy)
|
||||
{
|
||||
if (this->MultiBlockTreeHelper)
|
||||
vtkm::cont::Timer timer;
|
||||
timer.Start();
|
||||
// We are running in parallel and need to merge the contour tree in PostExecute
|
||||
// TODO/FIXME: Make sure this still makes sense
|
||||
if (this->MultiBlockSpatialDecomposition.GetGlobalNumberOfBlocks() == 1)
|
||||
{
|
||||
vtkm::cont::Timer timer;
|
||||
timer.Start();
|
||||
// We are running in parallel and need to merge the contour tree in PostExecute
|
||||
if (MultiBlockTreeHelper->GetGlobalNumberOfBlocks() == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto field =
|
||||
input.GetPartition(0).GetField(this->GetActiveFieldName(), this->GetActiveFieldAssociation());
|
||||
vtkm::filter::FieldMetadata metaData(field);
|
||||
|
||||
vtkm::filter::FilterTraits<ContourTreeUniformDistributed> traits;
|
||||
vtkm::cont::CastAndCall(vtkm::filter::ApplyPolicyFieldActive(field, policy, traits),
|
||||
vtkm::filter::contourtree_distributed_detail::PostExecuteCaller{},
|
||||
this,
|
||||
input,
|
||||
result,
|
||||
metaData,
|
||||
policy);
|
||||
|
||||
this->MultiBlockTreeHelper.reset();
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Perf,
|
||||
std::endl
|
||||
<< " " << std::setw(38) << std::left << "Contour Tree Filter PostExecute"
|
||||
<< ": " << timer.GetElapsedTime() << " seconds");
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto field = // TODO/FIXME: Correct for more than one block per rank?
|
||||
input.GetPartition(0).GetField(this->GetActiveFieldName(), this->GetActiveFieldAssociation());
|
||||
vtkm::filter::FieldMetadata metaData(field);
|
||||
|
||||
vtkm::filter::FilterTraits<ContourTreeUniformDistributed> traits;
|
||||
vtkm::cont::CastAndCall(vtkm::filter::ApplyPolicyFieldActive(field, policy, traits),
|
||||
vtkm::filter::contourtree_distributed_detail::PostExecuteCaller{},
|
||||
this,
|
||||
input,
|
||||
result,
|
||||
metaData,
|
||||
policy);
|
||||
|
||||
VTKM_LOG_S(vtkm::cont::LogLevel::Perf,
|
||||
std::endl
|
||||
<< " " << std::setw(38) << std::left << "Contour Tree Filter PostExecute"
|
||||
<< ": " << timer.GetElapsedTime() << " seconds");
|
||||
}
|
||||
|
||||
} // namespace filter
|
||||
} // namespace vtkm::filter
|
||||
|
@ -130,7 +130,7 @@ public:
|
||||
|
||||
// Print the contour tree we computed
|
||||
std::cout << "Computed Contour Tree" << std::endl;
|
||||
vtkm::worklet::contourtree_augmented::PrintEdgePairArray(saddlePeak);
|
||||
vtkm::worklet::contourtree_augmented::PrintEdgePairArrayColumnLayout(saddlePeak);
|
||||
// Print the expected contour tree
|
||||
std::cout << "Expected Contour Tree" << std::endl;
|
||||
std::cout << " 0 12" << std::endl;
|
||||
@ -177,7 +177,7 @@ public:
|
||||
|
||||
// Print the contour tree we computed
|
||||
std::cout << "Computed Contour Tree" << std::endl;
|
||||
vtkm::worklet::contourtree_augmented::PrintEdgePairArray(saddlePeak);
|
||||
vtkm::worklet::contourtree_augmented::PrintEdgePairArrayColumnLayout(saddlePeak);
|
||||
// Print the expected contour tree
|
||||
std::cout << "Expected Contour Tree" << std::endl;
|
||||
std::cout << " 10 20" << std::endl;
|
||||
@ -229,7 +229,7 @@ public:
|
||||
|
||||
// Print the contour tree we computed
|
||||
std::cout << "Computed Contour Tree" << std::endl;
|
||||
vtkm::worklet::contourtree_augmented::PrintEdgePairArray(saddlePeak);
|
||||
vtkm::worklet::contourtree_augmented::PrintEdgePairArrayColumnLayout(saddlePeak);
|
||||
// Print the expected contour tree
|
||||
std::cout << "Expected Contour Tree" << std::endl;
|
||||
std::cout << " 0 67" << std::endl;
|
||||
@ -285,7 +285,7 @@ public:
|
||||
|
||||
// Print the contour tree we computed
|
||||
std::cout << "Computed Contour Tree" << std::endl;
|
||||
vtkm::worklet::contourtree_augmented::PrintEdgePairArray(saddlePeak);
|
||||
vtkm::worklet::contourtree_augmented::PrintEdgePairArrayColumnLayout(saddlePeak);
|
||||
// Print the expected contour tree
|
||||
std::cout << "Expected Contour Tree" << std::endl;
|
||||
std::cout << " 0 112" << std::endl;
|
||||
@ -341,7 +341,7 @@ public:
|
||||
|
||||
// Print the contour tree we computed
|
||||
std::cout << "Computed Contour Tree" << std::endl;
|
||||
vtkm::worklet::contourtree_augmented::PrintEdgePairArray(saddlePeak);
|
||||
vtkm::worklet::contourtree_augmented::PrintEdgePairArrayColumnLayout(saddlePeak);
|
||||
// Print the expected contour tree
|
||||
std::cout << "Expected Contour Tree" << std::endl;
|
||||
std::cout << " 0 118" << std::endl;
|
||||
@ -402,7 +402,7 @@ public:
|
||||
|
||||
// Print the contour tree we computed
|
||||
std::cout << "Computed Contour Tree" << std::endl;
|
||||
vtkm::worklet::contourtree_augmented::PrintEdgePairArray(saddlePeak);
|
||||
vtkm::worklet::contourtree_augmented::PrintEdgePairArrayColumnLayout(saddlePeak);
|
||||
// Print the expected contour tree
|
||||
std::cout << "Expected Contour Tree" << std::endl;
|
||||
std::cout << " 0 203" << std::endl;
|
||||
|
@ -166,10 +166,10 @@ public:
|
||||
inline void Init(vtkm::Id dataSize);
|
||||
|
||||
// debug routine
|
||||
inline void DebugPrint(const char* message, const char* fileName, long lineNum) const;
|
||||
inline std::string DebugPrint(const char* message, const char* fileName, long lineNum) const;
|
||||
|
||||
// print contents
|
||||
inline void PrintContent() const;
|
||||
inline void PrintContent(std::ostream& outStream = std::cout) const;
|
||||
|
||||
// print routines
|
||||
inline void PrintDotSuperStructure() const;
|
||||
@ -201,49 +201,47 @@ void ContourTree::Init(vtkm::Id dataSize)
|
||||
} // Init()
|
||||
|
||||
|
||||
inline void ContourTree::PrintContent() const
|
||||
inline void ContourTree::PrintContent(std::ostream& outStream /*= std::cout*/) const
|
||||
{
|
||||
PrintHeader(this->Arcs.GetNumberOfValues());
|
||||
PrintIndices("Arcs", this->Arcs);
|
||||
PrintIndices("Superparents", this->Superparents);
|
||||
std::cout << std::endl;
|
||||
PrintHeader(this->Supernodes.GetNumberOfValues());
|
||||
PrintIndices("Supernodes", this->Supernodes);
|
||||
PrintIndices("Superarcs", this->Superarcs);
|
||||
PrintIndices("Hyperparents", this->Hyperparents);
|
||||
PrintIndices("When Xferred", this->WhenTransferred);
|
||||
std::cout << std::endl;
|
||||
PrintHeader(this->Hypernodes.GetNumberOfValues());
|
||||
PrintIndices("Hypernodes", this->Hypernodes);
|
||||
PrintIndices("Hyperarcs", this->Hyperarcs);
|
||||
PrintHeader(Augmentnodes.GetNumberOfValues());
|
||||
PrintIndices("Augmentnodes", Augmentnodes);
|
||||
PrintIndices("Augmentarcs", this->Augmentarcs);
|
||||
std::cout << std::endl;
|
||||
std::cout << "NumIterations: " << this->NumIterations << std::endl;
|
||||
PrintHeader(this->FirstSupernodePerIteration.GetNumberOfValues());
|
||||
PrintIndices("First SN Per Iter", this->FirstSupernodePerIteration);
|
||||
PrintIndices("First HN Per Iter", this->FirstHypernodePerIteration);
|
||||
PrintHeader(this->Arcs.GetNumberOfValues(), outStream);
|
||||
PrintIndices("Arcs", this->Arcs, -1, outStream); // -1 -> thisArcs.size()
|
||||
PrintIndices("Superparents", this->Superparents, -1, outStream);
|
||||
outStream << std::endl;
|
||||
PrintHeader(this->Supernodes.GetNumberOfValues(), outStream);
|
||||
PrintIndices("Supernodes", this->Supernodes, -1, outStream);
|
||||
PrintIndices("Superarcs", this->Superarcs, -1, outStream);
|
||||
PrintIndices("Hyperparents", this->Hyperparents, -1, outStream);
|
||||
PrintIndices("When Xferred", this->WhenTransferred, -1, outStream);
|
||||
outStream << std::endl;
|
||||
PrintHeader(this->Hypernodes.GetNumberOfValues(), outStream);
|
||||
PrintIndices("Hypernodes", this->Hypernodes, -1, outStream);
|
||||
PrintIndices("Hyperarcs", this->Hyperarcs, -1, outStream);
|
||||
PrintHeader(Augmentnodes.GetNumberOfValues(), outStream);
|
||||
PrintIndices("Augmentnodes", Augmentnodes, -1, outStream);
|
||||
PrintIndices("Augmentarcs", this->Augmentarcs, -1, outStream);
|
||||
outStream << std::endl;
|
||||
outStream << "NumIterations: " << this->NumIterations << std::endl;
|
||||
PrintHeader(this->FirstSupernodePerIteration.GetNumberOfValues(), outStream);
|
||||
PrintIndices("First SN Per Iter", this->FirstSupernodePerIteration, -1, outStream);
|
||||
PrintIndices("First HN Per Iter", this->FirstHypernodePerIteration, -1, outStream);
|
||||
}
|
||||
|
||||
void ContourTree::DebugPrint(const char* message, const char* fileName, long lineNum) const
|
||||
std::string ContourTree::DebugPrint(const char* message, const char* fileName, long lineNum) const
|
||||
{ // DebugPrint()
|
||||
#ifdef DEBUG_PRINT
|
||||
std::cout << "---------------------------" << std::endl;
|
||||
std::cout << std::setw(30) << std::left << fileName << ":" << std::right << std::setw(4)
|
||||
<< lineNum << std::endl;
|
||||
std::cout << std::left << std::string(message) << std::endl;
|
||||
std::cout << "Contour Tree Contains: " << std::endl;
|
||||
std::cout << "---------------------------" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::stringstream resultStream;
|
||||
resultStream << std::endl;
|
||||
resultStream << "---------------------------" << std::endl;
|
||||
resultStream << std::setw(30) << std::left << fileName << ":" << std::right << std::setw(4)
|
||||
<< lineNum << std::endl;
|
||||
resultStream << std::left << std::string(message) << std::endl;
|
||||
resultStream << "Contour Tree Contains: " << std::endl;
|
||||
resultStream << "---------------------------" << std::endl;
|
||||
resultStream << std::endl;
|
||||
|
||||
this->PrintContent(resultStream);
|
||||
|
||||
return resultStream.str();
|
||||
|
||||
this->PrintContent();
|
||||
#else
|
||||
// Avoid unused parameter warnings
|
||||
(void)message;
|
||||
(void)fileName;
|
||||
(void)lineNum;
|
||||
#endif
|
||||
} // DebugPrint()
|
||||
|
||||
void ContourTree::PrintDotSuperStructure() const
|
||||
|
@ -1051,7 +1051,7 @@ void ContourTreeMaker::DebugPrint(const char* message, const char* fileName, lon
|
||||
|
||||
// this->JoinTree.DebugPrint((childString + std::string(": Join Tree")).c_str(), fileName, lineNum);
|
||||
// this->SplitTree.DebugPrint((childString + std::string(": Split Tree")).c_str(), fileName, lineNum);
|
||||
this->ContourTreeResult.DebugPrint(
|
||||
std::cout << this->ContourTreeResult.DebugPrint(
|
||||
(childString + std::string(": Contour Tree")).c_str(), fileName, lineNum);
|
||||
std::cout
|
||||
<< "==========================================================================================="
|
||||
|
@ -78,7 +78,7 @@ namespace contourtree_augmented
|
||||
|
||||
// local constants to allow changing the spacing as needed
|
||||
constexpr int PRINT_WIDTH = 12;
|
||||
constexpr int PREFIX_WIDTH = 24;
|
||||
constexpr int PREFIX_WIDTH = 30;
|
||||
|
||||
template <typename T, typename StorageType>
|
||||
void PrintValues(std::string label,
|
||||
@ -263,9 +263,45 @@ inline void PrintLabelledDataBlock(std::string label,
|
||||
} // PrintLabelledDataBlock()
|
||||
|
||||
|
||||
// routine for printing list of edge pairs. Used, e.g., to print the sorted list of saddle peaks from the ContourTree
|
||||
inline void PrintEdgePairArray(const EdgePairArray& edgePairArray,
|
||||
// routine for printing list of edge pairs in row format, i.e., First and Second of the Edge
|
||||
// are printed separated. Used, e.g.,in standard debug.
|
||||
inline void PrintEdgePairArray(std::string label,
|
||||
const EdgePairArray& edgePairArray,
|
||||
vtkm::Id nIndices,
|
||||
std::ostream& outStream = std::cout)
|
||||
{ // PrintEdgePairArray()
|
||||
// -1 means full size
|
||||
if (nIndices == -1)
|
||||
{
|
||||
nIndices = edgePairArray.GetNumberOfValues();
|
||||
}
|
||||
// now print them out
|
||||
auto edgePairArrayConstPortal = edgePairArray.ReadPortal();
|
||||
|
||||
// print the high end
|
||||
PrintLabel(label + " First", outStream);
|
||||
for (vtkm::Id superarc = 0; superarc < nIndices; superarc++)
|
||||
{ // per edge
|
||||
outStream << std::right << std::setw(PRINT_WIDTH)
|
||||
<< edgePairArrayConstPortal.Get(superarc).first << " ";
|
||||
}
|
||||
outStream << std::endl;
|
||||
|
||||
// print the low end
|
||||
PrintLabel(label + " Second", outStream);
|
||||
for (vtkm::Id superarc = 0; superarc < nIndices; superarc++)
|
||||
{ // per superarc
|
||||
outStream << std::right << std::setw(PRINT_WIDTH)
|
||||
<< edgePairArrayConstPortal.Get(superarc).second << std::endl;
|
||||
} // per superarc
|
||||
outStream << std::endl;
|
||||
} // PrintEdgePairArray()
|
||||
|
||||
|
||||
// routine for printing list of edge pairs in column format (first, second).
|
||||
// Used, e.g., to print the sorted list of saddle peaks from the ContourTree
|
||||
inline void PrintEdgePairArrayColumnLayout(const EdgePairArray& edgePairArray,
|
||||
std::ostream& outStream = std::cout)
|
||||
{ // PrintEdgePairArray()
|
||||
// now print them out
|
||||
auto edgePairArrayConstPortal = edgePairArray.ReadPortal();
|
||||
|
@ -75,8 +75,15 @@ constexpr vtkm::Id IS_ASCENDING = std::numeric_limits<vtkm::Id>::max() / 16 + 1;
|
||||
constexpr vtkm::Id INDEX_MASK = std::numeric_limits<vtkm::Id>::max() / 16; //0x07FFFFFF || 0x07FFFFFFFFFFFFFF
|
||||
constexpr vtkm::Id CV_OTHER_FLAG = std::numeric_limits<vtkm::Id>::max() / 8 + 1; //0x10000000 || 0x1000000000000000
|
||||
constexpr vtkm::Id ELEMENT_EXISTS = std::numeric_limits<vtkm::Id>::max() / 4 + 1; //0x20000000 || 0x2000000000000000 , same as IS_SUPERNODE
|
||||
// clang-format on
|
||||
|
||||
// flags for testing regular vertices
|
||||
constexpr vtkm::Id IS_LOWER_LEAF = static_cast<vtkm::Id>(0);
|
||||
constexpr vtkm::Id IS_UPPER_LEAF = static_cast<vtkm::Id>(1);
|
||||
constexpr vtkm::Id IS_REGULAR = static_cast<vtkm::Id>(2);
|
||||
constexpr vtkm::Id IS_SADDLE = static_cast<vtkm::Id>(3);
|
||||
constexpr vtkm::Id IS_ATTACHMENT = static_cast<vtkm::Id>(4);
|
||||
|
||||
// clang-format on
|
||||
using IdArrayType = vtkm::cont::ArrayHandle<vtkm::Id>;
|
||||
|
||||
using EdgePair = vtkm::Pair<vtkm::Id, vtkm::Id>; // here EdgePair.first=low and EdgePair.second=high
|
||||
|
@ -50,8 +50,8 @@
|
||||
// Oliver Ruebel (LBNL)
|
||||
//==============================================================================
|
||||
|
||||
#ifndef vtk_m_worklet_contourtree_distributed_boundary_restricted_augmented_contour_tree_h
|
||||
#define vtk_m_worklet_contourtree_distributed_boundary_restricted_augmented_contour_tree_h
|
||||
#ifndef vtk_m_worklet_contourtree_distributed_boundary_tree_h
|
||||
#define vtk_m_worklet_contourtree_distributed_boundary_tree_h
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/PrintVectors.h>
|
||||
@ -74,11 +74,11 @@ namespace contourtree_distributed
|
||||
///
|
||||
/// A contour tree for boundary vertices with the interior abstracted.
|
||||
/// This is primarily a data storage class. The actual constuction of
|
||||
/// the BRACT is performed by the BoundaryRestrictedAugmentedContourTreeMaker
|
||||
/// the BRACT is performed by the BoundaryTreeMaker
|
||||
/// (BRACTMaker). As a data store, this class primarily stores a set of
|
||||
/// arrays and provides convenience functions for interacting with the
|
||||
/// the data, e.g., to export the data to dot.
|
||||
class BoundaryRestrictedAugmentedContourTree
|
||||
class BoundaryTree
|
||||
{ // class BRACT
|
||||
public:
|
||||
// for each vertex, we store the index
|
||||
@ -87,6 +87,9 @@ public:
|
||||
// and the ID of the vertex it connects to (or NO_SUCH_ELEMENT)
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Superarcs;
|
||||
|
||||
// constructor
|
||||
BoundaryTree() {}
|
||||
|
||||
// prints the contents of the BRACT for comparison with sweep and merge
|
||||
std::string Print();
|
||||
|
||||
@ -96,21 +99,23 @@ public:
|
||||
const Mesh& mesh,
|
||||
const FieldArrayType& fieldArray,
|
||||
const vtkm::Id3 blockOrigin,
|
||||
const vtkm::Id3 blockSize,
|
||||
const vtkm::Id3 globalSize) const;
|
||||
|
||||
// prints the contents of the BRACT as a dot file using global IDs (version for CT mesh)
|
||||
template <typename FieldType>
|
||||
std::string PrintGlobalDot(
|
||||
const char* label,
|
||||
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>& mesh);
|
||||
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>& mesh) const;
|
||||
|
||||
// prints the contents of the BRACT in debug format
|
||||
std::string DebugPrint(const char* message, const char* fileName, long lineNum);
|
||||
void PrintContent(std::ostream& outStream) const;
|
||||
std::string DebugPrint(const char* message, const char* fileName, long lineNum) const;
|
||||
};
|
||||
|
||||
|
||||
// prints the contents of the BRACT for comparison with sweep and merge
|
||||
std::string BoundaryRestrictedAugmentedContourTree::Print()
|
||||
std::string BoundaryTree::Print()
|
||||
{ // Print
|
||||
// Use string steam to record text so the user can print it however they like
|
||||
std::stringstream resultStream;
|
||||
@ -138,25 +143,22 @@ std::string BoundaryRestrictedAugmentedContourTree::Print()
|
||||
|
||||
// secondary version which takes the mesh as a parameter
|
||||
template <typename Mesh, typename FieldArrayType>
|
||||
std::string BoundaryRestrictedAugmentedContourTree::PrintGlobalDot(const char* label,
|
||||
const Mesh& mesh,
|
||||
const FieldArrayType& fieldArray,
|
||||
const vtkm::Id3 blockOrigin,
|
||||
const vtkm::Id3 globalSize) const
|
||||
std::string BoundaryTree::PrintGlobalDot(const char* label,
|
||||
const Mesh& mesh,
|
||||
const FieldArrayType& fieldArray,
|
||||
const vtkm::Id3 blockOrigin,
|
||||
const vtkm::Id3 blockSize,
|
||||
const vtkm::Id3 globalSize) const
|
||||
{ // PrintGlobalDot
|
||||
VTKM_IS_ARRAY_HANDLE(FieldArrayType);
|
||||
std::stringstream resultStream;
|
||||
// print the header information
|
||||
resultStream << "digraph BRACT" << std::endl;
|
||||
resultStream << "\t{" << std::endl;
|
||||
resultStream << "\tlabel=\"" << label << "\"\n\tlabelloc=t\n\tfontsize=30" << std::endl;
|
||||
// create a relabeler
|
||||
vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler relabeler(blockOrigin[0],
|
||||
blockOrigin[1],
|
||||
blockOrigin[2],
|
||||
mesh.NumRows,
|
||||
mesh.NumCols,
|
||||
globalSize[0],
|
||||
globalSize[1]);
|
||||
vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler relabeler(
|
||||
blockOrigin, blockSize, globalSize);
|
||||
|
||||
// loop through all nodes
|
||||
auto vertexIndexPortal = this->VertexIndex.ReadPortal();
|
||||
@ -203,9 +205,9 @@ std::string BoundaryRestrictedAugmentedContourTree::PrintGlobalDot(const char* l
|
||||
|
||||
// prints the contents of the BRACT as a dot file using global IDs (version for CT mesh)
|
||||
template <typename FieldType>
|
||||
std::string BoundaryRestrictedAugmentedContourTree::PrintGlobalDot(
|
||||
std::string BoundaryTree::PrintGlobalDot(
|
||||
const char* label,
|
||||
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>& mesh)
|
||||
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>& mesh) const
|
||||
{ //PrintGlobalDot
|
||||
std::stringstream resultStream;
|
||||
// print the header information
|
||||
@ -216,7 +218,7 @@ std::string BoundaryRestrictedAugmentedContourTree::PrintGlobalDot(
|
||||
// loop through all nodes
|
||||
auto vertexIndexPortal = this->VertexIndex.ReadPortal();
|
||||
auto globalMeshIndexPortal = mesh.GlobalMeshIndex.ReadPortal();
|
||||
auto sortedValuesPortal = mesh.SortedValued.ReadPortal();
|
||||
auto sortedValuesPortal = mesh.SortedValues.ReadPortal();
|
||||
auto superarcsPortal = this->Superarcs.ReadPortal();
|
||||
for (vtkm::Id node = 0; node < this->VertexIndex.GetNumberOfValues(); node++)
|
||||
{ // per node
|
||||
@ -255,11 +257,21 @@ std::string BoundaryRestrictedAugmentedContourTree::PrintGlobalDot(
|
||||
} //PrintGlobalDot
|
||||
|
||||
// debug routine
|
||||
inline std::string BoundaryRestrictedAugmentedContourTree::DebugPrint(const char* message,
|
||||
const char* fileName,
|
||||
long lineNum)
|
||||
void BoundaryTree::PrintContent(std::ostream& outStream) const
|
||||
{
|
||||
vtkm::worklet::contourtree_augmented::PrintHeader(this->VertexIndex.GetNumberOfValues(),
|
||||
outStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"Vertex Index", this->VertexIndex, -1, outStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices("Superarcs", this->Superarcs, -1, outStream);
|
||||
}
|
||||
|
||||
inline std::string BoundaryTree::DebugPrint(const char* message,
|
||||
const char* fileName,
|
||||
long lineNum) const
|
||||
{ // DebugPrint
|
||||
std::stringstream resultStream;
|
||||
#ifdef DEBUG_PRINT
|
||||
resultStream << "[CUTHERE]-------------------------------------------------------" << std::endl;
|
||||
resultStream << std::setw(30) << std::left << fileName << ":" << std::right << std::setw(4)
|
||||
<< lineNum << std::endl;
|
||||
@ -267,16 +279,16 @@ inline std::string BoundaryRestrictedAugmentedContourTree::DebugPrint(const char
|
||||
resultStream << "Boundary Restricted Augmented Contour Tree Contains: " << std::endl;
|
||||
resultStream << "----------------------------------------------------------------" << std::endl;
|
||||
|
||||
vtkm::worklet::contourtree_augmented::PrintHeader(this->VertexIndex.GetNumberOfValues(),
|
||||
resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"Vertex Index", this->VertexIndex, -1, resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"Superarcs", this->Superarcs, -1, resultStream);
|
||||
this->PrintContent(resultStream);
|
||||
|
||||
resultStream << "---------------------------" << std::endl;
|
||||
resultStream << std::endl;
|
||||
resultStream << std::flush;
|
||||
#else
|
||||
(void)message;
|
||||
(void)fileName;
|
||||
(void)lineNum;
|
||||
#endif
|
||||
return resultStream.str();
|
||||
} // DebugPrint
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,11 +13,19 @@ set(headers
|
||||
SpatialDecomposition.h
|
||||
MultiBlockContourTreeHelper.h
|
||||
MergeBlockFunctor.h
|
||||
BoundaryRestrictedAugmentedContourTree.h
|
||||
BoundaryRestrictedAugmentedContourTreeMaker.h
|
||||
InteriorForest.h
|
||||
BoundaryTree.h
|
||||
BoundaryTreeMaker.h
|
||||
HierarchicalContourTree.h
|
||||
HierarchicalContourTreeDeviceData.h
|
||||
TreeGrafter.h
|
||||
ComputeDistributedContourTreeFunctor.h
|
||||
DistributedContourTreeBlockData.h
|
||||
PrintGraph.h
|
||||
)
|
||||
|
||||
vtkm_declare_headers(${headers})
|
||||
|
||||
add_subdirectory(bract_maker)
|
||||
add_subdirectory(boundary_tree_maker)
|
||||
add_subdirectory(tree_grafter)
|
||||
add_subdirectory(hierarchical_contour_tree)
|
||||
|
@ -0,0 +1,386 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_computedistributedcontourtreefunctor_h
|
||||
#define vtk_m_worklet_contourtree_distributed_computedistributedcontourtreefunctor_h
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
// clang-format off
|
||||
VTKM_THIRDPARTY_PRE_INCLUDE
|
||||
#include <vtkm/thirdparty/diy/diy.h>
|
||||
VTKM_THIRDPARTY_POST_INCLUDE
|
||||
// clang-format on
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
|
||||
// Functor needed so we can discover the FieldType and DeviceAdapter template parameters to call MergeWith
|
||||
struct MergeContourTreeMeshFunctor
|
||||
{
|
||||
template <typename DeviceAdapterTag, typename FieldType>
|
||||
bool operator()(DeviceAdapterTag,
|
||||
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>& in,
|
||||
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>& out) const
|
||||
{
|
||||
out.template MergeWith<DeviceAdapterTag>(in);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Functor used by DIY reduce the merge data blocks in parallel
|
||||
template <typename FieldType>
|
||||
class ComputeDistributedContourTreeFunctor
|
||||
{
|
||||
public:
|
||||
ComputeDistributedContourTreeFunctor(vtkm::Id3 globalSize)
|
||||
: GlobalSize(globalSize)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()(
|
||||
vtkm::worklet::contourtree_distributed::DistributedContourTreeBlockData<FieldType>*
|
||||
block, // local Block.
|
||||
const vtkmdiy::ReduceProxy& rp, // communication proxy
|
||||
const vtkmdiy::RegularSwapPartners& // partners of the current block (unused)
|
||||
) const
|
||||
{
|
||||
const auto selfid = rp.gid();
|
||||
//DEBUGOUT//std::cout << "Entering ComputeDistributedContourTreeFunctor::operator() for GID " << selfid << std::endl;
|
||||
|
||||
// Get rank (for debug output only)
|
||||
const vtkm::Id rank = vtkm::cont::EnvironmentTracker::GetCommunicator().rank();
|
||||
|
||||
// Here we do the deque first before the send due to the way the iteration is handled in DIY, i.e., in each iteration
|
||||
// A block needs to first collect the data from its neighours and then send the combined block to its neighbours
|
||||
// for the next iteration.
|
||||
// 1. dequeue the block and compute the new contour tree and contour tree mesh for the block if we have the hight GID
|
||||
std::vector<int> incoming;
|
||||
rp.incoming(incoming);
|
||||
//std::cout << "Incoming size is " << incoming.size() << std::endl;
|
||||
for (const int ingid : incoming)
|
||||
{
|
||||
// NOTE/IMPORTANT: In each round we should have only one swap partner (despite for-loop here).
|
||||
// If that assumption does not hold, it will break things.
|
||||
if (ingid != selfid)
|
||||
{
|
||||
vtkm::Id3 otherBlockOrigin;
|
||||
rp.dequeue(ingid, otherBlockOrigin);
|
||||
vtkm::Id3 otherBlockSize;
|
||||
rp.dequeue(ingid, otherBlockSize);
|
||||
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType> otherContourTreeMesh;
|
||||
rp.dequeue(ingid, otherContourTreeMesh);
|
||||
#if 0
|
||||
// FIXME: Delete after debugging
|
||||
std::cout << "Our block has extents: " << block->BlockOrigin << " " << block->BlockSize << std::endl;
|
||||
std::cout << "Received block from " << ingid << " with extents: " << otherBlockOrigin << " " << otherBlockSize << std::endl;
|
||||
|
||||
std::cout << "=================== BEFORE COMBINING =====================" << std::endl;
|
||||
block->ContourTreeMeshes.back().DebugPrint("OUR CTM", __FILE__, __LINE__);
|
||||
otherContourTreeMesh.DebugPrint("OTHER CTM", __FILE__, __LINE__);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
char buffer[256];
|
||||
std::snprintf(buffer, sizeof(buffer), "BeforeCombine_MyMesh_ContourTreeMesh_Rank%lld_Round%d.txt", rank, rp.round());
|
||||
block->ContourTreeMeshes.back().Save(buffer);
|
||||
std::snprintf(buffer, sizeof(buffer), "BeforeCombine_Other_ContourTreeMesh_Rank%lld_Round%d.txt", rank, rp.round());
|
||||
otherContourTreeMesh.Save(buffer);
|
||||
#endif
|
||||
|
||||
// Merge the two contour tree meshes
|
||||
vtkm::cont::TryExecute(
|
||||
MergeContourTreeMeshFunctor{}, otherContourTreeMesh, block->ContourTreeMeshes.back());
|
||||
|
||||
char buffer[256];
|
||||
std::snprintf(buffer,
|
||||
sizeof(buffer),
|
||||
"AfterCombine_ContourTreeMesh_Rank%d_Block%d_Round%d.txt",
|
||||
static_cast<int>(rank),
|
||||
static_cast<int>(block->BlockIndex),
|
||||
rp.round());
|
||||
block->ContourTreeMeshes.back().Save(buffer);
|
||||
|
||||
#if 0
|
||||
// FIXME: Delete after debugging
|
||||
std::cout << "================== AFTER COMBINING =================" << std::endl;
|
||||
std::cout << "OUR CTM" << std::endl;
|
||||
block->ContourTreeMeshes.back().DebugPrint("OUR CTM", __FILE__, __LINE__);
|
||||
#endif
|
||||
|
||||
// Compute the origin and size of the new block
|
||||
vtkm::Id3 currBlockOrigin{
|
||||
std::min(otherBlockOrigin[0], block->BlockOrigin[0]),
|
||||
std::min(otherBlockOrigin[1], block->BlockOrigin[1]),
|
||||
std::min(otherBlockOrigin[2], block->BlockOrigin[2]),
|
||||
};
|
||||
vtkm::Id3 currBlockMaxIndex{ // Needed only to compute the block size
|
||||
std::max(otherBlockOrigin[0] + otherBlockSize[0],
|
||||
block->BlockOrigin[0] + block->BlockSize[0]),
|
||||
std::max(otherBlockOrigin[1] + otherBlockSize[1],
|
||||
block->BlockOrigin[1] + block->BlockSize[1]),
|
||||
std::max(otherBlockOrigin[2] + otherBlockSize[2],
|
||||
block->BlockOrigin[2] + block->BlockSize[2])
|
||||
};
|
||||
vtkm::Id3 currBlockSize{ currBlockMaxIndex[0] - currBlockOrigin[0],
|
||||
currBlockMaxIndex[1] - currBlockOrigin[1],
|
||||
currBlockMaxIndex[2] - currBlockOrigin[2] };
|
||||
|
||||
// Compute the contour tree from our merged mesh
|
||||
vtkm::Id currNumIterations;
|
||||
block->ContourTrees.emplace_back(); // Create new empty contour tree object
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType currSortOrder;
|
||||
vtkm::worklet::ContourTreeAugmented worklet;
|
||||
vtkm::Id3 maxIdx{ currBlockOrigin[0] + currBlockSize[0] - 1,
|
||||
currBlockOrigin[1] + currBlockSize[1] - 1,
|
||||
currBlockOrigin[2] + currBlockSize[2] - 1 };
|
||||
auto meshBoundaryExecObj = block->ContourTreeMeshes.back().GetMeshBoundaryExecutionObject(
|
||||
this->GlobalSize, currBlockOrigin, maxIdx);
|
||||
worklet.Run(block->ContourTreeMeshes.back()
|
||||
.SortedValues, // Unused param. Provide something to keep the API happy
|
||||
block->ContourTreeMeshes.back(),
|
||||
block->ContourTrees.back(),
|
||||
currSortOrder,
|
||||
currNumIterations,
|
||||
1, // Fully augmented FIXME: Verify
|
||||
meshBoundaryExecObj);
|
||||
#if 0
|
||||
// FIXME: Delete after debugging
|
||||
std::cout << "=================== BEGIN: COMBINED CONTOUR TREE =========================" << std::endl;
|
||||
block->ContourTrees.back().PrintContent();
|
||||
std::cout << "=================== END: COMBINED CONTOUR TREE =========================" << std::endl;
|
||||
#endif
|
||||
|
||||
// Update block extents
|
||||
block->BlockOrigin = currBlockOrigin;
|
||||
block->BlockSize = currBlockSize;
|
||||
}
|
||||
}
|
||||
|
||||
// If we are not in the first round (contour tree mesh for that round was pre-computed
|
||||
// in filter outside functor) and if we are sending to someone else (i.e., not in
|
||||
// last round) then compute contour tree mesh to send and save it.
|
||||
if (rp.round() != 0 && rp.out_link().size() != 0)
|
||||
{
|
||||
#if 0
|
||||
// If we have the fully augmented contour tree
|
||||
block->ContourTreeMeshes.emplace_back(
|
||||
block->ContourTrees.back().Arcs, block->ContourTreeMeshes.back()
|
||||
);
|
||||
|
||||
char buffer[256];
|
||||
std::snprintf(buffer, sizeof(buffer), "CombinedMeshes_GID%d_Round%d.txt", selfid, rp.round());
|
||||
block->ContourTreeMeshes.back().Save(buffer);
|
||||
#endif
|
||||
|
||||
vtkm::Id3 maxIdx{ block->BlockOrigin[0] + block->BlockSize[0] - 1,
|
||||
block->BlockOrigin[1] + block->BlockSize[1] - 1,
|
||||
block->BlockOrigin[2] + block->BlockSize[2] - 1 };
|
||||
|
||||
char buffer[256];
|
||||
std::snprintf(buffer,
|
||||
sizeof(buffer),
|
||||
"BRACTInputCTM_Rank%d_Block%d_Round%d.ctm_txt",
|
||||
static_cast<int>(rank),
|
||||
static_cast<int>(block->BlockIndex),
|
||||
static_cast<int>(block->ContourTreeMeshes.size() - 1));
|
||||
block->ContourTreeMeshes.back().Save(buffer);
|
||||
std::snprintf(buffer,
|
||||
sizeof(buffer),
|
||||
"BRACTComputation_Rank%d_Block%d_Round%d.txt",
|
||||
static_cast<int>(rank),
|
||||
static_cast<int>(block->BlockIndex),
|
||||
rp.round());
|
||||
std::ofstream os(buffer);
|
||||
os << "Block Origin: " << block->BlockOrigin << " Block Size: " << block->BlockSize
|
||||
<< " Block MaxIdx: " << maxIdx << std::endl;
|
||||
os << "================= INPUT ===================" << std::endl;
|
||||
os << "+++++++++++++++++ Contour Tree +++++++++++++++++" << std::endl;
|
||||
block->ContourTrees.back().PrintContent(os);
|
||||
os << "+++++++++++++++++ Contour Tree Mesh +++++++++++++++++" << std::endl;
|
||||
block->ContourTreeMeshes.back().PrintContent(os);
|
||||
|
||||
// TODO: GET THIS COMPILING
|
||||
// save the corresponding .gv file for the contour tree mesh
|
||||
// std::string contourTreeMeshFileName = std::string("Rank_") + std::to_string(static_cast<int>(rank)) + std::string("_Block_") + std::to_string(static_cast<int>(block->BlockIndex)) + "_Round_" + std::to_string(rp.round()) + "_Partner_" + std::to_string(ingid) + std::string("_Step_0_Combined_Mesh.gv");
|
||||
// std::ofstream contourTreeMeshFile(contourTreeMeshFileName);
|
||||
// contourTreeMeshFile << vtkm::worklet::contourtree_distributed::ContourTreeMeshDotGraphPrint<FieldType>
|
||||
// ( std::string("Block ") + std::to_string(static_cast<int>(block->BlockIndex)) + " Round " + std::to_string(rp.round()) + " Partner " + std::to_string(ingid) + std::string(" Step 0 Combined Mesh"),
|
||||
// block->ContourTreeMeshes.back(), worklet::contourtree_distributed::SHOW_CONTOUR_TREE_MESH_ALL);
|
||||
//
|
||||
// // and the ones for the contour tree regular and superstructures
|
||||
// std::string regularStructureFileName = std::string("Rank_") + std::to_string(static_cast<int>(rank)) + std::string("_Block_") + std::to_string(static_cast<int>(block->BlockIndex)) + "_Round_" + std::to_string(rp.round()) + " Partner " + std::to_string(ingid) + std::string("_Step_1_Contour_Tree_Regular_Structure.gv");
|
||||
// std::ofstream regularStructureFile(regularStructureFileName);
|
||||
// regularStructureFile << worklet::contourtree_distributed::ContourTreeDotGraphPrint<T, MeshType, vtkm::worklet::contourtree_augmented::IdArrayType()>
|
||||
// ( std::string("Block ") + std::to_string(static_cast<int>(block->BlockIndex)) + " Round " + std::to_string(rp.round()) + " Partner " + std::to_string(ingid) + std::string(" Step 1 Contour Tree Regular Structure"),
|
||||
// block->Meshes.back(),
|
||||
// block->ContourTrees.back(),
|
||||
// worklet::contourtree_distributed::SHOW_REGULAR_STRUCTURE|worklet::contourtree_distributed::SHOW_ALL_IDS);
|
||||
//
|
||||
// std::string superStructureFileName = std::string("Rank_") + std::to_string(static_cast<int>(rank)) + std::string("_Block_") + std::to_string(static_cast<int>(block->BlockIndex)) + "_Round_" + std::to_string(rp.round()) + " Partner " + std::to_string(ingid) + std::string("_Step_2_Contour_Tree_Super_Structure.gv");
|
||||
// std::ofstream superStructureFile(superStructureFileName);
|
||||
// superStructureFile << worklet::contourtree_distributed::ContourTreeDotGraphPrint<T, MeshType, vtkm::worklet::contourtree_augmented::IdArrayType()>
|
||||
// ( std::string("Block ") + std::to_string(static_cast<int>(block->BlockIndex)) + " Round " + std::to_string(rp.round()) + " Partner " + std::to_string(ingid) + std::string(" Step 2 Contour Tree Super Structure"),
|
||||
// block->Meshes.back(),
|
||||
// block->ContourTrees.back(),
|
||||
// worklet::contourtree_distributed::SHOW_SUPER_STRUCTURE|worklet::contourtree_distributed::SHOW_HYPER_STRUCTURE|worklet::contourtree_distributed::SHOW_ALL_IDS|worklet::contourtree_distributed::SHOW_ALL_SUPERIDS|worklet::contourtree_distributed::SHOW_ALL_HYPERIDS);
|
||||
|
||||
// Compute BRACT
|
||||
vtkm::worklet::contourtree_distributed::BoundaryTree boundaryTree;
|
||||
// ... Get the mesh boundary object
|
||||
auto meshBoundaryExecObj = block->ContourTreeMeshes.back().GetMeshBoundaryExecutionObject(
|
||||
this->GlobalSize, block->BlockOrigin, maxIdx);
|
||||
// Make the BRACT and InteriorForest (i.e., residue)
|
||||
block->InteriorForests.emplace_back();
|
||||
std::cout << "Calling BRACT Maker" << std::endl;
|
||||
auto boundaryTreeMaker = vtkm::worklet::contourtree_distributed::BoundaryTreeMaker<
|
||||
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>,
|
||||
vtkm::worklet::contourtree_augmented::MeshBoundaryContourTreeMeshExec>(
|
||||
&(block->ContourTreeMeshes.back()),
|
||||
meshBoundaryExecObj,
|
||||
block->ContourTrees.back(),
|
||||
&boundaryTree,
|
||||
&(block->InteriorForests.back()));
|
||||
// Construct the BRACT and InteriorForest. Since we are working on a ContourTreeMesh we do
|
||||
// not need to provide and IdRelabeler here in order to compute the InteriorForest
|
||||
boundaryTreeMaker.Construct();
|
||||
os << "================= OUTPUT ===================" << std::endl;
|
||||
os << "+++++++++++++++++ BRACT +++++++++++++++++++" << std::endl;
|
||||
os << boundaryTree.DebugPrint("validate", __FILE__, __LINE__);
|
||||
os << "+++++++++++++++++ BRACT Contour Tree Mesh +++++++++++++++++++" << std::endl;
|
||||
|
||||
//char buffer[256];
|
||||
std::snprintf(buffer,
|
||||
sizeof(buffer),
|
||||
"GID %d, Round %d, Block %d, Computed by BRACTMaker",
|
||||
selfid,
|
||||
rp.round(),
|
||||
static_cast<int>(block->BlockIndex));
|
||||
std::string debug_dot = boundaryTree.PrintGlobalDot(buffer, block->ContourTreeMeshes.back());
|
||||
std::snprintf(buffer,
|
||||
sizeof(buffer),
|
||||
"BRACT_Rank%d__Block%d_Round%d.gv",
|
||||
static_cast<int>(rank),
|
||||
static_cast<int>(block->BlockIndex),
|
||||
rp.round());
|
||||
std::ofstream dotStream(buffer);
|
||||
dotStream << debug_dot;
|
||||
// Construct contour tree mesh from BRACT
|
||||
block->ContourTreeMeshes.emplace_back(
|
||||
boundaryTree.VertexIndex, boundaryTree.Superarcs, block->ContourTreeMeshes.back());
|
||||
block->ContourTreeMeshes.back().PrintContent(os);
|
||||
//char buffer[256];
|
||||
std::snprintf(buffer,
|
||||
sizeof(buffer),
|
||||
"CombinedMeshes_Rank%d_Block%d_Round%lu.ctm_txt",
|
||||
static_cast<int>(rank),
|
||||
static_cast<int>(block->BlockIndex),
|
||||
block->ContourTreeMeshes.size() - 1);
|
||||
block->ContourTreeMeshes.back().Save(buffer);
|
||||
}
|
||||
|
||||
// TODO: GET THIS COMPILING
|
||||
// save the Boundary Tree as a dot file
|
||||
// std::string boundaryTreeFileName = std::string("Rank_") + std::to_string(static_cast<int>(rank)) + std::string("_Block_") + std::to_string(static_cast<int>(block->BlockIndex)) + "_Round_" + std::to_string(rp.round()) + "_Partner_" + std::to_string(ingid) + std::string("_Step_3_Boundary_Tree.gv");
|
||||
// std::ofstream boundaryTreeFile(boundaryTreeFileName);
|
||||
// boundaryTreeFile << vtkm::worklet::contourtree_distributed::BoundaryTreeDotGraphPrint
|
||||
// ( std::string("Block ") + std::to_string(static_cast<int>(block->BlockIndex)) + " Round " + std::to_string(rp.round()) + " Partner " + std::to_string(ingid) + std::string(" Step 3 Boundary Tree"),
|
||||
// block->Meshes.back()],
|
||||
// block->BoundaryTrees.back());
|
||||
//
|
||||
// // and save the Interior Forest as another dot file
|
||||
// std::string interiorForestFileName = std::string("Rank_") + std::to_string(static_cast<int>(rank)) + std::string("_Block_") + std::to_string(static_cast<int>(block->BlockIndex)) + "_Round_" + std::to_string(rp.round()) + "_Partner_" + std::to_string(ingid) + std::string("_Step_4_Interior_Forest.gv");
|
||||
// std::ofstream interiorForestFile(interiorForestFileName);
|
||||
// interiorForestFileName << InteriorForestDotGraphPrintFile<MeshType>
|
||||
// ( std::string("Block ") + std::to_string(static_cast<int>(block->BlockIndex)) + " Round " + std::to_string(rp.round()) + " Partner " + std::to_string(ingid) + std::string(" Step 4 Interior Forest"),
|
||||
// block->InteriorForests.back(),
|
||||
// block->ContourTrees.back(),
|
||||
// block->BoundaryTrees.back(),
|
||||
// block->Meshes.back());
|
||||
//
|
||||
// // save the corresponding .gv file
|
||||
// std::string boundaryTreeMeshFileName = std::string("Rank_") + std::to_string(static_cast<int>(rank)) + std::string("_Block_") + std::to_string(static_cast<int>(block->BlockIndex)) + "_Round_" + std::to_string(rp.round()) + "_Partner_" + std::to_string(ingid) + std::string("_Step_5_Boundary_Tree_Mesh.gv");
|
||||
// std::ofstream boundaryTreeMeshFile(boundaryTreeMeshFileName);
|
||||
// boundaryTreeMeshFile << vtkm::worklet::contourtree_distributed::ContourTreeMeshDotGraphPrint<FieldType>
|
||||
// ( std::string("Block ") + std::to_string(static_cast<int>(block->BlockIndex)) + " Round " + std::to_string(rp.round()) + " Partner " + std::to_string(ingid) + std::string(" Step 5 Boundary Tree Mesh"),
|
||||
// block->ContourTreeMeshes.back(),
|
||||
// worklet::contourtree_distributed::SHOW_CONTOUR_TREE_MESH_ALL);
|
||||
|
||||
// Send our current block (which is either our original block or the one we just combined from the ones we received) to our next neighbour.
|
||||
// Once a rank has send his block (either in its orignal or merged form) it is done with the reduce
|
||||
for (int cc = 0; cc < rp.out_link().size(); ++cc)
|
||||
{
|
||||
auto target = rp.out_link().target(cc);
|
||||
if (target.gid != selfid)
|
||||
{
|
||||
rp.enqueue(target, block->BlockOrigin);
|
||||
rp.enqueue(target, block->BlockSize);
|
||||
rp.enqueue(target, block->ContourTreeMeshes.back());
|
||||
}
|
||||
}
|
||||
} //end ComputeDistributedContourTreeFunctor
|
||||
|
||||
private:
|
||||
vtkm::Id3 GlobalSize; // Extends of the global mesh
|
||||
};
|
||||
|
||||
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -78,7 +78,7 @@ struct ContourTreeBlockData
|
||||
// ContourTreeMesh data
|
||||
vtkm::Id NumVertices;
|
||||
// TODO Should be able to remove sortOrder here, but we need to figure out what to return in the worklet instead
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType SortOrder;
|
||||
// vtkm::worklet::contourtree_augmented::IdArrayType SortOrder;
|
||||
vtkm::cont::ArrayHandle<FieldType> SortedValue;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType GlobalMeshIndex;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Neighbours;
|
||||
@ -108,7 +108,6 @@ struct Serialization<vtkm::worklet::contourtree_distributed::ContourTreeBlockDat
|
||||
const vtkm::worklet::contourtree_distributed::ContourTreeBlockData<FieldType>& block)
|
||||
{
|
||||
vtkmdiy::save(bb, block.NumVertices);
|
||||
vtkmdiy::save(bb, block.SortOrder);
|
||||
vtkmdiy::save(bb, block.SortedValue);
|
||||
vtkmdiy::save(bb, block.GlobalMeshIndex);
|
||||
vtkmdiy::save(bb, block.Neighbours);
|
||||
@ -124,7 +123,6 @@ struct Serialization<vtkm::worklet::contourtree_distributed::ContourTreeBlockDat
|
||||
vtkm::worklet::contourtree_distributed::ContourTreeBlockData<FieldType>& block)
|
||||
{
|
||||
vtkmdiy::load(bb, block.NumVertices);
|
||||
vtkmdiy::load(bb, block.SortOrder);
|
||||
vtkmdiy::load(bb, block.SortedValue);
|
||||
vtkmdiy::load(bb, block.GlobalMeshIndex);
|
||||
vtkmdiy::load(bb, block.Neighbours);
|
||||
|
@ -0,0 +1,131 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
// Copyright (c) 2018, The Regents of the University of California, through
|
||||
// Lawrence Berkeley National Laboratory (subject to receipt of any required approvals
|
||||
// from the U.S. Dept. of Energy). All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// (1) Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// (2) Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// (3) Neither the name of the University of California, Lawrence Berkeley National
|
||||
// Laboratory, U.S. Dept. of Energy nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without
|
||||
// specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//=============================================================================
|
||||
//
|
||||
// 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_worklet_contourtree_distributed_contourtreeblockdata_h
|
||||
#define vtk_m_worklet_contourtree_distributed_contourtreeblockdata_h
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/meshtypes/ContourTreeMesh.h>
|
||||
|
||||
// clang-format off
|
||||
VTKM_THIRDPARTY_PRE_INCLUDE
|
||||
#include <vtkm/thirdparty/diy/diy.h>
|
||||
VTKM_THIRDPARTY_POST_INCLUDE
|
||||
// clang-format on
|
||||
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
template <typename FieldType>
|
||||
struct DistributedContourTreeBlockData
|
||||
{
|
||||
static void* create() { return new DistributedContourTreeBlockData<FieldType>; }
|
||||
static void destroy(void* b)
|
||||
{
|
||||
delete static_cast<DistributedContourTreeBlockData<FieldType>*>(b);
|
||||
}
|
||||
|
||||
vtkm::Id BlockIndex;
|
||||
std::vector<vtkm::worklet::contourtree_augmented::ContourTree> ContourTrees;
|
||||
std::vector<vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>> ContourTreeMeshes;
|
||||
std::vector<vtkm::worklet::contourtree_distributed::InteriorForest> InteriorForests;
|
||||
|
||||
// Block metadata
|
||||
vtkm::Id3 BlockOrigin; // Origin of the data block
|
||||
vtkm::Id3 BlockSize; // Extends of the data block
|
||||
};
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
|
||||
namespace vtkmdiy
|
||||
{
|
||||
|
||||
// Struct to serialize ContourTreeMesh objects (i.e., load/save) needed in parralle for DIY
|
||||
template <typename FieldType>
|
||||
struct Serialization<vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>>
|
||||
{
|
||||
static void save(vtkmdiy::BinaryBuffer& bb,
|
||||
const vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>& ctm)
|
||||
{
|
||||
vtkmdiy::save(bb, ctm.NumVertices);
|
||||
//vtkmdiy::save(bb, ctm.SortOrder);
|
||||
vtkmdiy::save(bb, ctm.SortedValues);
|
||||
vtkmdiy::save(bb, ctm.GlobalMeshIndex);
|
||||
vtkmdiy::save(bb, ctm.Neighbours);
|
||||
vtkmdiy::save(bb, ctm.FirstNeighbour);
|
||||
vtkmdiy::save(bb, ctm.MaxNeighbours);
|
||||
}
|
||||
|
||||
static void load(vtkmdiy::BinaryBuffer& bb,
|
||||
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>& ctm)
|
||||
{
|
||||
vtkmdiy::load(bb, ctm.NumVertices);
|
||||
//vtkmdiy::load(bb, ctm.SortOrder);
|
||||
vtkmdiy::load(bb, ctm.SortedValues);
|
||||
vtkmdiy::load(bb, ctm.GlobalMeshIndex);
|
||||
vtkmdiy::load(bb, ctm.Neighbours);
|
||||
vtkmdiy::load(bb, ctm.FirstNeighbour);
|
||||
vtkmdiy::load(bb, ctm.MaxNeighbours);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mangled_vtkmdiy_namespace
|
||||
|
||||
|
||||
#endif
|
@ -39,23 +39,42 @@
|
||||
//
|
||||
//=============================================================================
|
||||
//
|
||||
// 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.
|
||||
// Parallel Peak Pruning v. 2.0
|
||||
//
|
||||
// The PPP2 algorithm and software were jointly developed by
|
||||
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
|
||||
// Oliver Ruebel (LBNL)
|
||||
//==============================================================================
|
||||
// Started June 15, 2017
|
||||
//
|
||||
// Copyright Hamish Carr, University of Leeds
|
||||
//
|
||||
// HierarchicalContourTree.cpp - Hierarchical version of contour tree that captures all of the
|
||||
// superarcs relevant for a particular block. It is constructed by grafting missing edges
|
||||
// into the tree at all levels
|
||||
//
|
||||
//=======================================================================================
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
// There are several significant differences from the ContourTree class, in particular the
|
||||
// semantics of storage:
|
||||
// i. Hyper arcs are processed inside to outside instead of outside to inside
|
||||
// This is to allow the superarcs in higher blocks to be a prefix of those in lower blocks
|
||||
// We can do this by inverting the loop order and processing each level separately, so
|
||||
// we don't need to renumber (whew!)
|
||||
// ii. If the superarc is -1, it USED to mean the root of the tree. Now it can also mean
|
||||
// the root of a lower-level subtree. in this case, the superparent will show which
|
||||
// existing superarc it inserts into.
|
||||
//
|
||||
//=======================================================================================
|
||||
|
||||
#ifndef vtk_m_worklet_contourtree_distributed_hierarchical_contour_tree_h
|
||||
#define vtk_m_worklet_contourtree_distributed_hierarchical_contour_tree_h
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
#include <vtkm/worklet/contourtree_augmented/meshtypes/ContourTreeMesh.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/hierarchical_contour_tree/FindRegularByGlobal.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/hierarchical_contour_tree/FindSuperArcForUnknownNode.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/hierarchical_contour_tree/InitalizeSuperchildrenWorklet.h>
|
||||
#include <vtkm/worklet/contourtree_distributed/hierarchical_contour_tree/PermuteComparator.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
@ -67,14 +86,741 @@ namespace contourtree_distributed
|
||||
|
||||
/// \brief Hierarchical Contour Tree data structure
|
||||
///
|
||||
/// TODO this class still needs to be implemented
|
||||
/// This class contains all the structures to construct/store the HierarchicalContourTree.
|
||||
/// Functions used on the Device are then implemented in the HierarchicalContourTreeDeviceData
|
||||
/// class which stores the prepared array portals we need for those functions.
|
||||
///
|
||||
template <typename FieldType>
|
||||
class HierarchicalContourTree
|
||||
{
|
||||
public:
|
||||
VTKM_EXEC_CONT
|
||||
HierarchicalContourTree();
|
||||
|
||||
// REGULAR arrays: i.e. over all nodes in the tree, including regular
|
||||
// the full list of global IDs for the regular nodes
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType RegularNodeGlobalIds;
|
||||
// we will also need to track the data values
|
||||
vtkm::cont::ArrayHandle<FieldType> DataValues;
|
||||
|
||||
// an array to support searching by global ID
|
||||
// given a global ID, find its position in the regular node index
|
||||
// To do so, we keep an index by global ID of their positions in the array
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType RegularNodeSortOrder;
|
||||
// the supernode ID for each regular node: for most, this will be NO_SUCH_ELEMENT
|
||||
// but this makes lookups for supernode ID a lot easier
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Regular2Supernode;
|
||||
// the superparent for each regular node
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Superparents;
|
||||
|
||||
// SUPER arrays: i.e. over all supernodes in the tree
|
||||
// the ID in the globalID array
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Supernodes;
|
||||
// where the supernode connects to
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Superarcs;
|
||||
// the hyperparent for each supernode
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Hyperparents;
|
||||
// the hypernode ID for each supernode: often NO_SUCH_ELEMENT
|
||||
// but it makes lookups easier
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Super2Hypernode;
|
||||
|
||||
// which iteration & round the vertex is transferred in
|
||||
// the second of these is the same as "whenTransferred", but inverted order
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType WhichRound;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType WhichIteration;
|
||||
|
||||
// HYPER arrays: i.e. over all hypernodes in the tree
|
||||
// the ID in the supernode array
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Hypernodes;
|
||||
// where the hypernode connects to
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Hyperarcs;
|
||||
// the number of child supernodes on the superarc (including the start node)
|
||||
// and not including any inserted in the hierarchy
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Superchildren;
|
||||
|
||||
// how many rounds of fan-in were used to construct it
|
||||
vtkm::Id NumRounds;
|
||||
|
||||
// TODO: HAC to confirm where the next 6 arrays are used.
|
||||
// HAC: these arrays store the numbers of reg/super/hyper nodes at each level of the hierarchy
|
||||
// They are filled in from the top down, and are fundamentally CPU side control variables
|
||||
// They will be needed for hypersweeps.
|
||||
|
||||
// May be for hypersweeps later on. SHOULD be primarily CPU side
|
||||
/// arrays holding the logical size of the arrays at each level
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType NumRegularNodesInRound;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType NumSupernodesInRound;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType NumHypernodesInRound;
|
||||
|
||||
/// how many iterations needed for the hypersweep at each level
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType NumIterations;
|
||||
|
||||
/// vectors tracking the segments used in each iteration of the hypersweep
|
||||
std::vector<vtkm::worklet::contourtree_augmented::IdArrayType> FirstSupernodePerIteration;
|
||||
std::vector<vtkm::worklet::contourtree_augmented::IdArrayType> FirstHypernodePerIteration;
|
||||
|
||||
/// routine to create a FindRegularByGlobal object that we can use as an input for worklets to call the function
|
||||
FindRegularByGlobal GetFindRegularByGlobal()
|
||||
{
|
||||
return FindRegularByGlobal(this->RegularNodeSortOrder, this->RegularNodeGlobalIds);
|
||||
}
|
||||
|
||||
/// routine to create a FindSuperArcForUnknownNode object that we can use as an input for worklets to call the function
|
||||
FindSuperArcForUnknownNode<FieldType> GetFindSuperArcForUnknownNode()
|
||||
{
|
||||
return FindSuperArcForUnknownNode<FieldType>(this->Superparents,
|
||||
this->Supernodes,
|
||||
this->Superarcs,
|
||||
this->Superchildren,
|
||||
this->WhichRound,
|
||||
this->WhichIteration,
|
||||
this->Hyperparents,
|
||||
this->Hypernodes,
|
||||
this->Hyperarcs,
|
||||
this->RegularNodeGlobalIds,
|
||||
this->DataValues);
|
||||
}
|
||||
|
||||
/// routine to initialize the hierarchical tree with the top level tree
|
||||
VTKM_CONT
|
||||
HierarchicalContourTree() {}
|
||||
void Initialize(vtkm::Id numRounds,
|
||||
vtkm::worklet::contourtree_augmented::ContourTree& tree,
|
||||
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>& mesh);
|
||||
|
||||
/// utility routines for the path probes
|
||||
std::string RegularString(const vtkm::Id regularId) const;
|
||||
std::string SuperString(const vtkm::Id superId) const;
|
||||
std::string HyperString(const vtkm::Id hyperId) const;
|
||||
|
||||
/// routine to probe a given node and trace it's hyperpath to the root
|
||||
std::string ProbeHyperPath(const vtkm::Id regularId, const vtkm::Id maxLength = -1) const;
|
||||
|
||||
/// routine to probe a given node and trace it's superpath to the root
|
||||
std::string ProbeSuperPath(const vtkm::Id regularId, const vtkm::Id maxLength = -1) const;
|
||||
|
||||
/// Outputs the Hierarchical Tree in Dot format for visualization
|
||||
std::string PrintDotSuperStructure(const char* label) const;
|
||||
|
||||
/// debug routine
|
||||
std::string DebugPrint(const char* message, const char* fileName, long lineNum) const;
|
||||
|
||||
private:
|
||||
/// Used internally to Invoke worklets
|
||||
vtkm::cont::Invoker Invoke;
|
||||
};
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
template <typename FieldType>
|
||||
HierarchicalContourTree<FieldType>::HierarchicalContourTree()
|
||||
{ // constructor
|
||||
NumRegularNodesInRound.ReleaseResources();
|
||||
NumSupernodesInRound.ReleaseResources();
|
||||
NumHypernodesInRound.ReleaseResources();
|
||||
NumIterations.ReleaseResources();
|
||||
} // constructor
|
||||
|
||||
|
||||
/// routine to initialize the hierarchical tree with the top level tree
|
||||
VTKM_CONT
|
||||
template <typename FieldType>
|
||||
void HierarchicalContourTree<FieldType>::Initialize(
|
||||
vtkm::Id numRounds,
|
||||
vtkm::worklet::contourtree_augmented::ContourTree& tree,
|
||||
vtkm::worklet::contourtree_augmented::ContourTreeMesh<FieldType>& mesh)
|
||||
{ // Initialize(..)
|
||||
// TODO: If any other arrays are only copied in this function but will not be modified then we could just assign instead of copy them and make them const
|
||||
// set the initial logical size of the arrays: note that we need to keep level 0 separate, so have an extra level at the top
|
||||
this->NumRounds = numRounds;
|
||||
{
|
||||
auto tempZeroArray = vtkm::cont::ArrayHandleConstant<vtkm::Id>(0, this->NumRounds + 1);
|
||||
vtkm::cont::Algorithm::Copy(tempZeroArray, this->NumIterations);
|
||||
vtkm::cont::Algorithm::Copy(tempZeroArray, this->NumRegularNodesInRound);
|
||||
this->NumRegularNodesInRound.WritePortal().Set(this->NumRounds, tree.Nodes.GetNumberOfValues());
|
||||
vtkm::cont::Algorithm::Copy(tempZeroArray, this->NumSupernodesInRound);
|
||||
this->NumSupernodesInRound.WritePortal().Set(this->NumRounds,
|
||||
tree.Supernodes.GetNumberOfValues());
|
||||
vtkm::cont::Algorithm::Copy(tempZeroArray, this->NumHypernodesInRound);
|
||||
this->NumHypernodesInRound.WritePortal().Set(this->NumRounds,
|
||||
tree.Hypernodes.GetNumberOfValues());
|
||||
}
|
||||
// copy the iterations of the top level hypersweep - this is +2: one because we are counting inclusively, the second because we need an
|
||||
// extra one at the end to compute sizes with deltas
|
||||
this->NumIterations.WritePortal().Set(this->NumRounds, tree.NumIterations);
|
||||
this->FirstSupernodePerIteration.resize(static_cast<std::size_t>(this->NumRounds + 1));
|
||||
this->FirstSupernodePerIteration[static_cast<std::size_t>(this->NumRounds)].Allocate(
|
||||
this->NumIterations.ReadPortal().Get(this->NumRounds) + 2);
|
||||
this->FirstHypernodePerIteration.resize(static_cast<std::size_t>(this->NumRounds + 1));
|
||||
this->FirstHypernodePerIteration[static_cast<std::size_t>(this->NumRounds)].Allocate(
|
||||
this->NumIterations.ReadPortal().Get(this->NumRounds) + 2);
|
||||
|
||||
// now copy in the details
|
||||
// TODO: These arrays are allocated above. Make sure Copy does not shrink the size of the array if it is allocated larger
|
||||
vtkm::cont::Algorithm::Copy(
|
||||
tree.FirstSupernodePerIteration,
|
||||
this->FirstSupernodePerIteration[static_cast<std::size_t>(this->NumRounds)]);
|
||||
vtkm::cont::Algorithm::Copy(
|
||||
tree.FirstHypernodePerIteration,
|
||||
this->FirstHypernodePerIteration[static_cast<std::size_t>(this->NumRounds)]);
|
||||
|
||||
// set the sizes for the arrays
|
||||
// vtkm::Id treeSize = tree.Superparents.GetNumberOfValues(); // TODO: defined in original code but seems to be unused
|
||||
this->RegularNodeGlobalIds.Allocate(tree.Nodes.GetNumberOfValues());
|
||||
this->DataValues.Allocate(mesh.SortedValues.GetNumberOfValues());
|
||||
this->RegularNodeSortOrder.Allocate(tree.Nodes.GetNumberOfValues());
|
||||
this->Superparents.Allocate(tree.Superparents.GetNumberOfValues());
|
||||
{
|
||||
auto tempNSE = vtkm::cont::ArrayHandleConstant<vtkm::Id>(
|
||||
vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT, tree.Nodes.GetNumberOfValues());
|
||||
vtkm::cont::Algorithm::Copy(tempNSE, this->Regular2Supernode);
|
||||
}
|
||||
|
||||
this->Supernodes.Allocate(tree.Supernodes.GetNumberOfValues());
|
||||
this->Superarcs.Allocate(tree.Superarcs.GetNumberOfValues());
|
||||
this->Hyperparents.Allocate(tree.Hyperparents.GetNumberOfValues());
|
||||
{
|
||||
auto tempNSE = vtkm::cont::ArrayHandleConstant<vtkm::Id>(
|
||||
vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT, tree.Supernodes.GetNumberOfValues());
|
||||
vtkm::cont::Algorithm::Copy(tempNSE, this->Super2Hypernode);
|
||||
}
|
||||
this->WhichRound.Allocate(tree.Supernodes.GetNumberOfValues());
|
||||
this->WhichIteration.Allocate(tree.Supernodes.GetNumberOfValues());
|
||||
|
||||
this->Hypernodes.Allocate(tree.Hypernodes.GetNumberOfValues());
|
||||
this->Hyperarcs.Allocate(tree.Hyperarcs.GetNumberOfValues());
|
||||
this->Superchildren.Allocate(tree.Hyperarcs.GetNumberOfValues());
|
||||
|
||||
//copy the regular nodes
|
||||
vtkm::cont::Algorithm::Copy(mesh.GlobalMeshIndex, this->RegularNodeGlobalIds);
|
||||
vtkm::cont::Algorithm::Copy(mesh.SortedValues, this->DataValues);
|
||||
|
||||
// we want to be able to search by global mesh index. That means we need to have an index array, sorted indirectly on globalMeshIndex
|
||||
vtkm::cont::Algorithm::Copy(
|
||||
vtkm::cont::ArrayHandleIndex(RegularNodeSortOrder.GetNumberOfValues()), RegularNodeSortOrder);
|
||||
vtkm::cont::Algorithm::Sort(RegularNodeSortOrder, PermuteComparator(this->RegularNodeGlobalIds));
|
||||
vtkm::cont::Algorithm::Copy(tree.Superparents, this->Superparents);
|
||||
|
||||
// copy in the supernodes
|
||||
vtkm::cont::Algorithm::Copy(tree.Supernodes, this->Supernodes);
|
||||
vtkm::cont::Algorithm::Copy(tree.Superarcs, this->Superarcs);
|
||||
vtkm::cont::Algorithm::Copy(tree.Hyperparents, this->Hyperparents);
|
||||
|
||||
vtkm::cont::Algorithm::Copy(
|
||||
vtkm::cont::ArrayHandleConstant<vtkm::Id>(numRounds, this->WhichRound.GetNumberOfValues()),
|
||||
this->WhichRound);
|
||||
vtkm::cont::Algorithm::Copy(tree.WhenTransferred, this->WhichIteration);
|
||||
|
||||
// now set the regular to supernode array up: it's already been set to NO_SUCH_ELEMENT
|
||||
{
|
||||
auto regular2SupernodePermuted =
|
||||
vtkm::cont::make_ArrayHandlePermutation(this->Supernodes, this->Regular2Supernode);
|
||||
vtkm::cont::Algorithm::Copy(vtkm::cont::ArrayHandleIndex(this->Supernodes.GetNumberOfValues()),
|
||||
regular2SupernodePermuted);
|
||||
}
|
||||
// copy in the hypernodes
|
||||
vtkm::cont::Algorithm::Copy(tree.Hypernodes, this->Hypernodes);
|
||||
vtkm::cont::Algorithm::Copy(tree.Hyperarcs, this->Hyperarcs);
|
||||
|
||||
// now set the supernode to hypernode array up: it's already been set to NO_SUCH_ELEMENT
|
||||
{
|
||||
auto super2HypernodePermuted =
|
||||
vtkm::cont::make_ArrayHandlePermutation(this->Hypernodes, this->Super2Hypernode);
|
||||
vtkm::cont::Algorithm::Copy(vtkm::cont::ArrayHandleIndex(this->Hypernodes.GetNumberOfValues()),
|
||||
super2HypernodePermuted);
|
||||
}
|
||||
{
|
||||
auto initalizeSuperchildrenWorklet = InitalizeSuperchildrenWorklet();
|
||||
this->Invoke(initalizeSuperchildrenWorklet,
|
||||
this->Hyperarcs, // Input
|
||||
this->Hypernodes, // Input
|
||||
this->Superchildren // Output
|
||||
);
|
||||
}
|
||||
} // Initialize(..)
|
||||
|
||||
|
||||
/// utility routine for the path probes
|
||||
VTKM_CONT
|
||||
template <typename FieldType>
|
||||
std::string HierarchicalContourTree<FieldType>::RegularString(const vtkm::Id regularId) const
|
||||
{ // RegularString()
|
||||
std::stringstream resultStream;
|
||||
// this can get called before the regular ID is fully stored
|
||||
if (regularId >= this->DataValues.GetNumberOfValues())
|
||||
{
|
||||
resultStream << "Regular ID: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(regularId, resultStream);
|
||||
resultStream << " Value: N/A Global ID: N/A Regular ID: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(regularId, resultStream);
|
||||
resultStream << " SNode ID: N/A Superparent: N/A";
|
||||
}
|
||||
else
|
||||
{
|
||||
resultStream << "Regular ID: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(regularId, resultStream);
|
||||
resultStream << " Value: " << this->DataValues.ReadPortal.Get(regularId);
|
||||
resultStream << " Global ID: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(
|
||||
this->RegularNodeGlobalIds.ReadPortal().Get(regularId), resultStream);
|
||||
resultStream << " Regular ID: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(regularId, resultStream);
|
||||
resultStream << " SNode ID: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(
|
||||
this->Regular2Supernode.ReadPortal().Get(regularId), resultStream);
|
||||
resultStream << "Superparents: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(
|
||||
this->Superparents.ReadPortal().Get(regularId));
|
||||
}
|
||||
return resultStream.str();
|
||||
} // RegularString()
|
||||
|
||||
|
||||
/// utility routine for the path probes
|
||||
VTKM_CONT
|
||||
template <typename FieldType>
|
||||
std::string HierarchicalContourTree<FieldType>::SuperString(const vtkm::Id superId) const
|
||||
{ // SuperString()
|
||||
std::stringstream resultStream;
|
||||
if (vtkm::worklet::contourtree_augmented::NoSuchElement(superId))
|
||||
{
|
||||
resultStream << "Super ID: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(superId, resultStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultStream << "Super ID: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(superId, resultStream);
|
||||
resultStream << " Value: "
|
||||
<< this->DataValues.ReadPortal.Get(this->Supernodes.ReadPortal().Get(
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(superId)));
|
||||
resultStream << " Global ID: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(
|
||||
this->RegularNodeGlobalIds.ReadPortal().Get(this->Supernodes.ReadPortal().Get(
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(superId))),
|
||||
resultStream);
|
||||
resultStream << " Regular Id: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(
|
||||
this->Supernodes.ReadPortal(vtkm::worklet::contourtree_augmented::MaskedIndex(superId)),
|
||||
resultStream);
|
||||
resultStream << " Superarc: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(
|
||||
this->Superarcs.ReadPortal(vtkm::worklet::contourtree_augmented::MaskedIndex(superId)),
|
||||
resultStream);
|
||||
resultStream << " HNode ID: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(
|
||||
this->Super2Hypernode.ReadPortal(vtkm::worklet::contourtree_augmented::MaskedIndex(superId)),
|
||||
resultStream);
|
||||
resultStream << " Hyperparent: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(
|
||||
this->Hyperparents.ReadPortal(vtkm::worklet::contourtree_augmented::MaskedIndex(superId)),
|
||||
resultStream);
|
||||
resultStream << " Round: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(
|
||||
this->WhichRound.ReadPortal(vtkm::worklet::contourtree_augmented::MaskedIndex(superId)),
|
||||
resultStream);
|
||||
resultStream << " Iteration: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(
|
||||
this->WhichIteration.ReadPortal(vtkm::worklet::contourtree_augmented::MaskedIndex(superId)),
|
||||
resultStream);
|
||||
}
|
||||
return resultStream.str();
|
||||
} // SuperString()
|
||||
|
||||
|
||||
/// utility routine for the path probes
|
||||
VTKM_CONT
|
||||
template <typename FieldType>
|
||||
std::string HierarchicalContourTree<FieldType>::HyperString(const vtkm::Id hyperId) const
|
||||
{ // HyperString()
|
||||
std::stringstream resultStream;
|
||||
if (vtkm::worklet::contourtree_augmented::NoSuchElement(hyperId))
|
||||
{
|
||||
resultStream << "Hyper ID: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(hyperId, resultStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultStream << "Hyper Id: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(hyperId, resultStream);
|
||||
resultStream << " Value: "
|
||||
<< this->DataValues.ReadPortal.Get(
|
||||
this->Supernodes.ReadPortal().Get(this->Hypernodes.ReadPortal.Get(
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(hyperId))));
|
||||
resultStream << " Global ID: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(
|
||||
this->RegularNodeGlobalIds.ReadPortal().Get(
|
||||
this->Supernodes.ReadPortal().Get(this->Hypernodes.ReadPortal.Get(
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(hyperId)))),
|
||||
resultStream);
|
||||
resultStream << " Regular ID: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(
|
||||
this->Supernodes.ReadPortal().Get(this->Hypernodes.ReadPortal.Get(
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(hyperId))),
|
||||
resultStream);
|
||||
resultStream << " Super ID: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(
|
||||
this->Hypernodes.ReadPortal.Get(vtkm::worklet::contourtree_augmented::MaskedIndex(hyperId)),
|
||||
resultStream);
|
||||
resultStream << " Hyperarc: ";
|
||||
vtkm::worklet::contourtree_augmented::PrintIndexType(
|
||||
this->Hyperarcs.ReadPortal.Get(vtkm::worklet::contourtree_augmented::MaskedIndex(hyperId)),
|
||||
resultStream);
|
||||
resultStream << " Superchildren: "
|
||||
<< this->Superchildren.ReadPortal().Get(
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(hyperId));
|
||||
}
|
||||
return resultStream.str();
|
||||
} // HyperString()
|
||||
|
||||
/// routine to probe a given node and trace it's hyperpath to the root
|
||||
VTKM_CONT
|
||||
template <typename FieldType>
|
||||
std::string HierarchicalContourTree<FieldType>::ProbeHyperPath(const vtkm::Id regularId,
|
||||
const vtkm::Id maxLength) const
|
||||
{ // ProbeHyperPath()
|
||||
std::stringstream resultStream;
|
||||
resultStream << "Probing HyperPath\n";
|
||||
resultStream << "Node: " << this->RegularString(regularId) << std::endl;
|
||||
|
||||
// find the superparent
|
||||
vtkm::Id superparent = this->Superparents.ReadPortal().Get(regularId);
|
||||
resultStream << "Superparent: " << SuperString(superparent) << std::endl;
|
||||
|
||||
// and the hyperparent
|
||||
vtkm::Id hyperparent = this->Hyperparents.ReadPortal().Get(superparent);
|
||||
|
||||
// now trace the path inwards: terminate on last round when we have null hyperarc
|
||||
vtkm::Id length = 0;
|
||||
while (true)
|
||||
{ // loop inwards
|
||||
length++;
|
||||
if (length > maxLength && maxLength > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
resultStream << "Hyperparent: " << this->HyperString(hyperparent) << std::endl;
|
||||
|
||||
// retrieve the target of the hyperarc
|
||||
vtkm::Id hypertarget = this->Hyperarcs.ReadPortal().Get(hyperparent);
|
||||
|
||||
resultStream << "Hypertarget: "
|
||||
<< SuperString(vtkm::worklet::contourtree_augmented::MaskedIndex(hypertarget))
|
||||
<< std::endl;
|
||||
|
||||
// mask the hypertarget
|
||||
vtkm::Id maskedHypertarget = vtkm::worklet::contourtree_augmented::MaskedIndex(hypertarget);
|
||||
|
||||
// test for null superarc: can only be root or attachment point
|
||||
if (vtkm::worklet::contourtree_augmented::NoSuchElement(hypertarget))
|
||||
{ // root or attachment point
|
||||
// we're done
|
||||
break;
|
||||
} // root or attachment point
|
||||
else
|
||||
{ // ordinary supernode
|
||||
hyperparent = this->Hyperparents.ReadPortal().Get(maskedHypertarget);
|
||||
} // ordinary supernode
|
||||
|
||||
// now take the new superparent's hyperparent/hypertarget
|
||||
hypertarget = this->Hyperarcs.ReadPortal().Get(hyperparent);
|
||||
} // loop inwards
|
||||
|
||||
resultStream << "Probe Complete" << std::endl << std::endl;
|
||||
return resultStream.str();
|
||||
} // ProbeHyperPath()
|
||||
|
||||
|
||||
|
||||
|
||||
/// routine to probe a given node and trace it's superpath to the root
|
||||
VTKM_CONT
|
||||
template <typename FieldType>
|
||||
std::string HierarchicalContourTree<FieldType>::ProbeSuperPath(const vtkm::Id regularId,
|
||||
const vtkm::Id maxLength) const
|
||||
{
|
||||
std::stringstream resultStream;
|
||||
// find the superparent
|
||||
vtkm::Id superparent = this->Superparents.ReadPortal.Get(regularId);
|
||||
auto superarcsPortal = this->Superarcs.ReadPortal();
|
||||
auto whichRoundPortal = this->WhichRound.ReadPortal();
|
||||
// now trace the path inwards: terminate on last round when we have null hyperarc
|
||||
vtkm::Id length = 0;
|
||||
while (true)
|
||||
{ // loop inwards
|
||||
length++;
|
||||
if (length > maxLength && maxLength > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// retrieve the target of the superarc
|
||||
vtkm::Id supertarget = superarcsPortal.Get(superparent);
|
||||
|
||||
resultStream << "Superparent: " << this->SuperString(superparent) << std::endl;
|
||||
resultStream << "Supertarget: "
|
||||
<< this->SuperString(
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(supertarget))
|
||||
<< std::endl;
|
||||
|
||||
// mask the supertarget
|
||||
vtkm::Id maskedSupertarget = vtkm::worklet::contourtree_augmented::MaskedIndex(supertarget);
|
||||
// and retrieve it's supertarget
|
||||
vtkm::Id nextSupertarget = superarcsPortal.Get(maskedSupertarget);
|
||||
vtkm::Id maskedNextSupertarget =
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(nextSupertarget);
|
||||
resultStream << "Next target: " << this->SuperString(nextSupertarget) << std::endl;
|
||||
|
||||
// test for null superarc: can only be root or attachment point
|
||||
if (vtkm::worklet::contourtree_augmented::NoSuchElement(nextSupertarget))
|
||||
{ // root or attachment point
|
||||
// test round: if it's the last one, only the root has a null edge
|
||||
if (whichRoundPortal.Get(maskedNextSupertarget) == this->NumRounds)
|
||||
// we're done
|
||||
break;
|
||||
else // attachment point
|
||||
superparent = maskedNextSupertarget;
|
||||
} // root or attachment point
|
||||
else
|
||||
{ // ordinary supernode
|
||||
superparent = maskedSupertarget;
|
||||
} // ordinary supernode
|
||||
} // loop inwards
|
||||
|
||||
resultStream << "Probe Complete" << std::endl << std::endl;
|
||||
return resultStream.str();
|
||||
}
|
||||
|
||||
/// Outputs the Hierarchical Tree in Dot format for visualization
|
||||
VTKM_CONT
|
||||
template <typename FieldType>
|
||||
std::string HierarchicalContourTree<FieldType>::PrintDotSuperStructure(const char* label) const
|
||||
{ // PrintDotSuperStructure
|
||||
// make a copy of the label
|
||||
std::string filename("temp/");
|
||||
filename += label;
|
||||
|
||||
// replace spaces with underscores
|
||||
for (unsigned int strChar = 0; strChar < filename.length(); strChar++)
|
||||
if (filename[strChar] == ' ')
|
||||
filename[strChar] = '_';
|
||||
|
||||
// add the .gv suffix
|
||||
filename += ".gv";
|
||||
|
||||
// generate an output stream
|
||||
std::ofstream outstream(filename);
|
||||
|
||||
// print the header information
|
||||
outstream << "digraph RegularTree\n\t{\n";
|
||||
outstream << "\tsize=\"6.5, 9\"\n\tratio=\"fill\"\n";
|
||||
outstream << "\tlabel=\"" << label << "\"\n\tlabelloc=t\n\tfontsize=30\n";
|
||||
|
||||
// create the NULL (root) node
|
||||
outstream << "\t// NULL node to use as a root for the tree\n";
|
||||
outstream << "\tNULL [style=filled,fillcolor=white,shape=point,label=\"NULL\"];\n";
|
||||
|
||||
outstream << "\t// Supernodes\n";
|
||||
// loop through all supernodes
|
||||
for (vtkm::Id supernode = 0; supernode < this->Supernodes.GetNumberOfValues; supernode++)
|
||||
{ // per supernode
|
||||
vtkm::Id regularID = this->Supernodes[supernode];
|
||||
// print the supernode, making hypernodes double octagons
|
||||
outstream
|
||||
<< " SN" << std::setw(1) << supernode
|
||||
<< " [style=filled,fillcolor=white,shape=" << std::setw(1)
|
||||
<< ((this->Hypernodes[this->Hyperparents[supernode]] == supernode)
|
||||
? "doublecircle"
|
||||
: "circle") // hypernodes are double-circles
|
||||
<< ",label=\"sn" << std::setw(4) << supernode << " h" << std::setw(1)
|
||||
<< ((this->Hypernodes[this->Hyperparents[supernode]] == supernode)
|
||||
? "n"
|
||||
: "p") // hypernodes show "hn001" (their own ID), supernodes show "hp001" (their hyperparent)
|
||||
<< std::setw(4) << this->Hyperparents[supernode] << "\\nm" << std::setw(1) << regularID
|
||||
<< " g" << std::setw(4) << this->RegularNodeGlobalIDs[regularID] << "\\nrd" << std::setw(1)
|
||||
<< this->WhichRound[supernode] << " it" << std::setw(4)
|
||||
<< contourtree_augmented::MaskedIndex(this->WhichIteration[supernode]) << "\"];\n";
|
||||
} // per supernode
|
||||
|
||||
outstream << "\t// Superarc nodes\n";
|
||||
// now repeat to create nodes for the middle of each superarc (to represent the superarcs themselves)
|
||||
for (vtkm::Id superarc = 0; superarc < this->Superarcs.GetNumberOfValues; superarc++)
|
||||
{ // per superarc
|
||||
// print the superarc vertex
|
||||
outstream
|
||||
<< "\tSA" << std::setw(1) << superarc
|
||||
<< " [shape=circle,fillcolor=white,fixedsize=true,height=0.5,width=0.5,label=\"\"];\n";
|
||||
} // per superarc
|
||||
|
||||
outstream << "\t// Superarc edges\n";
|
||||
// loop through all superarcs to draw them
|
||||
for (vtkm::Id superarc = 0; superarc < this->Superarcs.GetNumberOfValues; superarc++)
|
||||
{ // per superarc
|
||||
// retrieve ID of target supernode
|
||||
vtkm::Id superarcFrom = superarc;
|
||||
vtkm::Id superarcTo = this->Superarcs[superarcFrom];
|
||||
|
||||
// if this is true, it may be the last pruned vertex
|
||||
if (contourtree_augmented::NoSuchElement(superarcTo))
|
||||
{ // no superarc
|
||||
// if it occurred on the final round, it's the global root and is shown as the NULL node
|
||||
if (this->WhichRound[superarcFrom] == this->NRounds)
|
||||
{ // root node
|
||||
outstream << "\tSN" << std::setw(1) << superarcFrom << " -> SA" << std::setw(1) << superarc
|
||||
<< " [label=\"S" << std::setw(1) << superarc << "\",style=dotted]\n";
|
||||
outstream << "\tSN" << std::setw(1) << superarc << " -> NULL[label=\"S" << std::setw(1)
|
||||
<< superarc << "\",style=dotted]\n";
|
||||
} // root node
|
||||
else
|
||||
{ // attachment point
|
||||
// otherwise, the target is actually a superarc vertex not a supernode vertex
|
||||
// so we use the regular ID to retrieve the superparent which tells us which superarc we insert into
|
||||
vtkm::Id regularFrom = this->Supernodes[superarcFrom];
|
||||
superarcTo = this->Superparents[regularFrom];
|
||||
|
||||
// output a suitable edge
|
||||
outstream << "\tSN" << std::setw(1) << superarcFrom << " -> SA" << std::setw(1)
|
||||
<< superarcTo << "[label=\"S" << std::setw(1) << superarc << "\",style=dotted]\n";
|
||||
} // attachment point
|
||||
} // no superarc
|
||||
|
||||
else
|
||||
{ // there is a superarc
|
||||
// retrieve the ascending flag
|
||||
bool ascendingSuperarc = contourtree_augmented::IsAscending(superarcTo);
|
||||
|
||||
// strip out the flags
|
||||
superarcTo = contourtree_augmented::MaskedIndex(superarcTo);
|
||||
|
||||
// how we print depends on whether the superarc ascends
|
||||
outstream << "\tSN" << std::setw(1) << (ascendingSuperarc ? superarcTo : superarcFrom)
|
||||
<< " -> SA" << std::setw(1) << superarc << " [label=\"S" << std::setw(1) << superarc
|
||||
<< "\"" << (ascendingSuperarc ? ",dir=\"back\"" : "") << ",arrowhead=\"none\"]\n";
|
||||
outstream << "\tSA" << std::setw(1) << superarc << " -> SN" << std::setw(1)
|
||||
<< (ascendingSuperarc ? superarcFrom : superarcTo) << " [label=\"S" << std::setw(1)
|
||||
<< superarc << "\"" << (ascendingSuperarc ? ",dir=\"back\"" : "")
|
||||
<< ",arrowhead=\"none\"]\n";
|
||||
} // there is a superarc
|
||||
} // per superarc
|
||||
|
||||
outstream << "\t// Hyperarcs\n";
|
||||
// now loop through the hyperarcs to draw them
|
||||
for (vtkm::Id hyperarc = 0; hyperarc < this->Hyperarcs.GetNumberOfValues; hyperarc++)
|
||||
{ // per hyperarc
|
||||
// retrieve ID of target hypernode
|
||||
vtkm::Id hyperarcFrom = this->Hypernodes[hyperarc];
|
||||
vtkm::Id hyperarcTo = this->Hyperarcs[hyperarc];
|
||||
|
||||
// if this is true, it is the last pruned vertex & needs a hyperarc to the root
|
||||
if (contourtree_augmented::NoSuchElement(hyperarcTo))
|
||||
outstream << "\tSN" << std::setw(1) << hyperarcFrom << " -> NULL[label=\"H" << std::setw(1)
|
||||
<< hyperarc << "\",penwidth=5.0,style=dotted]\n";
|
||||
else
|
||||
{ // not the last one
|
||||
// otherwise, retrieve the ascending flag
|
||||
bool ascendingHyperarc = contourtree_augmented::IsAscending(hyperarcTo);
|
||||
|
||||
// strip out the flags
|
||||
hyperarcTo = contourtree_augmented::MaskedIndex(hyperarcTo);
|
||||
|
||||
// how we print depends on whether the hyperarc ascends
|
||||
outstream << "\tSN" << std::setw(1) << (ascendingHyperarc ? hyperarcTo : hyperarcFrom)
|
||||
<< " -> SN" << std::setw(1) << (ascendingHyperarc ? hyperarcFrom : hyperarcTo)
|
||||
<< "[label=\"H" << std::setw(1) << hyperarc << "\",penwidth=5.0,dir=\"back\"]\n";
|
||||
} // not the last one
|
||||
} // per hyperarc
|
||||
|
||||
// print the footer information
|
||||
outstream << "\t}\n";
|
||||
|
||||
return std::string("HierarchicalContourTree<FieldType>::PrintDotSuperStructure() Complete");
|
||||
} // PrintDotSuperStructure
|
||||
|
||||
/// debug routine
|
||||
VTKM_CONT
|
||||
template <typename FieldType>
|
||||
std::string HierarchicalContourTree<FieldType>::DebugPrint(const char* message,
|
||||
const char* fileName,
|
||||
long lineNum) const
|
||||
{
|
||||
std::stringstream resultStream;
|
||||
resultStream << std::endl;
|
||||
resultStream << "[CUTHERE]-------------------------------" << std::endl;
|
||||
resultStream << std::setw(30) << std::left << fileName << ":" << std::right << std::setw(4)
|
||||
<< lineNum << std::endl;
|
||||
resultStream << std::left << std::string(message) << std::endl;
|
||||
resultStream << "Hierarchical Contour Tree Contains: " << std::endl;
|
||||
resultStream << "----------------------------------------" << std::endl;
|
||||
resultStream << std::endl;
|
||||
|
||||
vtkm::worklet::contourtree_augmented::PrintHeader(this->RegularNodeGlobalIds.GetNumberOfValues(),
|
||||
resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"Regular Nodes (global ID)", this->RegularNodeGlobalIds, -1, resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintValues(
|
||||
"Data Values", this->DataValues, -1, resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"Regular Node Sort Order", this->RegularNodeSortOrder, -1, resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"Superparents (unsorted)", this->Superparents, -1, resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"Supernode ID (if any)", this->Regular2Supernode, -1, resultStream);
|
||||
resultStream << std::endl;
|
||||
vtkm::worklet::contourtree_augmented::PrintHeader(this->Supernodes.GetNumberOfValues(),
|
||||
resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"Supernodes (regular index)", this->Supernodes, -1, resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"Superarcs (supernode index)", this->Superarcs, -1, resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"Hyperparents (hypernode index)", this->Hyperparents, -1, resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"Hypernode ID (if any)", this->Super2Hypernode, -1, resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"Which Round", this->WhichRound, -1, resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"Which Iteration", this->WhichIteration, -1, resultStream);
|
||||
resultStream << std::endl;
|
||||
vtkm::worklet::contourtree_augmented::PrintHeader(this->Hypernodes.GetNumberOfValues(),
|
||||
resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"Hypernodes (supernode index)", this->Hypernodes, -1, resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"Hyperarcs (supernode index)", this->Hyperarcs, -1, resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"Superchildren", this->Superchildren, -1, resultStream);
|
||||
resultStream << std::endl;
|
||||
resultStream << "nRounds: " << this->NumRounds << std::endl;
|
||||
vtkm::worklet::contourtree_augmented::PrintHeader(
|
||||
this->NumRegularNodesInRound.GetNumberOfValues(), resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"nRegular Nodes In Round", this->NumRegularNodesInRound, -1, resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"nSupernodes In Round", this->NumSupernodesInRound, -1, resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"nHypernodes In Round", this->NumHypernodesInRound, -1, resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintHeader(this->NumIterations.GetNumberOfValues(),
|
||||
resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"nIterations", this->NumIterations, -1, resultStream);
|
||||
for (vtkm::Id whichRound = 0; whichRound < this->NumIterations.GetNumberOfValues(); whichRound++)
|
||||
{ // per round
|
||||
resultStream << "Round " << whichRound << std::endl;
|
||||
vtkm::worklet::contourtree_augmented::PrintHeader(
|
||||
this->FirstSupernodePerIteration[static_cast<std::size_t>(whichRound)].GetNumberOfValues(),
|
||||
resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"First Supernode Per Iteration",
|
||||
this->FirstSupernodePerIteration[static_cast<std::size_t>(whichRound)],
|
||||
-1,
|
||||
resultStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"First Hypernode Per Iteration",
|
||||
this->FirstHypernodePerIteration[static_cast<std::size_t>(whichRound)],
|
||||
-1,
|
||||
resultStream);
|
||||
resultStream << std::endl;
|
||||
} // per round
|
||||
return resultStream.str();
|
||||
}
|
||||
|
||||
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
|
151
vtkm/worklet/contourtree_distributed/InteriorForest.h
Normal file
151
vtkm/worklet/contourtree_distributed/InteriorForest.h
Normal file
@ -0,0 +1,151 @@
|
||||
//============================================================================
|
||||
// Copyright (c) Kitware, Inc.
|
||||
// All rights reserved.
|
||||
// See LICENSE.txt for details.
|
||||
//
|
||||
// This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the above copyright notice for more information.
|
||||
//============================================================================
|
||||
// Copyright (c) 2018, The Regents of the University of California, through
|
||||
// Lawrence Berkeley National Laboratory (subject to receipt of any required approvals
|
||||
// from the U.S. Dept. of Energy). All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// (1) Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// (2) Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// (3) Neither the name of the University of California, Lawrence Berkeley National
|
||||
// Laboratory, U.S. Dept. of Energy nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without
|
||||
// specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//================================================================================
|
||||
//
|
||||
// Parallel Peak Pruning v. 2.0
|
||||
//
|
||||
// Started June 15, 2017
|
||||
//
|
||||
// Copyright Hamish Carr, University of Leeds
|
||||
//
|
||||
// TreeResidue.h - A data structure storing the residue information for transfer
|
||||
// to the grafting phase
|
||||
//
|
||||
//================================================================================
|
||||
//
|
||||
// COMMENTS:
|
||||
//
|
||||
//
|
||||
//================================================================================
|
||||
|
||||
|
||||
#ifndef vtk_m_worklet_contourtree_distributed_interior_forest_h
|
||||
#define vtk_m_worklet_contourtree_distributed_interior_forest_h
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/PrintVectors.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
|
||||
/// \brief The contour tree of a data block restricted to the interior of a data block
|
||||
///
|
||||
/// The Boundary Restricted Augemented Contour Tree (BRACT) represents the contours
|
||||
/// that cross the boundary of a data block. In contrast, this class represents all contours
|
||||
/// that remain in the interior. Alternatively, the interior tree can be interpreted as the
|
||||
/// residue (i.e., the part that are left over) from removing the BRACT from the full contour tree.
|
||||
/// of a data block
|
||||
class InteriorForest
|
||||
{ // class InteriorForest
|
||||
public:
|
||||
// array of vertices in the bract (by mesh index)
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType BractMeshIndices;
|
||||
|
||||
// array of flags for whether necessary (i.e. needed in the BRACT)
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType IsNecessary;
|
||||
|
||||
// arrays of nodes above and below supernodes for hierarchical search
|
||||
// stored as global IDs
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Above;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Below;
|
||||
|
||||
// constructor
|
||||
InteriorForest() {}
|
||||
|
||||
// prints the contents of the object in a standard format
|
||||
void PrintContent(std::ostream& outStream) const;
|
||||
std::string DebugPrint(const char* message, const char* fileName, long lineNum) const;
|
||||
};
|
||||
|
||||
|
||||
// debug routine
|
||||
inline void InteriorForest::PrintContent(std::ostream& outStream) const
|
||||
{
|
||||
// Per Supernode Arrays
|
||||
vtkm::worklet::contourtree_augmented::PrintHeader(this->IsNecessary.GetNumberOfValues(),
|
||||
outStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"IsNecessary", this->IsNecessary, -1, outStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices("Above", this->Above, -1, outStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices("Below", this->Below, -1, outStream);
|
||||
|
||||
// BRACT Sized Arrays
|
||||
vtkm::worklet::contourtree_augmented::PrintHeader(this->BractMeshIndices.GetNumberOfValues(),
|
||||
outStream);
|
||||
vtkm::worklet::contourtree_augmented::PrintIndices(
|
||||
"BRACT Mesh Indices", this->BractMeshIndices, -1, outStream);
|
||||
}
|
||||
|
||||
inline std::string InteriorForest::DebugPrint(const char* message,
|
||||
const char* fileName,
|
||||
long lineNum) const
|
||||
{ // DebugPrint
|
||||
std::stringstream resultStream;
|
||||
resultStream << "[CUTHERE]---------------------------------------------" << std::endl;
|
||||
resultStream << std::setw(30) << std::left << fileName << ":" << std::right << std::setw(4)
|
||||
<< lineNum << " ";
|
||||
resultStream << std::left << std::string(message) << std::endl;
|
||||
|
||||
resultStream << "------------------------------------------------------" << std::endl;
|
||||
resultStream << "Residue Contains: " << std::endl;
|
||||
resultStream << "------------------------------------------------------" << std::endl;
|
||||
|
||||
this->PrintContent(resultStream);
|
||||
|
||||
resultStream << "------------------------------------------------------" << std::endl;
|
||||
resultStream << std::endl;
|
||||
return resultStream.str();
|
||||
} // DebugPrint
|
||||
|
||||
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -66,7 +66,6 @@
|
||||
#include <vtkm/cont/PartitionedDataSet.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/data_set_mesh/IdRelabeler.h>
|
||||
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
@ -98,6 +97,7 @@ public:
|
||||
VTKM_CONT
|
||||
~MultiBlockContourTreeHelper(void)
|
||||
{
|
||||
// FIXME: This shouldn't be necessary as arrays will get deleted anyway
|
||||
LocalContourTrees.clear();
|
||||
LocalSortOrders.clear();
|
||||
}
|
||||
@ -201,7 +201,6 @@ public:
|
||||
SpatialDecomposition MultiBlockSpatialDecomposition;
|
||||
std::vector<vtkm::worklet::contourtree_augmented::ContourTree> LocalContourTrees;
|
||||
std::vector<vtkm::worklet::contourtree_augmented::IdArrayType> LocalSortOrders;
|
||||
|
||||
}; // end MultiBlockContourTreeHelper
|
||||
|
||||
} // namespace contourtree_distributed
|
||||
|
1440
vtkm/worklet/contourtree_distributed/PrintGraph.h
Normal file
1440
vtkm/worklet/contourtree_distributed/PrintGraph.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -54,6 +54,11 @@
|
||||
#define vtk_m_worklet_contourtree_distributed_spatialdecomposition_h
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/cont/BoundsCompute.h>
|
||||
#include <vtkm/cont/BoundsGlobalCompute.h>
|
||||
#include <vtkm/cont/EnvironmentTracker.h>
|
||||
#include <vtkm/cont/PartitionedDataSet.h>
|
||||
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
// clang-format off
|
||||
@ -91,8 +96,7 @@ public:
|
||||
{
|
||||
if (this->NumberOfDimensions() == 2)
|
||||
{
|
||||
// may need to change back when porting ot later verison of VTKM/vtkmdiy
|
||||
vtkmdiy::DiscreteBounds domain(0); //(2);
|
||||
vtkmdiy::DiscreteBounds domain(2);
|
||||
domain.min[0] = domain.min[1] = 0;
|
||||
domain.max[0] = static_cast<int>(this->GlobalSize[0]);
|
||||
domain.max[1] = static_cast<int>(this->GlobalSize[1]);
|
||||
@ -100,8 +104,7 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
// may need to change back when porting to later version of VTMK/vtkmdiy
|
||||
vtkmdiy::DiscreteBounds domain(0); //(3);
|
||||
vtkmdiy::DiscreteBounds domain(3);
|
||||
domain.min[0] = domain.min[1] = domain.min[2] = 0;
|
||||
domain.max[0] = static_cast<int>(this->GlobalSize[0]);
|
||||
domain.max[1] = static_cast<int>(this->GlobalSize[1]);
|
||||
@ -119,6 +122,33 @@ public:
|
||||
|
||||
inline vtkm::Id GetLocalNumberOfBlocks() const { return LocalBlockSizes.GetNumberOfValues(); }
|
||||
|
||||
inline static vtkm::Bounds GetGlobalBounds(const vtkm::cont::PartitionedDataSet& input)
|
||||
{
|
||||
// Get the spatial bounds of a multi -block data set
|
||||
vtkm::Bounds bounds = vtkm::cont::BoundsGlobalCompute(input);
|
||||
return bounds;
|
||||
}
|
||||
|
||||
inline static vtkm::Bounds GetLocalBounds(const vtkm::cont::PartitionedDataSet& input)
|
||||
{
|
||||
// Get the spatial bounds of a multi -block data set
|
||||
vtkm::Bounds bounds = vtkm::cont::BoundsCompute(input);
|
||||
return bounds;
|
||||
}
|
||||
|
||||
inline static vtkm::Id GetGlobalNumberOfBlocks(const vtkm::cont::PartitionedDataSet& input)
|
||||
{
|
||||
auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator();
|
||||
vtkm::Id localSize = input.GetNumberOfPartitions();
|
||||
vtkm::Id globalSize = 0;
|
||||
#ifdef VTKM_ENABLE_MPI
|
||||
vtkmdiy::mpi::all_reduce(comm, localSize, globalSize, std::plus<vtkm::Id>{});
|
||||
#else
|
||||
globalSize = localSize;
|
||||
#endif
|
||||
return globalSize;
|
||||
}
|
||||
|
||||
// Number of blocks along each dimension
|
||||
vtkm::Id3 BlocksPerDimension;
|
||||
// Size of the global mesh
|
||||
|
1536
vtkm/worklet/contourtree_distributed/TreeGrafter.h
Normal file
1536
vtkm/worklet/contourtree_distributed/TreeGrafter.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -84,7 +84,7 @@ public:
|
||||
VTKM_EXEC void operator()(const vtkm::Id& returnIndex,
|
||||
const vtkm::Id& newVertexIdValue,
|
||||
const OutFieldPortalType& upNeighbourPortal,
|
||||
const OutFieldPortalType& downNeighbourPortal)
|
||||
const OutFieldPortalType& downNeighbourPortal) const
|
||||
{
|
||||
// per vertex
|
||||
// necessary vertices
|
@ -95,7 +95,7 @@ public:
|
||||
const vtkm::Id boundaryNecessaryId,
|
||||
const InFieldPortalType meshSortOrderPortal,
|
||||
const OutFieldPortalType& boundaryIndicesPortal,
|
||||
const OutFieldPortalType& bractVertexSupersetPortal)
|
||||
const OutFieldPortalType& bractVertexSupersetPortal) const
|
||||
{
|
||||
// per supernode
|
||||
if (isNecessaryAndInterior)
|
@ -89,7 +89,7 @@ public:
|
||||
VTKM_EXEC void operator()(const vtkm::Id& boundaryVertexSortID,
|
||||
const InFieldPortalType& superparentsPortal,
|
||||
const InFieldPortalType& supernodesPortal,
|
||||
const OutFieldPortalType& isNecessaryAndInteriorPortal)
|
||||
const OutFieldPortalType& isNecessaryAndInteriorPortal) const
|
||||
{
|
||||
vtkm::Id superparent = superparentsPortal.Get(boundaryVertexSortID);
|
||||
// if the superparent's supernode is the vertex, they match
|
@ -54,9 +54,11 @@
|
||||
#define vtk_m_worklet_contourtree_distributed_bract_maker_bract_node_comparator_h
|
||||
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ArrayHandleVirtual.h>
|
||||
#include <vtkm/cont/ExecutionObjectBase.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
@ -67,18 +69,20 @@ namespace bract_maker
|
||||
{
|
||||
|
||||
|
||||
// device implementation of the comparator used for sorting hyperarcs
|
||||
/// device implementation of the comparator used for sorting hyperarcs
|
||||
template <typename DeviceAdapter>
|
||||
class BRACTNodeComparatorImpl
|
||||
{
|
||||
public:
|
||||
using IdArrayPortalType =
|
||||
typename vtkm::cont::ArrayHandle<vtkm::Id>::template ExecutionTypes<DeviceAdapter>::PortalConst;
|
||||
|
||||
/// The ContourTreeMesh uses a smart ArrayHandleIndex instead of a regular IdArrayType array that is why we use a ArrayHandleVirtual here
|
||||
using SortIndexPortalType = typename vtkm::cont::ArrayHandleVirtual<
|
||||
vtkm::Id>::template ExecutionTypes<DeviceAdapter>::PortalConst;
|
||||
// constructor - takes vectors as parameters
|
||||
VTKM_CONT
|
||||
BRACTNodeComparatorImpl(const IdArrayPortalType& regularIdPortal,
|
||||
const IdArrayPortalType& meshSortIndexPortal)
|
||||
const SortIndexPortalType& meshSortIndexPortal)
|
||||
: RegularIdPortal(regularIdPortal)
|
||||
, MeshSortIndexPortal(meshSortIndexPortal)
|
||||
{ // constructor
|
||||
@ -109,7 +113,7 @@ public:
|
||||
|
||||
private:
|
||||
IdArrayPortalType RegularIdPortal;
|
||||
IdArrayPortalType MeshSortIndexPortal;
|
||||
SortIndexPortalType MeshSortIndexPortal;
|
||||
}; // BRACTNodeComparatorImpl
|
||||
|
||||
/// comparator used to compare hyperarcs for sort
|
||||
@ -119,7 +123,7 @@ public:
|
||||
// constructor - takes vectors as parameters
|
||||
VTKM_CONT
|
||||
BRACTNodeComparator(const vtkm::worklet::contourtree_augmented::IdArrayType& regularId,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& meshSortIndex)
|
||||
const vtkm::cont::ArrayHandleVirtual<vtkm::Id>& meshSortIndex)
|
||||
: RegularId(regularId)
|
||||
, MeshSortIndex(meshSortIndex)
|
||||
{ // constructor
|
||||
@ -137,7 +141,8 @@ public:
|
||||
|
||||
private:
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType RegularId;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType MeshSortIndex;
|
||||
/// The ContourTreeMesh uses a smart ArrayHandleIndex instead of a regular IdArrayType array that is why we use a ArrayHandleVirtual here
|
||||
vtkm::cont::ArrayHandleVirtual<vtkm::Id> MeshSortIndex;
|
||||
}; // BRACTNodeComparator
|
||||
|
||||
} // namespace bract_maker
|
@ -84,7 +84,7 @@ public:
|
||||
template <typename InFieldPortalType, typename OutFieldPortalType>
|
||||
VTKM_EXEC void operator()(const InFieldPortalType& boundarySuperparentsPortal,
|
||||
const vtkm::Id& boundaryVertex,
|
||||
const OutFieldPortalType& superarcIntrinsicBoundaryCountPortal)
|
||||
const OutFieldPortalType& superarcIntrinsicBoundaryCountPortal) const
|
||||
{
|
||||
if (boundaryVertex == 0)
|
||||
{
|
||||
@ -103,7 +103,7 @@ public:
|
||||
// ii. Now set the last one explicitly
|
||||
if (boundaryVertex == (this->NumBoundary - 1))
|
||||
{
|
||||
superarcIntrinsicBoundaryCountPortal.Set(superarcId) = this->NumBoundary;
|
||||
superarcIntrinsicBoundaryCountPortal.Set(superarcId, this->NumBoundary);
|
||||
}
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
@ -143,7 +143,7 @@ public:
|
||||
template <typename InFieldPortalType, typename OutFieldPortalType>
|
||||
VTKM_EXEC void operator()(const InFieldPortalType& boundarySuperparentsPortal,
|
||||
const vtkm::Id& boundaryVertex,
|
||||
const OutFieldPortalType& superarcIntrinsicBoundaryCountPortal)
|
||||
const OutFieldPortalType& superarcIntrinsicBoundaryCountPortal) const
|
||||
{
|
||||
if (boundaryVertex == 0)
|
||||
{
|
@ -29,6 +29,7 @@ set(headers
|
||||
CompressRegularisedNodesResolveRootWorklet.h
|
||||
CompressRegularisedNodesTransferVerticesWorklet.h
|
||||
CompressRegularisedNodesFillBractSuperarcsWorklet.h
|
||||
SetInteriorForestWorklet.h
|
||||
ArraySumFunctor.h
|
||||
NoSuchElementFunctor.h
|
||||
SelectRangeFunctor.h
|
@ -73,14 +73,14 @@ public:
|
||||
using ControlSignature = void(FieldInOut newVertexId, // Input/Output
|
||||
FieldIn keptInBract // input
|
||||
);
|
||||
using ExecutionSignature = void(_1, _2);
|
||||
using ExecutionSignature = _1(_1, _2);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
CompressRegularisedNodesCopyNecessaryRegularNodesWorklet() {}
|
||||
|
||||
VTKM_EXEC vtkm::Id operator()(const vtkm::Id& newVertexIdIn, const vtkm::Id& keptInBract)
|
||||
VTKM_EXEC vtkm::Id operator()(vtkm::Id& newVertexIdIn, const vtkm::Id& keptInBract) const
|
||||
{
|
||||
return (!vtkm::worklet::contourtree_augmented::NoSuchElement(newVertexIdIn)) ? (keptInBract - 1)
|
||||
: newVertexIdIn;
|
@ -73,7 +73,7 @@ public:
|
||||
WholeArrayIn reverseSorter,
|
||||
FieldIn vertexSorter,
|
||||
FieldOut bractSuperarcs);
|
||||
using ExecutionSignature = void(_1, _2, _3);
|
||||
using ExecutionSignature = _4(_1, _2, _3);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
@ -83,7 +83,7 @@ public:
|
||||
template <typename InFieldPortalType>
|
||||
VTKM_EXEC vtkm::Id operator()(const InFieldPortalType newSuperarcPortal,
|
||||
const InFieldPortalType reverseSorterPortal,
|
||||
const vtkm::Id& vertexSorterIndex)
|
||||
const vtkm::Id& vertexSorterIndex) const
|
||||
{
|
||||
vtkm::Id newSuperarcIndex = newSuperarcPortal.Get(vertexSorterIndex);
|
||||
if (vtkm::worklet::contourtree_augmented::NoSuchElement(newSuperarcIndex))
|
@ -88,7 +88,7 @@ public:
|
||||
const vtkm::Id& bractSuperarcIdIn,
|
||||
const InFieldPortalType& downNeighbourPortal,
|
||||
const InFieldPortalType& upNeighbourPortal,
|
||||
const OutFieldPortalType& newSuperarcPortal)
|
||||
const OutFieldPortalType& newSuperarcPortal) const
|
||||
{
|
||||
// per vertex
|
||||
// skip all unnecessary vertices
|
@ -80,7 +80,8 @@ public:
|
||||
CompressRegularisedNodesResolveRootWorklet() {}
|
||||
|
||||
template <typename InOutFieldPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::Id& newIndex, const InOutFieldPortalType& newSuperarcPortal)
|
||||
VTKM_EXEC void operator()(const vtkm::Id& newIndex,
|
||||
const InOutFieldPortalType& newSuperarcPortal) const
|
||||
{
|
||||
// per kept vertex
|
||||
// retrieve it to register
|
@ -71,20 +71,24 @@ class CompressRegularisedNodesTransferVerticesWorklet : public vtkm::worklet::Wo
|
||||
public:
|
||||
using ControlSignature = void(FieldIn bractVertexSuperset, // input
|
||||
FieldIn newVertexId, // input
|
||||
FieldOut newVertexIndex);
|
||||
using ExecutionSignature = void(_1, _2);
|
||||
WholeArrayOut newVertexIndex);
|
||||
using ExecutionSignature = void(_1, _2, _3);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
CompressRegularisedNodesTransferVerticesWorklet() {}
|
||||
|
||||
VTKM_EXEC vtkm::Id operator()(const vtkm::Id& bractVertexSupersetIndex,
|
||||
const vtkm::Id& newVertexIdIn)
|
||||
template <typename OutPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::Id& bractVertexSupersetIndex,
|
||||
const vtkm::Id& newVertexIdIn,
|
||||
const OutPortalType& newVertexIndexPortal) const
|
||||
{
|
||||
return (!vtkm::worklet::contourtree_augmented::NoSuchElement(newVertexIdIn))
|
||||
? bractVertexSupersetIndex
|
||||
: 0;
|
||||
if (!vtkm::worklet::contourtree_augmented::NoSuchElement(newVertexIdIn))
|
||||
{
|
||||
newVertexIndexPortal.Set(newVertexIdIn, bractVertexSupersetIndex);
|
||||
}
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
for (indexType returnIndex = 0; returnIndex < bractVertexSuperset.size(); returnIndex++)
|
@ -88,7 +88,9 @@ public:
|
||||
VTKM_EXEC_CONT
|
||||
FindBractSuperarcsSuperarcToWorklet() {}
|
||||
|
||||
template <typename InFieldPortalType, typename OutFieldPortalType>
|
||||
template <typename InFieldPortalType,
|
||||
typename MeshSortOrderPortalType,
|
||||
typename OutFieldPortalType>
|
||||
VTKM_EXEC vtkm::Id operator()(const vtkm::Id& from,
|
||||
const InFieldPortalType& bractVertexSupersetPortal,
|
||||
const InFieldPortalType& boundaryIndicesPortal,
|
||||
@ -97,8 +99,8 @@ public:
|
||||
const InFieldPortalType& contourtreeHyperparentsPortal,
|
||||
const InFieldPortalType& contourtreeHyperarcsPortal,
|
||||
const InFieldPortalType& contourtreeSupernodesPortal,
|
||||
const InFieldPortalType& meshSortOrderPortal,
|
||||
const OutFieldPortalType& treeToSupersetPortal)
|
||||
const MeshSortOrderPortalType& meshSortOrderPortal,
|
||||
const OutFieldPortalType& treeToSupersetPortal) const
|
||||
{
|
||||
// find the sort order, super- and hyper- parent
|
||||
// vtkm::Id fromIndex = bractVertexSupersetPortal.Get(from);
|
@ -86,7 +86,7 @@ public:
|
||||
VTKM_EXEC void operator()(const vtkm::Id& boundaryIndex,
|
||||
const InFieldPortalType superparentsPortal,
|
||||
const InFieldPortalType superarcsPortal,
|
||||
const OutFieldPortalType& isNecessaryPortal)
|
||||
const OutFieldPortalType& isNecessaryPortal) const
|
||||
{
|
||||
// per boundary node
|
||||
// find the superparent
|
@ -76,7 +76,7 @@ public:
|
||||
FieldIn superarcDependentBoundaryCount, // (input)
|
||||
WholeArrayOut isNecessary // (output)
|
||||
);
|
||||
using ExecutionSignature = void(_1, _2, _3, _4);
|
||||
using ExecutionSignature = void(_1, _2, _3);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
@ -89,7 +89,7 @@ public:
|
||||
template <typename OutFieldPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::Id& superarc,
|
||||
const vtkm::Id& dependentWeight,
|
||||
const OutFieldPortalType& isNecessaryPortal)
|
||||
const OutFieldPortalType& isNecessaryPortal) const
|
||||
{
|
||||
// skip the stub superarc at the root
|
||||
if (vtkm::worklet::contourtree_augmented::NoSuchElement(superarc))
|
@ -84,14 +84,19 @@ public:
|
||||
VTKM_EXEC_CONT
|
||||
IdentifyRegularisedSupernodesStepOneWorklet() {}
|
||||
|
||||
template <typename InFieldPortalType, typename OutFieldPortalType>
|
||||
// We use a separate MeshSortIndexPortalType (also it may strictly not be necessary) because
|
||||
// the ContourTreeMehs uses a ArrayHandleIndex for its SortIndex and the other mesh types
|
||||
// use a IdArrayType (i.e., ArrayHandle<vtkm::Id>
|
||||
template <typename InFieldPortalType,
|
||||
typename MeshSortIndexPortalType,
|
||||
typename OutFieldPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::Id& from,
|
||||
const vtkm::Id& to,
|
||||
const InFieldPortalType& bractVertexSupersetPortal,
|
||||
const InFieldPortalType& meshSortIndexPortal,
|
||||
const MeshSortIndexPortalType& meshSortIndexPortal,
|
||||
const InFieldPortalType& upNeighbourPortal,
|
||||
const InFieldPortalType& downNeighbourPortal,
|
||||
const OutFieldPortalType& newVertexIdPortal)
|
||||
const OutFieldPortalType& newVertexIdPortal) const
|
||||
{
|
||||
// per vertex
|
||||
if (vtkm::worklet::contourtree_augmented::NoSuchElement(to))
|
@ -75,7 +75,6 @@ public:
|
||||
FieldIn downNeighbour, // input
|
||||
ExecObject meshBoundary, // input
|
||||
WholeArrayOut newVertexId // output
|
||||
|
||||
);
|
||||
using ExecutionSignature = void(InputIndex, _1, _2, _3, _4, _5);
|
||||
using InputDomain = _1;
|
||||
@ -84,13 +83,13 @@ public:
|
||||
VTKM_EXEC_CONT
|
||||
IdentifyRegularisedSupernodesStepTwoWorklet() {}
|
||||
|
||||
template <typename InFieldPortalType, typename MeshBoundaryType, typename OutFieldPortalType>
|
||||
template <typename MeshBoundaryType, typename OutFieldPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::Id& boundaryNode,
|
||||
const vtkm::Id& bractVertexSupersetValue,
|
||||
const vtkm::Id& upNeighbourValue,
|
||||
const vtkm::Id& downNeighbourValue,
|
||||
const MeshBoundaryType& meshBoundary,
|
||||
const OutFieldPortalType& newVertexIdPortal)
|
||||
const OutFieldPortalType& newVertexIdPortal) const
|
||||
{
|
||||
// per vertex
|
||||
// check for leaf criticality
|
||||
@ -100,7 +99,9 @@ public:
|
||||
newVertexIdPortal.Set(boundaryNode, vtkm::worklet::contourtree_augmented::ELEMENT_EXISTS);
|
||||
}
|
||||
// retrieve mesh index (i.e., bractVertexSupersetValue) & check whether on the boundary
|
||||
if (meshBoundary.liesOnBoundary(bractVertexSupersetValue))
|
||||
if (
|
||||
meshBoundary.LiesOnBoundary(
|
||||
bractVertexSupersetValue)) // TODO: This may need to change to isNecessary when we change to boundary critical points
|
||||
{
|
||||
newVertexIdPortal.Set(boundaryNode, vtkm::worklet::contourtree_augmented::ELEMENT_EXISTS);
|
||||
}
|
@ -80,9 +80,9 @@ public:
|
||||
PointerDoubleUpDownNeighboursWorklet() {}
|
||||
|
||||
template <typename InOutFieldPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::Id* returnIndex,
|
||||
VTKM_EXEC void operator()(const vtkm::Id returnIndex,
|
||||
const InOutFieldPortalType& upNeighbourPortal,
|
||||
const InOutFieldPortalType& downNeighbourPortal)
|
||||
const InOutFieldPortalType& downNeighbourPortal) const
|
||||
{
|
||||
// per vertex
|
||||
// retrieve nbr & see if it's terminal
|
@ -78,7 +78,7 @@ public:
|
||||
WholeArrayIn accumulatedBoundaryCountPortal, // (input)
|
||||
WholeArrayInOut supernodeTransferBoundaryCountPortal // (input/output)
|
||||
);
|
||||
using ExecutionSignature = void(InputIndex, _1, _2, _3, _4, _5);
|
||||
using ExecutionSignature = void(InputIndex, _1, _2, _3, _4);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
@ -90,7 +90,7 @@ public:
|
||||
const InFieldPortalType& hyperarcTargetSortPermutationPortal,
|
||||
const InFieldPortalType& hyperarcsPortal,
|
||||
const InFieldPortalType& accumulatedBoundaryCountPortal,
|
||||
const InOutFieldPortalType& supernodeTransferBoundaryCountPortal)
|
||||
const InOutFieldPortalType& supernodeTransferBoundaryCountPortal) const
|
||||
{
|
||||
// the prefix sum of the first element is the correct value anyway so we can ignore it
|
||||
if (hyperarc == 0)
|
@ -89,11 +89,12 @@ public:
|
||||
}
|
||||
|
||||
template <typename InFieldPortalType, typename InOutFieldPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::Id& supernode,
|
||||
const InFieldPortalType& hyperparentsPortal,
|
||||
const InFieldPortalType& hypernodesPortal,
|
||||
const InFieldPortalType& superarcDependentBoundaryCountPortal,
|
||||
const InOutFieldPortalType& newSuperArcDependentBoundaryCountPortal)
|
||||
VTKM_EXEC void operator()(
|
||||
const vtkm::Id& supernode,
|
||||
const InFieldPortalType& hyperparentsPortal,
|
||||
const InFieldPortalType& hypernodesPortal,
|
||||
const InFieldPortalType& superarcDependentBoundaryCountPortal,
|
||||
const InOutFieldPortalType& newSuperArcDependentBoundaryCountPortal) const
|
||||
{
|
||||
// A. Retrieve hyperparent & convert to supernode ID
|
||||
vtkm::Id hyperparent = hyperparentsPortal.Get(supernode);
|
@ -79,7 +79,7 @@ public:
|
||||
WholeArrayIn accumulatedBoundaryCountPortal, // (input)
|
||||
WholeArrayInOut supernodeTransferBoundaryCountPortal // (input/output)
|
||||
);
|
||||
using ExecutionSignature = void(InputIndex, _1, _2, _3, _4, _5);
|
||||
using ExecutionSignature = void(InputIndex, _1, _2, _3, _4);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
@ -91,7 +91,7 @@ public:
|
||||
const InFieldPortalType& hyperarcTargetSortPermutationPortal,
|
||||
const InFieldPortalType& hyperarcsPortal,
|
||||
const InFieldPortalType& accumulatedBoundaryCountPortal,
|
||||
const InOutFieldPortalType& supernodeTransferBoundaryCountPortal)
|
||||
const InOutFieldPortalType& supernodeTransferBoundaryCountPortal) const
|
||||
{
|
||||
// per hyperarc
|
||||
// retrieve the hypertarget
|
@ -91,7 +91,7 @@ public:
|
||||
VTKM_EXEC void operator()(const vtkm::Id& hypernode,
|
||||
const InFieldPortalType& hypernodesPortal,
|
||||
const InFieldPortalType& superarcDependentBoundaryCountPortal,
|
||||
const OutFieldPortalType& hyperarcDependentBoundaryCountPortal)
|
||||
const OutFieldPortalType& hyperarcDependentBoundaryCountPortal) const
|
||||
{
|
||||
// v. per hypernode
|
||||
// A.Transfer dependent count from last superarc to hyperarc
|
@ -70,7 +70,7 @@ class SelectRangeFunctor
|
||||
{
|
||||
public:
|
||||
VTKM_EXEC_CONT
|
||||
SelectRangeFunctor();
|
||||
SelectRangeFunctor() {}
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
SelectRangeFunctor(const vtkm::worklet::contourtree_augmented::IdArrayType& dataArray,
|
@ -0,0 +1,207 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_bract_maker_set_interior_forest_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_bract_maker_set_interior_forest_worklet_h
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace bract_maker
|
||||
{
|
||||
|
||||
/// Worklet to transfer the dependent counts for hyperarcs
|
||||
/// Part of the BoundaryRestrictedAugmentedContourTree.PropagateBoundaryCounts function
|
||||
class SetInteriorForestWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using ControlSignature = void(FieldIn contourTreeSupernodes, // input
|
||||
FieldIn interiorForestIsNecessary, // input
|
||||
FieldIn boundaryTreeMakerTree2Superset, // input
|
||||
WholeArrayIn meshGlobalIdsFromMeshIndices, // input
|
||||
WholeArrayIn boundaryTreeMakerUpNeighbour, // input
|
||||
WholeArrayIn boundaryTreeMakerDownNeighbour, // input
|
||||
FieldOut interiorForestAbove, // output
|
||||
FieldOut interiorForestBelow // output
|
||||
);
|
||||
using ExecutionSignature = void(_1, _2, _3, _4, _5, _6, _7, _8);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
SetInteriorForestWorklet() {}
|
||||
|
||||
// Allow for different portal type for the meshGlobalIds as they may be a fancy
|
||||
// array handle rather than a portal direclty to a IdArrayType
|
||||
template <typename InFieldPortalType, typename GlobalIdFieldPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::Id& sortId,
|
||||
const vtkm::Id& isNecessary,
|
||||
const vtkm::Id& supersetId,
|
||||
const GlobalIdFieldPortalType& meshGlobalIdsPortal,
|
||||
const InFieldPortalType& upNeighbourPortal,
|
||||
const InFieldPortalType& downNeighbourPortal,
|
||||
vtkm::Id& interiorForestAbove,
|
||||
vtkm::Id& interiorForestBelow) const
|
||||
{
|
||||
(void)
|
||||
sortId; // TODO: Remove if not needed. This was included in original code but seems unused. Avoid compiler warning.
|
||||
// per supernode
|
||||
// ignore supernodes that weren't marked necessary, since they will never be searched for
|
||||
// all nodes to be searched for are necessary, but not all necessary nodes will be searched for
|
||||
if (isNecessary)
|
||||
{ // necessary supernode
|
||||
// first, convert it to a sort ID: Asignement of sortId from contourTreeSupernodes done on input
|
||||
// now find it in the superset: Assignment of supersetId from boundaryTreeMakerTree2Superset done on input
|
||||
|
||||
// find the up neighbour and convert it to a global ID: note that we may have a leaf
|
||||
// in which case this may be NO_SUCH_ELEMENT. This will not be searched for, but for safety,
|
||||
// we will test for it explicitly
|
||||
vtkm::Id upSupersetId = upNeighbourPortal.Get(supersetId);
|
||||
if (vtkm::worklet::contourtree_augmented::NoSuchElement(upSupersetId))
|
||||
{ // no up neighbour
|
||||
interiorForestAbove = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
|
||||
} // no up neighbour
|
||||
else
|
||||
{ // up neighbour exists
|
||||
// mask it to get a superset ID
|
||||
upSupersetId = vtkm::worklet::contourtree_augmented::MaskedIndex(upSupersetId);
|
||||
// look up the mesh ID. NOTE: meshGlobalIdsPortal is already indexed by bractVertexSuperset
|
||||
// so we no longer need to do the bractVertexSupersetPortal.Get(upSupersetId); lookup here
|
||||
vtkm::Id upMeshId = upSupersetId;
|
||||
// then store the global ID in the "above" array
|
||||
interiorForestAbove = meshGlobalIdsPortal.Get(upMeshId);
|
||||
} // up neighbour exists
|
||||
|
||||
// do the same for the down neighbour
|
||||
vtkm::Id downSupersetId = downNeighbourPortal.Get(supersetId);
|
||||
if (vtkm::worklet::contourtree_augmented::NoSuchElement(downSupersetId))
|
||||
{ // no down neighbour
|
||||
interiorForestBelow = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
|
||||
} // no down neighbour
|
||||
else
|
||||
{ // down neighbour exists
|
||||
// mask it to get a superset ID
|
||||
downSupersetId = vtkm::worklet::contourtree_augmented::MaskedIndex(downSupersetId);
|
||||
// look up the mesh ID. NOTE: meshGlobalIdsPortal is already indexed by bractVertexSuperset
|
||||
// so we no longer need to do the bractVertexSupersetPortal.Get(downSupersetId); lookup here
|
||||
vtkm::Id downMeshId = downSupersetId;
|
||||
// then store the global ID in the "above" array
|
||||
interiorForestBelow = meshGlobalIdsPortal.Get(downMeshId);
|
||||
} // up neighbour exists
|
||||
} // necessary supernode
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
for (indexType supernode = 0; supernode < contourTree->supernodes.size(); supernode++)
|
||||
{ // per supernode
|
||||
// ignore supernodes that weren't marked necessary, since they will never be searched for
|
||||
// all nodes to be searched for are necessary, but not all necessary nodes will be searched for
|
||||
if (residue->isNecessary[supernode])
|
||||
{ // necessary supernode
|
||||
// first, convert it to a sort ID
|
||||
indexType sortID = contourTree->supernodes[supernode];
|
||||
// now find it in the superset
|
||||
indexType supersetID = tree2Superset[supernode];
|
||||
|
||||
// find the up neighbour and convert it to a global ID: note that we may have a leaf
|
||||
// in which case this may be NO_SUCH_ELEMENT. This will not be searched for, but for safety,
|
||||
// we will test for it explicitly
|
||||
indexType upSupersetID = upNeighbour[supersetID];
|
||||
if (noSuchElement(upSupersetID))
|
||||
{ // no up neighbour
|
||||
residue->above[supernode] = NO_SUCH_ELEMENT;
|
||||
} // no up neighbour
|
||||
else
|
||||
{ // up neighbour exists
|
||||
// mask it to get a superset ID
|
||||
upSupersetID = maskedIndex(upSupersetID);
|
||||
// look up the mesh ID
|
||||
indexType upMeshID = bractVertexSuperset[upSupersetID];
|
||||
// then store the global ID in the "above" array
|
||||
residue->above[supernode] = mesh->GetGlobalIDFromMeshIndex(upMeshID);
|
||||
} // up neighbour exists
|
||||
|
||||
// do the same for the down neighbour
|
||||
indexType downSupersetID = downNeighbour[supersetID];
|
||||
if (noSuchElement(downSupersetID))
|
||||
{ // no down neighbour
|
||||
residue->below[supernode] = NO_SUCH_ELEMENT;
|
||||
} // no down neighbour
|
||||
else
|
||||
{ // down neighbour exists
|
||||
// mask it to get a superset ID
|
||||
downSupersetID = maskedIndex(downSupersetID);
|
||||
// look up the mesh ID
|
||||
indexType downMeshID = bractVertexSuperset[downSupersetID];
|
||||
// then store the global ID in the "above" array
|
||||
residue->below[supernode] = mesh->GetGlobalIDFromMeshIndex(downMeshID);
|
||||
} // up neighbour exists
|
||||
} // necessary supernode
|
||||
} // per supernode
|
||||
*/
|
||||
}
|
||||
|
||||
}; // SetInteriorForestWorklet
|
||||
|
||||
|
||||
} // namespace bract_maker
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -83,13 +83,18 @@ public:
|
||||
VTKM_EXEC_CONT
|
||||
SetUpAndDownNeighboursWorklet() {}
|
||||
|
||||
template <typename InFieldPortalType, typename OutFieldPortalType>
|
||||
// We use a separate MeshSortIndexPortalType (also it may strictly not be necessary) because
|
||||
// the ContourTreeMehs uses a ArrayHandleIndex for its SortIndex and the other mesh types
|
||||
// use a IdArrayType (i.e., ArrayHandle<vtkm::Id>
|
||||
template <typename InFieldPortalType,
|
||||
typename MeshSortIndexPortalType,
|
||||
typename OutFieldPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::Id& from,
|
||||
vtkm::Id& to,
|
||||
InFieldPortalType bractVertexSupersetPortal,
|
||||
InFieldPortalType meshSortIndexPortal,
|
||||
OutFieldPortalType upNeighbourPortal,
|
||||
OutFieldPortalType downNeighbourPortal)
|
||||
const vtkm::Id& to,
|
||||
const InFieldPortalType& bractVertexSupersetPortal,
|
||||
const MeshSortIndexPortalType& meshSortIndexPortal,
|
||||
const OutFieldPortalType& upNeighbourPortal,
|
||||
const OutFieldPortalType& downNeighbourPortal) const
|
||||
{
|
||||
// per vertex
|
||||
// ignore the last terminating edge
|
@ -0,0 +1,18 @@
|
||||
##============================================================================
|
||||
## 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.
|
||||
##============================================================================
|
||||
|
||||
set(headers
|
||||
FindRegularByGlobal.h
|
||||
FindSuperArcForUnknownNode.h
|
||||
PermuteComparator.h
|
||||
InitalizeSuperchildrenWorklet.h
|
||||
)
|
||||
|
||||
vtkm_declare_headers(${headers})
|
200
vtkm/worklet/contourtree_distributed/hierarchical_contour_tree/FindRegularByGlobal.h
Normal file
200
vtkm/worklet/contourtree_distributed/hierarchical_contour_tree/FindRegularByGlobal.h
Normal file
@ -0,0 +1,200 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_find_regular_by_global_device_data_h
|
||||
#define vtk_m_worklet_contourtree_distributed_find_regular_by_global_device_data_h
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
|
||||
|
||||
/// Device implementation of FindRegularByGlobal for the HierarchicalContourTree
|
||||
template <typename DeviceTag>
|
||||
class FindRegularByGlobalDeviceData
|
||||
{
|
||||
public:
|
||||
using IndicesPortalType =
|
||||
typename vtkm::worklet::contourtree_augmented::IdArrayType::template ExecutionTypes<
|
||||
DeviceTag>::PortalConst;
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
FindRegularByGlobalDeviceData(
|
||||
vtkm::cont::Token& token,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& regularNodeSortOrder,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& regularNodeGlobalIds)
|
||||
{
|
||||
// Prepare the arrays for input and store the array portals
|
||||
// so that they can be used inside a workelt
|
||||
this->RegularNodeSortOrder = regularNodeSortOrder.PrepareForInput(DeviceTag(), token);
|
||||
this->RegularNodeGlobalIds = regularNodeGlobalIds.PrepareForInput(DeviceTag(), token);
|
||||
}
|
||||
|
||||
/// Define also as an operator so that we can use it in ArrayHandleTransform directly
|
||||
VTKM_EXEC_CONT
|
||||
vtkm::Id operator()(vtkm::Id globalId) const { return this->FindRegularByGlobal(globalId); }
|
||||
|
||||
// TODO: This is just a binary search. Does VTKm have an implementation we can use to replace this with?
|
||||
/// routine to search the array of regular nodes for a particular global ID
|
||||
VTKM_EXEC_CONT
|
||||
vtkm::Id FindRegularByGlobal(vtkm::Id globalId) const
|
||||
{ // FindRegularByGlobal()
|
||||
// this is just a binary search, but the C++ STL doesn't seem to implement it . . .
|
||||
vtkm::Id left = 0;
|
||||
vtkm::Id right = this->RegularNodeSortOrder.GetNumberOfValues() - 1;
|
||||
|
||||
// pull LHE into register & check whether target is in range
|
||||
vtkm::Id leftId = this->RegularNodeGlobalIds.Get(this->RegularNodeSortOrder.Get(left));
|
||||
if (leftId > globalId)
|
||||
{
|
||||
return vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
|
||||
}
|
||||
|
||||
// exact match on the left
|
||||
if (leftId == globalId)
|
||||
{
|
||||
return this->RegularNodeSortOrder.Get(left);
|
||||
}
|
||||
|
||||
// pull RHE into register & check whether target is in range
|
||||
vtkm::Id rightId = this->RegularNodeGlobalIds.Get(this->RegularNodeSortOrder.Get(right));
|
||||
// RHE is less than target, so not present
|
||||
if (rightId < globalId)
|
||||
{
|
||||
return vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
|
||||
}
|
||||
|
||||
// exact match on the right
|
||||
if (rightId == globalId)
|
||||
{
|
||||
return this->RegularNodeSortOrder.Get(right);
|
||||
}
|
||||
|
||||
// loop until the two meet
|
||||
while (left <= right)
|
||||
{ // while loop
|
||||
|
||||
// compute the midpoint
|
||||
vtkm::Id mid = (left + right) / 2;
|
||||
vtkm::Id midId = this->RegularNodeGlobalIds.Get(this->RegularNodeSortOrder.Get(mid));
|
||||
|
||||
// compare with the value
|
||||
if (midId == globalId)
|
||||
{ // exact match
|
||||
return this->RegularNodeSortOrder.Get(mid);
|
||||
} // exact match
|
||||
|
||||
if (midId < globalId)
|
||||
{ // mid is lower: global is in right half
|
||||
left = mid + 1;
|
||||
leftId = this->RegularNodeGlobalIds.Get(this->RegularNodeSortOrder.Get(left));
|
||||
} // mid is lower: global is in right half
|
||||
|
||||
if (midId > globalId)
|
||||
{ // mid is higher: global is in left half
|
||||
right = mid - 1;
|
||||
rightId = this->RegularNodeGlobalIds.Get(this->RegularNodeSortOrder.Get(right));
|
||||
} // mid is higher: global is in left half
|
||||
} // while loop
|
||||
|
||||
// if we fell through, we didn't find it
|
||||
return vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
|
||||
} // FindRegularByGlobal()
|
||||
|
||||
private:
|
||||
// Array portals needed by FindRegularByGlobal
|
||||
IndicesPortalType RegularNodeSortOrder;
|
||||
IndicesPortalType RegularNodeGlobalIds;
|
||||
};
|
||||
|
||||
|
||||
/// ExecutionObject to generate a device object to use FindRegularByGlobal for the HierarchicalContourTree
|
||||
class FindRegularByGlobal : public vtkm::cont::ExecutionObjectBase
|
||||
{
|
||||
public:
|
||||
/// constructor
|
||||
VTKM_EXEC_CONT
|
||||
FindRegularByGlobal(const vtkm::worklet::contourtree_augmented::IdArrayType& regularNodeSortOrder,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& regularNodeGlobalIds)
|
||||
: RegularNodeSortOrder(regularNodeSortOrder)
|
||||
, RegularNodeGlobalIds(regularNodeGlobalIds)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
template <typename DeviceTag>
|
||||
FindRegularByGlobalDeviceData<DeviceTag> PrepareForExecution(DeviceTag,
|
||||
vtkm::cont::Token& token) const
|
||||
{
|
||||
return FindRegularByGlobalDeviceData<DeviceTag>(
|
||||
token, this->RegularNodeSortOrder, this->RegularNodeGlobalIds);
|
||||
}
|
||||
|
||||
private:
|
||||
// Array portals needed by FindRegularByGlobal
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType RegularNodeSortOrder;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType RegularNodeGlobalIds;
|
||||
};
|
||||
|
||||
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
504
vtkm/worklet/contourtree_distributed/hierarchical_contour_tree/FindSuperArcForUnknownNode.h
Normal file
504
vtkm/worklet/contourtree_distributed/hierarchical_contour_tree/FindSuperArcForUnknownNode.h
Normal file
@ -0,0 +1,504 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_find_superarc_for_unknown_node_h
|
||||
#define vtk_m_worklet_contourtree_distributed_find_superarc_for_unknown_node_h
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
|
||||
|
||||
/// Device implementation of FindSuperArcForUnknownNode for the HierarchicalContourTree
|
||||
template <typename FieldType, typename DeviceTag>
|
||||
class FindSuperArcForUnknownNodeDeviceData
|
||||
{
|
||||
public:
|
||||
using IndicesPortalType =
|
||||
typename vtkm::worklet::contourtree_augmented::IdArrayType::template ExecutionTypes<
|
||||
DeviceTag>::PortalConst;
|
||||
using DataPortalType =
|
||||
typename vtkm::cont::ArrayHandle<FieldType>::template ExecutionTypes<DeviceTag>::PortalConst;
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
FindSuperArcForUnknownNodeDeviceData(
|
||||
vtkm::cont::Token& token,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& superparents,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& supernodes,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& superarcs,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& superchildren,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& whichRound,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& whichIteration,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& hyperparents,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& hypernodes,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& hyperarcs,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& regularNodeGlobalIds,
|
||||
const vtkm::cont::ArrayHandle<FieldType>& dataValues)
|
||||
{
|
||||
// Prepare the arrays for input and store the array portals
|
||||
// so that they can be used inside a workelt
|
||||
this->Superparents = superparents.PrepareForInput(DeviceTag(), token);
|
||||
this->Supernodes = supernodes.PrepareForInput(DeviceTag(), token);
|
||||
this->Superarcs = superarcs.PrepareForInput(DeviceTag(), token);
|
||||
this->Superchildren = superchildren.PrepareForInput(DeviceTag(), token);
|
||||
this->WhichRound = whichRound.PrepareForInput(DeviceTag(), token);
|
||||
this->WhichIteration = whichIteration.PrepareForInput(DeviceTag(), token);
|
||||
this->Hyperparents = hyperparents.PrepareForInput(DeviceTag(), token);
|
||||
this->Hypernodes = hypernodes.PrepareForInput(DeviceTag(), token);
|
||||
this->Hyperarcs = hyperarcs.PrepareForInput(DeviceTag(), token);
|
||||
this->RegularNodeGlobalIds = regularNodeGlobalIds.PrepareForInput(DeviceTag(), token);
|
||||
this->DataValues = dataValues.PrepareForInput(DeviceTag(), token);
|
||||
}
|
||||
|
||||
/// routine to find the superarc to which a given global Id/value pair maps
|
||||
/// given a known pair of vertices by their regular Ids, one above, one below
|
||||
/// assumes that the vertex being searched for is NOT in the hierarchical tree (at all)
|
||||
/// and that the above/below pair ARE in the hierarchical tree
|
||||
VTKM_EXEC
|
||||
vtkm::Id FindSuperArcForUnknownNode(vtkm::Id nodeGlobalId,
|
||||
FieldType nodeValue,
|
||||
vtkm::Id above,
|
||||
vtkm::Id below) const
|
||||
{ // FindSuperArcForUnknownNode()
|
||||
// the hyperparent which we need to search along
|
||||
vtkm::Id hyperparent = 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);
|
||||
|
||||
// if the two superparents match, we must be on the same superarc, and we are done
|
||||
if (aboveSuperparent == belowSuperparent)
|
||||
{
|
||||
return aboveSuperparent;
|
||||
}
|
||||
|
||||
// now it gets slightly tricky. While we know that the above / below pair straddle the node of interest, it is not guaranteed that
|
||||
// their superparents will. What we do is to take the two ends of the "above" superarc - one of which is guaranteed to be at least as high
|
||||
// as the above node. We choose that, and the inverse at the lower end. We can determine this from the ascending flag for the superarc
|
||||
vtkm::Id aboveSuperarc = this->Superarcs.Get(aboveSuperparent);
|
||||
// there are two possibilities here.
|
||||
// I. It could be null, which means that "aboveSuperparent" is either the root of the tree or an attachment point. This can only happen
|
||||
// if "above" IS the root/attachment point, so we can safely keep it.
|
||||
// II. In all other cases, there is a superarc, and if it's ascending, we take the destination instead of the source.
|
||||
if (!vtkm::worklet::contourtree_augmented::NoSuchElement(aboveSuperarc) &&
|
||||
(vtkm::worklet::contourtree_augmented::IsAscending(aboveSuperarc)))
|
||||
{
|
||||
aboveSuperparent = vtkm::worklet::contourtree_augmented::MaskedIndex(aboveSuperarc);
|
||||
}
|
||||
|
||||
// and the same at the lower end
|
||||
vtkm::Id belowSuperarc = this->Superarcs.Get(belowSuperparent);
|
||||
if (!vtkm::worklet::contourtree_augmented::NoSuchElement(belowSuperarc) &&
|
||||
(!vtkm::worklet::contourtree_augmented::IsAscending(belowSuperarc)))
|
||||
{
|
||||
belowSuperparent = vtkm::worklet::contourtree_augmented::MaskedIndex(belowSuperarc);
|
||||
}
|
||||
|
||||
// we now have as an invariant that the above, below supernodes straddle the node of interest
|
||||
|
||||
// retrieve the corresponding hyperparents: we no longer need to worry whether we straddle, as the iteration takes care of pruning in
|
||||
// the correct direction
|
||||
vtkm::Id aboveHyperparent = this->Hyperparents.Get(aboveSuperparent);
|
||||
vtkm::Id belowHyperparent = this->Hyperparents.Get(belowSuperparent);
|
||||
|
||||
// now test to see if we have the same hyperparent:
|
||||
// if we do, choose it and fall through the following while loop
|
||||
if (aboveHyperparent == belowHyperparent)
|
||||
{
|
||||
hyperparent = aboveHyperparent;
|
||||
}
|
||||
|
||||
// loop until we have matching hyperparents - i.e. until we're on the same hyperarc
|
||||
while (aboveHyperparent != belowHyperparent)
|
||||
{ // different hyperparents
|
||||
// otherwise, they must be different, and we can ask which prunes first
|
||||
// the rule is that we do it by hierarchical round first, iteration second, so
|
||||
vtkm::Id belowRound = this->WhichRound.Get(this->Hypernodes.Get(belowHyperparent));
|
||||
vtkm::Id belowIteration = vtkm::worklet::contourtree_augmented::MaskedIndex(
|
||||
this->WhichIteration.Get(this->Hypernodes.Get(belowHyperparent)));
|
||||
|
||||
vtkm::Id aboveRound = this->WhichRound.Get(this->Hypernodes.Get(aboveHyperparent));
|
||||
vtkm::Id aboveIteration = vtkm::worklet::contourtree_augmented::MaskedIndex(
|
||||
this->WhichIteration.Get(this->Hypernodes.Get(aboveHyperparent)));
|
||||
|
||||
// and a variable for which end prunes first
|
||||
vtkm::Id pruningEnd = PRUNE_LOW;
|
||||
|
||||
// now search until we find a hyperarc
|
||||
while (vtkm::worklet::contourtree_augmented::NoSuchElement(hyperparent))
|
||||
{ // until we have set a hyperparent
|
||||
// decide which end prunes first
|
||||
// low round #'s prune first
|
||||
if (belowRound < aboveRound)
|
||||
{
|
||||
pruningEnd = PRUNE_LOW;
|
||||
}
|
||||
else if (belowRound > aboveRound)
|
||||
{
|
||||
pruningEnd = PRUNE_HIGH;
|
||||
}
|
||||
// in the same round, low iterations prune first
|
||||
else if (belowIteration < aboveIteration)
|
||||
{
|
||||
pruningEnd = PRUNE_LOW;
|
||||
}
|
||||
else if (belowIteration > aboveIteration)
|
||||
{
|
||||
pruningEnd = PRUNE_HIGH;
|
||||
}
|
||||
// perfect match
|
||||
else if (aboveHyperparent == belowHyperparent)
|
||||
{
|
||||
pruningEnd = PRUNE_FINAL;
|
||||
}
|
||||
else // prune either end first
|
||||
{
|
||||
pruningEnd = PRUNE_LOW;
|
||||
}
|
||||
|
||||
// now, depending on the case
|
||||
switch (pruningEnd)
|
||||
{ // switch on pruning end
|
||||
case PRUNE_FINAL:
|
||||
{ // last hyperarc left can prune both ends simultaneously
|
||||
// in this case, both have the same hyperparent set (& its arbitrary between them)
|
||||
// this will cause the loop to exit
|
||||
hyperparent = aboveHyperparent;
|
||||
break;
|
||||
} // last hyperarc left can prune both ends simultaneously
|
||||
case PRUNE_LOW:
|
||||
{ // low end prunes first
|
||||
// here, we test the hyperarc to see if the upper end is higher than the target
|
||||
// if it is, we've overshot, but at least we now know which hyperarc
|
||||
vtkm::Id hyperTarget = vtkm::worklet::contourtree_augmented::MaskedIndex(
|
||||
this->Hyperarcs.Get(belowHyperparent));
|
||||
vtkm::Id hyperTargetRegularId = this->Supernodes.Get(hyperTarget);
|
||||
vtkm::Id hyperTargetGlobalId = this->RegularNodeGlobalIds.Get(hyperTargetRegularId);
|
||||
FieldType hyperTargetValue = this->DataValues.Get(hyperTargetRegularId);
|
||||
|
||||
// now compare, with simulation of simplicity
|
||||
// success means we've found the hyperarc
|
||||
if ((hyperTargetValue > nodeValue) ||
|
||||
((hyperTargetValue == nodeValue) && (hyperTargetGlobalId > nodeGlobalId)))
|
||||
{ // overshoot
|
||||
hyperparent = belowHyperparent;
|
||||
} // overshoot
|
||||
// failure means we update the low end and keep going
|
||||
else
|
||||
{ // no overshoot
|
||||
// the next hyperarc is always the hyperparent, even for attachment points
|
||||
belowHyperparent = this->Hyperparents.Get(hyperTarget);
|
||||
// the round and iteration, however, need to be set from the hyperparent
|
||||
// since an attachment point will have a different round / iteration from it's hyperparent
|
||||
belowSuperparent = this->Hypernodes.Get(belowHyperparent);
|
||||
belowRound = this->WhichRound.Get(belowSuperparent);
|
||||
belowIteration = vtkm::worklet::contourtree_augmented::MaskedIndex(
|
||||
this->WhichIteration.Get(belowSuperparent));
|
||||
} // no overshoot
|
||||
break;
|
||||
} // low end prunes first
|
||||
case PRUNE_HIGH:
|
||||
{ // high end prunes first
|
||||
// here, we test the hyperarc to see if the lower end is lower than the target
|
||||
// if it is, we've overshot, but at least we now know which hyperarc
|
||||
// this differs from the hypersweep logic in the regular tree
|
||||
vtkm::Id hyperTarget = vtkm::worklet::contourtree_augmented::MaskedIndex(
|
||||
this->Hyperarcs.Get(aboveHyperparent));
|
||||
vtkm::Id hyperTargetRegularId = this->Supernodes.Get(hyperTarget);
|
||||
vtkm::Id hyperTargetGlobalId = this->RegularNodeGlobalIds.Get(hyperTargetRegularId);
|
||||
FieldType hyperTargetValue = this->DataValues.Get(hyperTargetRegularId);
|
||||
|
||||
// now compare, with simulation of simplicity
|
||||
// success means we've found the hyperarc
|
||||
if ((hyperTargetValue < nodeValue) ||
|
||||
((hyperTargetValue == nodeValue) && (hyperTargetGlobalId < nodeGlobalId)))
|
||||
{ // overshoot
|
||||
hyperparent = aboveHyperparent;
|
||||
} // overshoot
|
||||
// failure means we update the low end and keep going
|
||||
else
|
||||
{ // no overshoot
|
||||
// the next hyperarc is always the hyperparent, even for attachment points
|
||||
aboveHyperparent = this->Hyperparents.Get(hyperTarget);
|
||||
// the round and iteration, however, need to be set from the hyperparent
|
||||
// since an attachment point will have a different round / iteration from it's hyperparent
|
||||
// this differs from the hypersweep logic in the regular tree
|
||||
aboveSuperparent = this->Hypernodes.Get(aboveHyperparent);
|
||||
aboveRound = this->WhichRound.Get(aboveSuperparent);
|
||||
aboveIteration = vtkm::worklet::contourtree_augmented::MaskedIndex(
|
||||
this->WhichIteration.Get(aboveSuperparent));
|
||||
} // no overshoot
|
||||
break;
|
||||
} // high end prunes first
|
||||
} // switch on pruning end
|
||||
} // until we have set a hyperparent
|
||||
|
||||
// if we found one, then we exit this loop too
|
||||
if (!vtkm::worklet::contourtree_augmented::NoSuchElement(hyperparent))
|
||||
{
|
||||
break;
|
||||
}
|
||||
} // different hyperparents
|
||||
|
||||
// We are now on the correct hyperarc and "merely" need to find the correct superarc with a binary search.
|
||||
// We are, however, guaranteed to have a data value strictly in the range of the hyperarc
|
||||
// Moreover, we are already guaranteed that the data value is strictly in the range on the hyperarc
|
||||
if (vtkm::worklet::contourtree_augmented::IsAscending(this->Hyperarcs.Get(hyperparent)))
|
||||
{ // ascending hyperarc
|
||||
// the supernodes on the hyperarc are in sorted low-high order
|
||||
vtkm::Id lowSupernode = this->Hypernodes.Get(hyperparent);
|
||||
// now that we have stored "superchildren", this next bit is easier than it used to be
|
||||
vtkm::Id highSupernode =
|
||||
this->Hypernodes.Get(hyperparent) + this->Superchildren.Get(hyperparent) - 1;
|
||||
|
||||
// now, the high supernode may be lower than the element, because the node belongs
|
||||
// between it and the high end of the hyperarc. In this case, the high supernode's ascending superarc is the correct one
|
||||
vtkm::Id highSupernodeRegularId = this->Supernodes.Get(highSupernode);
|
||||
vtkm::Id highSupernodeGlobalId = this->RegularNodeGlobalIds.Get(highSupernodeRegularId);
|
||||
FieldType highValue = this->DataValues.Get(highSupernodeRegularId);
|
||||
// simulation of simplicity
|
||||
if ((highValue < nodeValue) ||
|
||||
((highValue == nodeValue) && (highSupernodeGlobalId < nodeGlobalId)))
|
||||
{ // last superarc
|
||||
return highSupernode;
|
||||
} // last superarc
|
||||
// otherwise, we do a binary search of the superarcs
|
||||
else
|
||||
{ // node between high & low
|
||||
// keep going until we span exactly
|
||||
while (highSupernode - lowSupernode > 1)
|
||||
{ // binary search
|
||||
// find the midway supernode
|
||||
vtkm::Id midSupernode = (lowSupernode + highSupernode) / 2;
|
||||
vtkm::Id midSupernodeRegularId = this->Supernodes.Get(midSupernode);
|
||||
vtkm::Id midSupernodeGlobalId = this->RegularNodeGlobalIds.Get(midSupernodeRegularId);
|
||||
FieldType midValue = this->DataValues.Get(midSupernodeRegularId);
|
||||
|
||||
// test against the node (with simulation of simplicity)
|
||||
if ((midValue > nodeValue) ||
|
||||
((midValue == nodeValue) && (midSupernodeGlobalId > nodeGlobalId)))
|
||||
{ // mid higher
|
||||
highSupernode = midSupernode;
|
||||
} // mid higher
|
||||
// == can't happen since node is regular
|
||||
else
|
||||
{ // mid lower
|
||||
lowSupernode = midSupernode;
|
||||
} // mid lower
|
||||
} // binary search
|
||||
// we've now narrowed down the search and found the superarc we wanted, so return it
|
||||
// for an ascending arc, the Id is that of the lower end
|
||||
return lowSupernode;
|
||||
} // node between high & low
|
||||
} // ascending hyperarc
|
||||
else
|
||||
{ // descending hyperarc
|
||||
// the supernodes on the hyperarc are in sorted high-low order
|
||||
vtkm::Id highSupernode = this->Hypernodes.Get(hyperparent);
|
||||
// now that we have stored "superchildren", this next bit is easier than it used to be
|
||||
vtkm::Id lowSupernode =
|
||||
this->Hypernodes.Get(hyperparent) + this->Superchildren.Get(hyperparent) - 1;
|
||||
|
||||
// now, the low supernode may be higher than the element, because the node belongs
|
||||
// between it and the low end of the hyperarc. In this case, the low supernode's descending superarc is the correct one
|
||||
vtkm::Id lowSupernodeRegularId = this->Supernodes.Get(lowSupernode);
|
||||
vtkm::Id lowSupernodeGlobalId = this->RegularNodeGlobalIds.Get(lowSupernodeRegularId);
|
||||
FieldType lowValue = this->DataValues.Get(lowSupernodeRegularId);
|
||||
// simulation of simplicity
|
||||
if ((lowValue > nodeValue) ||
|
||||
((lowValue == nodeValue) && (lowSupernodeGlobalId >= nodeGlobalId)))
|
||||
{
|
||||
return lowSupernode;
|
||||
}
|
||||
// otherwise, we do a binary search of the superarcs
|
||||
else
|
||||
{ // node between low & high
|
||||
// keep going until we span exactly
|
||||
while (lowSupernode - highSupernode > 1)
|
||||
{ // binary search
|
||||
// find the midway supernode
|
||||
vtkm::Id midSupernode = (highSupernode + lowSupernode) / 2;
|
||||
vtkm::Id midSupernodeRegularId = this->Supernodes.Get(midSupernode);
|
||||
vtkm::Id midSupernodeGlobalId = this->RegularNodeGlobalIds.Get(midSupernodeRegularId);
|
||||
FieldType midValue = this->DataValues.Get(midSupernodeRegularId);
|
||||
// test against the node (with simulation of simplicity)
|
||||
if ((midValue > nodeValue) ||
|
||||
((midValue == nodeValue) && (midSupernodeGlobalId > nodeGlobalId)))
|
||||
{ // mid higher
|
||||
highSupernode = midSupernode;
|
||||
} // mid higher
|
||||
// == can't happen since node is regular
|
||||
else
|
||||
{ // mid lower
|
||||
lowSupernode = midSupernode;
|
||||
} // mid lower
|
||||
} // binary search
|
||||
// we've now narrowed down the search and found the superarc we wanted, so return it
|
||||
// for an ascending arc, the Id is that of the lower end
|
||||
return highSupernode;
|
||||
} // node between low & high
|
||||
} // descending hyperarc
|
||||
|
||||
// paranoia - return a known bad value
|
||||
return vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
|
||||
} // FindSuperArcForUnknownNode()
|
||||
|
||||
private:
|
||||
// these are used to make it simpler to search through the hierarchy
|
||||
static constexpr vtkm::Id PRUNE_LOW = static_cast<vtkm::Id>(0);
|
||||
static constexpr vtkm::Id PRUNE_HIGH = static_cast<vtkm::Id>(1);
|
||||
static constexpr vtkm::Id PRUNE_FINAL = static_cast<vtkm::Id>(2);
|
||||
|
||||
// Array portals needed by FindSuperArcForUnknownNode
|
||||
// These arrays all originate from the HierarchicalContourTree
|
||||
IndicesPortalType Superparents;
|
||||
IndicesPortalType Supernodes;
|
||||
IndicesPortalType Superarcs;
|
||||
IndicesPortalType Superchildren;
|
||||
IndicesPortalType WhichRound;
|
||||
IndicesPortalType WhichIteration;
|
||||
IndicesPortalType Hyperparents;
|
||||
IndicesPortalType Hypernodes;
|
||||
IndicesPortalType Hyperarcs;
|
||||
IndicesPortalType RegularNodeGlobalIds;
|
||||
DataPortalType DataValues;
|
||||
};
|
||||
|
||||
|
||||
/// ExecutionObject to generate a device object to use FindSuperArcForUnknownNode for the HierarchicalContourTree
|
||||
///
|
||||
/// This is a routine to find the superarc to which a given global Id/value pair maps
|
||||
/// given a known pair of vertices by their regular Ids, one above, one below
|
||||
/// assumes that the vertex being searched for is NOT in the hierarchical tree (at all)
|
||||
/// and that the above/below pair ARE in the hierarchical tree
|
||||
template <typename FieldType>
|
||||
class FindSuperArcForUnknownNode : public vtkm::cont::ExecutionObjectBase
|
||||
{
|
||||
public:
|
||||
/// constructor
|
||||
VTKM_EXEC_CONT
|
||||
FindSuperArcForUnknownNode(
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& superparents,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& supernodes,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& superarcs,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& superchildren,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& whichRound,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& whichIteration,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& hyperparents,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& hypernodes,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& hyperarcs,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& regularNodeGlobalIds,
|
||||
const vtkm::cont::ArrayHandle<FieldType>& dataValues)
|
||||
: Superparents(superparents)
|
||||
, Supernodes(supernodes)
|
||||
, Superarcs(superarcs)
|
||||
, Superchildren(superchildren)
|
||||
, WhichRound(whichRound)
|
||||
, WhichIteration(whichIteration)
|
||||
, Hyperparents(hyperparents)
|
||||
, Hypernodes(hypernodes)
|
||||
, Hyperarcs(hyperarcs)
|
||||
, RegularNodeGlobalIds(regularNodeGlobalIds)
|
||||
, DataValues(dataValues)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
template <typename DeviceTag>
|
||||
FindSuperArcForUnknownNodeDeviceData<FieldType, DeviceTag> PrepareForExecution(
|
||||
DeviceTag,
|
||||
vtkm::cont::Token& token) const
|
||||
{
|
||||
return FindSuperArcForUnknownNodeDeviceData<FieldType, DeviceTag>(token,
|
||||
this->Superparents,
|
||||
this->Supernodes,
|
||||
this->Superarcs,
|
||||
this->Superchildren,
|
||||
this->WhichRound,
|
||||
this->WhichIteration,
|
||||
this->Hyperparents,
|
||||
this->Hypernodes,
|
||||
this->Hyperarcs,
|
||||
this->RegularNodeGlobalIds,
|
||||
this->DataValues);
|
||||
}
|
||||
|
||||
private:
|
||||
// Arrays needed by FindSuperArcForUnknownNode
|
||||
// These arrays all originate from the HierarchicalContourTree
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Superparents;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Supernodes;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Superarcs;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Superchildren;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType WhichRound;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType WhichIteration;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Hyperparents;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Hypernodes;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Hyperarcs;
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType RegularNodeGlobalIds;
|
||||
vtkm::cont::ArrayHandle<FieldType> DataValues;
|
||||
};
|
||||
|
||||
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
122
vtkm/worklet/contourtree_distributed/hierarchical_contour_tree/InitalizeSuperchildrenWorklet.h
Normal file
122
vtkm/worklet/contourtree_distributed/hierarchical_contour_tree/InitalizeSuperchildrenWorklet.h
Normal file
@ -0,0 +1,122 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_hierarchical_contour_tree_initialize_superchildren_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_hierarchical_contour_tree_initialize_superchildren_worklet_h
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
|
||||
/// Compute the superarc "to" for every bract node
|
||||
/// Part of the BoundaryRestrictedAugmentedContourTree.FindBractSuperarcs function
|
||||
class InitalizeSuperchildrenWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using ControlSignature = void(FieldIn hyperarcs, // input
|
||||
WholeArrayIn hypernodes, // input
|
||||
FieldOut superchildren // output
|
||||
);
|
||||
using ExecutionSignature = _3(InputIndex, _1, _2);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
InitalizeSuperchildrenWorklet() {}
|
||||
|
||||
template <typename InFieldPortalType>
|
||||
VTKM_EXEC vtkm::Id operator()(const vtkm::Id& hyperarc,
|
||||
const vtkm::Id& hyperarcVal,
|
||||
const InFieldPortalType& hypernodesPortal) const
|
||||
{
|
||||
// per hyperarc
|
||||
// test for root element
|
||||
if (vtkm::worklet::contourtree_augmented::NoSuchElement(hyperarcVal))
|
||||
{
|
||||
// root has one superchild: the root supernode
|
||||
return static_cast<vtkm::Id>(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise, compute a delta
|
||||
return hypernodesPortal.Get(hyperarc + 1) - hypernodesPortal.Get(hyperarc);
|
||||
}
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
for (indexType hyperarc = 0; hyperarc < hyperarcs.size(); hyperarc++)
|
||||
{ // per hyperarc
|
||||
// test for root element
|
||||
if (noSuchElement(hyperarcs[hyperarc]))
|
||||
// root has one superchild: the root supernode
|
||||
superchildren[hyperarc] = 1;
|
||||
else
|
||||
// otherwise, compute a delta
|
||||
superchildren[hyperarc] = hypernodes[hyperarc+1] - hypernodes[hyperarc];
|
||||
} // per hyperarc
|
||||
*/
|
||||
} // operator()()
|
||||
|
||||
}; // InitalizeSuperchildrenWorklet
|
||||
|
||||
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -0,0 +1,148 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_permute_comparator_h
|
||||
#define vtk_m_worklet_contourtree_distributed_permute_comparator_h
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ExecutionObjectBase.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
|
||||
|
||||
// comparator used for initial sort of data values
|
||||
template <typename DeviceAdapter>
|
||||
class PermuteComparatorImpl
|
||||
{
|
||||
public:
|
||||
using IdPortalType =
|
||||
typename vtkm::worklet::contourtree_augmented::IdArrayType::template ExecutionTypes<
|
||||
DeviceAdapter>::PortalConst;
|
||||
|
||||
// constructor - takes vectors as parameters
|
||||
VTKM_CONT
|
||||
PermuteComparatorImpl(const vtkm::worklet::contourtree_augmented::IdArrayType& lookup,
|
||||
vtkm::cont::Token& token)
|
||||
{ // constructor
|
||||
LookupPortal = lookup.PrepareForInput(DeviceAdapter(), token);
|
||||
} // constructor
|
||||
|
||||
// () operator - gets called to do comparison
|
||||
VTKM_EXEC
|
||||
bool operator()(const vtkm::Id& i, const vtkm::Id& j) const
|
||||
{ // operator()
|
||||
// first make sure we have the "top" end set correctly
|
||||
vtkm::Id indI = this->LookupPortal.Get(i);
|
||||
vtkm::Id indJ = this->LookupPortal.Get(j);
|
||||
|
||||
// primary sort on indexed value
|
||||
if (indI < indJ)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (indI > indJ)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// secondart sort on index
|
||||
if (i < j)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (j < i)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// fallback just in case
|
||||
return false;
|
||||
} // operator()
|
||||
|
||||
private:
|
||||
IdPortalType LookupPortal;
|
||||
|
||||
}; // PermuteComparatorImpl
|
||||
|
||||
class PermuteComparator : public vtkm::cont::ExecutionObjectBase
|
||||
{
|
||||
public:
|
||||
// constructor - takes vectors as parameters
|
||||
VTKM_CONT
|
||||
PermuteComparator(const vtkm::worklet::contourtree_augmented::IdArrayType& lookup)
|
||||
: Lookup(lookup)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename DeviceAdapter>
|
||||
VTKM_CONT PermuteComparatorImpl<DeviceAdapter> PrepareForExecution(DeviceAdapter,
|
||||
vtkm::cont::Token& token) const
|
||||
{
|
||||
return PermuteComparatorImpl<DeviceAdapter>(this->Lookup, token);
|
||||
}
|
||||
|
||||
private:
|
||||
vtkm::worklet::contourtree_augmented::IdArrayType Lookup;
|
||||
}; // PermuteComparator
|
||||
|
||||
} // namespace contourtree_augmented
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -0,0 +1,37 @@
|
||||
##============================================================================
|
||||
## 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.
|
||||
##============================================================================
|
||||
|
||||
set(headers
|
||||
GetHierarchicalIdsWorklet.h
|
||||
InitActiceSuperarcIdWorklet.h
|
||||
InitActiceSuperarcsWorklet.h
|
||||
GraftInteriorForestsSetTransferIterationWorklet.h
|
||||
FindCriticalPointsSetUpDownNeighboursWorklet.h
|
||||
FindCriticalPointsFindSaddlesWorklet.h
|
||||
FindCriticalPointsFindLeafsWorklet.h
|
||||
FindCriticalPointsFindTerminalElementsWorklet.h
|
||||
CollapseRegularChainsWorklet.h
|
||||
IdentifyLeafHyperarcsWorklet.h
|
||||
SuperarcWasTransferredPredicate.h
|
||||
NewHypernodePredicate.h
|
||||
HyperNodeWhenComparator.h
|
||||
SuperNodeWhenComparator.h
|
||||
NewNodePredicate.h
|
||||
ListNewNodesCopyIdsWorklet.h
|
||||
CopyNewHypernodesWorklet.h
|
||||
CopyNewSupernodesWorklet.h
|
||||
CopyNewSupernodesSetSuperchildrenWorklet.h
|
||||
PermuteComparator.h
|
||||
CopyNewNodesSetSuperparentsWorklet.h
|
||||
CopyFirstSupernodePerIterationWorklet.h
|
||||
CopyFirstHypernodePerIterationWorklet.h
|
||||
)
|
||||
|
||||
vtkm_declare_headers(${headers})
|
@ -0,0 +1,141 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_collapse_regular_chains_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_collapse_regular_chains_worklet_h
|
||||
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
// Worklet implementing the inner parallel loop to collaps the regular chains in TreeGrafter.CollapseRegularChains
|
||||
class CollapseRegularChainsWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using ControlSignature = void(
|
||||
FieldIn
|
||||
activeSuperarcs, // input iteration index. loop to one less than ContourTree->Supernodes.GetNumberOfValues()
|
||||
WholeArrayInOut upNeighbour, // output/input
|
||||
WholeArrayInOut downNeighbour // output/input
|
||||
);
|
||||
|
||||
using ExecutionSignature = void(_1, _2, _3);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
CollapseRegularChainsWorklet() {}
|
||||
|
||||
template <typename InOutFieldPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::worklet::contourtree_augmented::EdgePair& activeSuperarc,
|
||||
const InOutFieldPortalType& upNeighbourPortal,
|
||||
const InOutFieldPortalType& downNeighbourPortal) const
|
||||
{ // operator ()
|
||||
// per active superarc
|
||||
vtkm::Id lowEnd = activeSuperarc.first;
|
||||
vtkm::Id highEnd = activeSuperarc.second;
|
||||
|
||||
// retrieve both ends
|
||||
vtkm::Id lowEndUpNeighbour = upNeighbourPortal.Get(lowEnd);
|
||||
vtkm::Id highEndDownNeighbour = downNeighbourPortal.Get(highEnd);
|
||||
|
||||
// if the lower end's up is not terminal, update
|
||||
if (!vtkm::worklet::contourtree_augmented::IsTerminalElement(lowEndUpNeighbour))
|
||||
{
|
||||
upNeighbourPortal.Set(lowEnd, upNeighbourPortal.Get(lowEndUpNeighbour));
|
||||
}
|
||||
|
||||
// if the upper end's down is not terminal, update
|
||||
if (!vtkm::worklet::contourtree_augmented::IsTerminalElement(highEndDownNeighbour))
|
||||
{
|
||||
downNeighbourPortal.Set(highEnd, downNeighbourPortal.Get(highEndDownNeighbour));
|
||||
}
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
// loop through the vertices, updating up and down
|
||||
for (indexType activeSuper = 0; activeSuper < activeSuperarcs.size(); activeSuper++)
|
||||
{ // per active superarc
|
||||
indexType lowEnd = activeSuperarcs[activeSuper].low, highEnd = activeSuperarcs[activeSuper].high;
|
||||
|
||||
// retrieve both ends
|
||||
indexType lowEndUpNeighbour = upNeighbour[lowEnd];
|
||||
indexType highEndDownNeighbour = downNeighbour[highEnd];
|
||||
|
||||
// if the lower end's up is not terminal, update
|
||||
if (!isTerminalElement(lowEndUpNeighbour))
|
||||
upNeighbour[lowEnd] = upNeighbour[lowEndUpNeighbour];
|
||||
|
||||
// if the upper end's down is not terminal, update
|
||||
if (!isTerminalElement(highEndDownNeighbour))
|
||||
downNeighbour[highEnd] = downNeighbour[highEndDownNeighbour];
|
||||
} // per active superarc
|
||||
*/
|
||||
} // operator ()
|
||||
|
||||
}; // CollapseRegularChainsWorklet
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
147
vtkm/worklet/contourtree_distributed/tree_grafter/CopyFirstHypernodePerIterationWorklet.h
Normal file
147
vtkm/worklet/contourtree_distributed/tree_grafter/CopyFirstHypernodePerIterationWorklet.h
Normal file
@ -0,0 +1,147 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_copy_first_hypernode_per_iteration_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_copy_first_hypernode_per_iteration_worklet_h
|
||||
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
/// Worklet implementing the copy of the first supernode per iteration in TreeGrafter::CopyIterationDetails
|
||||
class CopyFirstHypernodePerIterationWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using ControlSignature = void(
|
||||
FieldIn
|
||||
newHypernode, // input. Set to ArrayHandleCounting<vtkm::Id>(nOldHypernodes, 1, nTotalHypernodes-nOldHypernodes)
|
||||
WholeArrayIn hierarchicalTreeHypernodes, // input
|
||||
WholeArrayIn hierarchicalTreeWhichIteration, //input
|
||||
WholeArrayInOut
|
||||
hierarchicalTreeFirstHypernodePerIteration //output. should be set to hierarchicalTree.firstHypernodePerIteration[theRound]. // TODO: is it sufficient to use WholeArrayOut?
|
||||
);
|
||||
|
||||
using ExecutionSignature = void(_1, _2, _3, _4);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
CopyFirstHypernodePerIterationWorklet(vtkm::Id numOldHypernodes)
|
||||
: NumOldHypernodes(numOldHypernodes)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename InFieldPortalType, typename OutFieldPortalType>
|
||||
VTKM_EXEC void operator()(
|
||||
const vtkm::Id& newHypernode,
|
||||
const InFieldPortalType& hierarchicalTreeHypernodesPortal,
|
||||
const InFieldPortalType& hierarchicalTreeWhichIterationPortal,
|
||||
const OutFieldPortalType& hierarchicalTreeFirstHypernodePerIterationPortal) const
|
||||
{ // operator ()
|
||||
// per new hypernode
|
||||
vtkm::Id supernodeId = hierarchicalTreeHypernodesPortal.Get(newHypernode);
|
||||
vtkm::Id wasTransferred = vtkm::worklet::contourtree_augmented::MaskedIndex(
|
||||
hierarchicalTreeWhichIterationPortal.Get(supernodeId));
|
||||
|
||||
// the first one defines the zeroth iteration: changes in iteration number define the others
|
||||
if (newHypernode == this->NumOldHypernodes)
|
||||
{ // LHE
|
||||
hierarchicalTreeFirstHypernodePerIterationPortal.Set(0, newHypernode);
|
||||
} // LHE
|
||||
else if (wasTransferred !=
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(
|
||||
hierarchicalTreeWhichIterationPortal.Get(
|
||||
hierarchicalTreeHypernodesPortal.Get(newHypernode - 1))))
|
||||
{ // other breakpoint
|
||||
hierarchicalTreeFirstHypernodePerIterationPortal.Set(wasTransferred, newHypernode);
|
||||
} // other breakpoint
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
for (indexType newHypernode = nOldHypernodes; newHypernode < nTotalHypernodes; newHypernode++)
|
||||
{ // per new hypernode
|
||||
indexType supernodeID = hierarchicalTree.hypernodes[newHypernode];
|
||||
indexType wasTransferred = maskedIndex(hierarchicalTree.whichIteration[supernodeID]);
|
||||
|
||||
// the first one defines the zeroth iteration: changes in iteration number define the others
|
||||
if (newHypernode == nOldHypernodes)
|
||||
{ // LHE
|
||||
hierarchicalTree.firstHypernodePerIteration[theRound][0] = newHypernode;
|
||||
} // LHE
|
||||
else if (wasTransferred != maskedIndex(hierarchicalTree.whichIteration[hierarchicalTree.hypernodes[newHypernode-1]]))
|
||||
{ // other breakpoint
|
||||
hierarchicalTree.firstHypernodePerIteration[theRound][wasTransferred] = newHypernode;
|
||||
} // other breakpoint
|
||||
} // per new hypernode
|
||||
*/
|
||||
} // operator ()
|
||||
|
||||
private:
|
||||
vtkm::Id NumOldHypernodes;
|
||||
|
||||
}; // CopyNewHypernodes
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
147
vtkm/worklet/contourtree_distributed/tree_grafter/CopyFirstSupernodePerIterationWorklet.h
Normal file
147
vtkm/worklet/contourtree_distributed/tree_grafter/CopyFirstSupernodePerIterationWorklet.h
Normal file
@ -0,0 +1,147 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_copy_first_supernode_per_iteration_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_copy_first_supernode_per_iteration_worklet_h
|
||||
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
/// Worklet implementing the copy of the first supernode per iteration in TreeGrafter::CopyIterationDetails
|
||||
class CopyFirstSupernodePerIterationWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using ControlSignature = void(
|
||||
FieldIn
|
||||
newSupernode, // fancy ArrayHandleCounting(nOldSupernodes, 1, nTotalSupernodes - nOldSupernodes)
|
||||
WholeArrayIn hierarchicalTreeWhichIteration, // input
|
||||
WholeArrayInOut
|
||||
hierarchicalTreeFirstSupernodePerIteration // output. Should be set to hierarchicalTree.firstSupernodePerIteration[theRound]/ // TODO: is it sufficient to use WholeArrayOut?
|
||||
);
|
||||
|
||||
using ExecutionSignature = void(_1, _2, _3);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
CopyFirstSupernodePerIterationWorklet(vtkm::Id numOldSupernodes)
|
||||
: NumOldSupernodes(numOldSupernodes)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename InFieldPortalType, typename OutFieldPortalType>
|
||||
VTKM_EXEC void operator()(
|
||||
const vtkm::Id& newSupernode,
|
||||
const InFieldPortalType& hierarchicalTreeWhichIterationPortal,
|
||||
const OutFieldPortalType& hierarchicalTreeFirstSupernodePerIterationPortal
|
||||
|
||||
) const
|
||||
{ // operator ()
|
||||
// per new supernode
|
||||
// the LHE is the first new supernode: it just stores
|
||||
if (newSupernode == this->NumOldSupernodes)
|
||||
{
|
||||
hierarchicalTreeFirstSupernodePerIterationPortal.Set(0, newSupernode);
|
||||
}
|
||||
// otherwise we only write if we detect a change in iterations
|
||||
else
|
||||
{ // not LHE
|
||||
if (vtkm::worklet::contourtree_augmented::MaskedIndex(
|
||||
hierarchicalTreeWhichIterationPortal.Get(newSupernode)) !=
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(
|
||||
hierarchicalTreeWhichIterationPortal.Get(newSupernode - 1)))
|
||||
{
|
||||
hierarchicalTreeFirstSupernodePerIterationPortal.Set(
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(
|
||||
hierarchicalTreeWhichIterationPortal.Get(newSupernode)),
|
||||
newSupernode);
|
||||
}
|
||||
} // not LHE
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
for (indexType newSupernode = nOldSupernodes; newSupernode < nTotalSupernodes; newSupernode++)
|
||||
{ // per new supernode
|
||||
// the LHE is the first new supernode: it just stores
|
||||
if (newSupernode == nOldSupernodes)
|
||||
hierarchicalTree.firstSupernodePerIteration[theRound][0] = newSupernode;
|
||||
// otherwise we only write if we detect a change in iterations
|
||||
else
|
||||
{ // not LHE
|
||||
if (maskedIndex(hierarchicalTree.whichIteration[newSupernode]) != maskedIndex(hierarchicalTree.whichIteration[newSupernode-1]))
|
||||
hierarchicalTree.firstSupernodePerIteration[theRound][maskedIndex(hierarchicalTree.whichIteration[newSupernode])] = newSupernode;
|
||||
} // not LHE
|
||||
} // per new supernode
|
||||
*/
|
||||
} // operator ()
|
||||
|
||||
private:
|
||||
vtkm::Id NumOldSupernodes;
|
||||
|
||||
}; // CopyNewHypernodes
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -0,0 +1,161 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_copy_new_hypernodes_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_copy_new_hypernodes_worklet_h
|
||||
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
// Worklet implementing the inner parallel loop to collaps the regular chains in TreeGrafter.CollapseRegularChains
|
||||
class CopyNewHypernodesWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using ControlSignature = void(FieldIn newHypernodes, // input iteration index.
|
||||
WholeArrayIn hierarchicalSuperId, // input
|
||||
WholeArrayIn hierarchicalHyperarc, // input
|
||||
WholeArrayOut hierarchicalTreeHypernodes, // output
|
||||
WholeArrayOut hierarchicalTreeHyperarcs // output
|
||||
);
|
||||
|
||||
using ExecutionSignature = void(InputIndex, _1, _2, _3, _4, _5);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
CopyNewHypernodesWorklet(vtkm::Id numOldHypernodes)
|
||||
: NumOldHypernodes(numOldHypernodes)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename InFieldPortalType, typename OutFieldPortalType>
|
||||
VTKM_EXEC void operator()(
|
||||
const vtkm::Id& newHypernode, // position in newHypernodes arrays
|
||||
const vtkm::Id&
|
||||
oldSupernodeId, // old hypernode ID & super ID, i.e., newHypernodes[newHypernode]
|
||||
const InFieldPortalType& hierarchicalSuperIdPortal, // input
|
||||
const InFieldPortalType& hierarchicalHyperarcPortal, // input
|
||||
const OutFieldPortalType& hierarchicalTreeHypernodesPortal, // output
|
||||
const OutFieldPortalType& hierarchicalTreeHyperarcsPortal // output
|
||||
) const
|
||||
{ // operator ()
|
||||
// per new hypernode
|
||||
// retrieve the old hypernode ID & super ID (DONE as part of the worklet invocation)
|
||||
// convert into new IDs
|
||||
vtkm::Id newHypernodeId = this->NumOldHypernodes + newHypernode;
|
||||
vtkm::Id newHypernodeSuperId = hierarchicalSuperIdPortal.Get(oldSupernodeId);
|
||||
|
||||
// store the new hypernode ID
|
||||
hierarchicalTreeHypernodesPortal.Set(newHypernodeId, newHypernodeSuperId);
|
||||
|
||||
// retrieve the hyperarc and convert, carrying masking bits
|
||||
vtkm::Id newHyperarcOldSuperId = hierarchicalHyperarcPortal.Get(oldSupernodeId);
|
||||
vtkm::Id isAscendingHyperarc =
|
||||
vtkm::worklet::contourtree_augmented::IsAscending(newHyperarcOldSuperId)
|
||||
? vtkm::worklet::contourtree_augmented::IS_ASCENDING
|
||||
: 0x0;
|
||||
newHyperarcOldSuperId =
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(newHyperarcOldSuperId);
|
||||
vtkm::Id newHyperarcNewSuperId =
|
||||
hierarchicalSuperIdPortal.Get(newHyperarcOldSuperId) | isAscendingHyperarc;
|
||||
|
||||
// and store it
|
||||
hierarchicalTreeHyperarcsPortal.Set(newHypernodeId, newHyperarcNewSuperId);
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
// B. Copy in the hypernodes & hyperarcs
|
||||
for (indexType newHypernode = 0; newHypernode < nNewHypernodes; newHypernode++)
|
||||
{ // per new hypernode
|
||||
// retrieve the old hypernode ID & super ID
|
||||
indexType oldSupernodeID = newHypernodes[newHypernode];
|
||||
|
||||
// convert into new IDs
|
||||
indexType newHypernodeID = nOldHypernodes + newHypernode;
|
||||
indexType newHypernodeSuperID = hierarchicalSuperID[oldSupernodeID];
|
||||
|
||||
// store the new hypernode ID
|
||||
hierarchicalTree.hypernodes[newHypernodeID] = newHypernodeSuperID;
|
||||
|
||||
// retrieve the hyperarc and convert, carrying masking bits
|
||||
indexType newHyperarcOldSuperID = hierarchicalHyperarc[oldSupernodeID];
|
||||
indexType isAscendingHyperarc = isAscending(newHyperarcOldSuperID) ? IS_ASCENDING : 0x0;
|
||||
newHyperarcOldSuperID = maskedIndex(newHyperarcOldSuperID);
|
||||
indexType newHyperarcNewSuperID = hierarchicalSuperID[newHyperarcOldSuperID] | isAscendingHyperarc;
|
||||
|
||||
// and store it
|
||||
hierarchicalTree.hyperarcs[newHypernodeID] = newHyperarcNewSuperID;
|
||||
} // per new hypernode
|
||||
*/
|
||||
} // operator ()
|
||||
|
||||
private:
|
||||
vtkm::Id NumOldHypernodes;
|
||||
|
||||
}; // CopyNewHypernodes
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
226
vtkm/worklet/contourtree_distributed/tree_grafter/CopyNewNodesSetSuperparentsWorklet.h
Normal file
226
vtkm/worklet/contourtree_distributed/tree_grafter/CopyNewNodesSetSuperparentsWorklet.h
Normal file
@ -0,0 +1,226 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_copy_new_nodes_set_superparents_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_copy_new_nodes_set_superparents_worklet_h
|
||||
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
// Worklet implementing the sorting out the superparents as part of TreeGrafter::CopyNewNodes
|
||||
class CopyNewNodesSetSuperparentsWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
// TODO: Some WholeArrayIn could potentially be made FieldIn if we reshuffeled the arrays via newNodes beforehand
|
||||
using ControlSignature = void(FieldIn newNodes, // input and iteration index
|
||||
WholeArrayIn meshSortIndex, // input
|
||||
WholeArrayIn meshSortOrder, // input
|
||||
WholeArrayIn contourTreeSuperparents, // input
|
||||
WholeArrayIn contourTreeSuperarcs, // input
|
||||
WholeArrayIn contourTreeSupernodes, // input
|
||||
WholeArrayIn hierarchicalRegularId, // input
|
||||
WholeArrayIn hierarchicalTreeId, // input
|
||||
WholeArrayIn hierarchicalTreeRegularNodeGlobalIds, // input
|
||||
WholeArrayIn hierarchicalTreeDataValues, // input
|
||||
ExecObject findSuperArcForUnknownNode, // input
|
||||
WholeArrayOut hierarchicalTreeSuperparents // output
|
||||
);
|
||||
|
||||
using ExecutionSignature = void(InputIndex, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
CopyNewNodesSetSuperparentsWorklet(const vtkm::Id& numOldNodes)
|
||||
: NumOldNodes(numOldNodes)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename InFieldPortalType,
|
||||
typename MeshSortIndexPortalType,
|
||||
typename MeshSortOrderPortalType,
|
||||
typename DataValuePortalType,
|
||||
typename FindSuperExecType,
|
||||
typename OutFieldPortalType>
|
||||
VTKM_EXEC void operator()(
|
||||
const vtkm::Id& newNode,
|
||||
const vtkm::Id&
|
||||
oldNodeId, // convert to a node Id in the current level's tree when calling the worklet
|
||||
const MeshSortIndexPortalType& meshSortIndexPortal,
|
||||
const MeshSortOrderPortalType& meshSortOrderPortal,
|
||||
const InFieldPortalType& contourTreeSuperparentsPortal,
|
||||
const InFieldPortalType& contourTreeSuperarcsPortal,
|
||||
const InFieldPortalType& contourTreeSupernodesPortal,
|
||||
const InFieldPortalType& hierarchicalRegularIdPortal,
|
||||
const InFieldPortalType& hierarchicalTreeIdPortal,
|
||||
const InFieldPortalType& hierarchicalTreeRegularNodeGlobalIdsPortal,
|
||||
const DataValuePortalType& hierarchicalTreeDataValuesPortal,
|
||||
const FindSuperExecType& findSuperArcForUnknownNode,
|
||||
const OutFieldPortalType& hierarchicalTreeSuperparentsPortal
|
||||
|
||||
) const
|
||||
{ // operator ()
|
||||
// per new node
|
||||
// index into hierarchical tree
|
||||
vtkm::Id newNodeId = this->NumOldNodes + newNode;
|
||||
// retrieve the old parent superarc
|
||||
vtkm::Id oldSortIndex = meshSortIndexPortal.Get(oldNodeId);
|
||||
vtkm::Id oldSuperparent = contourTreeSuperparentsPortal.Get(oldSortIndex);
|
||||
// and to a regular Id
|
||||
vtkm::Id oldSuperparentNewRegularId = hierarchicalRegularIdPortal.Get(oldSuperparent);
|
||||
|
||||
// Assuming that the new supernodes & hypernodes have been transferred, EVERY supernode in the old tree
|
||||
// now has hierarchicalRegularId set correctly. Since every regular node belongs on a superarc in the old tree,
|
||||
// we can use the ends of the superarc to invoke a search in the hierarchical tree for the superparent.
|
||||
// This is therefore logically dependent on having the superstructure & hyperstructure updated first
|
||||
|
||||
// supernodes will already have their superparent set in CopyNewSupernodes()
|
||||
if (vtkm::worklet::contourtree_augmented::NoSuchElement(
|
||||
hierarchicalTreeSuperparentsPortal.Get(newNodeId)))
|
||||
{ // it's not a supernode
|
||||
// retrieve the end of the superarc & convert to hierarchical regular Id, plus identify whether it ascends
|
||||
vtkm::Id oldSupertargetSuperId = contourTreeSuperarcsPortal.Get(oldSuperparent);
|
||||
bool oldSuperarcAscends =
|
||||
vtkm::worklet::contourtree_augmented::IsAscending(oldSupertargetSuperId);
|
||||
oldSupertargetSuperId =
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(oldSupertargetSuperId);
|
||||
vtkm::Id oldSupertargetOldSortId = contourTreeSupernodesPortal.Get(oldSupertargetSuperId);
|
||||
vtkm::Id oldSupertargetOldRegularId = meshSortOrderPortal.Get(oldSupertargetOldSortId);
|
||||
vtkm::Id oldSupertargetNewRegularId =
|
||||
hierarchicalTreeIdPortal.Get(oldSupertargetOldRegularId);
|
||||
|
||||
// set up variables for our pruning search
|
||||
// collect the low end's values
|
||||
vtkm::Id lowEndRegularId =
|
||||
oldSuperarcAscends ? oldSuperparentNewRegularId : oldSupertargetNewRegularId;
|
||||
vtkm::Id highEndRegularId =
|
||||
oldSuperarcAscends ? oldSupertargetNewRegularId : oldSuperparentNewRegularId;
|
||||
|
||||
// pull the data value at the node
|
||||
vtkm::Id nodeGlobalId = hierarchicalTreeRegularNodeGlobalIdsPortal.Get(newNodeId);
|
||||
auto nodeValue = hierarchicalTreeDataValuesPortal.Get(newNodeId);
|
||||
|
||||
// now ask the hierarchical tree for the correct superparent
|
||||
hierarchicalTreeSuperparentsPortal.Set(
|
||||
newNodeId,
|
||||
findSuperArcForUnknownNode.FindSuperArcForUnknownNode(
|
||||
nodeGlobalId, nodeValue, highEndRegularId, lowEndRegularId));
|
||||
} // it's not a supernode
|
||||
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
for (indexType newNode = 0; newNode < newNodes.size(); newNode++)
|
||||
{ // per new node
|
||||
// convert to a node ID in the current level's tree
|
||||
indexType oldNodeID = newNodes[newNode];
|
||||
// index into hierarchical tree
|
||||
indexType newNodeID = nOldNodes + newNode;
|
||||
// retrieve the old parent superarc
|
||||
indexType oldSortIndex = mesh->SortIndex(oldNodeID);
|
||||
indexType oldSuperparent = contourTree->superparents[oldSortIndex];
|
||||
// and to a regular ID
|
||||
indexType oldSuperparentNewRegularID = hierarchicalRegularID[oldSuperparent];
|
||||
|
||||
// Assuming that the new supernodes & hypernodes have been transferred, EVERY supernode in the old tree
|
||||
// now has hierarchicalRegularID set correctly. Since every regular node belongs on a superarc in the old tree,
|
||||
// we can use the ends of the superarc to invoke a search in the hierarchical tree for the superparent.
|
||||
// This is therefore logically dependent on having the superstructure & hyperstructure updated first
|
||||
|
||||
// supernodes will already have their superparent set in CopyNewSupernodes()
|
||||
if (noSuchElement(hierarchicalTree.superparents[newNodeID]))
|
||||
{ // it's not a supernode
|
||||
// retrieve the end of the superarc & convert to hierarchical regular ID, plus identify whether it ascends
|
||||
indexType oldSupertargetSuperID = contourTree->superarcs[oldSuperparent];
|
||||
bool oldSuperarcAscends = isAscending(oldSupertargetSuperID);
|
||||
oldSupertargetSuperID = maskedIndex(oldSupertargetSuperID);
|
||||
indexType oldSupertargetOldSortID = contourTree->supernodes[oldSupertargetSuperID];
|
||||
indexType oldSupertargetOldRegularID = mesh->SortOrder(oldSupertargetOldSortID);
|
||||
indexType oldSupertargetNewRegularID = hierarchicalTreeID[oldSupertargetOldRegularID];
|
||||
|
||||
// set up variables for our pruning search
|
||||
// collect the low end's values
|
||||
indexType lowEndRegularID = oldSuperarcAscends ? oldSuperparentNewRegularID : oldSupertargetNewRegularID;
|
||||
indexType highEndRegularID = oldSuperarcAscends ? oldSupertargetNewRegularID : oldSuperparentNewRegularID;
|
||||
|
||||
// pull the data value at the node
|
||||
indexType nodeGlobalID = hierarchicalTree.regularNodeGlobalIDs[newNodeID];
|
||||
dataType nodeValue = hierarchicalTree.dataValues[newNodeID];
|
||||
|
||||
// now ask the hierarchical tree for the correct superparent
|
||||
hierarchicalTree.superparents[newNodeID] = hierarchicalTree.FindSuperArcForUnknownNode(nodeGlobalID, nodeValue, highEndRegularID, lowEndRegularID);
|
||||
} // it's not a supernode
|
||||
} // per new node
|
||||
*/
|
||||
} // operator ()
|
||||
|
||||
private:
|
||||
vtkm::Id NumOldNodes;
|
||||
|
||||
}; // CopyNewHypernodes
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
161
vtkm/worklet/contourtree_distributed/tree_grafter/CopyNewSupernodesSetSuperchildrenWorklet.h
Normal file
161
vtkm/worklet/contourtree_distributed/tree_grafter/CopyNewSupernodesSetSuperchildrenWorklet.h
Normal file
@ -0,0 +1,161 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_copy_new_supernodes_set_superchildren_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_copy_new_supernodes_set_superchildren_worklet_h
|
||||
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
/// Worklet to loop to set the number of superchildren per hyperarc as part of TreeGrafter::CopyNewSupernodes
|
||||
class CopyNewSupernodesSetSuperchildrenWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
// TODO: Access to hierarchicalTreeSuperarcs and hierarchicalTreeHyperparents could potentially be imporved by using an ArrayView instead
|
||||
using ControlSignature = void(
|
||||
FieldIn newSupernodeIndex, // input array starting at 0 to NewSupernodes.GetNumberOfValues();
|
||||
WholeArrayIn hierarchicalTreeSuperarcs, //input
|
||||
WholeArrayIn hierarchicalTreeHyperparents, // input
|
||||
WholeArrayIn hierarchicalTreeHypernodes, //input
|
||||
WholeArrayOut hierarchicalTreeSuperchildren // output
|
||||
);
|
||||
|
||||
using ExecutionSignature = void(_1, _2, _3, _4, _5);
|
||||
using InputDomain = _1;
|
||||
|
||||
/// Default Constructor
|
||||
/// @param[in]numhierarchicalTreeSupernodes should be set to hierarchicalTree.Supernodes.GetNumberOfValues()
|
||||
VTKM_EXEC_CONT
|
||||
CopyNewSupernodesSetSuperchildrenWorklet(vtkm::Id numHierarchicalTreeSupernodes)
|
||||
: NumHierarchicalTreeSupernodes(numHierarchicalTreeSupernodes)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename InFieldPortalType, typename OutFieldPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::Id& newSupernodeIndex,
|
||||
const InFieldPortalType& hierarchicalTreeSuperarcsPortal,
|
||||
const InFieldPortalType& hierarchicalTreeHyperparentsPortal,
|
||||
const InFieldPortalType& hierarchicalTreeHypernodesPortal,
|
||||
const OutFieldPortalType hierarchicalTreeSuperchildrenPortal
|
||||
|
||||
) const
|
||||
{ // operator ()
|
||||
// convert from 0...NumNewSupernodes index to [hierarchicalTree.supernodes.size() - newSupernodes.size(), hierarchicalTree.supernodes.size())
|
||||
vtkm::Id newSupernode = (this->NumHierarchicalTreeSupernodes - 1) - newSupernodeIndex;
|
||||
|
||||
// per new supernode
|
||||
// attachment points have NULL superarcs and can be ignored
|
||||
if (vtkm::worklet::contourtree_augmented::NoSuchElement(
|
||||
hierarchicalTreeSuperarcsPortal.Get(newSupernode)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// OK: we are now guaranteed to have a valid hyperparent
|
||||
vtkm::Id hyperparent = hierarchicalTreeHyperparentsPortal.Get(newSupernode);
|
||||
|
||||
// we could still be at the end of the array, so we have to test explicitly
|
||||
if (newSupernode == NumHierarchicalTreeSupernodes - 1)
|
||||
{
|
||||
// compute the delta and store it
|
||||
hierarchicalTreeSuperchildrenPortal.Set(hyperparent,
|
||||
NumHierarchicalTreeSupernodes -
|
||||
hierarchicalTreeHypernodesPortal.Get(hyperparent));
|
||||
}
|
||||
else if (hyperparent != hierarchicalTreeHyperparentsPortal.Get(newSupernode + 1))
|
||||
{
|
||||
hierarchicalTreeSuperchildrenPortal.Set(
|
||||
hyperparent, newSupernode + 1 - hierarchicalTreeHypernodesPortal.Get(hyperparent));
|
||||
}
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
for (indexType newSupernode = hierarchicalTree.supernodes.size() - newSupernodes.size(); newSupernode < hierarchicalTree.supernodes.size(); newSupernode++)
|
||||
{ // per new supernode
|
||||
// attachment points have NULL superarcs and can be ignored
|
||||
if (noSuchElement(hierarchicalTree.superarcs[newSupernode]))
|
||||
continue;
|
||||
|
||||
// OK: we are now guaranteed to have a valid hyperparent
|
||||
indexType hyperparent = hierarchicalTree.hyperparents[newSupernode];
|
||||
|
||||
// we could still be at the end of the array, so we have to test explicitly
|
||||
if (newSupernode == hierarchicalTree.supernodes.size() - 1)
|
||||
// compute the delta and store it
|
||||
hierarchicalTree.superchildren[hyperparent] = hierarchicalTree.supernodes.size() - hierarchicalTree.hypernodes[hyperparent];
|
||||
else if (hyperparent != hierarchicalTree.hyperparents[newSupernode + 1])
|
||||
hierarchicalTree.superchildren[hyperparent] = newSupernode + 1 - hierarchicalTree.hypernodes[hyperparent];
|
||||
} // per new supernode
|
||||
|
||||
*/
|
||||
} // operator ()
|
||||
|
||||
private:
|
||||
vtkm::Id NumHierarchicalTreeSupernodes; /// hierarchicalTree.supernodes.size()
|
||||
|
||||
}; // CopyNewHypernodes
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -0,0 +1,417 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_copy_new_supernodes_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_copy_new_supernodes_worklet_h
|
||||
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
// Worklet implementing TreeGrafter.CopyNewSupernodes
|
||||
class CopyNewSupernodesWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using ControlSignature = void(WholeArrayIn newSupernode, // input and iteration index
|
||||
WholeArrayIn contourTreeSupernodes, // input
|
||||
WholeArrayIn meshSorterOrder, // input
|
||||
WholeArrayIn hierarchicalTreeId, // input
|
||||
WholeArrayIn whenTransferred, // input
|
||||
WholeArrayIn hierarchicalSuperparent, // input
|
||||
WholeArrayIn hierarchicalHyperparent, //input
|
||||
WholeArrayIn hierarchicalSuperId, // input
|
||||
WholeArrayIn hierarchicalHyperId, // input
|
||||
WholeArrayIn hierarchicalHyperarc, // input
|
||||
WholeArrayOut hierarchicalTreeSupernodes, // output
|
||||
WholeArrayOut hierarchicalTreeWhichRound, // output
|
||||
WholeArrayOut hierarchicalTreeWhichIteration, // output
|
||||
WholeArrayOut hierarchicalTreeSuperarcs, // output
|
||||
WholeArrayInOut hierarchicalRegularId, // input/output
|
||||
WholeArrayInOut hierarchicalTreeHyperparents, // input/output
|
||||
WholeArrayInOut hierarchicalTreeSuperparents // input/output
|
||||
);
|
||||
|
||||
using ExecutionSignature =
|
||||
void(InputIndex, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
CopyNewSupernodesWorklet(vtkm::Id theRound, vtkm::Id numOldSupernodes)
|
||||
: TheRound(theRound)
|
||||
, NumOldSupernodes(numOldSupernodes)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename InFieldPortalType,
|
||||
typename SortOrderPortalType,
|
||||
typename OutFieldPortalType,
|
||||
typename InOutFieldPortalType>
|
||||
VTKM_EXEC void operator()(
|
||||
const vtkm::Id& newSupernode,
|
||||
const InFieldPortalType& newSupernodesPortal,
|
||||
const InFieldPortalType& contourTreeSupernodesPortal,
|
||||
const SortOrderPortalType&
|
||||
meshSortOrderPortal, // depending on the mesh type these may be differnt fancy arrays
|
||||
const InFieldPortalType& hierarchicalTreeIdPortal,
|
||||
const InFieldPortalType& whenTransferredPortal,
|
||||
const InFieldPortalType& hierarchicalSuperparentPortal,
|
||||
const InFieldPortalType& hierarchicalHyperparentPortal,
|
||||
const InFieldPortalType& hierarchicalSuperIdPortal,
|
||||
const InFieldPortalType& hierarchicalHyperIdPortal,
|
||||
const InFieldPortalType& hierarchicalHyperarcPortal,
|
||||
const OutFieldPortalType& hierarchicalTreeSupernodesPortal,
|
||||
const OutFieldPortalType& hierarchicalTreeWhichRoundPortal,
|
||||
const OutFieldPortalType& hierarchicalTreeWhichIterationPortal,
|
||||
const OutFieldPortalType& hierarchicalTreeSuperarcsPortal,
|
||||
const InOutFieldPortalType& hierarchicalRegularIdPortal,
|
||||
const InOutFieldPortalType& hierarchicalTreeHyperparentsPortal,
|
||||
const InOutFieldPortalType& hierarchicalTreeSuperparentsPortal
|
||||
|
||||
) const
|
||||
{ // operator ()
|
||||
// per new supernode
|
||||
// retrieve the old supernode & regular node Ids
|
||||
vtkm::Id oldSupernodeId = newSupernodesPortal.Get(newSupernode);
|
||||
vtkm::Id oldSortId = contourTreeSupernodesPortal.Get(oldSupernodeId);
|
||||
vtkm::Id oldRegularId = meshSortOrderPortal.Get(oldSortId);
|
||||
|
||||
// convert to new Ids
|
||||
vtkm::Id newRegularId = hierarchicalTreeIdPortal.Get(oldRegularId);
|
||||
vtkm::Id newSupernodeId = this->NumOldSupernodes + newSupernode;
|
||||
|
||||
// set the supernode accordingly
|
||||
hierarchicalTreeSupernodesPortal.Set(newSupernodeId, newRegularId);
|
||||
|
||||
// and set the round and iteration
|
||||
hierarchicalTreeWhichRoundPortal.Set(newSupernodeId, this->TheRound);
|
||||
hierarchicalTreeWhichIterationPortal.Set(newSupernodeId,
|
||||
whenTransferredPortal.Get(oldSupernodeId));
|
||||
|
||||
// We want to set the superarc and hyperparent. At this point, supernodes fall into four groups:
|
||||
// I. Present in the hierarchical tree as supernodes No work required (not in newSupernodes)
|
||||
// II. Present in the hierarchical tree as regular nodes only Added as supernode. Hyperparent only needs to be set.
|
||||
// III. Not present in the hierarchical tree: attachment point Super/hyper parent stored in hierarchical Ids
|
||||
// IV. Not present, and not an attachment point Super/hyper parent stored in local Ids
|
||||
// Note that I. is already taken care of, so we test whether the supernode was previously in the hierarchical tree at all
|
||||
vtkm::Id storedRegularId = hierarchicalRegularIdPortal.Get(oldSupernodeId);
|
||||
|
||||
// and set the regular Id in the hierarchical tree (even if it is already set)
|
||||
hierarchicalRegularIdPortal.Set(oldSupernodeId, newRegularId);
|
||||
|
||||
// now we sort out hyperparent
|
||||
if (!vtkm::worklet::contourtree_augmented::NoSuchElement(storedRegularId))
|
||||
{ // present: II
|
||||
// if it isn't already a supernode, it is "only" a regular node
|
||||
if (newSupernodeId >= this->NumOldSupernodes)
|
||||
{ // regular but not super
|
||||
// in this case, it already has a superparent (because it is already present in the tree as a regular node)
|
||||
// so we look up the relevant hyperparent
|
||||
hierarchicalTreeHyperparentsPortal.Set(
|
||||
newSupernodeId,
|
||||
hierarchicalTreeHyperparentsPortal.Get(
|
||||
hierarchicalTreeSuperparentsPortal.Get(storedRegularId)));
|
||||
// we set this to indicate that it's an attachment point
|
||||
hierarchicalTreeSuperarcsPortal.Set(newSupernodeId,
|
||||
vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT);
|
||||
} // regular but not super
|
||||
} // present: actually II
|
||||
else
|
||||
{ // not present: III or IV
|
||||
// attachment point (III) or free point (IV)
|
||||
if (!vtkm::worklet::contourtree_augmented::NoSuchElement(
|
||||
hierarchicalSuperparentPortal.Get(oldSupernodeId)))
|
||||
{ // attachment point
|
||||
// we've already captured the super-/hyper- parent in an earlier stage
|
||||
hierarchicalTreeSuperparentsPortal.Set(newRegularId,
|
||||
hierarchicalSuperparentPortal.Get(oldSupernodeId));
|
||||
hierarchicalTreeHyperparentsPortal.Set(newSupernodeId,
|
||||
hierarchicalHyperparentPortal.Get(oldSupernodeId));
|
||||
// and the superarc should indicate an attachment point
|
||||
hierarchicalTreeSuperarcsPortal.Set(newSupernodeId,
|
||||
vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT);
|
||||
} // attachment point
|
||||
// otherwise, we have a brand new free supernode, which is it's own superparent
|
||||
else
|
||||
{ // free point
|
||||
// this is a supernode that was never in the hierarchical tree in the first place
|
||||
// it is its own superparent, and has a new hyperparent in old supernode Ids (often itself)
|
||||
// and can use that to look up the new hyperId
|
||||
vtkm::Id hierarchicalHyperparentOldSuperId =
|
||||
hierarchicalHyperparentPortal.Get(oldSupernodeId);
|
||||
vtkm::Id hierarchicalHyperparentNewHyperId =
|
||||
hierarchicalHyperIdPortal.Get(hierarchicalHyperparentOldSuperId);
|
||||
hierarchicalTreeHyperparentsPortal.Set(newSupernodeId, hierarchicalHyperparentNewHyperId);
|
||||
// since it is its own superparent, this is easy . . .
|
||||
hierarchicalTreeSuperparentsPortal.Set(newRegularId, newSupernodeId);
|
||||
|
||||
// now the hard part: fill in the superarc
|
||||
vtkm::Id hierarchicalHyperarcOldSuperId =
|
||||
hierarchicalHyperarcPortal.Get(hierarchicalHyperparentOldSuperId);
|
||||
vtkm::Id isAscendingHyperarc =
|
||||
vtkm::worklet::contourtree_augmented::IsAscending(hierarchicalHyperarcOldSuperId)
|
||||
? vtkm::worklet::contourtree_augmented::IS_ASCENDING
|
||||
: 0x0;
|
||||
hierarchicalHyperarcOldSuperId =
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(hierarchicalHyperarcOldSuperId);
|
||||
vtkm::Id hierarchicalHyperarcNewSuperId =
|
||||
hierarchicalSuperIdPortal.Get(hierarchicalHyperarcOldSuperId);
|
||||
|
||||
// we have located each supernode on a hyperarc
|
||||
// and we have to work out the supernode each connects to
|
||||
// unfortunately, the attachment points complicate this compared to the old code
|
||||
// for sweeping later, we will set the # of superchildren, but we don't have that yet
|
||||
|
||||
// So the test will have to be the following:
|
||||
// i. the "neighbour" is the +1 index
|
||||
// ii. if the neighbour is off the end, we take the end of the hyperarc
|
||||
// iii. if the neighbour has flagged as an attachment point, we take the end of the hyperarc
|
||||
// iv. in all other cases, we take the neighbour
|
||||
// Note that we are saved some trouble by the fact that this code only applies to free points
|
||||
|
||||
// the superarc is now set by checking to see if the neighbour has the same hyperparent:
|
||||
// if it does, our superarc goes to the next element
|
||||
// if not (or we're at array end), we go to the hyperarc's target
|
||||
// NOTE: we will store the OLD superarc Id at this stage, since we need it to sort out regular arcs
|
||||
// this means we will have to add a final loop to reset to hierarchical Ids
|
||||
vtkm::Id neighbour = newSupernode + 1;
|
||||
|
||||
// special case at end of array: map the old hyperarc Id to a new one
|
||||
if (neighbour >= newSupernodesPortal.GetNumberOfValues())
|
||||
{ // end of array
|
||||
hierarchicalTreeSuperarcsPortal.Set(newSupernodeId,
|
||||
hierarchicalHyperarcNewSuperId | isAscendingHyperarc);
|
||||
} // end of array
|
||||
else
|
||||
{ // not at the end of the array
|
||||
vtkm::Id nbrSuperId = newSupernodesPortal.Get(neighbour);
|
||||
|
||||
// immediately check for case iii. by looking at the hierarchicalSuperparent of the neighbour's old Id
|
||||
// if it's already set, it's because it's an attachment point
|
||||
if (!vtkm::worklet::contourtree_augmented::NoSuchElement(
|
||||
hierarchicalSuperparentPortal.Get(nbrSuperId)))
|
||||
{ // attachment point
|
||||
hierarchicalTreeSuperarcsPortal.Set(
|
||||
newSupernodeId, hierarchicalHyperarcNewSuperId | isAscendingHyperarc);
|
||||
} // attachment point
|
||||
else
|
||||
{ // not attachment point
|
||||
vtkm::Id nbrHyperparent = hierarchicalHyperparentPortal.Get(nbrSuperId);
|
||||
|
||||
// if they share a hyperparent, just take the neighbour
|
||||
if (nbrHyperparent == hierarchicalHyperparentOldSuperId)
|
||||
{ // shared hyperparent
|
||||
hierarchicalTreeSuperarcsPortal.Set(
|
||||
newSupernodeId, hierarchicalSuperIdPortal.Get(nbrSuperId) | isAscendingHyperarc);
|
||||
} // shared hyperparent
|
||||
// if not, take the target of the hyperarc
|
||||
else
|
||||
{ // not shared hyperparent
|
||||
hierarchicalTreeSuperarcsPortal.Set(
|
||||
newSupernodeId, hierarchicalHyperarcNewSuperId | isAscendingHyperarc);
|
||||
} // not shared hyperparent
|
||||
} // not attachment point
|
||||
} // not at the end of the array
|
||||
} // free point
|
||||
} // attachment point (III) or free point (IV)
|
||||
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
for (indexType newSupernode = 0; newSupernode < nNewSupernodes; newSupernode++)
|
||||
{ // per new supernode
|
||||
// retrieve the old supernode & regular node IDs
|
||||
indexType oldSupernodeID = newSupernodes[newSupernode];
|
||||
indexType oldSortID = contourTree->supernodes[oldSupernodeID];
|
||||
indexType oldRegularID = mesh->SortOrder(oldSortID);
|
||||
|
||||
// convert to new IDs
|
||||
indexType newRegularID = hierarchicalTreeID[oldRegularID];
|
||||
indexType newSupernodeID = nOldSupernodes + newSupernode;
|
||||
|
||||
// set the supernode accordingly
|
||||
hierarchicalTree.supernodes[newSupernodeID] = newRegularID;
|
||||
|
||||
// and set the round and iteration
|
||||
hierarchicalTree.whichRound[newSupernodeID] = theRound;
|
||||
hierarchicalTree.whichIteration[newSupernodeID] = whenTransferred[oldSupernodeID];
|
||||
|
||||
// We want to set the superarc and hyperparent. At this point, supernodes fall into four groups:
|
||||
// I. Present in the hierarchical tree as supernodes No work required (not in newSupernodes)
|
||||
// II. Present in the hierarchical tree as regular nodes only Added as supernode. Hyperparent only needs to be set.
|
||||
// III. Not present in the hierarchical tree: attachment point Super/hyper parent stored in hierarchical IDs
|
||||
// IV. Not present, and not an attachment point Super/hyper parent stored in local IDs
|
||||
// Note that I. is already taken care of, so we test whether the supernode was previously in the hierarchical tree at all
|
||||
indexType storedRegularID = hierarchicalRegularID[oldSupernodeID];
|
||||
|
||||
// and set the regular ID in the hierarchical tree (even if it is already set)
|
||||
hierarchicalRegularID[oldSupernodeID] = newRegularID;
|
||||
|
||||
// now we sort out hyperparent
|
||||
if (!noSuchElement(storedRegularID))
|
||||
{ // present: II
|
||||
// if it isn't already a supernode, it is "only" a regular node
|
||||
if (newSupernodeID >= nOldSupernodes)
|
||||
{ // regular but not super
|
||||
// in this case, it already has a superparent (because it is already present in the tree as a regular node)
|
||||
// so we look up the relevant hyperparent
|
||||
hierarchicalTree.hyperparents[newSupernodeID] = hierarchicalTree.hyperparents[hierarchicalTree.superparents[storedRegularID]];
|
||||
// we set this to indicate that it's an attachment point
|
||||
hierarchicalTree.superarcs[newSupernodeID] = NO_SUCH_ELEMENT;
|
||||
} // regular but not super
|
||||
} // present: actually II
|
||||
else
|
||||
{ // not present: III or IV
|
||||
// attachment point (III) or free point (IV)
|
||||
if (!noSuchElement(hierarchicalSuperparent[oldSupernodeID]))
|
||||
{ // attachment point
|
||||
// we've already captured the super-/hyper- parent in an earlier stage
|
||||
hierarchicalTree.superparents[newRegularID] = hierarchicalSuperparent[oldSupernodeID];
|
||||
hierarchicalTree.hyperparents[newSupernodeID] = hierarchicalHyperparent[oldSupernodeID];
|
||||
// and the superarc should indicate an attachment point
|
||||
hierarchicalTree.superarcs[newSupernodeID] = NO_SUCH_ELEMENT;
|
||||
} // attachment point
|
||||
// otherwise, we have a brand new free supernode, which is it's own superparent
|
||||
else
|
||||
{ // free point
|
||||
// this is a supernode that was never in the hierarchical tree in the first place
|
||||
// it is its own superparent, and has a new hyperparent in old supernode IDs (often itself)
|
||||
// and can use that to look up the new hyperID
|
||||
indexType hierarchicalHyperparentOldSuperID = hierarchicalHyperparent[oldSupernodeID];
|
||||
indexType hierarchicalHyperparentNewHyperID = hierarchicalHyperID[hierarchicalHyperparentOldSuperID];
|
||||
hierarchicalTree.hyperparents[newSupernodeID] = hierarchicalHyperparentNewHyperID;
|
||||
// since it is its own superparent, this is easy . . .
|
||||
hierarchicalTree.superparents[newRegularID] = newSupernodeID;
|
||||
|
||||
// now the hard part: fill in the superarc
|
||||
indexType hierarchicalHyperarcOldSuperID = hierarchicalHyperarc[hierarchicalHyperparentOldSuperID];
|
||||
indexType isAscendingHyperarc = isAscending(hierarchicalHyperarcOldSuperID) ? IS_ASCENDING : 0x0;
|
||||
hierarchicalHyperarcOldSuperID = maskedIndex(hierarchicalHyperarcOldSuperID);
|
||||
indexType hierarchicalHyperarcNewSuperID = hierarchicalSuperID[hierarchicalHyperarcOldSuperID];
|
||||
|
||||
// we have located each supernode on a hyperarc
|
||||
// and we have to work out the supernode each connects to
|
||||
// unfortunately, the attachment points complicate this compared to the old code
|
||||
// for sweeping later, we will set the # of superchildren, but we don't have that yet
|
||||
|
||||
// So the test will have to be the following:
|
||||
// i. the "neighbour" is the +1 index
|
||||
// ii. if the neighbour is off the end, we take the end of the hyperarc
|
||||
// iii. if the neighbour has flagged as an attachment point, we take the end of the hyperarc
|
||||
// iv. in all other cases, we take the neighbour
|
||||
// Note that we are saved some trouble by the fact that this code only applies to free points
|
||||
|
||||
// the superarc is now set by checking to see if the neighbour has the same hyperparent:
|
||||
// if it does, our superarc goes to the next element
|
||||
// if not (or we're at array end), we go to the hyperarc's target
|
||||
// NOTE: we will store the OLD superarc ID at this stage, since we need it to sort out regular arcs
|
||||
// this means we will have to add a final loop to reset to hierarchical IDs
|
||||
indexType neighbour = newSupernode+1;
|
||||
|
||||
// special case at end of array: map the old hyperarc ID to a new one
|
||||
if (neighbour >= newSupernodes.size())
|
||||
{ // end of array
|
||||
hierarchicalTree.superarcs[newSupernodeID] = hierarchicalHyperarcNewSuperID | isAscendingHyperarc;
|
||||
} // end of array
|
||||
else
|
||||
{ // not at the end of the array
|
||||
indexType nbrSuperID = newSupernodes[neighbour];
|
||||
|
||||
// immediately check for case iii. by looking at the hierarchicalSuperparent of the neighbour's old ID
|
||||
// if it's already set, it's because it's an attachment point
|
||||
if (!noSuchElement(hierarchicalSuperparent[nbrSuperID]))
|
||||
{ // attachment point
|
||||
hierarchicalTree.superarcs[newSupernodeID] = hierarchicalHyperarcNewSuperID | isAscendingHyperarc;
|
||||
} // attachment point
|
||||
else
|
||||
{ // not attachment point
|
||||
indexType nbrHyperparent = hierarchicalHyperparent[nbrSuperID];
|
||||
|
||||
// if they share a hyperparent, just take the neighbour
|
||||
if (nbrHyperparent == hierarchicalHyperparentOldSuperID)
|
||||
{ // shared hyperparent
|
||||
hierarchicalTree.superarcs[newSupernodeID] = hierarchicalSuperID[nbrSuperID] | isAscendingHyperarc;
|
||||
} // shared hyperparent
|
||||
// if not, take the target of the hyperarc
|
||||
else
|
||||
{ // not shared hyperparent
|
||||
hierarchicalTree.superarcs[newSupernodeID] = hierarchicalHyperarcNewSuperID | isAscendingHyperarc;
|
||||
} // not shared hyperparent
|
||||
} // not attachment point
|
||||
} // not at the end of the array
|
||||
} // free point
|
||||
} // attachment point (III) or free point (IV)
|
||||
} // per new supernode
|
||||
*/
|
||||
} // operator ()
|
||||
|
||||
private:
|
||||
vtkm::Id TheRound;
|
||||
vtkm::Id NumOldSupernodes;
|
||||
|
||||
}; // CopyNewHypernodes
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
147
vtkm/worklet/contourtree_distributed/tree_grafter/FindCriticalPointsFindLeafsWorklet.h
Normal file
147
vtkm/worklet/contourtree_distributed/tree_grafter/FindCriticalPointsFindLeafsWorklet.h
Normal file
@ -0,0 +1,147 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_find_critical_points_find_leafs_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_find_critical_points_find_leafs_worklet_h
|
||||
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
// Worklet used in TreeGrafter.FindCriticalPoints to flag the leafs
|
||||
class FindCriticalPointsFindLeafsWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using ControlSignature = void(
|
||||
FieldIn
|
||||
activeSuperarcs, // input iteration index. loop to one less than ContourTree->Supernodes.GetNumberOfValues()
|
||||
WholeArrayIn interiorForstIsNecessary, // input
|
||||
WholeArrayIn upNeighbour, // input
|
||||
WholeArrayIn downNeighbour, // input
|
||||
WholeArrayInOut supernodeType // output
|
||||
);
|
||||
|
||||
using ExecutionSignature = void(_1, _2, _3, _4, _5);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
FindCriticalPointsFindLeafsWorklet() {}
|
||||
|
||||
template <typename InFieldPortalType, typename InOutFieldPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::worklet::contourtree_augmented::EdgePair& activeSuperarc,
|
||||
const InFieldPortalType& isNecessaryPortal,
|
||||
const InFieldPortalType& upNeighbourPortal,
|
||||
const InFieldPortalType& downNeighbourPortal,
|
||||
const InOutFieldPortalType& supernodeTypePortal) const
|
||||
{ // operator ()
|
||||
// flag the leaves
|
||||
// per active superarc
|
||||
vtkm::Id lowEnd = activeSuperarc.first;
|
||||
vtkm::Id highEnd = activeSuperarc.second;
|
||||
|
||||
// if the low end thinks it ascends to the high end and does
|
||||
// not have a descent, then it must be a lower leaf, unless it's
|
||||
// necessary (i.e. an attachment)
|
||||
if ((supernodeTypePortal.Get(lowEnd) != vtkm::worklet::contourtree_augmented::IS_SADDLE) &&
|
||||
(upNeighbourPortal.Get(lowEnd) == highEnd) &&
|
||||
vtkm::worklet::contourtree_augmented::NoSuchElement(downNeighbourPortal.Get(lowEnd)) &&
|
||||
(!isNecessaryPortal.Get(lowEnd)))
|
||||
{
|
||||
supernodeTypePortal.Set(lowEnd, vtkm::worklet::contourtree_augmented::IS_LOWER_LEAF);
|
||||
}
|
||||
|
||||
// symmetrically for the high end
|
||||
if ((supernodeTypePortal.Get(highEnd) != vtkm::worklet::contourtree_augmented::IS_SADDLE) &&
|
||||
(downNeighbourPortal.Get(highEnd) == lowEnd) &&
|
||||
vtkm::worklet::contourtree_augmented::NoSuchElement(upNeighbourPortal.Get(highEnd)) &&
|
||||
(!isNecessaryPortal.Get(highEnd)))
|
||||
{
|
||||
supernodeTypePortal.Set(highEnd, vtkm::worklet::contourtree_augmented::IS_UPPER_LEAF);
|
||||
}
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
// flag the leaves
|
||||
for (indexType activeSuper = 0; activeSuper < activeSuperarcs.size(); activeSuper++)
|
||||
{ // per active superarc
|
||||
indexType lowEnd = activeSuperarcs[activeSuper].low, highEnd = activeSuperarcs[activeSuper].high;
|
||||
|
||||
// if the low end thinks it ascends to the high end and does not have a descent, then it must be a lower leaf, unless it's necessary (ie an attachment)
|
||||
if ((supernodeType[lowEnd] != IS_SADDLE) && (upNeighbour[lowEnd] == highEnd) && noSuchElement(downNeighbour[lowEnd]) && (!residue->isNecessary[lowEnd]))
|
||||
supernodeType[lowEnd] = IS_LOWER_LEAF;
|
||||
|
||||
// symmetrically for the high end
|
||||
if ((supernodeType[highEnd] != IS_SADDLE) && (downNeighbour[highEnd] == lowEnd) && noSuchElement(upNeighbour[highEnd]) && (!residue->isNecessary[highEnd]))
|
||||
supernodeType[highEnd] = IS_UPPER_LEAF;
|
||||
} // per active superarc
|
||||
|
||||
*/
|
||||
} // operator ()
|
||||
|
||||
}; // FindCriticalPointsFindLeafsWorklet
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
142
vtkm/worklet/contourtree_distributed/tree_grafter/FindCriticalPointsFindSaddlesWorklet.h
Normal file
142
vtkm/worklet/contourtree_distributed/tree_grafter/FindCriticalPointsFindSaddlesWorklet.h
Normal file
@ -0,0 +1,142 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_find_critical_points_find_saddles_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_find_critical_points_find_saddles_worklet_h
|
||||
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
// Worklet used in TreeGrafter.FindCriticalPoints to find and flag saddles
|
||||
class FindCriticalPointsFindSaddlesWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using ControlSignature = void(
|
||||
FieldIn
|
||||
activeSuperarcs, // input iteration index. loop to one less than ContourTree->Supernodes.GetNumberOfValues()
|
||||
WholeArrayIn interiorForstIsNecessary, // input
|
||||
WholeArrayIn upNeighbour, // input
|
||||
WholeArrayIn downNeighbour, // input
|
||||
WholeArrayOut supernodeType // output
|
||||
);
|
||||
|
||||
using ExecutionSignature = void(_1, _2, _3, _4, _5);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
FindCriticalPointsFindSaddlesWorklet() {}
|
||||
|
||||
template <typename InFieldPortalType, typename OutFieldPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::worklet::contourtree_augmented::EdgePair& activeSuperarc,
|
||||
const InFieldPortalType& isNecessaryPortal,
|
||||
const InFieldPortalType& upNeighbourPortal,
|
||||
const InFieldPortalType& downNeighbourPortal,
|
||||
const OutFieldPortalType& supernodeTypePortal) const
|
||||
{ // operator ()
|
||||
// per active superarc
|
||||
// retrieve the ends again
|
||||
vtkm::Id lowEnd = activeSuperarc.first;
|
||||
vtkm::Id highEnd = activeSuperarc.second;
|
||||
|
||||
// if the low end doesn't have the high end as the up neighbour, another arc succeeded in writing to it
|
||||
// which guarantees that it is a saddle (or an attachment - but we exclude that by testing it)
|
||||
if (!isNecessaryPortal.Get(lowEnd) && (upNeighbourPortal.Get(lowEnd) != highEnd))
|
||||
{
|
||||
supernodeTypePortal.Set(lowEnd, vtkm::worklet::contourtree_augmented::IS_SADDLE);
|
||||
}
|
||||
|
||||
// symmetrically for the high end
|
||||
if (!isNecessaryPortal.Get(highEnd) && (downNeighbourPortal.Get(highEnd) != lowEnd))
|
||||
{
|
||||
supernodeTypePortal.Set(highEnd, vtkm::worklet::contourtree_augmented::IS_SADDLE);
|
||||
}
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
// now test whether they match what we expect: if not, we've found a saddle
|
||||
for (indexType activeSuper = 0; activeSuper < activeSuperarcs.size(); activeSuper++)
|
||||
{ // per active superarc
|
||||
// retrieve the ends again
|
||||
indexType lowEnd = activeSuperarcs[activeSuper].low;
|
||||
indexType highEnd = activeSuperarcs[activeSuper].high;
|
||||
|
||||
// if the low end doesn't have the high end as the up neighbour, another arc succeeded in writing to it
|
||||
// which guarantees that it is a saddle (or an attachment - but we exclude that by testing it)
|
||||
if (!residue->isNecessary[lowEnd] && (upNeighbour[lowEnd] != highEnd))
|
||||
supernodeType[lowEnd] = IS_SADDLE;
|
||||
|
||||
// symmetrically for the high end
|
||||
if (!residue->isNecessary[highEnd] && (downNeighbour[highEnd] != lowEnd))
|
||||
supernodeType[highEnd] = IS_SADDLE;
|
||||
} // per active superarc
|
||||
*/
|
||||
} // operator ()
|
||||
|
||||
}; // FindCriticalPointsFindSaddlesWorklet
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
140
vtkm/worklet/contourtree_distributed/tree_grafter/FindCriticalPointsFindTerminalElementsWorklet.h
Normal file
140
vtkm/worklet/contourtree_distributed/tree_grafter/FindCriticalPointsFindTerminalElementsWorklet.h
Normal file
@ -0,0 +1,140 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_find_critical_points_find_terminal_elements_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_find_critical_points_find_terminal_elements_worklet_h
|
||||
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
// Worklet used in TreeGrafter.FindCriticalPoints to flag the terminal elements
|
||||
class FindCriticalPointsFindTerminalElementsWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using ControlSignature = void(
|
||||
FieldIn
|
||||
activeSuperarcs, // input iteration index. loop to one less than ContourTree->Supernodes.GetNumberOfValues()
|
||||
WholeArrayIn supernodeType, // input
|
||||
WholeArrayInOut upNeighbour, // output/input
|
||||
WholeArrayInOut downNeighbour // output/input
|
||||
);
|
||||
|
||||
using ExecutionSignature = void(_1, _2, _3, _4);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
FindCriticalPointsFindTerminalElementsWorklet() {}
|
||||
|
||||
template <typename InFieldPortalType, typename InOutFieldPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::worklet::contourtree_augmented::EdgePair& activeSuperarc,
|
||||
const InFieldPortalType& supernodeTypePortal,
|
||||
const InOutFieldPortalType& upNeighbourPortal,
|
||||
const InOutFieldPortalType& downNeighbourPortal
|
||||
|
||||
) const
|
||||
{ // operator ()
|
||||
// per active superarc
|
||||
vtkm::Id lowEnd = activeSuperarc.first;
|
||||
vtkm::Id highEnd = activeSuperarc.second;
|
||||
|
||||
// test to see whether the top end is critical
|
||||
if ((upNeighbourPortal.Get(lowEnd) == highEnd) &&
|
||||
(supernodeTypePortal.Get(highEnd) != vtkm::worklet::contourtree_augmented::IS_REGULAR))
|
||||
{
|
||||
upNeighbourPortal.Set(lowEnd,
|
||||
upNeighbourPortal.Get(lowEnd) |
|
||||
vtkm::worklet::contourtree_augmented::TERMINAL_ELEMENT);
|
||||
}
|
||||
// same for bottom end
|
||||
if ((downNeighbourPortal.Get(highEnd) == lowEnd) &&
|
||||
(supernodeTypePortal.Get(lowEnd) != vtkm::worklet::contourtree_augmented::IS_REGULAR))
|
||||
{
|
||||
downNeighbourPortal.Set(highEnd,
|
||||
downNeighbourPortal.Get(highEnd) |
|
||||
vtkm::worklet::contourtree_augmented::TERMINAL_ELEMENT);
|
||||
}
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
// one more pass to set terminal flags
|
||||
for (indexType activeSuper = 0; activeSuper < activeSuperarcs.size(); activeSuper++)
|
||||
{ // per active superarc
|
||||
indexType lowEnd = activeSuperarcs[activeSuper].low, highEnd = activeSuperarcs[activeSuper].high;
|
||||
|
||||
// test to see whether the top end is critical
|
||||
if ((upNeighbour[lowEnd] == highEnd) && (supernodeType[highEnd] != IS_REGULAR))
|
||||
upNeighbour[lowEnd] |= TERMINAL_ELEMENT;
|
||||
// same for bottom end
|
||||
if ((downNeighbour[highEnd] == lowEnd) && (supernodeType[lowEnd] != IS_REGULAR))
|
||||
downNeighbour[highEnd] |= TERMINAL_ELEMENT;
|
||||
} // per active superarc
|
||||
*/
|
||||
} // operator ()
|
||||
|
||||
}; // FindCriticalPointsFindTerminalElementsWorklet
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
146
vtkm/worklet/contourtree_distributed/tree_grafter/FindCriticalPointsSetUpDownNeighboursWorklet.h
Normal file
146
vtkm/worklet/contourtree_distributed/tree_grafter/FindCriticalPointsSetUpDownNeighboursWorklet.h
Normal file
@ -0,0 +1,146 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_find_critical_points_set_up_down_neighbours_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_find_critical_points_set_up_down_neighbours_worklet_h
|
||||
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
// In TreeGrafter.InitializeActiveSuperarcs set TreeGrafter.ActiveSuperarcs
|
||||
class FindCriticalPointsSetUpDownNeighboursWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using ControlSignature = void(
|
||||
FieldIn
|
||||
activeSuperarcs, // input iteration index. loop to one less than ContourTree->Supernodes.GetNumberOfValues()
|
||||
WholeArrayIn interiorForstIsNecessary, // input
|
||||
WholeArrayOut upNeighbour, // output
|
||||
WholeArrayOut downNeighbour, // output
|
||||
WholeArrayOut supernodeType // output
|
||||
);
|
||||
|
||||
using ExecutionSignature = void(_1, _2, _3, _4, _5);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
FindCriticalPointsSetUpDownNeighboursWorklet() {}
|
||||
|
||||
template <typename InFieldPortalType, typename OutFieldPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::worklet::contourtree_augmented::EdgePair& activeSuperarc,
|
||||
const InFieldPortalType& isNecessaryPortal,
|
||||
const OutFieldPortalType& upNeighbourPortal,
|
||||
const OutFieldPortalType& downNeighbourPortal,
|
||||
const OutFieldPortalType& supernodeTypePortal) const
|
||||
{ // operator ()
|
||||
// per active superarc
|
||||
// make local copies of the ends
|
||||
vtkm::Id lowEnd = activeSuperarc.first;
|
||||
vtkm::Id highEnd = activeSuperarc.second;
|
||||
|
||||
// set the up/down neighbours at each end
|
||||
upNeighbourPortal.Set(lowEnd, highEnd);
|
||||
downNeighbourPortal.Set(highEnd, lowEnd);
|
||||
|
||||
// and set criticality flags at both ends to attachment if they are necessary, regular otherwise
|
||||
vtkm::Id highType = isNecessaryPortal.Get(highEnd)
|
||||
? vtkm::worklet::contourtree_augmented::IS_ATTACHMENT
|
||||
: vtkm::worklet::contourtree_augmented::IS_REGULAR;
|
||||
vtkm::Id lowType = isNecessaryPortal.Get(lowEnd)
|
||||
? vtkm::worklet::contourtree_augmented::IS_ATTACHMENT
|
||||
: vtkm::worklet::contourtree_augmented::IS_REGULAR;
|
||||
|
||||
supernodeTypePortal.Set(lowEnd, lowType);
|
||||
supernodeTypePortal.Set(highEnd, highType);
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
// fill in the up/down neighbour arrays
|
||||
for (indexType activeSuper = 0; activeSuper < activeSuperarcs.size(); activeSuper++)
|
||||
{ // per active superarc
|
||||
// make local copies of the ends
|
||||
indexType lowEnd = activeSuperarcs[activeSuper].low;
|
||||
indexType highEnd = activeSuperarcs[activeSuper].high;
|
||||
|
||||
// set the up/down neighbours at each end
|
||||
upNeighbour[lowEnd] = highEnd;
|
||||
downNeighbour[highEnd] = lowEnd;
|
||||
|
||||
// and set criticality flags at both ends to attachment if they are necessary, regular otherwise
|
||||
indexType highType = residue->isNecessary[highEnd] ? IS_ATTACHMENT : IS_REGULAR;
|
||||
indexType lowType = residue->isNecessary[lowEnd] ? IS_ATTACHMENT : IS_REGULAR;
|
||||
|
||||
supernodeType[lowEnd] = lowType;
|
||||
supernodeType[highEnd] = highType;
|
||||
} // per active superarc
|
||||
*/
|
||||
} // operator ()
|
||||
|
||||
}; // FindCriticalPointsSetUpDownNeighboursWorklet
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -0,0 +1,289 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_get_hierarchical_ids_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_get_hierarchical_ids_worklet_h
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
// Worklet for retrieving correct Ids from hierarchical tree
|
||||
class GetHierarchicalIdsWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
// TODO: Need to decide for which we can use FieldIn/FieldOut instead of requiring transfer of the WholeArrayIn/Out
|
||||
using ControlSignature = void(
|
||||
// input (read-only) array
|
||||
FieldIn supernodes,
|
||||
|
||||
// reference (read-only) arrays
|
||||
FieldIn supernodeGlobalId,
|
||||
WholeArrayIn sortOrder,
|
||||
WholeArrayIn dataValue,
|
||||
FieldIn necessary,
|
||||
FieldIn above,
|
||||
FieldIn below,
|
||||
WholeArrayIn superparents,
|
||||
WholeArrayIn hyperparents,
|
||||
WholeArrayIn regular2Supernode,
|
||||
WholeArrayIn super2Hypernode,
|
||||
// Execution object to use the FindRegularByGlobal and FindSuperArcForUnknownNode for the hierarchical tree.
|
||||
ExecObject findRegularByGlobal,
|
||||
ExecObject findSuperArcForUnknownNode,
|
||||
|
||||
// output (write-only) arrays
|
||||
// NOTE: hierarchicalSuperId and hierarchicalHyperId are not always updated in the operator.
|
||||
// We, therfore, need to use FieldInOut to make sure the original value (typical NO_SUCH_ELEMTENT)
|
||||
// is not being overwritten (when just using FieldOut VTKm sets the value to 0)
|
||||
// TODO: We could potentially avoid the need for FieldInOut by always setting hierarchicalSuperId and hierarchicalHyperId to NO_SUCH_ELEMENT at the beginning
|
||||
FieldOut hierarchicalRegularId,
|
||||
FieldInOut hierarchicalSuperId,
|
||||
FieldInOut hierarchicalHyperId,
|
||||
FieldOut hierarchicalSuperparent,
|
||||
FieldOut hierarchicalHyperparent);
|
||||
|
||||
using ExecutionSignature =
|
||||
void(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
GetHierarchicalIdsWorklet() {}
|
||||
|
||||
// TODO: Discuss with Oliver when it's a ID, when it's a portal and when it's a reference
|
||||
template <typename InFieldPortalType,
|
||||
typename SortOrderPortalType,
|
||||
typename InFieldDataPortalType,
|
||||
typename FindRegularExecType,
|
||||
typename FindSuperExecType>
|
||||
VTKM_EXEC void operator()(
|
||||
// const vtkm::Id& supernode, // not used
|
||||
const vtkm::Id& oldSortId, // i.e, supernodes[supernode]
|
||||
const vtkm::Id&
|
||||
supernodeGlobalIdVal, // Depending on the mesh we may get a different fany array handle
|
||||
const SortOrderPortalType&
|
||||
sortOrder, // Depending on the mesh we may get a different fany array handle
|
||||
const InFieldDataPortalType& dataValues,
|
||||
const vtkm::Id& necessary,
|
||||
const vtkm::Id& upGlobalId, // = above[supernode]
|
||||
const vtkm::Id& dnGlobalId, // = below[supernode]
|
||||
const InFieldPortalType& superparents,
|
||||
const InFieldPortalType& hyperparents,
|
||||
const InFieldPortalType& regular2Supernode,
|
||||
const InFieldPortalType& super2Hypernode,
|
||||
const FindRegularExecType& findRegularByGlobal,
|
||||
const FindSuperExecType& findSuperArcForUnknownNode,
|
||||
vtkm::Id& hierarchicalRegularId,
|
||||
vtkm::Id& hierarchicalSuperId,
|
||||
vtkm::Id& hierarchicalHyperId,
|
||||
vtkm::Id& hierarchicalSuperparent,
|
||||
vtkm::Id& hierarchicalHyperparent) const
|
||||
{ // operator ()
|
||||
|
||||
// TODO: Need to check that this code is correct
|
||||
// TODO: Discuss with Oliver how to use the FindRegularByGlobal function
|
||||
vtkm::Id regularId = findRegularByGlobal.FindRegularByGlobal(supernodeGlobalIdVal);
|
||||
|
||||
// save the regular Id
|
||||
hierarchicalRegularId = regularId; // set return value
|
||||
|
||||
// Free supernode: if it was necessary, then it's potentially an attachment point
|
||||
if (vtkm::worklet::contourtree_augmented::NoSuchElement(regularId))
|
||||
// Super = NSE, Regular = NSE:
|
||||
{ // no such element regular or super
|
||||
// not marked as necessary: cannot be an attachment point
|
||||
if (!necessary)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// it was marked as necessary, but got regularised & therefore not a regular point in the parent
|
||||
// this means we are guaranteed that we have a valid up/down neighbour pair from our BRACT construction
|
||||
// and that the up/down neighbour pair are guaranteed to be at least regular in the hierarchical tree
|
||||
// vtkm::Id oldSortId = supernodes.Get(supernode);
|
||||
vtkm::Id oldRegularId = sortOrder.Get(oldSortId);
|
||||
auto dataValue = dataValues.Get(oldRegularId);
|
||||
|
||||
vtkm::Id upHierarchicalId = findRegularByGlobal.FindRegularByGlobal(upGlobalId);
|
||||
|
||||
vtkm::Id dnHierarchicalId = findRegularByGlobal.FindRegularByGlobal(dnGlobalId);
|
||||
|
||||
vtkm::Id superparentInHierarchy = findSuperArcForUnknownNode.FindSuperArcForUnknownNode(
|
||||
supernodeGlobalIdVal, dataValue, upHierarchicalId, dnHierarchicalId);
|
||||
hierarchicalSuperparent = superparentInHierarchy; // set return value
|
||||
hierarchicalHyperparent = hyperparents.Get(superparentInHierarchy); // set return value
|
||||
} // no such element regular or super
|
||||
else
|
||||
{ // regular Id exists
|
||||
// we want to know if the regular node has a superId. This is straightforward, since we have a lookup array
|
||||
vtkm::Id supernodeId = regular2Supernode.Get(regularId);
|
||||
vtkm::Id superparent = superparents.Get(regularId);
|
||||
|
||||
// if there is no superId yet, we will need to set one up
|
||||
if (vtkm::worklet::contourtree_augmented::NoSuchElement(supernodeId))
|
||||
{ // no supernode Id: regular but not super
|
||||
// We have a supernode in the lower level tree (which excludes boundary regular vertices from consideration)
|
||||
// This occurred AFTER regularisation, so either:
|
||||
// a) it was regularised, but is a boundary vertex and was therefore kept, or
|
||||
// b) it was not regularised, but is not critical once other blocks have been considered
|
||||
// In either case, it is now needed and must be inserted as an attachment point
|
||||
// Note that regularised interior attachment points are dealt with later
|
||||
// We assume as an invariant that all regular points in the hierarchical tree already have superparent correctly set
|
||||
// This means we know which superarc it belongs to, and therefore which hyperarc, so we take that as the insertion parent
|
||||
vtkm::Id hierSuperparent =
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(superparents.Get(regularId));
|
||||
// this is logically redundant since we won't use it, but it'll make debug easier
|
||||
hierarchicalSuperparent = hierSuperparent; // set return value
|
||||
hierarchicalHyperparent = hyperparents.Get(hierSuperparent); // set return value
|
||||
} // no supernode Id: regular but not super
|
||||
else
|
||||
{ // supernode Id exists
|
||||
// save the supernode Id
|
||||
hierarchicalSuperId = supernodeId; // Set return value
|
||||
|
||||
// we can also set the superparent & hyperparent at this point
|
||||
hierarchicalSuperparent = superparent; // set return value
|
||||
hierarchicalHyperparent = hyperparents.Get(supernodeId); // set return value
|
||||
|
||||
// now retrieve the hypernode Id (if any) & store it (even if it is already NO_SUCH_ELEMENT)
|
||||
hierarchicalHyperId = super2Hypernode.Get(supernodeId); // set return value
|
||||
} // supernode Id exists
|
||||
} // regular Id exists
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
// down-convert to a global ID
|
||||
// search in the hierarchy to find the regular ID
|
||||
indexType regularID = hierTree.FindRegularByGlobal(supernodeGlobalID[supernode]);
|
||||
hierarchicalRegularID[supernode] = regularID;
|
||||
|
||||
// Free supernode: if it was necessary, then it's potentially an attachment point
|
||||
if (noSuchElement(regularID))
|
||||
// Super = NSE, Regular = NSE:
|
||||
{ // no such element regular or super
|
||||
// not marked as necessary: cannot be an attachment point
|
||||
if (!residue->isNecessary[supernode])
|
||||
continue;
|
||||
|
||||
// it was marked as necessary, but got regularised & therefore not a regular point in the parent
|
||||
// this means we are guaranteed that we have a valid up/down neighbour pair from our BRACT construction
|
||||
// and that the up/down neighbour pair are guaranteed to be at least regular in the hierarchical tree
|
||||
indexType oldSortID = contourTree->supernodes[supernode];
|
||||
indexType oldRegularID = mesh->SortOrder(oldSortID);
|
||||
dataType dataValue = mesh->DataValue(oldRegularID);
|
||||
|
||||
indexType upGlobalID = residue->above[supernode];
|
||||
indexType upHierarchicalID = hierTree.FindRegularByGlobal(upGlobalID);
|
||||
|
||||
indexType dnGlobalID = residue->below[supernode];
|
||||
indexType dnHierarchicalID = hierTree.FindRegularByGlobal(dnGlobalID);
|
||||
|
||||
indexType superparentInHierarchy = hierTree.FindSuperArcForUnknownNode(supernodeGlobalID[supernode], dataValue, upHierarchicalID, dnHierarchicalID);
|
||||
hierarchicalSuperparent[supernode] = superparentInHierarchy;
|
||||
hierarchicalHyperparent[supernode] = hierTree.hyperparents[superparentInHierarchy];
|
||||
} // no such element regular or super
|
||||
else
|
||||
{ // regular ID exists
|
||||
// we want to know if the regular node has a superID. This is straightforward, since we have a lookup array
|
||||
indexType supernodeID = hierTree.regular2supernode[regularID];
|
||||
indexType superparent = hierTree.superparents[regularID];
|
||||
|
||||
// if there is no superID yet, we will need to set one up
|
||||
if (noSuchElement(supernodeID))
|
||||
{ // no supernode ID: regular but not super
|
||||
// We have a supernode in the lower level tree (which excludes boundary regular vertices from consideration)
|
||||
// This occurred AFTER regularisation, so either:
|
||||
// a) it was regularised, but is a boundary vertex and was therefore kept, or
|
||||
// b) it was not regularised, but is not critical once other blocks have been considered
|
||||
// In either case, it is now needed and must be inserted as an attachment point
|
||||
// Note that regularised interior attachment points are dealt with later
|
||||
// We assume as an invariant that all regular points in the hierarchical tree already have superparent correctly set
|
||||
// This means we know which superarc it belongs to, and therefore which hyperarc, so we take that as the insertion parent
|
||||
indexType hierSuperparent = maskedIndex(hierTree.superparents[regularID]);
|
||||
// this is logically redundant since we won't use it, but it'll make debug easier
|
||||
hierarchicalSuperparent[supernode] = hierSuperparent;
|
||||
hierarchicalHyperparent[supernode] = hierTree.hyperparents[hierSuperparent];
|
||||
} // no supernode ID: regular but not super
|
||||
else
|
||||
{ // supernode ID exists
|
||||
// save the supernode ID
|
||||
hierarchicalSuperID[supernode] = supernodeID;
|
||||
|
||||
// we can also set the superparent & hyperparent at this point
|
||||
hierarchicalSuperparent[supernode] = superparent;
|
||||
hierarchicalHyperparent[supernode] = hierTree.hyperparents[supernodeID];
|
||||
|
||||
// now retrieve the hypernode ID (if any) & store it (even if it is already NO_SUCH_ELEMENT)
|
||||
hierarchicalHyperID[supernode] = hierTree.super2hypernode[supernodeID];
|
||||
} // supernode ID exists
|
||||
} // regular ID exists
|
||||
} // per tree supernode
|
||||
*/
|
||||
} // operator ()
|
||||
|
||||
}; // BoundaryVerticiesPerSuperArcStepOneWorklet
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
126
vtkm/worklet/contourtree_distributed/tree_grafter/GraftInteriorForestsSetTransferIterationWorklet.h
Normal file
126
vtkm/worklet/contourtree_distributed/tree_grafter/GraftInteriorForestsSetTransferIterationWorklet.h
Normal file
@ -0,0 +1,126 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_graft_interior_forests_set_trandfer_iteration_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_graft_interior_forests_set_trandfer_iteration_worklet_h
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
/// Now set the transfer iteration for all attachment points
|
||||
/// If there were no supernodes to transfer, their types are all NO_SUCH_ELEMENT
|
||||
class GraftInteriorForestsSetTransferIterationWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
// NOTE: supernodeType is sized to ContourTree.Supernodes.GetNumberOfValues() so we can use it for our iteration
|
||||
// NOTE: for whenTransferred we neeed need FieldInOut type to avoid overwrite of existing value as not all values will be updated
|
||||
using ControlSignature = void(FieldIn supernodeType, // input
|
||||
FieldIn hierarchicalSuperId, // input
|
||||
FieldInOut whenTransferred // output
|
||||
);
|
||||
|
||||
using ExecutionSignature = void(_1, _2, _3);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
GraftInteriorForestsSetTransferIterationWorklet(const vtkm::Id& numTransferIterations)
|
||||
: NumTransferIterations(numTransferIterations)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_EXEC void operator()(const vtkm::Id& supernodeType,
|
||||
const vtkm::Id& hierarchicalSuperId,
|
||||
vtkm::Id& whenTransferred) const
|
||||
{ // operator ()
|
||||
if ((supernodeType == vtkm::worklet::contourtree_augmented::IS_ATTACHMENT) &&
|
||||
vtkm::worklet::contourtree_augmented::NoSuchElement(hierarchicalSuperId))
|
||||
{ // not a supernode in the hierarchical tree yet
|
||||
whenTransferred =
|
||||
(this->NumTransferIterations | vtkm::worklet::contourtree_augmented::IS_SUPERNODE);
|
||||
} // not a supernode in the hierarchical tree yet
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
// Now set the transfer iteration for all attachment points
|
||||
// If there were no supernodes to transfer, their types are all NO_SUCH_ELEMENT
|
||||
#pragma omp parallel for
|
||||
for (indexType supernode = 0; supernode < contourTree->supernodes.size(); supernode++)
|
||||
{ // per supernode
|
||||
// std::cout << "Supernode " << supernode << std::endl;
|
||||
if ((supernodeType[supernode] == IS_ATTACHMENT) && noSuchElement(hierarchicalSuperID[supernode]))
|
||||
{ // not a supernode in the hierarchical tree yet
|
||||
whenTransferred[supernode] = nTransferIterations | IS_SUPERNODE;
|
||||
} // not a supernode in the hierarchical tree yet
|
||||
} // per supernode
|
||||
*/
|
||||
} // operator ()
|
||||
|
||||
private:
|
||||
vtkm::Id NumTransferIterations;
|
||||
}; // BoundaryVerticiesPerSuperArcStepOneWorklet
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -0,0 +1,142 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_hypernode_when_comparator_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_hypernode_when_comparator_h
|
||||
|
||||
|
||||
#include <vtkm/cont/ExecutionObjectBase.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
/// Comparator used in TreeGrafter::ListNewHypernodes to sort the NewHypernodes arrays
|
||||
template <typename DeviceAdapter>
|
||||
class HyperNodeWhenComparatorImpl : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using IdArrayPortalType =
|
||||
typename vtkm::worklet::contourtree_augmented::IdArrayType::template ExecutionTypes<
|
||||
DeviceAdapter>::PortalConst;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
HyperNodeWhenComparatorImpl(const IdArrayPortalType& whenTransferredPortal)
|
||||
: WhenTransferredPortal(whenTransferredPortal)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_EXEC bool operator()(const vtkm::Id& leftSuperId, const vtkm::Id& rightSuperId) const
|
||||
{ // operator ()
|
||||
vtkm::Id maskedLeftWhen = vtkm::worklet::contourtree_augmented::MaskedIndex(
|
||||
this->WhenTransferredPortal.Get(leftSuperId));
|
||||
vtkm::Id maskedRightWhen = vtkm::worklet::contourtree_augmented::MaskedIndex(
|
||||
this->WhenTransferredPortal.Get(rightSuperId));
|
||||
|
||||
if (maskedLeftWhen < maskedRightWhen)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (maskedLeftWhen > maskedRightWhen)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// tie break on ID to make it canonical
|
||||
else
|
||||
{
|
||||
return (leftSuperId < rightSuperId);
|
||||
}
|
||||
|
||||
} // operator ()
|
||||
|
||||
private:
|
||||
IdArrayPortalType WhenTransferredPortal;
|
||||
|
||||
|
||||
}; // HyperNodeWhenComparator
|
||||
|
||||
|
||||
class HyperNodeWhenComparator : public vtkm::cont::ExecutionObjectBase
|
||||
{
|
||||
public:
|
||||
VTKM_CONT
|
||||
HyperNodeWhenComparator(const vtkm::worklet::contourtree_augmented::IdArrayType& whenTransferred)
|
||||
: WhenTransferred(whenTransferred)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename DeviceAdapter>
|
||||
VTKM_CONT HyperNodeWhenComparatorImpl<DeviceAdapter> PrepareForExecution(
|
||||
DeviceAdapter device,
|
||||
vtkm::cont::Token& token) const
|
||||
{
|
||||
return HyperNodeWhenComparatorImpl<DeviceAdapter>(
|
||||
this->WhenTransferred.PrepareForInput(device, token));
|
||||
}
|
||||
|
||||
private:
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& WhenTransferred;
|
||||
};
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -0,0 +1,329 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_identify_leaf_hyperarcs_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_identify_leaf_hyperarcs_worklet_h
|
||||
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
/// \brief Worklet implementing the TreeGrafter.IdentifyLeafHyperarcs function
|
||||
///
|
||||
/// At this stage, we have:
|
||||
/// i. hierarchicalRegularID set for any supernode stored at all in the parent
|
||||
/// ii. hierarchicalSuperID set for any supernode that is a supernode in the parent
|
||||
/// iii. hierarchicalHyperParent set for any attachment point
|
||||
/// iv. supernodeType set to indicate what type of supernode
|
||||
/// v. up/dn neighbours set for all supernodes
|
||||
///
|
||||
/// at the end of the chain collapse, the up/down neighbours define the start & end of the hyperarc
|
||||
/// one end may be a leaf, in which case we can transfer the hyperarc
|
||||
/// note that because we are grafting, we have a guarantee that they can't both be leaves
|
||||
/// we therefore:
|
||||
/// a. for leaves, determine whether up or down hyperarc, create hyperarc
|
||||
/// b. for regular vertices pointing to a leaf hyperarc, set superarc / hyperparent
|
||||
/// c. for other vertices, ignore
|
||||
class IdentifyLeafHyperarcsWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using ControlSignature = void(
|
||||
FieldIn
|
||||
activeSuperarcs, // input iteration index. loop to one less than ContourTree->Supernodes.GetNumberOfValues()
|
||||
WholeArrayIn supernodeType, // input
|
||||
WholeArrayIn upNeighbour, // input
|
||||
WholeArrayIn downNeighbour, // input
|
||||
WholeArrayOut hierarchicalHyperparent, //output
|
||||
WholeArrayOut hierarchicalHyperarcPortal, // output
|
||||
WholeArrayOut whenTransferredPortal // output
|
||||
);
|
||||
|
||||
using ExecutionSignature = void(_1, _2, _3, _4, _5, _6, _7);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
IdentifyLeafHyperarcsWorklet(const vtkm::Id& numTransferIterations)
|
||||
: NumTransferIterations(numTransferIterations)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename InFieldPortalType, typename OutFieldPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::worklet::contourtree_augmented::EdgePair& activeSuperarc,
|
||||
const InFieldPortalType supernodeTypePortal,
|
||||
const InFieldPortalType upNeighbourPortal,
|
||||
const InFieldPortalType downNeighbourPortal,
|
||||
const OutFieldPortalType& hierarchicalHyperparentPortal,
|
||||
const OutFieldPortalType& hierarchicalHyperarcPortal,
|
||||
const OutFieldPortalType& whenTransferredPortal) const
|
||||
{ // operator ()
|
||||
// per active superarc
|
||||
// retrieve the supernode IDs for the two ends
|
||||
vtkm::Id low = activeSuperarc.first;
|
||||
vtkm::Id high = activeSuperarc.second;
|
||||
|
||||
// test whether the top end is an upper leaf
|
||||
switch (supernodeTypePortal.Get(high))
|
||||
{ // switch on upper end
|
||||
case vtkm::worklet::contourtree_augmented::IS_UPPER_LEAF:
|
||||
{ // upper end is a leaf
|
||||
// in lower leaf rounds, never recognise these
|
||||
hierarchicalHyperparentPortal.Set(high, high);
|
||||
hierarchicalHyperarcPortal.Set(
|
||||
high, vtkm::worklet::contourtree_augmented::MaskedIndex(downNeighbourPortal.Get(high)));
|
||||
whenTransferredPortal.Set(
|
||||
high, this->NumTransferIterations | vtkm::worklet::contourtree_augmented::IS_HYPERNODE);
|
||||
break;
|
||||
} // upper end is a leaf
|
||||
case vtkm::worklet::contourtree_augmented::IS_REGULAR:
|
||||
{ // upper end is regular
|
||||
// notice that this is redundant, so will be set from both arcs
|
||||
// this is parallel safe, because it sets the same value anyway
|
||||
// testing would be more complex
|
||||
// find the up & down neighbours
|
||||
vtkm::Id upNbr =
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(upNeighbourPortal.Get(high));
|
||||
vtkm::Id downNbr =
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(downNeighbourPortal.Get(high));
|
||||
|
||||
// test the up neighbour first for leaf-hood
|
||||
// but only if the corresponding flag is true
|
||||
if (supernodeTypePortal.Get(upNbr) == vtkm::worklet::contourtree_augmented::IS_UPPER_LEAF)
|
||||
{ // up neighbour is an upper leaf
|
||||
hierarchicalHyperparentPortal.Set(high, upNbr);
|
||||
whenTransferredPortal.Set(
|
||||
high, this->NumTransferIterations | vtkm::worklet::contourtree_augmented::IS_SUPERNODE);
|
||||
} // up neighbour is an upper leaf
|
||||
// then the down neighbour (cannot both be true)
|
||||
else if (supernodeTypePortal.Get(downNbr) ==
|
||||
vtkm::worklet::contourtree_augmented::IS_LOWER_LEAF)
|
||||
{ // down neighbour is a lower leaf
|
||||
hierarchicalHyperparentPortal.Set(high, downNbr);
|
||||
whenTransferredPortal.Set(
|
||||
high, this->NumTransferIterations | vtkm::worklet::contourtree_augmented::IS_SUPERNODE);
|
||||
} // down neighbour is a lower leaf
|
||||
break;
|
||||
} // case: upper end is regular
|
||||
// all other cases do nothing
|
||||
case vtkm::worklet::contourtree_augmented::IS_SADDLE:
|
||||
case vtkm::worklet::contourtree_augmented::IS_ATTACHMENT:
|
||||
case vtkm::worklet::contourtree_augmented::IS_LOWER_LEAF:
|
||||
default:
|
||||
break;
|
||||
} // switch on upper end
|
||||
|
||||
// test whether the bottom end is a lower leaf
|
||||
switch (supernodeTypePortal.Get(low))
|
||||
{ // switch on lower end
|
||||
case vtkm::worklet::contourtree_augmented::IS_LOWER_LEAF:
|
||||
{ // lower end is a leaf
|
||||
hierarchicalHyperparentPortal.Set(low, low);
|
||||
hierarchicalHyperarcPortal.Set(
|
||||
low,
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(upNeighbourPortal.Get(low)) |
|
||||
vtkm::worklet::contourtree_augmented::IS_ASCENDING);
|
||||
whenTransferredPortal.Set(
|
||||
low, this->NumTransferIterations | vtkm::worklet::contourtree_augmented::IS_HYPERNODE);
|
||||
break;
|
||||
} // lower end is a leaf
|
||||
case vtkm::worklet::contourtree_augmented::IS_REGULAR:
|
||||
{ // lower end is regular
|
||||
// notice that this is redundant, so will be set from both arcs
|
||||
// this is parallel safe, because it sets the same value anyway
|
||||
// testing would be more complex
|
||||
// find the up & down neighbours
|
||||
vtkm::Id upNbr =
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(upNeighbourPortal.Get(low));
|
||||
vtkm::Id downNbr =
|
||||
vtkm::worklet::contourtree_augmented::MaskedIndex(downNeighbourPortal.Get(low));
|
||||
|
||||
// test the up neighbour first for leaf-hood
|
||||
if (supernodeTypePortal.Get(upNbr) == vtkm::worklet::contourtree_augmented::IS_UPPER_LEAF)
|
||||
{ // up neighbour is an upper leaf
|
||||
hierarchicalHyperparentPortal.Set(low, upNbr);
|
||||
whenTransferredPortal.Set(
|
||||
low, this->NumTransferIterations | vtkm::worklet::contourtree_augmented::IS_SUPERNODE);
|
||||
} // up neighbour is an upper leaf
|
||||
// then the down neighbour (cannot both be true)
|
||||
else if (supernodeTypePortal.Get(downNbr) ==
|
||||
vtkm::worklet::contourtree_augmented::IS_LOWER_LEAF)
|
||||
{ // down neighbour is a lower leaf
|
||||
hierarchicalHyperparentPortal.Set(low, downNbr);
|
||||
whenTransferredPortal.Set(
|
||||
low, this->NumTransferIterations | vtkm::worklet::contourtree_augmented::IS_SUPERNODE);
|
||||
} // down neighbour is a lower leaf
|
||||
break;
|
||||
} // lower end is regular
|
||||
// all other cases do nothing
|
||||
case vtkm::worklet::contourtree_augmented::IS_SADDLE:
|
||||
case vtkm::worklet::contourtree_augmented::IS_ATTACHMENT:
|
||||
case vtkm::worklet::contourtree_augmented::IS_UPPER_LEAF:
|
||||
default:
|
||||
break;
|
||||
} // switch on lower end
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
#pragma omp parallel for
|
||||
for (indexType activeSuper = 0; activeSuper < activeSuperarcs.size(); activeSuper++)
|
||||
{ // per active superarc
|
||||
// retrieve the supernode IDs for the two ends
|
||||
indexType low = activeSuperarcs[activeSuper].low;
|
||||
indexType high = activeSuperarcs[activeSuper].high;
|
||||
|
||||
// test whether the top end is an upper leaf
|
||||
switch (supernodeType[high])
|
||||
{ // switch on upper end
|
||||
case IS_UPPER_LEAF:
|
||||
{ // upper end is a leaf
|
||||
// in lower leaf rounds, never recognise these
|
||||
hierarchicalHyperparent[high] = high;
|
||||
hierarchicalHyperarc[high] = maskedIndex(downNeighbour[high]);
|
||||
whenTransferred[high] = nTransferIterations | IS_HYPERNODE;
|
||||
break;
|
||||
} // upper end is a leaf
|
||||
case IS_REGULAR:
|
||||
{ // upper end is regular
|
||||
// notice that this is redundant, so will be set from both arcs
|
||||
// this is parallel safe, because it sets the same value anyway
|
||||
// testing would be more complex
|
||||
// find the up & down neighbours
|
||||
indexType upNbr = maskedIndex(upNeighbour[high]);
|
||||
indexType downNbr = maskedIndex(downNeighbour[high]);
|
||||
|
||||
// test the up neighbour first for leaf-hood
|
||||
// but only if the corresponding flag is true
|
||||
if (supernodeType[upNbr] == IS_UPPER_LEAF)
|
||||
{ // up neighbour is an upper leaf
|
||||
hierarchicalHyperparent[high] = upNbr;
|
||||
whenTransferred[high] = nTransferIterations | IS_SUPERNODE;
|
||||
} // up neighbour is an upper leaf
|
||||
// then the down neighbour (cannot both be true)
|
||||
else if (supernodeType[downNbr] == IS_LOWER_LEAF)
|
||||
{ // down neighbour is a lower leaf
|
||||
hierarchicalHyperparent[high] = downNbr;
|
||||
whenTransferred[high] = nTransferIterations | IS_SUPERNODE;
|
||||
} // down neighbour is a lower leaf
|
||||
break;
|
||||
} // upper end is regular
|
||||
// all other cases do nothing
|
||||
case IS_SADDLE:
|
||||
case IS_ATTACHMENT:
|
||||
case IS_LOWER_LEAF:
|
||||
default:
|
||||
break;
|
||||
} // switch on upper end
|
||||
|
||||
// test whether the bottom end is a lower leaf
|
||||
switch (supernodeType[low])
|
||||
{ // switch on lower end
|
||||
case IS_LOWER_LEAF:
|
||||
{ // lower end is a leaf
|
||||
hierarchicalHyperparent[low] = low;
|
||||
hierarchicalHyperarc[low] = maskedIndex(upNeighbour[low]) | IS_ASCENDING;
|
||||
whenTransferred[low] = nTransferIterations | IS_HYPERNODE;
|
||||
break;
|
||||
} // lower end is a leaf
|
||||
case IS_REGULAR:
|
||||
{ // lower end is regular
|
||||
// notice that this is redundant, so will be set from both arcs
|
||||
// this is parallel safe, because it sets the same value anyway
|
||||
// testing would be more complex
|
||||
// find the up & down neighbours
|
||||
indexType upNbr = maskedIndex(upNeighbour[low]);
|
||||
indexType downNbr = maskedIndex(downNeighbour[low]);
|
||||
|
||||
// test the up neighbour first for leaf-hood
|
||||
if (supernodeType[upNbr] == IS_UPPER_LEAF)
|
||||
{ // up neighbour is an upper leaf
|
||||
hierarchicalHyperparent[low] = upNbr;
|
||||
whenTransferred[low] = nTransferIterations | IS_SUPERNODE;
|
||||
} // up neighbour is an upper leaf
|
||||
// then the down neighbour (cannot both be true)
|
||||
else if (supernodeType[downNbr] == IS_LOWER_LEAF)
|
||||
{ // down neighbour is a lower leaf
|
||||
hierarchicalHyperparent[low] = downNbr;
|
||||
whenTransferred[low] = nTransferIterations | IS_SUPERNODE;
|
||||
} // down neighbour is a lower leaf
|
||||
break;
|
||||
} // lower end is regular
|
||||
// all other cases do nothing
|
||||
case IS_SADDLE:
|
||||
case IS_ATTACHMENT:
|
||||
case IS_UPPER_LEAF:
|
||||
default:
|
||||
break;
|
||||
} // switch on lower end
|
||||
} // per active superarc
|
||||
*/
|
||||
} // operator ()
|
||||
|
||||
private:
|
||||
vtkm::Id NumTransferIterations;
|
||||
|
||||
}; // IdentifyLeafHyperarcsWorklet
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -0,0 +1,119 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_init_active_superarc_id_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_init_active_superarc_id_worklet_h
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
// In TreeGrafter.InitializeActiveSuperarcs set the temporary variable activeSuperarcId
|
||||
class InitActiceSuperarcIdWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using ControlSignature = void(
|
||||
FieldIn
|
||||
superarcIndex, // input iteration index. loop to one less than ContourTree->Supernodes.GetNumberOfValues()
|
||||
WholeArrayIn contourtreeSuperarcs, // input
|
||||
WholeArrayIn interiorForestIsNecessary, // input
|
||||
FieldOut activeSuperarcId // output
|
||||
);
|
||||
|
||||
using ExecutionSignature = _4(_1, _2, _3);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
InitActiceSuperarcIdWorklet() {}
|
||||
|
||||
template <typename InFieldPortalType>
|
||||
VTKM_EXEC vtkm::Id operator()(const vtkm::Id& superarcIndex,
|
||||
const InFieldPortalType& contourtreeSuperarcPortal,
|
||||
const InFieldPortalType& isNecessaryPortal) const
|
||||
{ // operator ()
|
||||
// retrieve the target
|
||||
vtkm::Id superarcTo = vtkm::worklet::contourtree_augmented::MaskedIndex(
|
||||
contourtreeSuperarcPortal.Get(superarcIndex));
|
||||
// now set the flag for which ones are needed
|
||||
return (!isNecessaryPortal.Get(superarcIndex) || !isNecessaryPortal.Get(superarcTo));
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
// loop to one less, i.e. excluding null superarc from root
|
||||
for (indexType superarc = 0; superarc < contourTree->supernodes.size() - 1; superarc++)
|
||||
{ // per superarc
|
||||
// retrieve the target
|
||||
indexType superarcTo = maskedIndex(contourTree->superarcs[superarc]);
|
||||
|
||||
// now set the flag for which ones are needed
|
||||
activeSuperarcID[superarc] = !residue->isNecessary[superarc] || !residue->isNecessary[superarcTo];
|
||||
} // per superarc
|
||||
*/
|
||||
} // operator ()
|
||||
|
||||
}; // BoundaryVerticiesPerSuperArcStepOneWorklet
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -0,0 +1,164 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_init_active_superarcs_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_init_active_superarcs_worklet_h
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
// In TreeGrafter.InitializeActiveSuperarcs set TreeGrafter.ActiveSuperarcs
|
||||
class InitActiceSuperarcsWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using ControlSignature = void(
|
||||
FieldIn
|
||||
superarcIndex, // input iteration index. loop to one less than ContourTree->Supernodes.GetNumberOfValues()
|
||||
WholeArrayIn contourTreeSuperarcs, // input
|
||||
WholeArrayIn interiorForestIsNecessary, // input
|
||||
FieldIn activeSuperarcId, // input
|
||||
WholeArrayOut activeSuperarcs // output
|
||||
);
|
||||
|
||||
using ExecutionSignature = void(_1, _2, _3, _4, _5);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
InitActiceSuperarcsWorklet() {}
|
||||
|
||||
template <typename InFieldPortalType, typename SuperarcsPortalType>
|
||||
VTKM_EXEC void operator()(
|
||||
const vtkm::Id& from, // same as superarc
|
||||
const InFieldPortalType& contourTreeSuperarcsPortal, // ContourTree->Superarcs[from]
|
||||
const InFieldPortalType& isNecessaryPortal,
|
||||
const vtkm::Id& activeSuperarcId,
|
||||
const SuperarcsPortalType& activeSuperarcsPortal) const
|
||||
{ // operator ()
|
||||
// per active supernode
|
||||
// retrieve the supernode ID in the CT
|
||||
// retrieve the superarc target
|
||||
vtkm::Id unmaskedTo = contourTreeSuperarcsPortal.Get(from);
|
||||
vtkm::Id to = vtkm::worklet::contourtree_augmented::MaskedIndex(unmaskedTo);
|
||||
|
||||
// test to see whether the superarc needs to be transferred
|
||||
if (isNecessaryPortal.Get(from) && isNecessaryPortal.Get(to))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// retrieve the position (note that -1 converts partial sum to prefix sum, since all values were 1's originally)
|
||||
vtkm::Id activeSuperarc = activeSuperarcId - 1;
|
||||
|
||||
// if to is higher
|
||||
if (vtkm::worklet::contourtree_augmented::IsAscending(unmaskedTo))
|
||||
{ // to is higher
|
||||
activeSuperarcsPortal.Set(activeSuperarc,
|
||||
vtkm::worklet::contourtree_augmented::EdgePair(from, to));
|
||||
} // to is higher
|
||||
else
|
||||
{ // to is lower
|
||||
activeSuperarcsPortal.Set(activeSuperarc,
|
||||
vtkm::worklet::contourtree_augmented::EdgePair(to, from));
|
||||
} // to is lower
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
// loop does not include the terminal superarc: hence the -1
|
||||
for (indexType superarc = 0; superarc < contourTree->supernodes.size() - 1; superarc++)
|
||||
{ // per active supernode
|
||||
// retrieve the supernode ID in the CT
|
||||
indexType from = superarc;
|
||||
|
||||
// retrieve the superarc target
|
||||
indexType unmaskedTo = contourTree->superarcs[from];
|
||||
indexType to = maskedIndex(unmaskedTo);
|
||||
|
||||
// test to see whether the superarc needs to be transferred
|
||||
if (residue->isNecessary[from] && residue->isNecessary[to])
|
||||
continue;
|
||||
|
||||
// retrieve the position (note that -1 converts partial sum to prefix sum, since all values were 1's originally)
|
||||
indexType activeSuperarc = activeSuperarcID[superarc] - 1;
|
||||
|
||||
// if to is higher
|
||||
if (isAscending(unmaskedTo))
|
||||
{ // to is higher
|
||||
activeSuperarcs[activeSuperarc].low = from;
|
||||
activeSuperarcs[activeSuperarc].high = to;
|
||||
} // to is higher
|
||||
else
|
||||
{ // to is lower
|
||||
activeSuperarcs[activeSuperarc].high = from;
|
||||
activeSuperarcs[activeSuperarc].low = to;
|
||||
} // to is lower
|
||||
} // per active supernode
|
||||
*/
|
||||
} // operator ()
|
||||
|
||||
}; // BoundaryVerticiesPerSuperArcStepOneWorklet
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -0,0 +1,120 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_list_new_nodes_copy_ids_worklet_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_list_new_nodes_copy_ids_worklet_h
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
// In TreeGrafter.InitializeActiveSuperarcs set TreeGrafter.ActiveSuperarcs
|
||||
class ListNewNodesCopyIdsWorklet : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using ControlSignature = void(
|
||||
FieldIn interiorForestBractMeshIndices, // input mesh ids
|
||||
FieldIn globalIdsForBractMeshIndices, // input iteration index.
|
||||
ExecObject findRegularByGlobal, // input to findRegularByGlobal
|
||||
WholeArrayOut
|
||||
hierarchicalTreeId // output (need WholeArrayOut because globalIdsForBractMeshIndices is 1 smaller and need to avoid false resize
|
||||
);
|
||||
|
||||
using ExecutionSignature = void(_1, _2, _3, _4);
|
||||
using InputDomain = _1;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
ListNewNodesCopyIdsWorklet() {}
|
||||
|
||||
template <typename ExecObjectType, typename OutFieldPortalType>
|
||||
VTKM_EXEC void operator()(const vtkm::Id& meshId,
|
||||
const vtkm::Id& globalId,
|
||||
const ExecObjectType& findRegularByGlobal,
|
||||
const OutFieldPortalType& hierarchicalTreeIdPortal) const
|
||||
{ // operator ()
|
||||
// the lookup to mesh->GetGlobalIDFromMeshIndex is done outside the worklet
|
||||
// for all mesh ids so all we need to do here is call FindRegularByGlobal
|
||||
hierarchicalTreeIdPortal.Set(meshId, findRegularByGlobal.FindRegularByGlobal(globalId));
|
||||
|
||||
// In serial this worklet implements the following operation
|
||||
/*
|
||||
for (indexType bractVertex = 0; bractVertex < residue->bractMeshIndices.size(); bractVertex++)
|
||||
{ // per vertex in the bract
|
||||
// retrieve mesh ID
|
||||
indexType meshID = residue->bractMeshIndices[bractVertex];
|
||||
|
||||
// now convert to a global index
|
||||
indexType globalID = mesh->GetGlobalIDFromMeshIndex(meshID);
|
||||
// look that one up and store the result (NO_SUCH_ELEMENT is acceptable, but should never occur)
|
||||
hierarchicalTreeID[meshID] = hierarchicalTree.FindRegularByGlobal(globalID);
|
||||
} // per vertex in the bract
|
||||
|
||||
*/
|
||||
} // operator ()
|
||||
|
||||
}; // BoundaryVerticiesPerSuperArcStepOneWorklet
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -0,0 +1,90 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_new_hypernode_predicate_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_new_hypernode_predicate_h
|
||||
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
//Simple functor to subset a VTKm ArrayHandle
|
||||
class NewHypernodePredicate
|
||||
{
|
||||
public:
|
||||
VTKM_EXEC_CONT
|
||||
NewHypernodePredicate() {}
|
||||
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
bool operator()(const vtkm::Id& hierarchicalHyperarcValue) const
|
||||
{
|
||||
return !static_cast<bool>(
|
||||
vtkm::worklet::contourtree_augmented::NoSuchElement(hierarchicalHyperarcValue));
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -0,0 +1,89 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_new_node_predicate_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_new_node_predicate_h
|
||||
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
//Simple functor to subset a VTKm ArrayHandle
|
||||
class NewNodePredicate
|
||||
{
|
||||
public:
|
||||
VTKM_EXEC_CONT
|
||||
NewNodePredicate() {}
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
bool operator()(const vtkm::Id& hierarchicalTreeIdValue) const
|
||||
{
|
||||
return static_cast<bool>(
|
||||
vtkm::worklet::contourtree_augmented::NoSuchElement(hierarchicalTreeIdValue));
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -0,0 +1,142 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_permute_comparator_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_permute_comparator_h
|
||||
|
||||
|
||||
#include <vtkm/cont/ExecutionObjectBase.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
/// Comparator used in TreeGrafter::ListNewSupernodes to sort the NewSupernodes arrays
|
||||
template <typename DeviceAdapter>
|
||||
class PermuteComparatorImpl : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using IdArrayPortalType =
|
||||
typename vtkm::worklet::contourtree_augmented::IdArrayType::template ExecutionTypes<
|
||||
DeviceAdapter>::PortalConst;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
PermuteComparatorImpl(const IdArrayPortalType& lookupArrayPortal)
|
||||
: LookupArrayPortal(lookupArrayPortal)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_EXEC bool operator()(const vtkm::Id& i, const vtkm::Id& j) const
|
||||
{ // operator ()
|
||||
// primary sort on indexed value
|
||||
if (this->LookupArrayPortal.Get(i) < this->LookupArrayPortal.Get(j))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (this->LookupArrayPortal.Get(i) > this->LookupArrayPortal.Get(j))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// secondary sort on index
|
||||
if (i < j)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (j < i)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// fallback just in case
|
||||
return false;
|
||||
|
||||
} // operator ()
|
||||
|
||||
private:
|
||||
IdArrayPortalType LookupArrayPortal;
|
||||
|
||||
}; // PermuteComparator
|
||||
|
||||
|
||||
class PermuteComparator : public vtkm::cont::ExecutionObjectBase
|
||||
{
|
||||
public:
|
||||
VTKM_CONT
|
||||
PermuteComparator(const vtkm::worklet::contourtree_augmented::IdArrayType& lookupArray)
|
||||
: LookupArray(lookupArray)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename DeviceAdapter>
|
||||
VTKM_CONT PermuteComparatorImpl<DeviceAdapter> PrepareForExecution(DeviceAdapter device,
|
||||
vtkm::cont::Token& token) const
|
||||
{
|
||||
return PermuteComparatorImpl<DeviceAdapter>(this->LookupArray.PrepareForInput(device, token));
|
||||
}
|
||||
|
||||
private:
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& LookupArray;
|
||||
};
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -0,0 +1,216 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_supernode_when_comparator_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_supernode_when_comparator_h
|
||||
|
||||
|
||||
#include <vtkm/cont/ExecutionObjectBase.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
/// Comparator used in TreeGrafter::ListNewSupernodes to sort the NewSupernodes arrays
|
||||
template <typename DeviceAdapter>
|
||||
class SuperNodeWhenComparatorImpl : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using IdArrayPortalType =
|
||||
typename vtkm::worklet::contourtree_augmented::IdArrayType::template ExecutionTypes<
|
||||
DeviceAdapter>::PortalConst;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
SuperNodeWhenComparatorImpl(const IdArrayPortalType& whenTransferredPortal,
|
||||
const IdArrayPortalType& hierarchicalHyperparentPortal,
|
||||
const IdArrayPortalType& hierarchicalHyperIdPortal,
|
||||
const IdArrayPortalType& hierarchicalHyperarcPortal,
|
||||
const IdArrayPortalType& contourTreeSupernodesPortal,
|
||||
const IdArrayPortalType& supernodeTypePortal)
|
||||
: WhenTransferredPortal(whenTransferredPortal)
|
||||
, HierarchicalHyperparentPortal(hierarchicalHyperparentPortal)
|
||||
, HierarchicalHyperIdPortal(hierarchicalHyperIdPortal)
|
||||
, HierarchicalHyperarcPortal(hierarchicalHyperarcPortal)
|
||||
, ContourTreeSupernodesPortal(contourTreeSupernodesPortal)
|
||||
, SupernodeTypePortal(supernodeTypePortal)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_EXEC bool operator()(const vtkm::Id& leftSuperId, const vtkm::Id& rightSuperId) const
|
||||
{ // operator ()
|
||||
vtkm::Id maskedLeftWhen = vtkm::worklet::contourtree_augmented::MaskedIndex(
|
||||
this->WhenTransferredPortal.Get(leftSuperId));
|
||||
vtkm::Id maskedRightWhen = vtkm::worklet::contourtree_augmented::MaskedIndex(
|
||||
this->WhenTransferredPortal.Get(rightSuperId));
|
||||
if (maskedLeftWhen < maskedRightWhen)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (maskedLeftWhen > maskedRightWhen)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// tie break on hyperparent
|
||||
vtkm::Id leftHyperparent = this->HierarchicalHyperparentPortal.Get(leftSuperId);
|
||||
if (this->SupernodeTypePortal.Get(leftSuperId) !=
|
||||
vtkm::worklet::contourtree_augmented::IS_ATTACHMENT)
|
||||
{
|
||||
leftHyperparent = this->HierarchicalHyperIdPortal.Get(leftHyperparent);
|
||||
}
|
||||
vtkm::Id rightHyperparent = this->HierarchicalHyperparentPortal.Get(rightSuperId);
|
||||
// if it's an attachment, it's already been converted to the new ID. If not, we need to
|
||||
if (this->SupernodeTypePortal.Get(rightSuperId) !=
|
||||
vtkm::worklet::contourtree_augmented::IS_ATTACHMENT)
|
||||
{
|
||||
rightHyperparent = this->HierarchicalHyperIdPortal.Get(rightHyperparent);
|
||||
}
|
||||
if (leftHyperparent < rightHyperparent)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (leftHyperparent > rightHyperparent)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// OK, they have the same hyperparent. But there are two possibilities:
|
||||
// A. they are both attachment points, and the hyperparent is already in the hierarchical tree
|
||||
// B. neither is an attachment point (same hyperparent implies this)
|
||||
// In A., we can't look up ascent / descent, so we will sort only on sort index - ie always ascending
|
||||
// In B., we look up the hyperarc and use it to bias the sort
|
||||
bool sortAscending = true;
|
||||
// if it's not an attachment, pull the hyperparent in old supernode IDs and use to retrieve hyperarc, then take flag
|
||||
if (this->SupernodeTypePortal.Get(leftSuperId) !=
|
||||
vtkm::worklet::contourtree_augmented::IS_ATTACHMENT)
|
||||
{
|
||||
sortAscending = vtkm::worklet::contourtree_augmented::IsAscending(
|
||||
this->HierarchicalHyperarcPortal.Get(HierarchicalHyperparentPortal.Get(leftSuperId)));
|
||||
}
|
||||
|
||||
// if they have the same hyperparent and the hyperarc is ascending, use usual test. If not, invert
|
||||
if (sortAscending)
|
||||
{
|
||||
return (this->ContourTreeSupernodesPortal.Get(leftSuperId) <
|
||||
this->ContourTreeSupernodesPortal.Get(rightSuperId));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (this->ContourTreeSupernodesPortal.Get(leftSuperId) >
|
||||
ContourTreeSupernodesPortal.Get(rightSuperId));
|
||||
}
|
||||
} // operator ()
|
||||
|
||||
private:
|
||||
IdArrayPortalType WhenTransferredPortal;
|
||||
IdArrayPortalType HierarchicalHyperparentPortal;
|
||||
IdArrayPortalType HierarchicalHyperIdPortal;
|
||||
IdArrayPortalType HierarchicalHyperarcPortal;
|
||||
IdArrayPortalType ContourTreeSupernodesPortal;
|
||||
IdArrayPortalType SupernodeTypePortal;
|
||||
}; // SuperNodeWhenComparator
|
||||
|
||||
|
||||
class SuperNodeWhenComparator : public vtkm::cont::ExecutionObjectBase
|
||||
{
|
||||
public:
|
||||
VTKM_CONT
|
||||
SuperNodeWhenComparator(
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& whenTransferred,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& hierarchicalHyperparent,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& hierarchicalHyperId,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& hierarchicalHyperarc,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& contourTreeSupernodes,
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& supernodeType)
|
||||
: WhenTransferred(whenTransferred)
|
||||
, HierarchicalHyperparent(hierarchicalHyperparent)
|
||||
, HierarchicalHyperId(hierarchicalHyperId)
|
||||
, HierarchicalHyperarc(hierarchicalHyperarc)
|
||||
, ContourTreeSupernodes(contourTreeSupernodes)
|
||||
, SupernodeType(supernodeType)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename DeviceAdapter>
|
||||
VTKM_CONT SuperNodeWhenComparatorImpl<DeviceAdapter> PrepareForExecution(
|
||||
DeviceAdapter device,
|
||||
vtkm::cont::Token& token) const
|
||||
{
|
||||
return SuperNodeWhenComparatorImpl<DeviceAdapter>(
|
||||
this->WhenTransferred.PrepareForInput(device, token),
|
||||
this->HierarchicalHyperparent.PrepareForInput(device, token),
|
||||
this->HierarchicalHyperId.PrepareForInput(device, token),
|
||||
this->HierarchicalHyperarc.PrepareForInput(device, token),
|
||||
this->ContourTreeSupernodes.PrepareForInput(device, token),
|
||||
this->SupernodeType.PrepareForInput(device, token));
|
||||
}
|
||||
|
||||
private:
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& WhenTransferred;
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& HierarchicalHyperparent;
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& HierarchicalHyperId;
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& HierarchicalHyperarc;
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& ContourTreeSupernodes;
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& SupernodeType;
|
||||
};
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -0,0 +1,130 @@
|
||||
//============================================================================
|
||||
// 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_worklet_contourtree_distributed_tree_grafter_superarc_was_transferred_predicate_h
|
||||
#define vtk_m_worklet_contourtree_distributed_tree_grafter_superarc_was_transferred_predicate_h
|
||||
|
||||
|
||||
#include <vtkm/cont/ExecutionObjectBase.h>
|
||||
#include <vtkm/worklet/contourtree_augmented/Types.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace worklet
|
||||
{
|
||||
namespace contourtree_distributed
|
||||
{
|
||||
namespace tree_grafter
|
||||
{
|
||||
|
||||
// Uniary predicate used in TreeGrafter.CompressActiveArrays to decide which active superarcs to keep
|
||||
template <typename DeviceAdapter>
|
||||
class SuperarcWasTransferredPredicateImpl : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
public:
|
||||
using IdArrayPortalType =
|
||||
typename vtkm::worklet::contourtree_augmented::IdArrayType::template ExecutionTypes<
|
||||
DeviceAdapter>::PortalConst;
|
||||
|
||||
// Default Constructor
|
||||
VTKM_EXEC_CONT
|
||||
SuperarcWasTransferredPredicateImpl(const IdArrayPortalType& whenTransferredPortal)
|
||||
: WhenTransferredPortal(whenTransferredPortal)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_EXEC bool operator()(const vtkm::worklet::contourtree_augmented::EdgePair& superarc) const
|
||||
{ // operator ()
|
||||
// if either end is marked as transferred, the arc must be gone already
|
||||
return ((!vtkm::worklet::contourtree_augmented::NoSuchElement(
|
||||
this->WhenTransferredPortal.Get(superarc.first))) ||
|
||||
(!vtkm::worklet::contourtree_augmented::NoSuchElement(
|
||||
this->WhenTransferredPortal.Get(superarc.second))));
|
||||
|
||||
} // operator ()
|
||||
|
||||
private:
|
||||
IdArrayPortalType WhenTransferredPortal;
|
||||
|
||||
|
||||
}; // SuperarcWasTransferredPredicate
|
||||
|
||||
|
||||
class SuperarcWasTransferredPredicate : public vtkm::cont::ExecutionObjectBase
|
||||
{
|
||||
public:
|
||||
VTKM_CONT
|
||||
SuperarcWasTransferredPredicate(
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& whenTransferred)
|
||||
: WhenTransferred(whenTransferred)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename DeviceAdapter>
|
||||
VTKM_CONT SuperarcWasTransferredPredicateImpl<DeviceAdapter> PrepareForExecution(
|
||||
DeviceAdapter device,
|
||||
vtkm::cont::Token& token) const
|
||||
{
|
||||
return SuperarcWasTransferredPredicateImpl<DeviceAdapter>(
|
||||
this->WhenTransferred.PrepareForInput(device, token));
|
||||
}
|
||||
|
||||
private:
|
||||
const vtkm::worklet::contourtree_augmented::IdArrayType& WhenTransferred;
|
||||
};
|
||||
|
||||
} // namespace tree_grafter
|
||||
} // namespace contourtree_distributed
|
||||
} // namespace worklet
|
||||
} // namespace vtkm
|
||||
|
||||
#endif
|
@ -750,7 +750,7 @@ public:
|
||||
contourTree, meshSortOrder, saddlePeak);
|
||||
// Print the contour tree we computed
|
||||
std::cout << "Computed Contour Tree" << std::endl;
|
||||
vtkm::worklet::contourtree_augmented::PrintEdgePairArray(saddlePeak);
|
||||
vtkm::worklet::contourtree_augmented::PrintEdgePairArrayColumnLayout(saddlePeak);
|
||||
// Print the expected contour tree
|
||||
std::cout << "Expected Contour Tree" << std::endl;
|
||||
std::cout << " 0 12" << std::endl;
|
||||
@ -816,7 +816,7 @@ public:
|
||||
contourTree, meshSortOrder, saddlePeak);
|
||||
// Print the contour tree we computed
|
||||
std::cout << "Computed Contour Tree" << std::endl;
|
||||
vtkm::worklet::contourtree_augmented::PrintEdgePairArray(saddlePeak);
|
||||
vtkm::worklet::contourtree_augmented::PrintEdgePairArrayColumnLayout(saddlePeak);
|
||||
// Print the expected contour tree
|
||||
std::cout << "Expected Contour Tree" << std::endl;
|
||||
std::cout << " 0 67" << std::endl;
|
||||
@ -889,7 +889,7 @@ public:
|
||||
contourTree, meshSortOrder, saddlePeak);
|
||||
// Print the contour tree we computed
|
||||
std::cout << "Computed Contour Tree" << std::endl;
|
||||
vtkm::worklet::contourtree_augmented::PrintEdgePairArray(saddlePeak);
|
||||
vtkm::worklet::contourtree_augmented::PrintEdgePairArrayColumnLayout(saddlePeak);
|
||||
// Print the expected contour tree
|
||||
std::cout << "Expected Contour Tree" << std::endl;
|
||||
std::cout << " 0 118" << std::endl;
|
||||
|
Loading…
Reference in New Issue
Block a user